View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  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,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.authz.support;
21  
22  
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashSet;
27  
28  import javax.naming.NamingException;
29  
30  import org.apache.directory.server.core.authn.AuthenticationInterceptor;
31  import org.apache.directory.server.core.authz.AciAuthorizationInterceptor;
32  import org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor;
33  import org.apache.directory.server.core.entry.ServerEntry;
34  import org.apache.directory.server.core.event.Evaluator;
35  import org.apache.directory.server.core.event.EventInterceptor;
36  import org.apache.directory.server.core.event.ExpressionEvaluator;
37  import org.apache.directory.server.core.interceptor.context.OperationContext;
38  import org.apache.directory.server.core.normalization.NormalizationInterceptor;
39  import org.apache.directory.server.core.operational.OperationalAttributeInterceptor;
40  import org.apache.directory.server.core.schema.SchemaInterceptor;
41  import org.apache.directory.server.core.subtree.RefinementEvaluator;
42  import org.apache.directory.server.core.subtree.RefinementLeafEvaluator;
43  import org.apache.directory.server.core.subtree.SubentryInterceptor;
44  import org.apache.directory.server.core.subtree.SubtreeEvaluator;
45  import org.apache.directory.server.core.trigger.TriggerInterceptor;
46  import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
47  import org.apache.directory.server.schema.registries.OidRegistry;
48  import org.apache.directory.server.schema.registries.Registries;
49  import org.apache.directory.shared.ldap.aci.ACITuple;
50  import org.apache.directory.shared.ldap.aci.MicroOperation;
51  import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
52  import org.apache.directory.shared.ldap.entry.Value;
53  import org.apache.directory.shared.ldap.exception.LdapNoPermissionException;
54  import org.apache.directory.shared.ldap.name.LdapDN;
55  
56  
57  /**
58   * An implementation of Access Control Decision Function (18.8, X.501).
59   * <p>
60   * This engine simply filters the collection of tuples using the following
61   * {@link ACITupleFilter}s sequentially:
62   * <ol>
63   * <li>{@link RelatedUserClassFilter}</li>
64   * <li>{@link RelatedProtectedItemFilter}</li>
65   * <li>{@link MaxValueCountFilter}</li>
66   * <li>{@link MaxImmSubFilter}</li>
67   * <li>{@link RestrictedByFilter}</li>
68   * <li>{@link MicroOperationFilter}</li>
69   * <li>{@link HighestPrecedenceFilter}</li>
70   * <li>{@link MostSpecificUserClassFilter}</li>
71   * <li>{@link MostSpecificProtectedItemFilter}</li>
72   * </ol>
73   * <p>
74   * Operation is determined to be permitted if and only if there is at least one
75   * tuple left and all of them grants the access. (18.8.4. X.501)
76   * 
77   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
78   * @version $Rev: 662440 $, $Date: 2008-06-02 16:00:23 +0200 (Mo, 02 Jun 2008) $
79   */
80  public class ACDFEngine
81  {
82      private final ACITupleFilter[] filters;
83  
84  
85      /**
86       * Creates a new instance.
87       * 
88       * @param oidRegistry an OID registry to be used by internal components
89       * @param attrTypeRegistry an attribute type registry to be used by internal components 
90       * 
91       * @throws NamingException if failed to initialize internal components
92       */
93      public ACDFEngine( OidRegistry oidRegistry, AttributeTypeRegistry attrTypeRegistry ) throws NamingException
94      {
95          Evaluator entryEvaluator = new ExpressionEvaluator( oidRegistry, attrTypeRegistry );
96          SubtreeEvaluator subtreeEvaluator = new SubtreeEvaluator( oidRegistry, attrTypeRegistry );
97          RefinementEvaluator refinementEvaluator = new RefinementEvaluator( new RefinementLeafEvaluator( oidRegistry ) );
98  
99          filters = new ACITupleFilter[] {
100             new RelatedUserClassFilter( subtreeEvaluator ),
101             new RelatedProtectedItemFilter( refinementEvaluator, entryEvaluator, oidRegistry, attrTypeRegistry ),
102             new MaxValueCountFilter(),
103             new MaxImmSubFilter(),
104             new RestrictedByFilter(),
105             new MicroOperationFilter(),
106             new HighestPrecedenceFilter(),
107             new MostSpecificUserClassFilter(),
108             new MostSpecificProtectedItemFilter() };
109     }
110 
111 
112     /**
113      * Checks the user with the specified name can access the specified resource
114      * (entry, attribute type, or attribute value) and throws {@link LdapNoPermissionException}
115      * if the user doesn't have any permission to perform the specified grants.
116      * 
117      * @param proxy the proxy to the partition nexus
118      * @param userGroupNames the collection of the group DNs the user who is trying to access the resource belongs
119      * @param username the DN of the user who is trying to access the resource
120      * @param entryName the DN of the entry the user is trying to access
121      * @param attrId the attribute type of the attribute the user is trying to access.
122      *               <tt>null</tt> if the user is not accessing a specific attribute type.
123      * @param attrValue the attribute value of the attribute the user is trying to access.
124      *                  <tt>null</tt> if the user is not accessing a specific attribute value.
125      * @param microOperations the {@link org.apache.directory.shared.ldap.aci.MicroOperation}s to perform
126      * @param aciTuples {@link org.apache.directory.shared.ldap.aci.ACITuple}s translated from {@link org.apache.directory.shared.ldap.aci.ACIItem}s in the subtree entries
127      * @param entryView in case of a Modify operation, view of the entry being modified as if the modification permitted and completed
128      * @throws NamingException if failed to evaluate ACI items
129      */
130     public void checkPermission( 
131         Registries registries, 
132         OperationContext opContext, 
133         Collection<LdapDN> userGroupNames, 
134         LdapDN username,
135         AuthenticationLevel authenticationLevel, 
136         LdapDN entryName, 
137         String attrId, 
138         Value<?> attrValue, 
139         Collection<MicroOperation> microOperations, 
140         Collection<ACITuple> aciTuples, 
141         ServerEntry entry, 
142         ServerEntry entryView ) throws Exception
143     {
144         if ( !hasPermission( registries, opContext, userGroupNames, username, authenticationLevel, entryName, 
145             attrId, attrValue, microOperations, aciTuples, entry, entryView ) )
146         {
147             throw new LdapNoPermissionException();
148         }
149     }
150 
151     public static final Collection<String> USER_LOOKUP_BYPASS;
152     static
153     {
154         Collection<String> c = new HashSet<String>();
155         c.add( NormalizationInterceptor.class.getName() );
156         c.add( AuthenticationInterceptor.class.getName() );
157 //        c.add( ReferralInterceptor.class.getName() );
158         c.add( AciAuthorizationInterceptor.class.getName() );
159         c.add( DefaultAuthorizationInterceptor.class.getName() );
160 //        c.add( ExceptionInterceptor.class.getName() );
161         c.add( OperationalAttributeInterceptor.class.getName() );
162         c.add( SchemaInterceptor.class.getName() );
163         c.add( SubentryInterceptor.class.getName() );
164 //        c.add( CollectiveAttributeInterceptor.class.getName() );
165         c.add( EventInterceptor.class.getName() );
166         c.add( TriggerInterceptor.class.getName() );
167         USER_LOOKUP_BYPASS = Collections.unmodifiableCollection( c );
168     }
169 
170 
171     /**
172      * Returns <tt>true</tt> if the user with the specified name can access the specified resource
173      * (entry, attribute type, or attribute value) and throws {@link LdapNoPermissionException}
174      * if the user doesn't have any permission to perform the specified grants.
175      * 
176      * @param proxy the proxy to the partition nexus
177      * @param userGroupNames the collection of the group DNs the user who is trying to access the resource belongs
178      * @param userName the DN of the user who is trying to access the resource
179      * @param entryName the DN of the entry the user is trying to access
180      * @param attrId the attribute type of the attribute the user is trying to access.
181      *               <tt>null</tt> if the user is not accessing a specific attribute type.
182      * @param attrValue the attribute value of the attribute the user is trying to access.
183      *                  <tt>null</tt> if the user is not accessing a specific attribute value.
184      * @param microOperations the {@link org.apache.directory.shared.ldap.aci.MicroOperation}s to perform
185      * @param aciTuples {@link org.apache.directory.shared.ldap.aci.ACITuple}s translated from {@link org.apache.directory.shared.ldap.aci.ACIItem}s in the subtree entries
186      * @param entryView in case of a Modify operation, view of the entry being modified as if the modification permitted and completed
187      */
188     public boolean hasPermission( 
189         Registries registries, 
190         OperationContext opContext, 
191         Collection<LdapDN> userGroupNames, 
192         LdapDN userName,
193         AuthenticationLevel authenticationLevel, 
194         LdapDN entryName, 
195         String attrId, 
196         Value<?> attrValue, 
197         Collection<MicroOperation> microOperations, 
198         Collection<ACITuple> aciTuples, 
199         ServerEntry entry, 
200         ServerEntry entryView ) throws Exception
201     {
202         if ( entryName == null )
203         {
204             throw new NullPointerException( "entryName" );
205         }
206 
207         ServerEntry userEntry = opContext.lookup( userName, USER_LOOKUP_BYPASS );
208 
209         // Determine the scope of the requested operation.
210         OperationScope scope;
211         
212         if ( attrId == null )
213         {
214             scope = OperationScope.ENTRY;
215         }
216         else if ( attrValue == null )
217         {
218             scope = OperationScope.ATTRIBUTE_TYPE;
219         }
220         else
221         {
222             scope = OperationScope.ATTRIBUTE_TYPE_AND_VALUE;
223         }
224 
225         // Clone aciTuples in case it is unmodifiable.
226         aciTuples = new ArrayList<ACITuple>( aciTuples );
227 
228         // Filter unrelated and invalid tuples
229         for ( ACITupleFilter filter : filters )
230         {
231             aciTuples = filter.filter( 
232                 registries, 
233                 aciTuples, 
234                 scope, 
235                 opContext, 
236                 userGroupNames, 
237                 userName, 
238                 userEntry,
239                 authenticationLevel, 
240                 entryName, 
241                 attrId, 
242                 attrValue, 
243                 entry, 
244                 microOperations, 
245                 entryView );
246         }
247 
248         // Deny access if no tuples left.
249         if ( aciTuples.size() == 0 )
250         {
251             return false;
252         }
253 
254         // Grant access if and only if one or more tuples remain and
255         // all grant access. Otherwise deny access.
256         for ( ACITuple tuple : aciTuples )
257         {
258             if ( !tuple.isGrant() )
259             {
260                 return false;
261             }
262         }
263 
264         return true;
265     }
266 }