]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
81324bc135c2589e9630dc9e0952adf1a2104dd8
[tmp/jakarta-migration.git] /
1 /**
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:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
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.
23  */
24 package org.collectionspace.services.authorization.spring;
25
26 import java.util.ArrayList;
27 import java.util.Iterator;
28 import java.util.List;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
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;
38
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;
48
49 /**
50  * Manages permissions in Spring Security
51  * @author 
52  */
53 public class SpringPermissionManager implements CSpacePermissionManager {
54
55     final Log log = LogFactory.getLog(SpringPermissionManager.class);
56     private SpringAuthorizationProvider provider;
57
58     SpringPermissionManager(SpringAuthorizationProvider provider) {
59         this.provider = provider;
60     }
61
62     /**
63      * addPermissions adds permissions according to the given grant for given
64      * resource#action for each given principal
65      * @param res
66      * @param action
67      * @param principals
68      * @param grant
69      * @throws PermissionException
70      */
71     @Override
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");
78
79         //add permission for each sid
80         for (Sid sid : sids) {
81             try {
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()
87                             + " grant=" + grant
88                             + " oid=" + oid.toString()
89                             + " perm=" + p.toString()
90                             + " sid=" + sid.toString());
91                 }
92
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()
98                             + " grant=" + grant
99                             + " action=" + action.toString()
100                             + " oid=" + oid.toString()
101                             + " perm=" + p.toString(), aex);
102                 }
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()
111                         + " grant=" + grant;
112                 if (log.isDebugEnabled()) {
113                     log.debug(msg, ex);
114                 }
115                 //don't know what might be wrong...stop
116                 provider.rollbackTransaction(status);
117                 if (ex instanceof PermissionException) {
118                     throw (PermissionException) ex;
119                 }
120                 throw new PermissionException(msg, ex);
121             }
122         }//rof
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()
128                     + " grant=" + grant
129                     + " oid=" + oid.toString()
130                     + " perm=" + p.toString()
131                     + " sids=" + sids.toString());
132         }
133     }
134
135     /**
136      * deletePermissions removes permisions for given resource#action for each given principal
137      * @param res
138      * @param action
139      * @param principals
140      * @throws PermissionNotFoundException
141      * @throws PermissionException
142      */
143     @Override
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) {
152             try {
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());
161                 }
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);
170                 }
171                 //keep going
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()) {
180                     log.debug(msg, ex);
181                 }
182                 //don't know what might be wrong...stop
183                 provider.rollbackTransaction(status);
184                 if (ex instanceof PermissionException) {
185                     throw (PermissionException) ex;
186                 }
187                 throw new PermissionException(msg, ex);
188             }
189         }
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());
198         }
199     }
200
201     /**
202      * deletePermissions
203      * @param res
204      * @param action
205      * @throws PermissionNotFoundException
206      * @throws PermissionException
207      */
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
210     @Override
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");
216         try {
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());
225             }
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()) {
244                 log.debug(msg, ex);
245             }
246             if (ex instanceof PermissionException) {
247                 throw (PermissionException) ex;
248             }
249             throw new PermissionException(msg, ex);
250         }
251
252     }
253
254     /**
255      * deletePermissions
256      * @param res
257      * @throws PermissionNotFoundException
258      * @throws PermissionException
259      */
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
262     @Override
263     public void deletePermissions(CSpaceResource res)
264             throws PermissionNotFoundException, PermissionException {
265         ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
266         TransactionStatus status = provider.beginTransaction("deletePermssion");
267         try {
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());
274             }
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()) {
289                 log.debug(msg, ex);
290             }
291             if (ex instanceof PermissionException) {
292                 throw (PermissionException) ex;
293             }
294             throw new PermissionException(msg, ex);
295         }
296     }
297
298     /**
299      * addPermission adds permission grant for given object identity for given permission
300      * for given sid
301      * @param oid
302      * @param permission
303      * @param sid
304      * @param grant
305      * @throws PermissionException
306      */
307     private void addPermission(ObjectIdentity oid, Permission permission,
308             Sid sid, boolean grant) throws PermissionException {
309         MutableAcl acl;
310
311         try {
312             acl = getAcl(oid);
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()
318                         + " grant=" + grant
319                         + " adding...");
320             }
321             acl = provider.getProviderAclService().createAcl(oid);
322         }
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);
332             }
333                 
334         } else {
335             acl.insertAce(acl.getEntries().size(), permission, sid, grant);
336             provider.getProviderAclService().updateAcl(acl);
337
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);
343             }
344         }
345     }
346     
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()) {
353                         return true;
354                 }
355         }
356         return false;
357     }
358
359     /**
360      * deletePermissions deletes given permission on given object id for given sid
361      * @param oid
362      * @param permission
363      * @param sid
364      */
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 */
367     {
368         int i = 0;
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");
375         }
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();
381             if (sid != null) {
382                 if (ace.getSid().equals(sid)
383                         && ace.getPermission().equals(permission)) {
384                     foundAces.add(i);
385                 }
386             } else {
387                 if (ace.getPermission().equals(permission)) {
388                     foundAces.add(i);
389                 }
390             }
391             i++;
392         }
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
396         }
397         provider.getProviderAclService().updateAcl(acl);
398
399         if (log.isDebugEnabled()) {
400             log.debug("deletePermissions: for acl oid=" + oid.toString()
401                     + " deleted " + i + " aces");
402         }
403     }
404
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());
410         }
411         return acl;
412     }
413 }