View Javadoc

1   /*
2    *   @(#) $Id: ACDFEngine.java 326083 2005-10-18 10:59:38Z akarasulu $
3    *   
4    *   Copyright 2004 The Apache Software Foundation
5    *
6    *   Licensed under the Apache License, Version 2.0 (the "License");
7    *   you may not use this file except in compliance with the License.
8    *   You may obtain a copy of the License at
9    *
10   *       http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing, software
13   *   distributed under the License is distributed on an "AS IS" BASIS,
14   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *   See the License for the specific language governing permissions and
16   *   limitations under the License.
17   *
18   */
19  package org.apache.ldap.server.authz.support;
20  
21  import java.util.*;
22  
23  import javax.naming.Name;
24  import javax.naming.NamingException;
25  import javax.naming.directory.Attributes;
26  
27  import org.apache.ldap.common.aci.ACIItem;
28  import org.apache.ldap.common.aci.ACITuple;
29  import org.apache.ldap.common.aci.AuthenticationLevel;
30  import org.apache.ldap.common.aci.MicroOperation;
31  import org.apache.ldap.common.exception.LdapNoPermissionException;
32  import org.apache.ldap.server.event.Evaluator;
33  import org.apache.ldap.server.event.ExpressionEvaluator;
34  import org.apache.ldap.server.schema.AttributeTypeRegistry;
35  import org.apache.ldap.server.schema.OidRegistry;
36  import org.apache.ldap.server.subtree.RefinementEvaluator;
37  import org.apache.ldap.server.subtree.RefinementLeafEvaluator;
38  import org.apache.ldap.server.subtree.SubtreeEvaluator;
39  import org.apache.ldap.server.partition.DirectoryPartitionNexusProxy;
40  
41  
42  /***
43   * An implementation of Access Control Decision Function (18.8, X.501).
44   * <p>
45   * This engine simply filters the collection of tuples using the following
46   * {@link ACITupleFilter}s sequentially:
47   * <ol>
48   * <li>{@link RelatedUserClassFilter}</li>
49   * <li>{@link RelatedProtectedItemFilter}</li>
50   * <li>{@link MaxValueCountFilter}</li>
51   * <li>{@link MaxImmSubFilter}</li>
52   * <li>{@link RestrictedByFilter}</li>
53   * <li>{@link MicroOperationFilter}</li>
54   * <li>{@link HighestPrecedenceFilter}</li>
55   * <li>{@link MostSpecificUserClassFilter}</li>
56   * <li>{@link MostSpecificProtectedItemFilter}</li>
57   * </ol>
58   * <p>
59   * Operation is determined to be permitted if and only if there is at least one
60   * tuple left and all of them grants the access. (18.8.4. X.501)
61   * 
62   * @author The Apache Directory Project
63   * @version $Rev: 326083 $, $Date: 2005-10-18 06:59:38 -0400 (Tue, 18 Oct 2005) $
64   */
65  public class ACDFEngine
66  {
67      private final ACITupleFilter[] filters;
68  
69      /***
70       * Creates a new instance.
71       * 
72       * @param oidRegistry an OID registry to be used by internal components
73       * @param attrTypeRegistry an attribute type registry to be used by internal components 
74       * 
75       * @throws NamingException if failed to initialize internal components
76       */
77      public ACDFEngine( OidRegistry oidRegistry, AttributeTypeRegistry attrTypeRegistry ) throws NamingException
78      {
79          Evaluator entryEvaluator = new ExpressionEvaluator( oidRegistry, attrTypeRegistry );
80          SubtreeEvaluator subtreeEvaluator = new SubtreeEvaluator( oidRegistry );
81          RefinementEvaluator refinementEvaluator = new RefinementEvaluator(
82                  new RefinementLeafEvaluator( oidRegistry ) );
83  
84          filters = new ACITupleFilter[] {
85                  new RelatedUserClassFilter( subtreeEvaluator ),
86                  new RelatedProtectedItemFilter( attrTypeRegistry, refinementEvaluator, entryEvaluator ),
87                  new MaxValueCountFilter(),
88                  new MaxImmSubFilter(),
89                  new RestrictedByFilter(),
90                  new MicroOperationFilter(),
91                  new HighestPrecedenceFilter(),
92                  new MostSpecificUserClassFilter(),
93                  new MostSpecificProtectedItemFilter(),
94          };
95      }
96  
97      /***
98       * Checks the user with the specified name can access the specified resource
99       * (entry, attribute type, or attribute value) and throws {@link LdapNoPermissionException}
100      * if the user doesn't have any permission to perform the specified grants.
101      * 
102      * @param proxy the proxy to the partition nexus
103      * @param userGroupNames the collection of the group DNs the user who is trying to access the resource belongs
104      * @param username the DN of the user who is trying to access the resource
105      * @param entryName the DN of the entry the user is trying to access 
106      * @param attrId the attribute type of the attribute the user is trying to access.
107      *               <tt>null</tt> if the user is not accessing a specific attribute type.
108      * @param attrValue the attribute value of the attribute the user is trying to access.
109      *                  <tt>null</tt> if the user is not accessing a specific attribute value.
110      * @param microOperations the {@link MicroOperation}s to perform
111      * @param aciTuples {@link ACITuple}s translated from {@link ACIItem}s in the subtree entries
112      * @throws NamingException if failed to evaluate ACI items
113      */
114     public void checkPermission(
115             DirectoryPartitionNexusProxy proxy,
116             Collection userGroupNames, Name username, AuthenticationLevel authenticationLevel,
117             Name entryName, String attrId, Object attrValue,
118             Collection microOperations, Collection aciTuples, Attributes entry ) throws NamingException
119     {
120         if( !hasPermission(
121                 proxy,
122                 userGroupNames, username, authenticationLevel,
123                 entryName, attrId, attrValue,
124                 microOperations, aciTuples, entry ) )
125         {
126             throw new LdapNoPermissionException();
127         }
128     }
129 
130 
131     public static final Collection USER_LOOKUP_BYPASS;
132     static
133     {
134         Collection c = new HashSet();
135         c.add( "normalizationService" );
136         c.add( "authenticationService" );
137         c.add( "authorizationService" );
138         c.add( "oldAuthorizationService" );
139         c.add( "schemaService" );
140         c.add( "subentryService" );
141         c.add( "operationalAttributeService" );
142         c.add( "eventService" );
143         USER_LOOKUP_BYPASS = Collections.unmodifiableCollection( c );
144     }
145 
146 
147     /***
148      * Returns <tt>true</tt> if the user with the specified name can access the specified resource
149      * (entry, attribute type, or attribute value) and throws {@link LdapNoPermissionException}
150      * if the user doesn't have any permission to perform the specified grants.
151      * 
152      * @param proxy the proxy to the partition nexus
153      * @param userGroupNames the collection of the group DNs the user who is trying to access the resource belongs
154      * @param userName the DN of the user who is trying to access the resource
155      * @param entryName the DN of the entry the user is trying to access 
156      * @param attrId the attribute type of the attribute the user is trying to access.
157      *               <tt>null</tt> if the user is not accessing a specific attribute type.
158      * @param attrValue the attribute value of the attribute the user is trying to access.
159      *                  <tt>null</tt> if the user is not accessing a specific attribute value.
160      * @param microOperations the {@link MicroOperation}s to perform
161      * @param aciTuples {@link ACITuple}s translated from {@link ACIItem}s in the subtree entries
162      */
163     public boolean hasPermission(
164             DirectoryPartitionNexusProxy proxy,
165             Collection userGroupNames, Name userName, AuthenticationLevel authenticationLevel,
166             Name entryName, String attrId, Object attrValue,
167             Collection microOperations, Collection aciTuples, Attributes entry ) throws NamingException
168     {
169         if( entryName == null )
170         {
171             throw new NullPointerException( "entryName" );
172         }
173 
174         Attributes userEntry = proxy.lookup( userName, USER_LOOKUP_BYPASS );
175 
176         // Determine the scope of the requested operation.
177         OperationScope scope;
178         if( attrId == null )
179         {
180             scope = OperationScope.ENTRY;
181         }
182         else if( attrValue == null )
183         {
184             scope = OperationScope.ATTRIBUTE_TYPE;
185         }
186         else
187         {
188             scope = OperationScope.ATTRIBUTE_TYPE_AND_VALUE;
189         }
190 
191         // Clone aciTuples in case it is unmodifiable.
192         aciTuples = new ArrayList( aciTuples );
193 
194         // Filter unrelated and invalid tuples
195         for( int i = 0; i < filters.length; i++ )
196         {
197             ACITupleFilter filter = filters[ i ];
198             aciTuples = filter.filter(
199                     aciTuples, scope, proxy,
200                     userGroupNames, userName, userEntry, authenticationLevel,
201                     entryName, attrId, attrValue, entry, microOperations );
202         }
203 
204         // Deny access if no tuples left.
205         if( aciTuples.size() == 0 )
206         {
207             return false;
208         }
209 
210         // Grant access if and only if one or more tuples remain and
211         // all grant access. Otherwise deny access.
212         for( Iterator i = aciTuples.iterator(); i.hasNext(); )
213         {
214             ACITuple tuple = ( ACITuple ) i.next();
215             if( !tuple.isGrant() )
216             {
217                 return false;
218             }
219         }
220 
221         return true;
222     }
223 }