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 19:39:54 +0100 (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 }