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 deletePermissionsFromRoles(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);
184 if (log.isDebugEnabled()) {
185 log.debug("deletedpermissions(res,action,prin[]), success for "
186 + " res=" + res.toString()
187 + " action=" + action.toString()
188 + " oid=" + oid.toString()
189 + " perm=" + p.toString()
190 + " sids=" + sids.toString());
198 * @throws PermissionNotFoundException
199 * @throws PermissionException
201 //non-javadoc NOTE: this is a very destructive operation. it would remove all permissions
202 //to access given resource#action for ANY role including administrators
204 public void deletePermissions(CSpaceResource res, CSpaceAction action)
205 throws PermissionNotFoundException, PermissionException {
207 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
208 Permission p = SpringAuthorizationProvider.getPermission(action);
210 deletePermissionFromRole(oid, p, null);
211 if (log.isDebugEnabled()) {
212 log.debug("deletepermissions(res,action) success, "
213 + " res=" + res.toString()
214 + " action=" + action.toString()
215 + " oid=" + oid.toString()
216 + " perm=" + p.toString());
218 } catch (AclDataAccessException aex) {
219 log.debug("deletepermissions(res,action) failed,"
220 + " oid=" + oid.toString()
221 + " res=" + res.toString()
222 + " action=" + action.toString()
223 + " oid=" + oid.toString()
224 + " perm=" + p.toString(), aex);
225 throw new PermissionException(aex);
226 } catch (Exception ex) {
227 String msg = "deletepermissions(res,action,prin[]) failed,"
228 + " oid=" + oid.toString()
229 + " res=" + res.toString()
230 + " action=" + action.toString()
231 + " oid=" + oid.toString()
232 + " perm=" + p.toString();
233 if (log.isDebugEnabled()) {
236 if (ex instanceof PermissionException) {
237 throw (PermissionException) ex;
239 throw new PermissionException(msg, ex);
247 * @throws PermissionNotFoundException
248 * @throws PermissionException
250 //non-javadoc NOTE: this is a very very destructive operation. it would remove all permissions
251 //to access given resource for ANY action for ANY role including administrators
253 public void deletePermissions(CSpaceResource res)
254 throws PermissionNotFoundException, PermissionException {
255 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
257 provider.getProviderAclService().deleteAcl(oid, true);
258 if (log.isDebugEnabled()) {
259 log.debug("deletepermissions(res) success, "
260 + " res=" + res.toString()
261 + " oid=" + oid.toString());
263 } catch (AclDataAccessException aex) {
264 log.debug("deletepermissions(res) failed,"
265 + " oid=" + oid.toString()
266 + " res=" + res.toString()
267 + " oid=" + oid.toString(), aex);
268 throw new PermissionException(aex);
269 } catch (Exception ex) {
270 String msg = "deletepermissions(res) failed,"
271 + " oid=" + oid.toString()
272 + " res=" + res.toString()
273 + " oid=" + oid.toString();
274 if (log.isDebugEnabled()) {
277 if (ex instanceof PermissionException) {
278 throw (PermissionException) ex;
280 throw new PermissionException(msg, ex);
285 * addPermission adds permission grant for given object identity for given permission
291 * @throws PermissionException
293 private void addPermissionToRole(ObjectIdentity oid, Permission permission,
294 Sid sid, boolean grant) throws PermissionException {
299 } catch (NotFoundException nfe) {
300 if (log.isDebugEnabled()) {
301 log.debug("addPermission: acl not found for oid=" + oid.toString()
302 + " perm=" + permission.toString()
303 + " sid=" + sid.toString()
307 acl = provider.getProviderAclService().createAcl(oid);
309 // Need to see if there is already an entry, so we do not duplicate (e.g.,
310 // when we run our permission-roles init more than once.
311 List<AccessControlEntry> aceEntries = acl.getEntries();
312 if (aceListHasEntry(aceEntries, permission, sid, grant)) {
313 if (log.isDebugEnabled()) {
314 log.debug("addPermission: Pre-existing acl for oid=" + oid.toString()
315 + " perm=" + permission.toString()
316 + " sid=" + sid.toString()
317 + " grant=" + grant);
321 acl.insertAce(acl.getEntries().size(), permission, sid, grant);
322 provider.getProviderAclService().updateAcl(acl);
324 if (log.isDebugEnabled()) {
325 log.debug("addPermission: added acl for oid=" + oid.toString()
326 + " perm=" + permission.toString()
327 + " sid=" + sid.toString()
328 + " grant=" + grant);
333 private boolean aceListHasEntry(List<AccessControlEntry> aceEntries, Permission permission,
334 Sid sid, boolean grant) {
335 for(AccessControlEntry entry : aceEntries) {
336 if(permission.equals(entry.getPermission())
337 && sid.equals(entry.getSid())
338 && grant == entry.isGranting()) {
346 * deletePermissions deletes given permission on given object id for given sid
351 //non-javadoc NOTE: if sid is null it would remove ACEs for all sid(s)
352 private void deletePermissionFromRole(ObjectIdentity oid, Permission permission, Sid sid) /** throws AclDataAccessException */
355 MutableAcl acl = getAcl(oid);
356 List<AccessControlEntry> acel = acl.getEntries();
357 int aces = acel.size();
358 if (log.isDebugEnabled()) {
359 log.debug("deletePermissions: for acl oid=" + oid.toString()
360 + " found " + aces + " aces");
362 ArrayList<Integer> foundAces = new ArrayList<Integer>();
363 Iterator iter = acel.listIterator();
364 //not possible to delete while iterating
365 while (iter.hasNext()) {
366 AccessControlEntry ace = (AccessControlEntry) iter.next();
368 if (ace.getSid().equals(sid)
369 && ace.getPermission().equals(permission)) {
373 if (ace.getPermission().equals(permission)) {
379 for (int j = foundAces.size() - 1; j >= 0; j--) {
380 //the following operation does not work while iterating in the while loop
381 acl.deleteAce(foundAces.get(j)); //autobox
383 provider.getProviderAclService().updateAcl(acl);
385 if (log.isDebugEnabled()) {
386 log.debug("deletePermissions: for acl oid=" + oid.toString()
387 + " deleted " + i + " aces");
391 private MutableAcl getAcl(ObjectIdentity oid) throws NotFoundException {
392 MutableAcl acl = null;
393 acl = (MutableAcl) provider.getProviderAclService().readAclById(oid);
394 if (log.isDebugEnabled()) {
395 log.debug("found acl for oid=" + oid.toString());