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;
47 import org.springframework.transaction.TransactionStatus;
50 * Manages permissions in Spring Security
53 public class SpringPermissionManager implements CSpacePermissionManager {
55 final Log log = LogFactory.getLog(SpringPermissionManager.class);
56 private SpringAuthorizationProvider provider;
58 SpringPermissionManager(SpringAuthorizationProvider provider) {
59 this.provider = provider;
63 * addPermissions adds permissions according to the given grant for given
64 * resource#action for each given principal
69 * @throws PermissionException
72 public void addPermissions(CSpaceResource res, CSpaceAction action, String[] principals, boolean grant)
73 throws PermissionException {
74 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
75 Sid[] sids = SpringAuthorizationProvider.getSids(principals);
76 Permission p = SpringAuthorizationProvider.getPermission(action);
77 TransactionStatus status = provider.beginTransaction("addPermssions");
79 //add permission for each sid
80 for (Sid sid : sids) {
82 addPermission(oid, p, sid, grant);
83 if (log.isDebugEnabled()) {
84 log.debug("addpermissions(res,action,prin[], grant), success for "
85 + " res=" + res.toString()
86 + " action=" + action.toString()
88 + " oid=" + oid.toString()
89 + " perm=" + p.toString()
90 + " sid=" + sid.toString());
93 } catch (AlreadyExistsException aex) {
94 if (log.isWarnEnabled()) {
95 log.warn("addpermissions(res,action,prin[], grant) failed,"
96 + " oid=" + oid.toString()
97 + " res=" + res.toString()
99 + " action=" + action.toString()
100 + " oid=" + oid.toString()
101 + " perm=" + p.toString(), aex);
103 throw new PermissionException("Permission already exists", aex);
104 } catch (Exception ex) {
105 String msg = "addpermissions(res,action,prin[], grant) failed,"
106 + " oid=" + oid.toString()
107 + " res=" + res.toString()
108 + " action=" + action.toString()
109 + " oid=" + oid.toString()
110 + " perm=" + p.toString()
112 if (log.isDebugEnabled()) {
115 //don't know what might be wrong...stop
116 provider.rollbackTransaction(status);
117 if (ex instanceof PermissionException) {
118 throw (PermissionException) ex;
120 throw new PermissionException(msg, ex);
123 provider.commitTransaction(status);
124 if (log.isDebugEnabled()) {
125 log.debug("addpermissions(res,action,prin[], grant), success for "
126 + " res=" + res.toString()
127 + " action=" + action.toString()
129 + " oid=" + oid.toString()
130 + " perm=" + p.toString()
131 + " sids=" + sids.toString());
136 * deletePermissions removes permisions for given resource#action for each given principal
140 * @throws PermissionNotFoundException
141 * @throws PermissionException
144 public void deletePermissions(CSpaceResource res, CSpaceAction action, String[] principals)
145 throws PermissionNotFoundException, PermissionException {
146 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
147 Sid[] sids = SpringAuthorizationProvider.getSids(principals);
148 Permission p = SpringAuthorizationProvider.getPermission(action);
149 TransactionStatus status = provider.beginTransaction("deletePermssions");
150 //delete permission for each sid
151 for (Sid sid : sids) {
153 deletePermissions(oid, p, sid);
154 if (log.isDebugEnabled()) {
155 log.debug("deletedpermissions(res,action,prin[]), success for "
156 + " res=" + res.toString()
157 + " action=" + action.toString()
158 + " oid=" + oid.toString()
159 + " perm=" + p.toString()
160 + " sid=" + sid.toString());
162 } catch (AclDataAccessException aex) {
163 if (log.isWarnEnabled()) {
164 log.debug("deletepermissions(res,action,prin[]) failed, "
165 + " oid=" + oid.toString()
166 + " res=" + res.toString()
167 + " action=" + action.toString()
168 + " oid=" + oid.toString()
169 + " perm=" + p.toString(), aex);
172 } catch (Exception ex) {
173 String msg = "deletepermissions(res,action,prin[]) failed,"
174 + " oid=" + oid.toString()
175 + " res=" + res.toString()
176 + " action=" + action.toString()
177 + " oid=" + oid.toString()
178 + " perm=" + p.toString();
179 if (log.isDebugEnabled()) {
182 //don't know what might be wrong...stop
183 provider.rollbackTransaction(status);
184 if (ex instanceof PermissionException) {
185 throw (PermissionException) ex;
187 throw new PermissionException(msg, ex);
190 provider.commitTransaction(status);
191 if (log.isDebugEnabled()) {
192 log.debug("deletedpermissions(res,action,prin[]), success for "
193 + " res=" + res.toString()
194 + " action=" + action.toString()
195 + " oid=" + oid.toString()
196 + " perm=" + p.toString()
197 + " sids=" + sids.toString());
205 * @throws PermissionNotFoundException
206 * @throws PermissionException
208 //non-javadoc NOTE: this is a very destructive operation. it would remove all permissions
209 //to access given resource#action for ANY role including administrators
211 public void deletePermissions(CSpaceResource res, CSpaceAction action)
212 throws PermissionNotFoundException, PermissionException {
213 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
214 Permission p = SpringAuthorizationProvider.getPermission(action);
215 TransactionStatus status = provider.beginTransaction("deletePermssions");
217 deletePermissions(oid, p, null);
218 provider.commitTransaction(status);
219 if (log.isDebugEnabled()) {
220 log.debug("deletepermissions(res,action) success, "
221 + " res=" + res.toString()
222 + " action=" + action.toString()
223 + " oid=" + oid.toString()
224 + " perm=" + p.toString());
226 } catch (AclDataAccessException aex) {
227 provider.rollbackTransaction(status);
228 log.debug("deletepermissions(res,action) failed,"
229 + " oid=" + oid.toString()
230 + " res=" + res.toString()
231 + " action=" + action.toString()
232 + " oid=" + oid.toString()
233 + " perm=" + p.toString(), aex);
234 throw new PermissionException(aex);
235 } catch (Exception ex) {
236 provider.rollbackTransaction(status);
237 String msg = "deletepermissions(res,action,prin[]) failed,"
238 + " oid=" + oid.toString()
239 + " res=" + res.toString()
240 + " action=" + action.toString()
241 + " oid=" + oid.toString()
242 + " perm=" + p.toString();
243 if (log.isDebugEnabled()) {
246 if (ex instanceof PermissionException) {
247 throw (PermissionException) ex;
249 throw new PermissionException(msg, ex);
257 * @throws PermissionNotFoundException
258 * @throws PermissionException
260 //non-javadoc NOTE: this is a very very destructive operation. it would remove all permissions
261 //to access given resource for ANY action for ANY role including administrators
263 public void deletePermissions(CSpaceResource res)
264 throws PermissionNotFoundException, PermissionException {
265 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
266 TransactionStatus status = provider.beginTransaction("deletePermssion");
268 provider.getProviderAclService().deleteAcl(oid, true);
269 provider.commitTransaction(status);
270 if (log.isDebugEnabled()) {
271 log.debug("deletepermissions(res) success, "
272 + " res=" + res.toString()
273 + " oid=" + oid.toString());
275 } catch (AclDataAccessException aex) {
276 provider.rollbackTransaction(status);
277 log.debug("deletepermissions(res) failed,"
278 + " oid=" + oid.toString()
279 + " res=" + res.toString()
280 + " oid=" + oid.toString(), aex);
281 throw new PermissionException(aex);
282 } catch (Exception ex) {
283 provider.rollbackTransaction(status);
284 String msg = "deletepermissions(res) failed,"
285 + " oid=" + oid.toString()
286 + " res=" + res.toString()
287 + " oid=" + oid.toString();
288 if (log.isDebugEnabled()) {
291 if (ex instanceof PermissionException) {
292 throw (PermissionException) ex;
294 throw new PermissionException(msg, ex);
299 * addPermission adds permission grant for given object identity for given permission
305 * @throws PermissionException
307 private void addPermission(ObjectIdentity oid, Permission permission,
308 Sid sid, boolean grant) throws PermissionException {
313 } catch (NotFoundException nfe) {
314 if (log.isDebugEnabled()) {
315 log.debug("addPermission: acl not found for oid=" + oid.toString()
316 + " perm=" + permission.toString()
317 + " sid=" + sid.toString()
321 acl = provider.getProviderAclService().createAcl(oid);
323 // Need to see if there is already an entry, so we do not duplicate (e.g.,
324 // when we run our permission-roles init more than once.
325 List<AccessControlEntry> aceEntries = acl.getEntries();
326 if(aceListHasEntry(aceEntries, permission, sid, grant)) {
327 if (log.isDebugEnabled()) {
328 log.debug("addPermission: Pre-existing acl for oid=" + oid.toString()
329 + " perm=" + permission.toString()
330 + " sid=" + sid.toString()
331 + " grant=" + grant);
335 acl.insertAce(acl.getEntries().size(), permission, sid, grant);
336 provider.getProviderAclService().updateAcl(acl);
338 if (log.isDebugEnabled()) {
339 log.debug("addPermission: added acl for oid=" + oid.toString()
340 + " perm=" + permission.toString()
341 + " sid=" + sid.toString()
342 + " grant=" + grant);
347 private boolean aceListHasEntry(List<AccessControlEntry> aceEntries, Permission permission,
348 Sid sid, boolean grant) {
349 for(AccessControlEntry entry : aceEntries) {
350 if(permission.equals(entry.getPermission())
351 && sid.equals(entry.getSid())
352 && grant == entry.isGranting()) {
360 * deletePermissions deletes given permission on given object id for given sid
365 //non-javadoc NOTE: if sid is null it would remove ACEs for all sid(s)
366 private void deletePermissions(ObjectIdentity oid, Permission permission, Sid sid) /** throws AclDataAccessException */
369 MutableAcl acl = getAcl(oid);
370 List<AccessControlEntry> acel = acl.getEntries();
371 int aces = acel.size();
372 if (log.isDebugEnabled()) {
373 log.debug("deletePermissions: for acl oid=" + oid.toString()
374 + " found " + aces + " aces");
376 ArrayList<Integer> foundAces = new ArrayList<Integer>();
377 Iterator iter = acel.listIterator();
378 //not possible to delete while iterating
379 while (iter.hasNext()) {
380 AccessControlEntry ace = (AccessControlEntry) iter.next();
382 if (ace.getSid().equals(sid)
383 && ace.getPermission().equals(permission)) {
387 if (ace.getPermission().equals(permission)) {
393 for (int j = foundAces.size() - 1; j >= 0; j--) {
394 //the following operation does not work while iterating in the while loop
395 acl.deleteAce(foundAces.get(j)); //autobox
397 provider.getProviderAclService().updateAcl(acl);
399 if (log.isDebugEnabled()) {
400 log.debug("deletePermissions: for acl oid=" + oid.toString()
401 + " deleted " + i + " aces");
405 private MutableAcl getAcl(ObjectIdentity oid) throws NotFoundException {
406 MutableAcl acl = null;
407 acl = (MutableAcl) provider.getProviderAclService().readAclById(oid);
408 if (log.isDebugEnabled()) {
409 log.debug("found acl for oid=" + oid.toString());