KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * ====================================================================
3  * Project: opencrx, http://www.opencrx.org/
4  * Name: $Id: AccessControl_1.java,v 1.50 2006/01/04 19:08:19 wfro Exp $
5  * Description: openCRX access control plugin
6  * Revision: $Revision: 1.50 $
7  * Owner: CRIXP AG, Switzerland, http://www.crixp.com
8  * Date: $Date: 2006/01/04 19:08:19 $
9  * ====================================================================
10  *
11  * This software is published under the BSD license
12  * as listed below.
13  *
14  * Copyright (c) 2004-2005, 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
57 package org.opencrx.kernel.layer.model;
58
59 import java.util.ArrayList JavaDoc;
60 import java.util.HashMap JavaDoc;
61 import java.util.HashSet JavaDoc;
62 import java.util.Iterator JavaDoc;
63 import java.util.List JavaDoc;
64 import java.util.ListIterator JavaDoc;
65 import java.util.Map JavaDoc;
66 import java.util.Set JavaDoc;
67
68 import org.opencrx.kernel.generic.OpenCrxException;
69 import org.opencrx.kernel.generic.SecurityKeys;
70 import org.openmdx.application.log.AppLog;
71 import org.openmdx.base.exception.ServiceException;
72 import org.openmdx.compatibility.base.application.configuration.Configuration;
73 import org.openmdx.compatibility.base.collection.SparseList;
74 import org.openmdx.compatibility.base.dataprovider.cci.AttributeSelectors;
75 import org.openmdx.compatibility.base.dataprovider.cci.AttributeSpecifier;
76 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject;
77 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject_1_0;
78 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderReply;
79 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest;
80 import org.openmdx.compatibility.base.dataprovider.cci.Dataprovider_1_0;
81 import org.openmdx.compatibility.base.dataprovider.cci.QualityOfService;
82 import org.openmdx.compatibility.base.dataprovider.cci.RequestCollection;
83 import org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader;
84 import org.openmdx.compatibility.base.dataprovider.cci.SharedConfigurationEntries;
85 import org.openmdx.compatibility.base.dataprovider.cci.SystemAttributes;
86 import org.openmdx.compatibility.base.dataprovider.layer.model.Standard_1;
87 import org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0;
88 import org.openmdx.compatibility.base.dataprovider.transport.adapter.Switch_1;
89 import org.openmdx.compatibility.base.naming.Path;
90 import org.openmdx.compatibility.base.query.FilterOperators;
91 import org.openmdx.compatibility.base.query.FilterProperty;
92 import org.openmdx.compatibility.base.query.Quantors;
93 import org.openmdx.kernel.exception.BasicException;
94 import org.openmdx.model1.accessor.basic.cci.ModelElement_1_0;
95 import org.openmdx.model1.accessor.basic.cci.Model_1_0;
96 import org.openmdx.uses.org.apache.commons.collections.map.LRUMap;
97
98 /**
99  * openCRX access control plugin. Implements the openCRX access control logic.
100  *
101  * This plugin is implemented as openMDX compatibility plugin. It will be
102  * migrated to a JMI plugin in one of the next versions.
103  */

104 public class AccessControl_1
105     extends Standard_1 {
106
107     //-------------------------------------------------------------------------
108
protected Path getUserIdentity(
109         Path accessPath,
110         String JavaDoc qualifiedPrincipalName
111     ) {
112         int pos = qualifiedPrincipalName.indexOf(":");
113         String JavaDoc segmentName = null;
114         String JavaDoc principalName = null;
115         if(pos < 0) {
116             System.err.println("FATAL: object has illegal formatted owner (<realm segment>:<subject name>): " + qualifiedPrincipalName + "; path=" + accessPath.toXri());
117             segmentName = "Root";
118             principalName = qualifiedPrincipalName;
119         }
120         else {
121             segmentName = qualifiedPrincipalName.substring(0, pos);
122             principalName = qualifiedPrincipalName.substring(pos+1);
123         }
124         // <= 1.7.1 compatibility. Principals with name 'admin'|'loader' must be
125
// mapped to 'admin-<segment>'
126
if(SecurityKeys.ADMIN_PRINCIPAL.equals(principalName) || SecurityKeys.LOADER_PRINCIPAL.equals(principalName)) {
127             principalName = principalName + SecurityKeys.ID_SEPARATOR + segmentName;
128         }
129         // <= 1.7.1 compatibility. Qualified principal name must have the
130
// format of a user principal
131
if(!principalName.endsWith(SecurityKeys.USER_SUFFIX)) {
132             principalName += "." + SecurityKeys.USER_SUFFIX;
133         }
134         Path principalIdentity = this.realmIdentity.getParent().getDescendant(
135             new String JavaDoc[]{segmentName, "principal", principalName}
136         );
137         return principalIdentity;
138     }
139
140     //-------------------------------------------------------------------------
141
protected Path getGroupIdentity(
142         Path accessPath,
143         String JavaDoc qualifiedPrincipalName
144     ) {
145         int pos = qualifiedPrincipalName.indexOf(":");
146         String JavaDoc segmentName = null;
147         String JavaDoc principalName = null;
148         if(pos < 0) {
149             System.err.println("FATAL: object has illegal formatted owner (<realm segment>:<subject name>): " + qualifiedPrincipalName + "; path=" + accessPath.toXri());
150             segmentName = "Root";
151             principalName = qualifiedPrincipalName;
152         }
153         else {
154             segmentName = qualifiedPrincipalName.substring(0, pos);
155             principalName = qualifiedPrincipalName.substring(pos+1);
156         }
157         Path principalIdentity = this.realmIdentity.getParent().getDescendant(
158             new String JavaDoc[]{segmentName, "principal", principalName}
159         );
160         return principalIdentity;
161     }
162
163     //-------------------------------------------------------------------------
164
protected String JavaDoc getQualifiedPrincipalName(
165         Path accessPath,
166         String JavaDoc principalName
167     ) {
168         return accessPath.get(4) + ":" + principalName;
169     }
170     
171     //-------------------------------------------------------------------------
172
protected String JavaDoc getQualifiedPrincipalName(
173         Path principalIdentity
174     ) {
175         return principalIdentity.get(6) + ":" + principalIdentity.getBase();
176     }
177     
178     //-------------------------------------------------------------------------
179
protected void completeOwningUserAndGroup(
180       ServiceHeader header,
181       DataproviderObject_1_0 object
182     ) throws ServiceException {
183         object.clearValues("owningUser");
184         object.clearValues("owningGroup");
185         if(object.values("owner").size() > 0) {
186             if((String JavaDoc)object.values("owner").get(0) == null) {
187                 AppLog.error("Values of attribute owner are corrupt. Element at index 0 (owning user) is missing. Fix the database", object);
188             }
189             else {
190                 object.values("owningUser").add(
191                     this.getUserIdentity(object.path(), (String JavaDoc)object.values("owner").get(0))
192                 );
193             }
194         }
195         for(int i = 1; i < object.values("owner").size(); i++) {
196             object.values("owningGroup").add(
197                 this.getGroupIdentity(object.path(), (String JavaDoc)object.values("owner").get(i))
198             );
199         }
200     }
201
202     //-------------------------------------------------------------------------
203
protected void completeObject(
204       ServiceHeader header,
205       DataproviderObject_1_0 object
206     ) throws ServiceException {
207         this.completeOwningUserAndGroup(
208             header,
209             object
210         );
211     }
212
213     //-------------------------------------------------------------------------
214
private void addToParentsCache(
215         DataproviderObject_1_0 object
216     ) {
217         if(
218             (object.getValues(SystemAttributes.OBJECT_CLASS) != null) &&
219             (object.values(SystemAttributes.OBJECT_CLASS).size() > 0)
220         ) {
221             this.cachedParents.put(
222                 object.path(),
223                 new DataproviderObject(object)
224             );
225         }
226         else {
227             AppLog.error("Missing object class. Object not added to cache", object.path());
228         }
229     }
230     
231     //-------------------------------------------------------------------------
232
protected DataproviderReply completeReply(
233       ServiceHeader header,
234       DataproviderReply reply
235     ) throws ServiceException {
236       for(int i = 0; i < reply.getObjects().length; i++) {
237           DataproviderObject object = reply.getObjects()[i];
238 // this.addToParentsCache(object);
239
this.completeObject(
240               header,
241               object
242           );
243       }
244       return reply;
245     }
246         
247     //-------------------------------------------------------------------------
248
protected boolean isPrincipalGroup(
249       DataproviderObject_1_0 object
250     ) throws ServiceException {
251         String JavaDoc objectClass = (String JavaDoc)object.values(SystemAttributes.OBJECT_CLASS).get(0);
252         return this.model.isSubtypeOf(
253             objectClass,
254             "org:opencrx:security:realm1:PrincipalGroup"
255         );
256     }
257
258     //-------------------------------------------------------------------------
259
protected boolean isSecureObject(
260       DataproviderObject_1_0 object
261     ) throws ServiceException {
262         String JavaDoc objectClass = (String JavaDoc)object.values(SystemAttributes.OBJECT_CLASS).get(0);
263         if(objectClass == null) {
264             AppLog.error("Undefined object class", object.path());
265             return true;
266         }
267         else {
268             return this.model.isSubtypeOf(
269                 objectClass,
270                 "org:opencrx:kernel:base:SecureObject"
271             );
272         }
273     }
274
275     //-------------------------------------------------------------------------
276
protected boolean isSecureObject(
277       ModelElement_1_0 type
278     ) throws ServiceException {
279         return this.model.isSubtypeOf(
280             type,
281             "org:opencrx:kernel:base:SecureObject"
282         );
283     }
284
285     //-------------------------------------------------------------------------
286
public RequestCollection getRunAsRootDelegation(
287     ) {
288         return new RequestCollection(
289             new ServiceHeader(SecurityKeys.ADMIN_PRINCIPAL + SecurityKeys.ID_SEPARATOR + "Root", null, false, new QualityOfService()),
290             this.router == null
291                 ? this.getDelegation()
292                 : this.router
293         );
294     }
295     
296     //-------------------------------------------------------------------------
297
/* (non-Javadoc)
298      * @see org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0#activate(short, org.openmdx.compatibility.base.application.configuration.Configuration, org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0)
299      */

300     public void activate(
301         short id,
302         Configuration configuration,
303         Layer_1_0 delegation
304     ) throws Exception JavaDoc {
305         super.activate(id, configuration, delegation);
306
307         // model
308
if(configuration.values(SharedConfigurationEntries.MODEL).size() > 0) {
309             this.model = (Model_1_0)configuration.values(SharedConfigurationEntries.MODEL).get(0);
310         }
311         else {
312             throw new ServiceException(
313                 BasicException.Code.DEFAULT_DOMAIN,
314                 BasicException.Code.INVALID_CONFIGURATION,
315                 null,
316                 "A model must be configured with options 'modelPackage' and 'packageImpl'"
317             );
318         }
319         
320         // realmIdentity
321
if(configuration.values(ConfigurationKeys.REALM_IDENTITY).size() > 0) {
322             this.realmIdentity = new Path((String JavaDoc)configuration.values(ConfigurationKeys.REALM_IDENTITY).get(0));
323         }
324         else {
325             throw new ServiceException(
326                 BasicException.Code.DEFAULT_DOMAIN,
327                 BasicException.Code.INVALID_CONFIGURATION,
328                 null,
329                 "A realm identity must be configured with option 'realmIdentity'"
330             );
331         }
332         
333         // configure router
334
SparseList dataproviderSource = configuration.values(
335             SharedConfigurationEntries.DATAPROVIDER_CONNECTION
336         );
337         SparseList delegationPathSource = configuration.values(
338             SharedConfigurationEntries.DELEGATION_PATH
339         );
340         if(delegationPathSource.isEmpty()){
341             if(dataproviderSource.isEmpty()) {
342               this.router = this.getDelegation();
343             }
344             else {
345                 throw new ServiceException(
346                     BasicException.Code.DEFAULT_DOMAIN,
347                     BasicException.Code.INVALID_CONFIGURATION,
348                     new BasicException.Parameter[]{},
349                     "The org:openmdx:compatibility:runtime1 model allowing to explore other dataproviders is deprecated." +
350                     " Specifying " + SharedConfigurationEntries.DATAPROVIDER_CONNECTION +
351                     " entries without their corresponding " + SharedConfigurationEntries.DELEGATION_PATH +
352                     " is not supported"
353                 );
354             }
355         }
356         else {
357             List JavaDoc dataproviderTarget = new ArrayList JavaDoc();
358             List JavaDoc delegationPathTarget = new ArrayList JavaDoc();
359             for(
360                 ListIterator JavaDoc dpi = delegationPathSource.populationIterator();
361                 dpi.hasNext();
362             ) {
363                 int i = dpi.nextIndex();
364                 Object JavaDoc dp = dataproviderSource.get(i);
365                 if(dp == null) {
366                     throw new ServiceException(
367                         BasicException.Code.DEFAULT_DOMAIN,
368                         BasicException.Code.INVALID_CONFIGURATION,
369                         new BasicException.Parameter[]{
370                             new BasicException.Parameter(SharedConfigurationEntries.DELEGATION_PATH, delegationPathSource),
371                             new BasicException.Parameter("index", i),
372                             new BasicException.Parameter(SharedConfigurationEntries.DATAPROVIDER_CONNECTION, dataproviderSource)
373                         },
374                         "The delegation path at the given index has no corresponding dataprovider counterpart"
375                     );
376                 }
377                 delegationPathTarget.add(
378                     new Path((String JavaDoc)dpi.next())
379                 );
380                 dataproviderTarget.add(dp);
381             }
382             this.router = new Switch_1(
383                 (Dataprovider_1_0[]) dataproviderTarget.toArray(
384                     new Dataprovider_1_0[dataproviderTarget.size()]
385                 ),
386                 Path.toPathArray(delegationPathTarget),
387                 this.getDelegation()
388             );
389         }
390     }
391     
392     //-------------------------------------------------------------------------
393
/**
394      * Set the current security context to the requesting principal, i.e.
395      * this.requestingPrincipal, this.currentSecurityContext, this.requestingUser.
396      */

397     private void assertSecurityContext(
398         ServiceHeader header,
399         DataproviderRequest request
400     ) throws ServiceException {
401         String JavaDoc principalName = header.getPrincipalChain().size() == 0
402             ? null
403             : (String JavaDoc)header.getPrincipalChain().get(0);
404         String JavaDoc realmName = SecurityKeys.ROOT_PRINCIPAL.equals(principalName)
405             ? "Root"
406             : request.path().get(4);
407         if(this.securityContexts.get(realmName) == null) {
408             this.securityContexts.put(
409                 realmName,
410                 new SecurityContext(
411                     this,
412                     this.realmIdentity.getParent().getChild(realmName)
413                 )
414             );
415         }
416         this.currentSecurityContext = (SecurityContext)this.securityContexts.get(realmName);
417         this.requestingPrincipal = this.currentSecurityContext.getPrincipal(principalName);
418         if(this.requestingPrincipal == null) {
419             throw new ServiceException(
420                 OpenCrxException.DOMAIN,
421                 OpenCrxException.AUTHORIZATION_FAILURE_MISSING_PRINCIPAL,
422                 new BasicException.Parameter[]{
423                     new BasicException.Parameter("principal", header.getPrincipalChain()),
424                     new BasicException.Parameter("param0", header.getPrincipalChain()),
425                     new BasicException.Parameter("param1", this.realmIdentity)
426                 },
427                 "Requested principal not found."
428             );
429         }
430         AppLog.detail("requesting principal", this.requestingPrincipal.path());
431         this.requestingUser = this.currentSecurityContext.getGroup(this.requestingPrincipal);
432     }
433     
434     //-------------------------------------------------------------------------
435
private DataproviderObject_1_0 getCachedParent(
436         Path parentPath
437     ) throws ServiceException {
438         DataproviderObject_1_0 parent = (DataproviderObject_1_0)this.cachedParents.get(parentPath);
439         if(parent == null) {
440             parent = this.delegation.addGetRequest(
441                 parentPath,
442                 AttributeSelectors.ALL_ATTRIBUTES,
443                 new AttributeSpecifier[]{}
444             );
445             this.addToParentsCache(parent);
446         }
447         return parent;
448     }
449     
450     //-------------------------------------------------------------------------
451
/* (non-Javadoc)
452      * @see org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0#prolog(org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader, org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest[])
453      */

454     public void prolog(
455         ServiceHeader header,
456         DataproviderRequest[] requests
457     ) throws ServiceException {
458         super.prolog(header, requests);
459         this.delegation = new RequestCollection(
460             header,
461             this.router == null
462                 ? this.getDelegation()
463                 : this.router
464           );
465     }
466
467     //-------------------------------------------------------------------------
468
/* (non-Javadoc)
469      * @see org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0#prolog(org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader, org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest[])
470      */

471     public void epilog(
472         ServiceHeader header,
473         DataproviderRequest[] requests,
474         DataproviderReply[] replies
475     ) throws ServiceException {
476         super.epilog(
477             header,
478             requests,
479             replies
480         );
481         this.requestingPrincipal = null;
482     }
483
484     //-------------------------------------------------------------------------
485
/* (non-Javadoc)
486      * @see org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0#create(org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader, org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest)
487      */

488     public DataproviderReply create(
489         ServiceHeader header,
490         DataproviderRequest request
491     ) throws ServiceException {
492
493         this.assertSecurityContext(
494             header,
495             request
496         );
497
498         // Check permission. Must have update permission for parent
499
DataproviderObject_1_0 parent = null;
500         if(request.path().size() >= 7) {
501             parent = this.getCachedParent(request.path().getPrefix(request.path().size()-2));
502             if(this.isSecureObject(parent)) {
503                 Set JavaDoc allowedPrincipals = new HashSet JavaDoc();
504                 if(parent.values("accessLevelUpdate").size() < 1) {
505                     AppLog.error("missing attribute value for accessLevelUpdate", parent);
506                 }
507                 else {
508                     allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals(
509                         this.requestingPrincipal,
510                         this.requestingUser,
511                         ((Number JavaDoc)parent.values("accessLevelUpdate").get(0)).shortValue()
512                     );
513                 }
514                 if(allowedPrincipals != null) {
515                     allowedPrincipals.retainAll(parent.values("owner"));
516                     if(allowedPrincipals.size() == 0) {
517                         throw new ServiceException(
518                             OpenCrxException.DOMAIN,
519                             OpenCrxException.AUTHORIZATION_FAILURE_CREATE,
520                             new BasicException.Parameter[]{
521                                 new BasicException.Parameter("object", request.path()),
522                                 new BasicException.Parameter("param0", request.path()),
523                                 new BasicException.Parameter("param1", this.requestingPrincipal.path())
524                             },
525                             "No permission to create object."
526                         );
527                     }
528                 }
529             }
530         }
531
532         // Create object
533
DataproviderObject newObject = request.object();
534         
535         // Set owner in case of secure objects
536
if(this.isSecureObject(newObject)) {
537             
538             // Owning user
539
String JavaDoc owningUser = null;
540             
541             // If new object is composite to user home set owning user to owning user of user home
542
if(
543                 (newObject.path().size() > USER_HOME_PATH_PATTERN.size()) &&
544                 newObject.path().getPrefix(USER_HOME_PATH_PATTERN.size()).isLike(USER_HOME_PATH_PATTERN) &&
545                 (parent.values("owner").size() > 0)
546             ) {
547                owningUser = (String JavaDoc)parent.values("owner").get(0);
548             }
549             // owning user set on new object
550
else if(newObject.values("owningUser").size() > 0) {
551                 owningUser = this.getQualifiedPrincipalName(
552                     (Path)newObject.values("owningUser").get(0)
553                 );
554             }
555             // set requesting principal as default
556
else {
557                 // if no user found set owner to segment administrator
558
owningUser = newObject.values("owner").size() == 0
559                     ? this.requestingUser == null
560                       ? this.getQualifiedPrincipalName(newObject.path(), SecurityKeys.ADMIN_PRINCIPAL)
561                       : this.getQualifiedPrincipalName(this.requestingUser.path())
562                     : (String JavaDoc)newObject.values("owner").get(0);
563             }
564             newObject.clearValues("owner").add(owningUser);
565
566             // Owning group
567
Set JavaDoc owningGroup = new HashSet JavaDoc();
568             if(newObject.getValues("owningGroup") != null) {
569                 for(Iterator JavaDoc i = newObject.values("owningGroup").iterator(); i.hasNext(); ) {
570                     owningGroup.add(
571                         this.getQualifiedPrincipalName((Path)i.next())
572                     );
573                 }
574             }
575             else {
576                 DataproviderObject_1_0 userGroup = this.requestingPrincipal == null
577                     ? null
578                     : this.currentSecurityContext.getPrimaryGroup(this.requestingPrincipal);
579                 owningGroup = new HashSet JavaDoc();
580                 if(parent != null) {
581                     List JavaDoc ownersParent = new ArrayList JavaDoc(parent.values("owner"));
582                     ownersParent.remove(
583                         this.getQualifiedPrincipalName(newObject.path(), SecurityKeys.USER_GROUP_USERS)
584                     );
585                     owningGroup.addAll(
586                         ownersParent.subList(1, ownersParent.size())
587                     );
588                 }
589                 owningGroup.add(
590                     userGroup == null
591                          ? this.getQualifiedPrincipalName(newObject.path(), "Unassigned")
592                          : this.getQualifiedPrincipalName(userGroup.path())
593                 );
594             }
595             newObject.values("owner").addAll(owningGroup);
596             
597             newObject.clearValues("owningUser");
598             newObject.clearValues("owningGroup");
599             // accessLevelBrowse
600
if(
601                 (newObject.values("accessLevelBrowse").size() != 1) ||
602                 (((Number JavaDoc)newObject.values("accessLevelBrowse").get(0)).shortValue() == SecurityKeys.ACCESS_LEVEL_NA)
603             ) {
604                 newObject.clearValues("accessLevelBrowse").add(
605                     new Short JavaDoc(SecurityKeys.ACCESS_LEVEL_DEEP)
606                 );
607             }
608             // accessLevelUpdate
609
if(
610                 (newObject.values("accessLevelUpdate").size() != 1) ||
611                 (((Number JavaDoc)newObject.values("accessLevelUpdate").get(0)).shortValue() == SecurityKeys.ACCESS_LEVEL_NA)
612             ) {
613                 newObject.clearValues("accessLevelUpdate").add(
614                     new Short JavaDoc(SecurityKeys.ACCESS_LEVEL_BASIC)
615                 );
616             }
617             // accessLevelDelete
618
if(
619                 (newObject.values("accessLevelDelete").size() != 1) ||
620                 (((Number JavaDoc)newObject.values("accessLevelDelete").get(0)).shortValue() == SecurityKeys.ACCESS_LEVEL_NA)
621             ) {
622                 newObject.clearValues("accessLevelDelete").add(
623                     new Short JavaDoc(SecurityKeys.ACCESS_LEVEL_BASIC)
624                 );
625             }
626         }
627         
628         return this.completeReply(
629             header,
630             super.create(header, request)
631         );
632     }
633
634     //-------------------------------------------------------------------------
635
/* (non-Javadoc)
636      * @see org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0#find(org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader, org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest)
637      */

638     public DataproviderReply find(
639         ServiceHeader header,
640         DataproviderRequest request
641     ) throws ServiceException {
642         this.assertSecurityContext(
643             header,
644             request
645         );
646         DataproviderObject_1_0 parent = this.getCachedParent(request.path().getParent());
647         ModelElement_1_0 referencedType = this.model.getTypes(request.path())[2];
648         if(this.isSecureObject(referencedType) && this.isSecureObject(parent)) {
649             Set JavaDoc allowedPrincipals = new HashSet JavaDoc();
650             if(parent.values("accessLevelBrowse").size() < 1) {
651                 AppLog.error("missing attribute value for accessLevelBrowse", parent);
652             }
653             else {
654                 allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals(
655                     this.requestingPrincipal,
656                     this.requestingUser,
657                     ((Number JavaDoc)parent.values("accessLevelBrowse").get(0)).shortValue()
658                 );
659             }
660             // allowedPrincipals == null --> global access. Do not restrict to allowed subjects
661
if(allowedPrincipals != null) {
662                 request.addAttributeFilterProperty(
663                     new FilterProperty(
664                         Quantors.THERE_EXISTS,
665                         "owner",
666                         FilterOperators.IS_IN,
667                         allowedPrincipals.toArray(new String JavaDoc[allowedPrincipals.size()])
668                     )
669                 );
670             }
671         }
672         return this.completeReply(
673             header,
674             super.find(header, request)
675         );
676     }
677
678     //-------------------------------------------------------------------------
679
/* (non-Javadoc)
680      * @see org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0#get(org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader, org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest)
681      */

682     public DataproviderReply get(
683         ServiceHeader header,
684         DataproviderRequest request
685     ) throws ServiceException {
686         this.assertSecurityContext(
687             header,
688             request
689         );
690         DataproviderReply reply = super.get(
691             header,
692             request
693         );
694         if(request.path().size() >= 7) {
695             DataproviderObject_1_0 parent = this.getCachedParent(
696                 request.path().getPrefix(request.path().size()-2)
697             );
698             ModelElement_1_0 referencedType = this.model.getTypes(request.path())[2];
699             if(this.isSecureObject(referencedType) && this.isSecureObject(parent)) {
700                 Set JavaDoc allowedPrincipals = new HashSet JavaDoc();
701                 if(parent.values("accessLevelBrowse").size() < 1) {
702                     AppLog.error("missing attribute value for accessLevelBrowse", parent);
703                 }
704                 else {
705                     allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals(
706                         this.requestingPrincipal,
707                         this.requestingUser,
708                         ((Number JavaDoc)parent.values("accessLevelBrowse").get(0)).shortValue()
709                     );
710                 }
711                 if(allowedPrincipals != null) {
712                     allowedPrincipals.retainAll(reply.getObject().values("owner"));
713                     if(allowedPrincipals.size() > 0) {
714                         return this.completeReply(
715                             header,
716                             reply
717                         );
718                     }
719                     else {
720                         throw new ServiceException(
721                             BasicException.Code.DEFAULT_DOMAIN,
722                             BasicException.Code.AUTHORIZATION_FAILURE,
723                             new BasicException.Parameter[]{
724                                 new BasicException.Parameter("path", request.path()),
725                                 new BasicException.Parameter("param0", request.path()),
726                                 new BasicException.Parameter("param1", this.requestingPrincipal.path())
727                             },
728                             "no permission to access requested object."
729                         );
730                     }
731                 }
732             }
733         }
734         return this.completeReply(
735             header,
736             reply
737         );
738     }
739
740     //-------------------------------------------------------------------------
741
/* (non-Javadoc)
742      * @see org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0#remove(org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader, org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest)
743      */

744     public DataproviderReply remove(
745         ServiceHeader header,
746         DataproviderRequest request
747     ) throws ServiceException {
748         
749         this.assertSecurityContext(
750             header,
751             request
752         );
753         
754         DataproviderObject_1_0 existingObject = this.delegation.addGetRequest(
755             request.path(),
756             AttributeSelectors.ALL_ATTRIBUTES,
757             new AttributeSpecifier[]{}
758         );
759         if(this.isSecureObject(existingObject)) {
760             
761             // assert that requesting user is allowed to update object
762
Set JavaDoc allowedPrincipals = new HashSet JavaDoc();
763             if(existingObject.values("accessLevelDelete").size() < 1) {
764                 AppLog.error("missing attribute value for accessLevelDelete", existingObject);
765             }
766             else {
767                 allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals(
768                     this.requestingPrincipal,
769                     this.requestingUser,
770                     ((Number JavaDoc)existingObject.values("accessLevelDelete").get(0)).shortValue()
771                 );
772             }
773             if(allowedPrincipals != null) {
774                 allowedPrincipals.retainAll(existingObject.values("owner"));
775                 // no permission
776
if(allowedPrincipals.size() == 0) {
777                     throw new ServiceException(
778                         OpenCrxException.DOMAIN,
779                         OpenCrxException.AUTHORIZATION_FAILURE_DELETE,
780                         new BasicException.Parameter[]{
781                             new BasicException.Parameter("object", request.path()),
782                             new BasicException.Parameter("param0", request.path()),
783                             new BasicException.Parameter("param1", this.requestingPrincipal.path())
784                         },
785                         "No permission to delete requested object."
786                     );
787                 }
788             }
789         }
790
791         this.cachedParents.remove(request.path());
792         return this.completeReply(
793             header,
794             super.remove(header, request)
795         );
796     }
797
798     //-------------------------------------------------------------------------
799
/* (non-Javadoc)
800      * @see org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0#replace(org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader, org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest)
801      */

802     public DataproviderReply replace(
803         ServiceHeader header,
804         DataproviderRequest request
805     ) throws ServiceException {
806         this.assertSecurityContext(
807             header,
808             request
809         );
810         DataproviderObject_1_0 existingObject = this.delegation.addGetRequest(
811             request.path(),
812             AttributeSelectors.ALL_ATTRIBUTES,
813             new AttributeSpecifier[]{}
814         );
815         if(this.isSecureObject(existingObject)) {
816             
817             // assert that requesting user is allowed to update object
818
Set JavaDoc allowedPrincipals = new HashSet JavaDoc();
819             if(existingObject.values("accessLevelUpdate").size() < 1) {
820                 AppLog.error("missing attribute value for accessLevelUpdate", existingObject);
821             }
822             else {
823                 allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals(
824                     this.requestingPrincipal,
825                     this.requestingUser,
826                     ((Number JavaDoc)existingObject.values("accessLevelUpdate").get(0)).shortValue()
827                 );
828             }
829             if(allowedPrincipals != null) {
830                 allowedPrincipals.retainAll(existingObject.values("owner"));
831                 // no permission
832
if(allowedPrincipals.size() == 0) {
833                     throw new ServiceException(
834                         OpenCrxException.DOMAIN,
835                         OpenCrxException.AUTHORIZATION_FAILURE_UPDATE,
836                         new BasicException.Parameter[]{
837                             new BasicException.Parameter("object", request.path()),
838                             new BasicException.Parameter("param0", request.path()),
839                             new BasicException.Parameter("param1", this.requestingPrincipal.path())
840                         },
841                         "No permission to update requested object."
842                     );
843                 }
844             }
845             // derive attribute owner from owningUser and owningGroup
846
DataproviderObject replacement = request.object();
847             
848             // Sets the attribute owner. owner[0] is set to the name of the owning user,
849
// owner[i] is set to the name of the owning group i-1.
850
replacement.clearValues("owner");
851             
852             // set 'owner' in case of secure objects
853
// owning user
854
String JavaDoc owningUser = null;
855             if(replacement.values("owningUser").size() > 0) {
856                 owningUser = this.getQualifiedPrincipalName((Path)replacement.values("owningUser").get(0));
857             }
858             else {
859                 // if no user found set owner to segment administrator
860
owningUser = existingObject.values("owner").size() == 0
861                     ? this.requestingUser == null ? this.getQualifiedPrincipalName(replacement.path(), SecurityKeys.ADMIN_PRINCIPAL) : this.getQualifiedPrincipalName(this.requestingUser.path())
862                     : (String JavaDoc)existingObject.values("owner").get(0);
863             }
864             replacement.values("owner").add(owningUser);
865             
866             // owning group
867
List JavaDoc owningGroup = new ArrayList JavaDoc();
868             if(replacement.getValues("owningGroup") != null) {
869                 // replace owning group
870
for(Iterator JavaDoc i = replacement.values("owningGroup").iterator(); i.hasNext(); ) {
871                     Path group = (Path)i.next();
872                     if(group != null) {
873                         owningGroup.add(
874                             this.getQualifiedPrincipalName(group)
875                         );
876                     }
877                 }
878             }
879             else {
880                 // keep existing owning group
881
if(existingObject.values("owner").size() > 1) {
882                     owningGroup.addAll(
883                         existingObject.values("owner").subList(1, existingObject.values("owner").size())
884                     );
885                 }
886             }
887             replacement.values("owner").addAll(owningGroup);
888             replacement.clearValues("owningUser");
889             replacement.clearValues("owningGroup");
890         }
891         
892         this.cachedParents.remove(request.path());
893         return this.completeReply(
894             header,
895             super.replace(header, request)
896         );
897     }
898
899     //-----------------------------------------------------------------------
900
private static final Path USER_HOME_PATH_PATTERN =
901         new Path("xri:@openmdx:org.opencrx.kernel.home1/provider/:*/segment/:*/userHome/:*");
902         
903     private Path realmIdentity = null;
904     protected RequestCollection delegation = null;
905     private Dataprovider_1_0 router = null;
906     private Model_1_0 model = null;
907
908     // Subject cache as map with identity as key and subject as value.
909
private Map JavaDoc securityContexts = new HashMap JavaDoc();
910     
911     // Current security context
912
private SecurityContext currentSecurityContext = null;
913     // Requesting principal
914
private DataproviderObject_1_0 requestingPrincipal = null;
915     // Group principal of requesting user
916
private DataproviderObject_1_0 requestingUser = null;
917     
918     // Cached parents (cleared on epilog)
919
private static final int MAX_CACHED_PARENTS = 1000;
920     private Map JavaDoc cachedParents = new LRUMap(MAX_CACHED_PARENTS);
921     
922 }
923
924 //--- End of File -----------------------------------------------------------
925
Popular Tags