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;
025
026import javax.naming.directory.SearchControls;
027
028import org.apache.directory.api.ldap.aci.ACITuple;
029import org.apache.directory.api.ldap.aci.ProtectedItem;
030import org.apache.directory.api.ldap.aci.protectedItem.MaxImmSubItem;
031import org.apache.directory.api.ldap.model.constants.SchemaConstants;
032import org.apache.directory.api.ldap.model.entry.Entry;
033import org.apache.directory.api.ldap.model.exception.LdapException;
034import org.apache.directory.api.ldap.model.exception.LdapOperationException;
035import org.apache.directory.api.ldap.model.exception.LdapOtherException;
036import org.apache.directory.api.ldap.model.filter.ExprNode;
037import org.apache.directory.api.ldap.model.filter.PresenceNode;
038import org.apache.directory.api.ldap.model.message.AliasDerefMode;
039import org.apache.directory.api.ldap.model.name.Dn;
040import org.apache.directory.api.ldap.model.schema.AttributeType;
041import org.apache.directory.api.ldap.model.schema.SchemaManager;
042import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
043import org.apache.directory.server.core.api.interceptor.context.OperationContext;
044import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
045
046
047/**
048 * An {@link ACITupleFilter} that discards all tuples that doesn't satisfy
049 * {@link org.apache.directory.api.ldap.aci.protectedItem.MaxImmSubItem} constraint if available. (18.8.3.3, X.501)
050 *
051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
052 */
053public class MaxImmSubFilter implements ACITupleFilter
054{
055    private final ExprNode childrenFilter;
056    private final SearchControls childrenSearchControls;
057
058
059    public MaxImmSubFilter( SchemaManager schemaManager )
060    {
061        AttributeType objectClassAt = null;
062
063        try
064        {
065            objectClassAt = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.OBJECT_CLASS_AT );
066        }
067        catch ( LdapException le )
068        {
069            // Do nothing
070        }
071
072        childrenFilter = new PresenceNode( objectClassAt );
073        childrenSearchControls = new SearchControls();
074        childrenSearchControls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
075    }
076
077
078    /**
079     * {@inheritDoc}
080     */
081    @Override
082    public Collection<ACITuple> filter( AciContext aciContext, OperationScope scope, Entry userEntry )
083        throws LdapException
084    {
085        ACI_LOG.debug( "Filtering MaxImmSub..." );
086
087        if ( aciContext.getEntryDn().isRootDse() )
088        {
089            return aciContext.getAciTuples();
090        }
091
092        if ( aciContext.getAciTuples().isEmpty() )
093        {
094            return aciContext.getAciTuples();
095        }
096
097        if ( scope != OperationScope.ENTRY )
098        {
099            return aciContext.getAciTuples();
100        }
101
102        int immSubCount = -1;
103
104        for ( Iterator<ACITuple> i = aciContext.getAciTuples().iterator(); i.hasNext(); )
105        {
106            ACITuple tuple = i.next();
107
108            if ( !tuple.isGrant() )
109            {
110                continue;
111            }
112
113            for ( ProtectedItem item : tuple.getProtectedItems() )
114            {
115                if ( item instanceof MaxImmSubItem )
116                {
117                    if ( immSubCount < 0 )
118                    {
119                        immSubCount = getImmSubCount( aciContext.getOperationContext(), aciContext.getEntryDn() );
120                    }
121
122                    MaxImmSubItem mis = ( MaxImmSubItem ) item;
123
124                    if ( immSubCount >= mis.getValue() )
125                    {
126                        i.remove();
127                        break;
128                    }
129                }
130            }
131        }
132
133        return aciContext.getAciTuples();
134    }
135
136
137    private int getImmSubCount( OperationContext opContext, Dn entryName ) throws LdapException
138    {
139        int cnt = 0;
140        EntryFilteringCursor results = null;
141
142        try
143        {
144            Dn baseDn = new Dn( opContext.getSession().getDirectoryService().getSchemaManager(),
145                entryName.getRdn( entryName.size() - 1 ) );
146            SearchOperationContext searchContext = new SearchOperationContext( opContext.getSession(),
147                baseDn, childrenFilter, childrenSearchControls );
148            searchContext.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );
149            searchContext.setPartition( opContext.getPartition() );
150            searchContext.setTransaction( opContext.getTransaction() );
151
152            results = opContext.getSession().getDirectoryService().getPartitionNexus().search( searchContext );
153
154            try
155            {
156                while ( results.next() )
157                {
158                    results.get();
159                    cnt++;
160                }
161            }
162            catch ( Exception e )
163            {
164                throw new LdapOtherException( e.getMessage(), e );
165            }
166        }
167        finally
168        {
169            if ( results != null )
170            {
171                try
172                {
173                    results.close();
174                }
175                catch ( Exception e )
176                {
177                    throw new LdapOperationException( e.getMessage(), e );
178                }
179            }
180        }
181
182        return cnt;
183    }
184}