2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.authorization.spring;
26 import java.util.ArrayList;
27 import java.util.Iterator;
28 import java.util.List;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
33 import org.collectionspace.services.authorization.CSpaceAction;
34 import org.collectionspace.services.authorization.spi.CSpacePermissionManager;
35 import org.collectionspace.services.authorization.CSpaceResource;
36 import org.collectionspace.services.authorization.PermissionException;
37 import org.collectionspace.services.authorization.PermissionNotFoundException;
39 import org.springframework.security.acls.model.AccessControlEntry;
40 import org.springframework.security.acls.model.AclDataAccessException;
41 import org.springframework.security.acls.model.AlreadyExistsException;
42 import org.springframework.security.acls.model.MutableAcl;
43 import org.springframework.security.acls.model.NotFoundException;
44 import org.springframework.security.acls.model.ObjectIdentity;
45 import org.springframework.security.acls.model.Permission;
46 import org.springframework.security.acls.model.Sid;
49 * Manages permissions in Spring Security
52 public class SpringPermissionManager implements CSpacePermissionManager {
54 final Log log = LogFactory.getLog(SpringPermissionManager.class);
55 private SpringAuthorizationProvider provider;
57 SpringPermissionManager(SpringAuthorizationProvider provider) {
58 this.provider = provider;
62 * addPermissions adds permissions according to the given grant for given
63 * resource#action for each given principal
68 * @throws PermissionException
71 public void addPermissionsToRoles(CSpaceResource res, CSpaceAction action, String[] principals, boolean grant)
72 throws PermissionException {
73 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
74 Sid[] sids = SpringAuthorizationProvider.getSids(principals);
75 Permission p = SpringAuthorizationProvider.getPermission(action);
77 //add permission for each sid
78 for (Sid sid : sids) {
80 addPermissionToRole(oid, p, sid, grant);
81 if (log.isDebugEnabled()) {
82 log.debug("addpermissions(res,action,prin[], grant), success for "
83 + " res=" + res.toString()
84 + " action=" + action.toString()
86 + " oid=" + oid.toString()
87 + " perm=" + p.toString()
88 + " sid=" + sid.toString());
91 } catch (AlreadyExistsException aex) {
92 if (log.isWarnEnabled()) {
93 log.warn("addpermissions(res,action,prin[], grant) failed,"
94 + " oid=" + oid.toString()
95 + " res=" + res.toString()
97 + " action=" + action.toString()
98 + " oid=" + oid.toString()
99 + " perm=" + p.toString(), aex);
101 throw new PermissionException("Permission already exists", aex);
102 } catch (Exception ex) {
103 String msg = "addpermissions(res,action,prin[], grant) failed,"
104 + " oid=" + oid.toString()
105 + " res=" + res.toString()
106 + " action=" + action.toString()
107 + " oid=" + oid.toString()
108 + " perm=" + p.toString()
110 if (log.isDebugEnabled()) {
113 //don't know what might be wrong...stop
114 if (ex instanceof PermissionException) {
115 throw (PermissionException) ex;
117 throw new PermissionException(msg, ex);
120 if (log.isDebugEnabled()) {
121 log.debug("addpermissions(res,action,prin[], grant), success for "
122 + " res=" + res.toString()
123 + " action=" + action.toString()
125 + " oid=" + oid.toString()
126 + " perm=" + p.toString()
127 + " sids=" + sids.toString());
132 * deletePermissions removes permisions for given resource#action for each given principal
136 * @throws PermissionNotFoundException
137 * @throws PermissionException
140 public void deletePermissionFromRoles(CSpaceResource res, CSpaceAction action, String[] principals)
141 throws PermissionNotFoundException, PermissionException {
142 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
143 Sid[] sids = SpringAuthorizationProvider.getSids(principals);
144 Permission p = SpringAuthorizationProvider.getPermission(action);
145 //delete permission for each sid
146 for (Sid sid : sids) {
148 deletePermissionFromRole(oid, p, sid);
149 if (log.isDebugEnabled()) {
150 log.debug("deletedpermissions(res,action,prin[]), success for "
151 + " res=" + res.toString()
152 + " action=" + action.toString()
153 + " oid=" + oid.toString()
154 + " perm=" + p.toString()
155 + " sid=" + sid.toString());
157 } catch (AclDataAccessException aex) {
158 if (log.isWarnEnabled()) {
159 log.debug("deletepermissions(res,action,prin[]) failed, "
160 + " oid=" + oid.toString()
161 + " res=" + res.toString()
162 + " action=" + action.toString()
163 + " oid=" + oid.toString()
164 + " perm=" + p.toString(), aex);
167 } catch (Exception ex) {
168 String msg = "deletepermissions(res,action,prin[]) failed,"
169 + " oid=" + oid.toString()
170 + " res=" + res.toString()
171 + " action=" + action.toString()
172 + " oid=" + oid.toString()
173 + " perm=" + p.toString();
174 if (log.isDebugEnabled()) {
177 //don't know what might be wrong...stop
178 if (ex instanceof PermissionException) {
179 throw (PermissionException) ex;
181 throw new PermissionException(msg, ex);
190 * @throws PermissionNotFoundException
191 * @throws PermissionException
193 //non-javadoc NOTE: this is a very destructive operation. it would remove all permissions
194 //to access given resource#action for ANY role including administrators
196 public void deletePermissions(CSpaceResource res, CSpaceAction action)
197 throws PermissionNotFoundException, PermissionException {
199 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
200 Permission p = SpringAuthorizationProvider.getPermission(action);
202 deletePermissionFromRole(oid, p, null);
203 if (log.isDebugEnabled()) {
204 log.debug("deletepermissions(res,action) success, "
205 + " res=" + res.toString()
206 + " action=" + action.toString()
207 + " oid=" + oid.toString()
208 + " perm=" + p.toString());
210 } catch (AclDataAccessException aex) {
211 log.debug("deletepermissions(res,action) failed,"
212 + " oid=" + oid.toString()
213 + " res=" + res.toString()
214 + " action=" + action.toString()
215 + " oid=" + oid.toString()
216 + " perm=" + p.toString(), aex);
217 throw new PermissionException(aex);
218 } catch (Exception ex) {
219 String msg = "deletepermissions(res,action,prin[]) failed,"
220 + " oid=" + oid.toString()
221 + " res=" + res.toString()
222 + " action=" + action.toString()
223 + " oid=" + oid.toString()
224 + " perm=" + p.toString();
225 if (log.isDebugEnabled()) {
228 if (ex instanceof PermissionException) {
229 throw (PermissionException) ex;
231 throw new PermissionException(msg, ex);
239 * @throws PermissionNotFoundException
240 * @throws PermissionException
242 //non-javadoc NOTE: this is a very very destructive operation. it would remove all permissions
243 //to access given resource for ANY action for ANY role including administrators
245 public void deletePermissions(CSpaceResource res)
246 throws PermissionNotFoundException, PermissionException {
247 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
249 provider.getProviderAclService().deleteAcl(oid, true);
250 if (log.isDebugEnabled()) {
251 log.debug("deletepermissions(res) success, "
252 + " res=" + res.toString()
253 + " oid=" + oid.toString());
255 } catch (AclDataAccessException aex) {
256 log.debug("deletepermissions(res) failed,"
257 + " oid=" + oid.toString()
258 + " res=" + res.toString()
259 + " oid=" + oid.toString(), aex);
260 throw new PermissionException(aex);
261 } catch (Exception ex) {
262 String msg = "deletepermissions(res) failed,"
263 + " oid=" + oid.toString()
264 + " res=" + res.toString()
265 + " oid=" + oid.toString();
266 if (log.isDebugEnabled()) {
269 if (ex instanceof PermissionException) {
270 throw (PermissionException) ex;
272 throw new PermissionException(msg, ex);
277 * addPermission adds permission grant for given object identity for given permission
283 * @throws PermissionException
285 private void addPermissionToRole(ObjectIdentity oid, Permission permission,
286 Sid sid, boolean grant) throws PermissionException {
291 } catch (NotFoundException nfe) {
292 if (log.isDebugEnabled()) {
293 log.debug("addPermission: acl not found for oid=" + oid.toString()
294 + " perm=" + permission.toString()
295 + " sid=" + sid.toString()
299 acl = provider.getProviderAclService().createAcl(oid);
301 // Need to see if there is already an entry, so we do not duplicate (e.g.,
302 // when we run our permission-roles init more than once.
303 List<AccessControlEntry> aceEntries = acl.getEntries();
304 if (aceListHasEntry(aceEntries, permission, sid, grant)) {
305 if (log.isDebugEnabled()) {
306 log.debug("addPermission: Pre-existing acl for oid=" + oid.toString()
307 + " perm=" + permission.toString()
308 + " sid=" + sid.toString()
309 + " grant=" + grant);
313 acl.insertAce(acl.getEntries().size(), permission, sid, grant);
314 provider.getProviderAclService().updateAcl(acl);
316 if (log.isDebugEnabled()) {
317 log.debug("addPermission: added acl for oid=" + oid.toString()
318 + " perm=" + permission.toString()
319 + " sid=" + sid.toString()
320 + " grant=" + grant);
325 private boolean aceListHasEntry(List<AccessControlEntry> aceEntries, Permission permission,
326 Sid sid, boolean grant) {
327 for(AccessControlEntry entry : aceEntries) {
328 if(permission.equals(entry.getPermission())
329 && sid.equals(entry.getSid())
330 && grant == entry.isGranting()) {
338 * deletePermissions deletes given permission on given object id for given sid
343 //non-javadoc NOTE: if sid is null it would remove ACEs for all sid(s)
344 private void deletePermissionFromRole(ObjectIdentity oid, Permission permission, Sid sid) /** throws AclDataAccessException */
347 MutableAcl acl = getAcl(oid);
348 List<AccessControlEntry> acel = acl.getEntries();
349 int aces = acel.size();
350 if (log.isDebugEnabled()) {
351 log.debug("deletePermissions: for acl oid=" + oid.toString()
352 + " found " + aces + " aces");
354 ArrayList<Integer> foundAces = new ArrayList<Integer>();
355 Iterator<AccessControlEntry> iter = acel.listIterator();
356 //not possible to delete while iterating
357 while (iter.hasNext()) {
358 AccessControlEntry ace = (AccessControlEntry) iter.next();
360 if (ace.getSid().equals(sid)
361 && ace.getPermission().equals(permission)) {
365 if (ace.getPermission().equals(permission)) {
372 boolean updateNeeded = false;
373 for (int j = foundAces.size() - 1; j >= 0; j--) {
374 //the following operation does not work while iterating in the while loop
375 acl.deleteAce(foundAces.get(j)); //autobox
380 provider.getProviderAclService().updateAcl(acl);
383 if (log.isDebugEnabled()) {
384 log.debug("deletePermissions: for acl oid=" + oid.toString()
385 + " deleted " + i + " aces");
389 private MutableAcl getAcl(ObjectIdentity oid) throws NotFoundException {
390 MutableAcl acl = null;
391 acl = (MutableAcl) provider.getProviderAclService().readAclById(oid);
392 if (log.isDebugEnabled()) {
393 log.debug("found acl for oid=" + oid.toString());