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 */
020package org.apache.directory.server.core.authz.support;
021
022
023import java.util.Collection;
024import java.util.Iterator;
025import java.util.Set;
026
027import org.apache.directory.api.ldap.aci.ACITuple;
028import org.apache.directory.api.ldap.aci.UserClass;
029import org.apache.directory.api.ldap.model.entry.Entry;
030import org.apache.directory.api.ldap.model.exception.LdapException;
031import org.apache.directory.api.ldap.model.name.Dn;
032import org.apache.directory.api.ldap.model.subtree.SubtreeSpecification;
033import org.apache.directory.server.core.api.subtree.SubtreeEvaluator;
034import org.apache.directory.server.i18n.I18n;
035
036
037/**
038 * An {@link ACITupleFilter} that discards all tuples whose {@link UserClass}es
039 * are not related with the current user. (18.8.3.1, X.501)
040 *
041 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
042 */
043public class RelatedUserClassFilter implements ACITupleFilter
044{
045    private final SubtreeEvaluator subtreeEvaluator;
046
047
048    public RelatedUserClassFilter( SubtreeEvaluator subtreeEvaluator )
049    {
050        this.subtreeEvaluator = subtreeEvaluator;
051    }
052
053
054    /**
055     * {@inheritDoc}
056     */
057    @Override
058    public Collection<ACITuple> filter( AciContext aciContext, OperationScope scope, Entry userEntry )
059        throws LdapException
060    {
061        if ( aciContext.getAciTuples().isEmpty() )
062        {
063            return aciContext.getAciTuples();
064        }
065
066        for ( Iterator<ACITuple> ii = aciContext.getAciTuples().iterator(); ii.hasNext(); )
067        {
068            ACITuple tuple = ii.next();
069
070            if ( tuple.isGrant() )
071            {
072                if ( !isRelated( aciContext.getUserGroupNames(),
073                    aciContext.getUserDn(),
074                    userEntry,
075                    aciContext.getEntryDn(),
076                    tuple.getUserClasses() )
077                    || aciContext.getAuthenticationLevel().compareTo( tuple.getAuthenticationLevel() ) < 0 )
078                {
079                    ii.remove();
080                }
081            }
082            else
083            // Denials
084            {
085                if ( !isRelated( aciContext.getUserGroupNames(),
086                    aciContext.getUserDn(),
087                    userEntry,
088                    aciContext.getEntryDn(),
089                    tuple.getUserClasses() )
090                    && aciContext.getAuthenticationLevel().compareTo( tuple.getAuthenticationLevel() ) >= 0 )
091                {
092                    ii.remove();
093                }
094            }
095        }
096
097        return aciContext.getAciTuples();
098    }
099
100
101    private boolean isRelated( Collection<String> userGroupNames, Dn userName, Entry userEntry,
102        Dn entryName, Collection<UserClass> userClasses ) throws LdapException
103    {
104        for ( UserClass userClass : userClasses )
105        {
106            if ( userClass == UserClass.ALL_USERS )
107            {
108                return true;
109            }
110            else if ( userClass == UserClass.THIS_ENTRY )
111            {
112                if ( userName.equals( entryName ) )
113                {
114                    return true;
115                }
116            }
117            else if ( userClass == UserClass.PARENT_OF_ENTRY )
118            {
119                if ( entryName.isDescendantOf( userName ) )
120                {
121                    return true;
122                }
123            }
124            else if ( userClass instanceof UserClass.Name )
125            {
126                UserClass.Name nameUserClass = ( UserClass.Name ) userClass;
127                
128                if ( ( userName != null ) && nameUserClass.getNames().contains( userName.getNormName() ) )
129                {
130                    return true;
131                }
132            }
133            else if ( userClass instanceof UserClass.UserGroup )
134            {
135                UserClass.UserGroup userGroupUserClass = ( UserClass.UserGroup ) userClass;
136
137                for ( String userGroupName : userGroupNames )
138                {
139                    Set<String> dns = userGroupUserClass.getNames();
140
141                    if ( userGroupName != null )
142                    {
143                        for ( String dn : dns )
144                        {
145                            if ( userGroupName.equals( dn ) )
146                            {
147                                return true;
148                            }
149                        }
150                    }
151                }
152            }
153            else if ( userClass instanceof UserClass.Subtree )
154            {
155                UserClass.Subtree subtree = ( UserClass.Subtree ) userClass;
156                if ( matchUserClassSubtree( userName, userEntry, subtree ) )
157                {
158                    return true;
159                }
160            }
161            else
162            {
163                throw new InternalError( I18n.err( I18n.ERR_233, userClass.getClass().getName() ) );
164            }
165        }
166
167        return false;
168    }
169
170
171    private boolean matchUserClassSubtree( Dn userName, Entry userEntry, UserClass.Subtree subtree )
172        throws LdapException
173    {
174        for ( SubtreeSpecification subtreeSpec : subtree.getSubtreeSpecifications() )
175        {
176            if ( subtreeEvaluator.evaluate( subtreeSpec, Dn.ROOT_DSE, userName, userEntry ) )
177            {
178                return true;
179            }
180        }
181
182        return false;
183    }
184}