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;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.collectionspace.services.authorization.CSpaceAction;
32 import org.collectionspace.services.authorization.spi.CSpacePermissionManager;
33 import org.collectionspace.services.authorization.CSpaceResource;
34 import org.collectionspace.services.authorization.PermissionException;
35 import org.collectionspace.services.authorization.PermissionNotFoundException;
36 import org.springframework.security.acls.model.AccessControlEntry;
37 import org.springframework.security.acls.model.AclDataAccessException;
38 import org.springframework.security.acls.model.AlreadyExistsException;
39 import org.springframework.security.acls.model.MutableAcl;
40 import org.springframework.security.acls.model.NotFoundException;
41 import org.springframework.security.acls.model.ObjectIdentity;
42 import org.springframework.security.acls.model.Permission;
43 import org.springframework.security.acls.model.Sid;
44 import org.springframework.transaction.TransactionStatus;
47 * Manages permissions in Spring Security
50 public class SpringPermissionManager implements CSpacePermissionManager {
52 final Log log = LogFactory.getLog(SpringPermissionManager.class);
53 private SpringAuthorizationProvider provider;
55 SpringPermissionManager(SpringAuthorizationProvider provider) {
56 this.provider = provider;
60 * addPermissions adds permissions according to the given grant for given
61 * resource#action for each given principal
66 * @throws PermissionException
69 public void addPermissions(CSpaceResource res, CSpaceAction action, String[] principals, boolean grant)
70 throws PermissionException {
71 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
72 Sid[] sids = SpringAuthorizationProvider.getSids(principals);
73 Permission p = SpringAuthorizationProvider.getPermission(action);
74 TransactionStatus status = provider.beginTransaction("addPermssions");
76 //add permission for each sid
77 for (Sid sid : sids) {
79 addPermission(oid, p, sid, grant);
80 if (log.isDebugEnabled()) {
81 log.debug("addpermissions(res,action,prin[], grant), success for "
82 + " res=" + res.toString()
83 + " action=" + action.toString()
85 + " oid=" + oid.toString()
86 + " perm=" + p.toString()
87 + " sid=" + sid.toString());
90 } catch (AlreadyExistsException aex) {
91 if (log.isWarnEnabled()) {
92 log.warn("addpermissions(res,action,prin[], grant) failed,"
93 + " oid=" + oid.toString()
94 + " res=" + res.toString()
96 + " action=" + action.toString()
97 + " oid=" + oid.toString()
98 + " perm=" + p.toString(), aex);
101 } catch (Exception ex) {
102 String msg = "addpermissions(res,action,prin[], grant) failed,"
103 + " oid=" + oid.toString()
104 + " res=" + res.toString()
105 + " action=" + action.toString()
106 + " oid=" + oid.toString()
107 + " perm=" + p.toString()
109 if (log.isDebugEnabled()) {
112 //don't know what might be wrong...stop
113 provider.rollbackTransaction(status);
114 if (ex instanceof PermissionException) {
115 throw (PermissionException) ex;
117 throw new PermissionException(msg, ex);
120 provider.commitTransaction(status);
121 if (log.isDebugEnabled()) {
122 log.debug("addpermissions(res,action,prin[], grant), success for "
123 + " res=" + res.toString()
124 + " action=" + action.toString()
126 + " oid=" + oid.toString()
127 + " perm=" + p.toString()
128 + " sids=" + sids.toString());
133 * deletePermissions removes permisions for given resource#action for each given principal
137 * @throws PermissionNotFoundException
138 * @throws PermissionException
141 public void deletePermissions(CSpaceResource res, CSpaceAction action, String[] principals)
142 throws PermissionNotFoundException, PermissionException {
143 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
144 Sid[] sids = SpringAuthorizationProvider.getSids(principals);
145 Permission p = SpringAuthorizationProvider.getPermission(action);
146 TransactionStatus status = provider.beginTransaction("deletePermssions");
147 //delete permission for each sid
148 for (Sid sid : sids) {
150 deletePermissions(oid, p, sid);
151 if (log.isDebugEnabled()) {
152 log.debug("deletedpermissions(res,action,prin[]), success for "
153 + " res=" + res.toString()
154 + " action=" + action.toString()
155 + " oid=" + oid.toString()
156 + " perm=" + p.toString()
157 + " sid=" + sid.toString());
159 } catch (AclDataAccessException aex) {
160 if (log.isWarnEnabled()) {
161 log.debug("deletepermissions(res,action,prin[]) failed, "
162 + " oid=" + oid.toString()
163 + " res=" + res.toString()
164 + " action=" + action.toString()
165 + " oid=" + oid.toString()
166 + " perm=" + p.toString(), aex);
169 } catch (Exception ex) {
170 String msg = "deletepermissions(res,action,prin[]) failed,"
171 + " oid=" + oid.toString()
172 + " res=" + res.toString()
173 + " action=" + action.toString()
174 + " oid=" + oid.toString()
175 + " perm=" + p.toString();
176 if (log.isDebugEnabled()) {
179 //don't know what might be wrong...stop
180 provider.rollbackTransaction(status);
181 if (ex instanceof PermissionException) {
182 throw (PermissionException) ex;
184 throw new PermissionException(msg, ex);
187 provider.commitTransaction(status);
188 if (log.isDebugEnabled()) {
189 log.debug("deletedpermissions(res,action,prin[]), success for "
190 + " res=" + res.toString()
191 + " action=" + action.toString()
192 + " oid=" + oid.toString()
193 + " perm=" + p.toString()
194 + " sids=" + sids.toString());
202 * @throws PermissionNotFoundException
203 * @throws PermissionException
205 //non-javadoc NOTE: this is a very destructive operation. it would remove all permissions
206 //to access given resource#action for ANY role including administrators
208 public void deletePermissions(CSpaceResource res, CSpaceAction action)
209 throws PermissionNotFoundException, PermissionException {
210 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
211 Permission p = SpringAuthorizationProvider.getPermission(action);
212 TransactionStatus status = provider.beginTransaction("deletePermssions");
214 deletePermissions(oid, p, null);
215 provider.commitTransaction(status);
216 if (log.isDebugEnabled()) {
217 log.debug("deletepermissions(res,action) success, "
218 + " res=" + res.toString()
219 + " action=" + action.toString()
220 + " oid=" + oid.toString()
221 + " perm=" + p.toString());
223 } catch (AclDataAccessException aex) {
224 provider.rollbackTransaction(status);
225 log.debug("deletepermissions(res,action) failed,"
226 + " oid=" + oid.toString()
227 + " res=" + res.toString()
228 + " action=" + action.toString()
229 + " oid=" + oid.toString()
230 + " perm=" + p.toString(), aex);
231 throw new PermissionException(aex);
232 } catch (Exception ex) {
233 provider.rollbackTransaction(status);
234 String msg = "deletepermissions(res,action,prin[]) failed,"
235 + " oid=" + oid.toString()
236 + " res=" + res.toString()
237 + " action=" + action.toString()
238 + " oid=" + oid.toString()
239 + " perm=" + p.toString();
240 if (log.isDebugEnabled()) {
243 if (ex instanceof PermissionException) {
244 throw (PermissionException) ex;
246 throw new PermissionException(msg, ex);
254 * @throws PermissionNotFoundException
255 * @throws PermissionException
257 //non-javadoc NOTE: this is a very very destructive operation. it would remove all permissions
258 //to access given resource for ANY action for ANY role including administrators
260 public void deletePermissions(CSpaceResource res)
261 throws PermissionNotFoundException, PermissionException {
262 ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
263 TransactionStatus status = provider.beginTransaction("deletePermssion");
265 provider.getProviderAclService().deleteAcl(oid, true);
266 provider.commitTransaction(status);
267 if (log.isDebugEnabled()) {
268 log.debug("deletepermissions(res) success, "
269 + " res=" + res.toString()
270 + " oid=" + oid.toString());
272 } catch (AclDataAccessException aex) {
273 provider.rollbackTransaction(status);
274 log.debug("deletepermissions(res) failed,"
275 + " oid=" + oid.toString()
276 + " res=" + res.toString()
277 + " oid=" + oid.toString(), aex);
278 throw new PermissionException(aex);
279 } catch (Exception ex) {
280 provider.rollbackTransaction(status);
281 String msg = "deletepermissions(res) failed,"
282 + " oid=" + oid.toString()
283 + " res=" + res.toString()
284 + " oid=" + oid.toString();
285 if (log.isDebugEnabled()) {
288 if (ex instanceof PermissionException) {
289 throw (PermissionException) ex;
291 throw new PermissionException(msg, ex);
296 * addPermission adds permission grant for given object identity for given permission
302 * @throws PermissionException
304 private void addPermission(ObjectIdentity oid, Permission permission,
305 Sid sid, boolean grant) throws PermissionException {
310 } catch (NotFoundException nfe) {
311 if (log.isDebugEnabled()) {
312 log.debug("addPermission: acl not found for oid=" + oid.toString()
313 + " perm=" + permission.toString()
314 + " sid=" + sid.toString()
318 acl = provider.getProviderAclService().createAcl(oid);
320 acl.insertAce(acl.getEntries().size(), permission, sid, grant);
321 provider.getProviderAclService().updateAcl(acl);
323 if (log.isDebugEnabled()) {
324 log.debug("addPermission: added acl for oid=" + oid.toString()
325 + " perm=" + permission.toString()
326 + " sid=" + sid.toString()
327 + " grant=" + grant);
332 * deletePermissions deletes given permission on given object id for given sid
337 //non-javadoc NOTE: if sid is null it would remove ACEs for all sid(s)
338 private void deletePermissions(ObjectIdentity oid, Permission permission, Sid sid) /** throws AclDataAccessException */
341 MutableAcl acl = getAcl(oid);
342 List<AccessControlEntry> acel = acl.getEntries();
343 int aces = acel.size();
344 if (log.isDebugEnabled()) {
345 log.debug("deletePermissions: for acl oid=" + oid.toString()
346 + " found " + aces + " aces");
348 ArrayList<Integer> foundAces = new ArrayList<Integer>();
349 Iterator iter = acel.listIterator();
350 //not possible to delete while iterating
351 while (iter.hasNext()) {
352 AccessControlEntry ace = (AccessControlEntry) iter.next();
354 if (ace.getSid().equals(sid)
355 && ace.getPermission().equals(permission)) {
359 if (ace.getPermission().equals(permission)) {
365 for (int j = foundAces.size() - 1; j >= 0; j--) {
366 //the following operation does not work while iterating in the while loop
367 acl.deleteAce(foundAces.get(j)); //autobox
369 provider.getProviderAclService().updateAcl(acl);
371 if (log.isDebugEnabled()) {
372 log.debug("deletePermissions: for acl oid=" + oid.toString()
373 + " deleted " + i + " aces");
377 private MutableAcl getAcl(ObjectIdentity oid) throws NotFoundException {
378 MutableAcl acl = null;
379 acl = (MutableAcl) provider.getProviderAclService().readAclById(oid);
380 if (log.isDebugEnabled()) {
381 log.debug("found acl for oid=" + oid.toString());