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.Collections;
025 import java.util.HashSet;
026 import java.util.Iterator;
027
028 import javax.naming.directory.SearchControls;
029
030 import org.apache.directory.server.core.authn.AuthenticationInterceptor;
031 import org.apache.directory.server.core.authz.AciAuthorizationInterceptor;
032 import org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor;
033 import org.apache.directory.server.core.event.EventInterceptor;
034 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
035 import org.apache.directory.server.core.interceptor.context.OperationContext;
036 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
037 import org.apache.directory.server.core.normalization.NormalizationInterceptor;
038 import org.apache.directory.server.core.operational.OperationalAttributeInterceptor;
039 import org.apache.directory.server.core.schema.SchemaInterceptor;
040 import org.apache.directory.server.core.subtree.SubentryInterceptor;
041 import org.apache.directory.shared.ldap.aci.ACITuple;
042 import org.apache.directory.shared.ldap.aci.MicroOperation;
043 import org.apache.directory.shared.ldap.aci.ProtectedItem;
044 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
045 import org.apache.directory.shared.ldap.constants.SchemaConstants;
046 import org.apache.directory.shared.ldap.entry.ServerEntry;
047 import org.apache.directory.shared.ldap.entry.Value;
048 import org.apache.directory.shared.ldap.filter.ExprNode;
049 import org.apache.directory.shared.ldap.filter.PresenceNode;
050 import org.apache.directory.shared.ldap.message.AliasDerefMode;
051 import org.apache.directory.shared.ldap.name.DN;
052 import org.apache.directory.shared.ldap.schema.SchemaManager;
053
054
055
056 /**
057 * An {@link ACITupleFilter} that discards all tuples that doesn't satisfy
058 * {@link org.apache.directory.shared.ldap.aci.ProtectedItem.MaxImmSub} constraint if available. (18.8.3.3, X.501)
059 *
060 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
061 * @version $Rev: 927146 $, $Date: 2010-03-24 20:39:54 +0200 (Wed, 24 Mar 2010) $
062 */
063 public class MaxImmSubFilter implements ACITupleFilter
064 {
065 private final ExprNode childrenFilter;
066 private final SearchControls childrenSearchControls;
067
068
069 public MaxImmSubFilter()
070 {
071 childrenFilter = new PresenceNode( SchemaConstants.OBJECT_CLASS_AT );
072 childrenSearchControls = new SearchControls();
073 childrenSearchControls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
074 }
075
076
077 public Collection<ACITuple> filter(
078 SchemaManager schemaManager,
079 Collection<ACITuple> tuples,
080 OperationScope scope,
081 OperationContext opContext,
082 Collection<DN> userGroupNames,
083 DN userName,
084 ServerEntry userEntry,
085 AuthenticationLevel authenticationLevel,
086 DN entryName,
087 String attrId,
088 Value<?> attrValue,
089 ServerEntry entry,
090 Collection<MicroOperation> microOperations,
091 ServerEntry entryView )
092 throws Exception
093 {
094 if ( entryName.size() == 0 )
095 {
096 return tuples;
097 }
098
099 if ( tuples.size() == 0 )
100 {
101 return tuples;
102 }
103
104 if ( scope != OperationScope.ENTRY )
105 {
106 return tuples;
107 }
108
109 int immSubCount = -1;
110
111 for ( Iterator<ACITuple> i = tuples.iterator(); i.hasNext(); )
112 {
113 ACITuple tuple = i.next();
114 if ( !tuple.isGrant() )
115 {
116 continue;
117 }
118
119 for ( ProtectedItem item : tuple.getProtectedItems() )
120 {
121 if ( item instanceof ProtectedItem.MaxImmSub )
122 {
123 if ( immSubCount < 0 )
124 {
125 immSubCount = getImmSubCount( schemaManager, opContext, entryName );
126 }
127
128 ProtectedItem.MaxImmSub mis = ( ProtectedItem.MaxImmSub ) item;
129 if ( immSubCount >= mis.getValue() )
130 {
131 i.remove();
132 break;
133 }
134 }
135 }
136 }
137
138 return tuples;
139 }
140
141 public static final Collection<String> SEARCH_BYPASS;
142 static
143 {
144 Collection<String> c = new HashSet<String>();
145 c.add( NormalizationInterceptor.class.getName() );
146 c.add( AuthenticationInterceptor.class.getName() );
147 c.add( AciAuthorizationInterceptor.class.getName() );
148 c.add( DefaultAuthorizationInterceptor.class.getName() );
149 c.add( OperationalAttributeInterceptor.class.getName() );
150 c.add( SchemaInterceptor.class.getName() );
151 c.add( SubentryInterceptor.class.getName() );
152 c.add( EventInterceptor.class.getName() );
153 SEARCH_BYPASS = Collections.unmodifiableCollection( c );
154 }
155
156
157 private int getImmSubCount( SchemaManager schemaManager, OperationContext opContext, DN entryName ) throws Exception
158 {
159 int cnt = 0;
160 EntryFilteringCursor results = null;
161
162 try
163 {
164 SearchOperationContext searchContext = new SearchOperationContext( opContext.getSession(),
165 ( DN ) entryName.getPrefix( 1 ), childrenFilter, childrenSearchControls );
166 searchContext.setByPassed( SEARCH_BYPASS );
167 searchContext.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );
168
169 results = opContext.getSession().getDirectoryService().getOperationManager().search( searchContext );
170
171 while ( results.next() )
172 {
173 results.get();
174 cnt++;
175 }
176
177 }
178 finally
179 {
180 if ( results != null )
181 {
182 results.close();
183 }
184 }
185
186 return cnt;
187 }
188 }