KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencrx > kernel > layer > model > SecurityContext


1 /*
2  * ====================================================================
3  * Project: opencrx, http://www.opencrx.org/
4  * Name: $Id: SecurityContext.java,v 1.15 2005/11/10 00:43:25 wfro Exp $
5  * Description: SecurityContext
6  * Revision: $Revision: 1.15 $
7  * Owner: CRIXP AG, Switzerland, http://www.crixp.com
8  * Date: $Date: 2005/11/10 00:43:25 $
9  * ====================================================================
10  *
11  * This software is published under the BSD license
12  * as listed below.
13  *
14  * Copyright (c) 2004, CRIXP Corp., Switzerland
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  *
21  * * Redistributions of source code must retain the above copyright
22  * notice, this list of conditions and the following disclaimer.
23  *
24  * * Redistributions in binary form must reproduce the above copyright
25  * notice, this list of conditions and the following disclaimer in
26  * the documentation and/or other materials provided with the
27  * distribution.
28  *
29  * * Neither the name of CRIXP Corp. nor the names of the contributors
30  * to openCRX may be used to endorse or promote products derived
31  * from this software without specific prior written permission
32  *
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
35  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
36  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
37  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
39  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
40  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
41  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
43  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46  * POSSIBILITY OF SUCH DAMAGE.
47  *
48  * ------------------
49  *
50  * This product includes software developed by the Apache Software
51  * Foundation (http://www.apache.org/).
52  *
53  * This product includes software developed by contributors to
54  * openMDX (http://www.openmdx.org/)
55  */

56 package org.opencrx.kernel.layer.model;
57
58 import java.util.HashMap JavaDoc;
59 import java.util.HashSet JavaDoc;
60 import java.util.Iterator JavaDoc;
61 import java.util.List JavaDoc;
62 import java.util.Map JavaDoc;
63 import java.util.Set JavaDoc;
64
65 import org.opencrx.kernel.generic.SecurityKeys;
66 import org.openmdx.application.log.AppLog;
67 import org.openmdx.base.exception.ServiceException;
68 import org.openmdx.compatibility.base.dataprovider.cci.AttributeSelectors;
69 import org.openmdx.compatibility.base.dataprovider.cci.AttributeSpecifier;
70 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject_1_0;
71 import org.openmdx.compatibility.base.dataprovider.cci.Orders;
72 import org.openmdx.compatibility.base.dataprovider.cci.RequestCollection;
73 import org.openmdx.compatibility.base.dataprovider.cci.SystemAttributes;
74 import org.openmdx.compatibility.base.naming.Path;
75 import org.openmdx.compatibility.base.query.FilterOperators;
76 import org.openmdx.compatibility.base.query.FilterProperty;
77 import org.openmdx.compatibility.base.query.Quantors;
78 import org.openmdx.kernel.exception.BasicException;
79
80 /**
81  * A security context manages the subjects of one subject segment.
82  */

83 public class SecurityContext {
84     
85     //-------------------------------------------------------------------------
86
public SecurityContext(
87         AccessControl_1 plugin,
88         Path realmIdentity
89     ) {
90         this.plugin = plugin;
91         this.realmIdentity = realmIdentity;
92         this.isActive = true;
93         if(System.getProperty(SecurityKeys.ENABLE_SECURITY_PROPERTY) != null) {
94             this.isActive = "true".equals(System.getProperty(SecurityKeys.ENABLE_SECURITY_PROPERTY));
95         }
96         if(!this.isActive) {
97             System.out.println("WARNING: AccessControl_1 is not active. Activate with system property " + SecurityKeys.ENABLE_SECURITY_PROPERTY + "=true. Default is true.");
98         }
99     }
100     
101     //-------------------------------------------------------------------------
102
private Set JavaDoc getAllSubgroups(
103         Path groupIdentity
104     ) throws ServiceException {
105         Set JavaDoc subgroups = new HashSet JavaDoc();
106         subgroups.add(
107             this.plugin.getQualifiedPrincipalName(groupIdentity)
108         );
109         for(Iterator JavaDoc i = this.groups.values().iterator(); i.hasNext(); ) {
110             DataproviderObject_1_0 group = (DataproviderObject_1_0)i.next();
111             if(group.values("isMemberOf").contains(groupIdentity)) {
112                 subgroups.addAll(
113                     this.getAllSubgroups(group.path())
114                 );
115                 subgroups.add(
116                     this.plugin.getQualifiedPrincipalName(group.path())
117                 );
118             }
119         }
120         return subgroups;
121     }
122     
123     //-------------------------------------------------------------------------
124
private Set JavaDoc getAllSupergroups(
125         Path groupIdentity
126     ) throws ServiceException {
127         Set JavaDoc supergroups = new HashSet JavaDoc();
128         DataproviderObject_1_0 group = (DataproviderObject_1_0)this.groups.get(groupIdentity);
129         if(group == null) {
130             AppLog.error("Can not find group in group list", "group=" + groupIdentity + "; groups=" + this.groups);
131         }
132         else {
133             supergroups.add(
134                 this.plugin.getQualifiedPrincipalName(groupIdentity)
135             );
136             for(Iterator JavaDoc i = group.values("isMemberOf").iterator(); i.hasNext(); ) {
137                 supergroups.addAll(
138                     this.getAllSupergroups((Path)i.next())
139                 );
140             }
141         }
142         return supergroups;
143     }
144     
145     //-------------------------------------------------------------------------
146
/**
147      * Assert the existence of the specified principal in the principals cache.
148      */

149     private void assertPrincipals(
150         String JavaDoc principalName,
151         boolean checkGroups
152     ) throws ServiceException {
153         RequestCollection delegation = this.plugin.getRunAsRootDelegation();
154         DataproviderObject_1_0 principal = null;
155         try {
156             principal = delegation.addGetRequest(
157                 this.realmIdentity.getDescendant(new String JavaDoc[]{"principal", principalName})
158             );
159             this.principals.put(
160                 principal.path().getBase(),
161                 principal
162             );
163         }
164         catch(ServiceException e) {
165             // Remove principal if not found
166
this.principals.remove(principalName);
167         }
168         AppLog.info("principal cache size", new Integer JavaDoc(this.principals.size()));
169         
170         if(checkGroups) {
171             // Cache principal groups
172
List JavaDoc principalGroups = delegation.addFindRequest(
173                 this.realmIdentity.getChild("principal"),
174                 new FilterProperty[]{
175                     new FilterProperty(
176                         Quantors.THERE_EXISTS,
177                         SystemAttributes.OBJECT_CLASS,
178                         FilterOperators.IS_IN,
179                         new String JavaDoc[]{"org:opencrx:security:realm1:PrincipalGroup"}
180                     )
181                 },
182                 AttributeSelectors.ALL_ATTRIBUTES,
183                 null,
184                 0,
185                 Integer.MAX_VALUE,
186                 Orders.ASCENDING
187             );
188             this.groups = new HashMap JavaDoc();
189             for(
190                 Iterator JavaDoc i = principalGroups.iterator();
191                 i.hasNext();
192             ) {
193                 DataproviderObject_1_0 principalGroup = (DataproviderObject_1_0)i.next();
194                 this.groups.put(
195                     principalGroup.path(),
196                     principalGroup
197                 );
198             }
199             
200             // Update group hierarchy
201
this.subgroups = new HashMap JavaDoc();
202             this.supergroups = new HashMap JavaDoc();
203             for(Iterator JavaDoc i = this.groups.keySet().iterator(); i.hasNext(); ) {
204                 Path groupIdentity = (Path)i.next();
205                 this.subgroups.put(
206                     this.plugin.getQualifiedPrincipalName(groupIdentity),
207                     this.getAllSubgroups(groupIdentity)
208                 );
209                 this.supergroups.put(
210                     this.plugin.getQualifiedPrincipalName(groupIdentity),
211                     this.getAllSupergroups(groupIdentity)
212                 );
213             }
214         }
215     }
216     
217     //-------------------------------------------------------------------------
218
protected DataproviderObject_1_0 getPrincipal(
219         String JavaDoc principalName
220     ) throws ServiceException {
221         
222         DataproviderObject_1_0 principal = this.principals == null
223             ? null
224             : (DataproviderObject_1_0)this.principals.get(principalName);
225
226         // Refresh subjects
227
if(
228             (principal == null) ||
229             (System.currentTimeMillis() > this.securityRealmCheckAt)
230         ) {
231             RequestCollection delegation = this.plugin.getRunAsRootDelegation();
232             DataproviderObject_1_0 realm = delegation.addGetRequest(
233                 this.realmIdentity,
234                 AttributeSelectors.ALL_ATTRIBUTES,
235                 new AttributeSpecifier[]{}
236             );
237             String JavaDoc securityRealmModifiedAt = (String JavaDoc)realm.values(SystemAttributes.MODIFIED_AT).get(0);
238             this.assertPrincipals(
239                 principalName,
240                 securityRealmModifiedAt.compareTo(this.securityRealmModifiedAt) != 0
241             );
242             this.securityRealmModifiedAt = securityRealmModifiedAt;
243             this.securityRealmCheckAt = System.currentTimeMillis() + SECURITY_REAL_CHECK_RATE;
244         }
245         
246         if(principal == null) {
247             principal = (DataproviderObject_1_0)this.principals.get(principalName);
248             if(principal == null) {
249                 AppLog.warning("principal not found", principalName);
250                 throw new ServiceException(
251                     BasicException.Code.DEFAULT_DOMAIN,
252                     BasicException.Code.NOT_FOUND,
253                     new BasicException.Parameter[]{
254                         new BasicException.Parameter("realm", this.realmIdentity),
255                         new BasicException.Parameter("principal", principalName)
256                     },
257                     "principal not found"
258                 );
259             }
260         }
261         return principal;
262     }
263
264     //-------------------------------------------------------------------------
265
protected DataproviderObject_1_0 getUserHome(
266         Path principalIdentity
267     ) throws ServiceException {
268         String JavaDoc providerName = principalIdentity.get(2);
269         String JavaDoc segmentName = principalIdentity.get(principalIdentity.size()-3);
270         RequestCollection delegation = this.plugin.getRunAsRootDelegation();
271         return delegation.addGetRequest(
272             new Path("xri:@openmdx:org.opencrx.kernel.home1/provider/" + providerName + "/segment/" + segmentName + "/userHome/" + principalIdentity.getBase()),
273             AttributeSelectors.ALL_ATTRIBUTES,
274             new AttributeSpecifier[]{}
275         );
276     }
277     
278     //-------------------------------------------------------------------------
279
protected DataproviderObject_1_0 getPrimaryGroup(
280         DataproviderObject_1_0 principal
281     ) throws ServiceException {
282         try {
283             DataproviderObject_1_0 userHome = this.getUserHome(principal.path());
284             Path userGroupIdentity = (Path)userHome.values("primaryGroup").get(0);
285             return userGroupIdentity == null
286                 ? this.getPrincipal(principal.path().getBase() + "." + SecurityKeys.USER_SUFFIX)
287                 : this.getPrincipal(userGroupIdentity.getBase());
288         }
289         // In case the principal does not have a user home
290
// which defines the primary group fallback to user principal
291
catch(Exception JavaDoc e) {
292             return this.getPrincipal(principal.path().getBase() + "." + SecurityKeys.USER_SUFFIX);
293         }
294     }
295     
296     //-------------------------------------------------------------------------
297
/**
298      * Get group principal for the given principal. The group principal is
299      * the assigned to the same subject as the given principal and is of type
300      * PrincipalGroup. The owningGroup of a openCRX object is a PrincipalGroup.
301      */

302     protected DataproviderObject_1_0 getGroup(
303         DataproviderObject_1_0 principal
304     ) throws ServiceException {
305         DataproviderObject_1_0 group = (DataproviderObject_1_0)this.groupMapping.get(principal.path());
306         if(group == null) {
307             RequestCollection delegation = this.plugin.getRunAsRootDelegation();
308             List JavaDoc owningGroups = delegation.addFindRequest(
309                 this.realmIdentity.getChild("principal"),
310                 new FilterProperty[]{
311                     new FilterProperty(
312                         Quantors.THERE_EXISTS,
313                         "subject",
314                         FilterOperators.IS_IN,
315                         new Object JavaDoc[]{
316                             principal.values("subject").get(0)
317                         }
318                     ),
319                     new FilterProperty(
320                         Quantors.THERE_EXISTS,
321                         SystemAttributes.OBJECT_CLASS,
322                         FilterOperators.IS_IN,
323                         new String JavaDoc[]{
324                             "org:opencrx:security:realm1:User"
325                         }
326                     )
327                 },
328                 AttributeSelectors.ALL_ATTRIBUTES,
329                 null,
330                 0,
331                 Integer.MAX_VALUE,
332                 Orders.ASCENDING
333             );
334             if(owningGroups.size() == 0) {
335                 throw new ServiceException(
336                     BasicException.Code.DEFAULT_DOMAIN,
337                     BasicException.Code.NOT_FOUND,
338                     new BasicException.Parameter[]{
339                         new BasicException.Parameter("principal", principal.path())
340                     },
341                     "Undefined user for principal"
342                 );
343             }
344             group = (DataproviderObject_1_0)owningGroups.iterator().next();
345             this.groupMapping.put(
346                 principal.path(),
347                 group
348             );
349         }
350         return group;
351     }
352     
353     //-------------------------------------------------------------------------
354
/**
355      * Return set of qualified names of subgroups of specified group subject.
356      */

357     protected Set JavaDoc getSubgroups(
358         String JavaDoc qualifiedPrincipalName
359     ) throws ServiceException {
360         Set JavaDoc subgroups = (Set JavaDoc)this.subgroups.get(qualifiedPrincipalName);
361         return subgroups == null
362             ? new HashSet JavaDoc()
363             : subgroups;
364     }
365     
366     //-------------------------------------------------------------------------
367
/**
368      * Return set of qualified names of subgroups of specified group subject.
369      */

370     protected Set JavaDoc getSupergroups(
371         String JavaDoc qualifiedPrincipalName
372     ) throws ServiceException {
373         Set JavaDoc supergroups = (Set JavaDoc)this.supergroups.get(qualifiedPrincipalName);
374         return supergroups == null
375             ? new HashSet JavaDoc()
376             : supergroups;
377     }
378     
379     //-------------------------------------------------------------------------
380
protected Set JavaDoc getAllowedPrincipals(
381         DataproviderObject_1_0 principal,
382         DataproviderObject_1_0 user,
383         short accessLevel
384     ) {
385         // GLOBAL
386
if(!this.isActive || (accessLevel == SecurityKeys.ACCESS_LEVEL_GLOBAL)) {
387             return null;
388         }
389         Set JavaDoc allowedPrincipals = new HashSet JavaDoc();
390         try {
391             // PRIVATE --> grant requesting user access to all owned objects
392
if(accessLevel >= SecurityKeys.ACCESS_LEVEL_PRIVATE) {
393                 allowedPrincipals.add(
394                     this.plugin.getQualifiedPrincipalName(principal.path())
395                 );
396                 allowedPrincipals.add(
397                     this.plugin.getQualifiedPrincipalName(user.path())
398                 );
399             }
400             // BASIC, DEEP --> all direct subgroups, supergroups
401
if((accessLevel == SecurityKeys.ACCESS_LEVEL_DEEP) || (accessLevel == SecurityKeys.ACCESS_LEVEL_BASIC)) {
402                 for(Iterator JavaDoc i = principal.values("isMemberOf").iterator(); i.hasNext(); ) {
403                     Path groupIdentity = (Path)i.next();
404                     allowedPrincipals.addAll(
405                         this.getSubgroups(this.plugin.getQualifiedPrincipalName(groupIdentity))
406                     );
407                 }
408                 // add all supergroups
409
for(Iterator JavaDoc i = principal.values("isMemberOf").iterator(); i.hasNext(); ) {
410                     Path groupIdentity = (Path)i.next();
411                     allowedPrincipals.addAll(
412                         this.getSupergroups(this.plugin.getQualifiedPrincipalName(groupIdentity))
413                     );
414                 }
415             }
416             // DEEP --> all subgroups of direct and supergroups
417
if(accessLevel == SecurityKeys.ACCESS_LEVEL_DEEP) {
418                 // add all subgroups of all supergroups
419
for(Iterator JavaDoc i = new HashSet JavaDoc(allowedPrincipals).iterator(); i.hasNext(); ) {
420                     allowedPrincipals.addAll(
421                         this.getSubgroups((String JavaDoc)i.next())
422                     );
423                 }
424             }
425         }
426         catch(ServiceException e) {
427             AppLog.warning("requesting principal can not be determined. Set of allowed principals = {}");
428             return allowedPrincipals;
429         }
430         // member of Root:Administrators --> access level global
431
return allowedPrincipals.contains(SecurityKeys.ROOT_ADMINISTRATORS_GROUP)
432             ? null
433             : allowedPrincipals;
434     }
435         
436     //-----------------------------------------------------------------------
437
// Variables
438
//-----------------------------------------------------------------------
439
private static final int SECURITY_REAL_CHECK_RATE = 10000;
440     
441     private final AccessControl_1 plugin;
442     private final Path realmIdentity;
443     
444     private Map JavaDoc principals = new HashMap JavaDoc();
445     private Map JavaDoc groups = null;
446     private boolean isActive = true;
447     private long securityRealmCheckAt = 0;
448     private String JavaDoc securityRealmModifiedAt = "";
449     
450     // Cache for group membership with qualified group name as key
451
// and list of subgroups as values.
452
private Map JavaDoc subgroups = null;
453     private Map JavaDoc supergroups = null;
454     
455     // principal -> principal group. Key is principal path,
456
// value is principal group path
457
private final Map JavaDoc groupMapping = new HashMap JavaDoc();
458
459 }
460
461 //--- End of File -----------------------------------------------------------
462
Popular Tags