001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.server.core.authz.support;
021    
022    
023    import java.util.Collection;
024    import java.util.Iterator;
025    import java.util.Set;
026    
027    import org.apache.directory.server.core.interceptor.context.OperationContext;
028    import org.apache.directory.server.core.subtree.SubtreeEvaluator;
029    import org.apache.directory.server.i18n.I18n;
030    import org.apache.directory.shared.ldap.aci.ACITuple;
031    import org.apache.directory.shared.ldap.aci.MicroOperation;
032    import org.apache.directory.shared.ldap.aci.UserClass;
033    import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
034    import org.apache.directory.shared.ldap.entry.ServerEntry;
035    import org.apache.directory.shared.ldap.entry.Value;
036    import org.apache.directory.shared.ldap.exception.LdapException;
037    import org.apache.directory.shared.ldap.name.DN;
038    import org.apache.directory.shared.ldap.schema.SchemaManager;
039    import org.apache.directory.shared.ldap.subtree.SubtreeSpecification;
040    
041    
042    /**
043     * An {@link ACITupleFilter} that discards all tuples whose {@link UserClass}es
044     * are not related with the current user. (18.8.3.1, X.501)
045     *
046     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
047     * @version $Rev: 928938 $, $Date: 2010-03-30 01:25:42 +0200 (Tue, 30 Mar 2010) $
048     */
049    public class RelatedUserClassFilter implements ACITupleFilter
050    {
051        private static final DN ROOTDSE_NAME = DN.EMPTY_DN;
052    
053        private final SubtreeEvaluator subtreeEvaluator;
054    
055    
056        public RelatedUserClassFilter(SubtreeEvaluator subtreeEvaluator)
057        {
058            this.subtreeEvaluator = subtreeEvaluator;
059        }
060    
061    
062        public Collection<ACITuple> filter( 
063                SchemaManager schemaManager, 
064                Collection<ACITuple> tuples, 
065                OperationScope scope, 
066                OperationContext opContext,
067                Collection<DN> userGroupNames, 
068                DN userName, 
069                ServerEntry userEntry, 
070                AuthenticationLevel authenticationLevel,
071                DN entryName, 
072                String attrId, 
073                Value<?> attrValue, 
074                ServerEntry entry, 
075                Collection<MicroOperation> microOperations,
076                ServerEntry entryView )
077            throws LdapException
078        {
079            if ( tuples.size() == 0 )
080            {
081                return tuples;
082            }
083    
084            for ( Iterator<ACITuple> ii = tuples.iterator(); ii.hasNext(); )
085            {
086                ACITuple tuple = ii.next();
087                
088                if ( tuple.isGrant() )
089                {
090                    if ( !isRelated( userGroupNames, 
091                                     userName, 
092                                     userEntry, 
093                                     entryName, 
094                                     tuple.getUserClasses() )
095                        || authenticationLevel.compareTo( tuple.getAuthenticationLevel() ) < 0 )
096                    {
097                        ii.remove();
098                    }
099                }
100                else
101                // Denials
102                {
103                    if ( !isRelated( userGroupNames, 
104                                     userName, 
105                                     userEntry, 
106                                     entryName, 
107                                     tuple.getUserClasses() )
108                        && authenticationLevel.compareTo( tuple.getAuthenticationLevel() ) >= 0 )
109                    {
110                        ii.remove();
111                    }
112                }
113            }
114    
115            return tuples;
116        }
117    
118    
119        private boolean isRelated( Collection<DN> userGroupNames, DN userName, ServerEntry userEntry, 
120            DN entryName, Collection<UserClass> userClasses ) throws LdapException
121        {
122            for ( UserClass userClass : userClasses )
123            {
124                if ( userClass == UserClass.ALL_USERS )
125                {
126                    return true;
127                }
128                else if ( userClass == UserClass.THIS_ENTRY )
129                {
130                    if ( userName.equals( entryName ) )
131                    {
132                        return true;
133                    }
134                }
135                else if ( userClass == UserClass.PARENT_OF_ENTRY )
136                {
137                    if ( entryName.isChildOf( userName ) )
138                    {
139                        return true;
140                    }
141                }
142                else if ( userClass instanceof UserClass.Name )
143                {
144                    UserClass.Name nameUserClass = ( UserClass.Name ) userClass;
145                    if ( nameUserClass.getNames().contains( userName ) )
146                    {
147                        return true;
148                    }
149                }
150                else if ( userClass instanceof UserClass.UserGroup )
151                {
152                    UserClass.UserGroup userGroupUserClass = ( UserClass.UserGroup ) userClass;
153                    
154                    for ( DN userGroupName : userGroupNames )
155                    {
156                        Set<DN> dns = userGroupUserClass.getNames();
157                        
158                        if ( userGroupName != null )
159                        {
160                            for ( DN dn : dns )
161                            {
162                                if ( userGroupName.getNormName().equals( dn.getNormName() ) )
163                                {
164                                    return true;
165                                }
166                            }
167                        }
168                    }
169                }
170                else if ( userClass instanceof UserClass.Subtree )
171                {
172                    UserClass.Subtree subtree = ( UserClass.Subtree ) userClass;
173                    if ( matchUserClassSubtree( userName, userEntry, subtree ) )
174                    {
175                        return true;
176                    }
177                }
178                else
179                {
180                    throw new InternalError( I18n.err( I18n.ERR_233, userClass.getClass().getName() ) );
181                }
182            }
183    
184            return false;
185        }
186    
187    
188        private boolean matchUserClassSubtree( DN userName, ServerEntry userEntry, UserClass.Subtree subtree )
189            throws LdapException
190        {
191            for ( SubtreeSpecification subtreeSpec : subtree.getSubtreeSpecifications() )
192            {
193                if ( subtreeEvaluator.evaluate( subtreeSpec, ROOTDSE_NAME, userName, userEntry ) )
194                {
195                    return true;
196                }
197            }
198    
199            return false;
200        }
201    }