1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.authz;
21
22
23 import org.apache.directory.server.core.CoreSession;
24 import org.apache.directory.server.core.entry.ServerAttribute;
25 import org.apache.directory.server.core.entry.ServerEntry;
26 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
27 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
28 import org.apache.directory.server.core.partition.PartitionNexus;
29 import org.apache.directory.server.schema.ConcreteNameComponentNormalizer;
30 import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
31 import org.apache.directory.server.schema.registries.OidRegistry;
32 import org.apache.directory.shared.ldap.aci.ACIItem;
33 import org.apache.directory.shared.ldap.aci.ACIItemParser;
34 import org.apache.directory.shared.ldap.aci.ACITuple;
35 import org.apache.directory.shared.ldap.constants.SchemaConstants;
36 import org.apache.directory.shared.ldap.entry.EntryAttribute;
37 import org.apache.directory.shared.ldap.entry.Modification;
38 import org.apache.directory.shared.ldap.entry.Value;
39 import org.apache.directory.shared.ldap.entry.client.ClientStringValue;
40 import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
41 import org.apache.directory.shared.ldap.filter.EqualityNode;
42 import org.apache.directory.shared.ldap.filter.ExprNode;
43 import org.apache.directory.shared.ldap.message.AliasDerefMode;
44 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
45 import org.apache.directory.shared.ldap.name.LdapDN;
46 import org.apache.directory.shared.ldap.name.NameComponentNormalizer;
47 import org.apache.directory.shared.ldap.schema.AttributeType;
48 import org.apache.directory.shared.ldap.schema.OidNormalizer;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import javax.naming.NamingException;
53 import javax.naming.directory.SearchControls;
54 import java.text.ParseException;
55 import java.util.ArrayList;
56 import java.util.Collections;
57 import java.util.HashMap;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.Map;
61
62
63
64
65
66
67
68
69
70
71 public class TupleCache
72 {
73
74 private static final Logger LOG = LoggerFactory.getLogger( TupleCache.class );
75
76
77 private final Map<String, List<ACITuple>> tuples = new HashMap<String, List<ACITuple>>();
78
79
80 private final PartitionNexus nexus;
81
82
83 private final ACIItemParser aciParser;
84
85
86 private AttributeType prescriptiveAciAT;
87
88
89
90
91 private Map<String, OidNormalizer> normalizerMap;
92
93
94
95
96
97
98
99
100 public TupleCache( CoreSession session ) throws Exception
101 {
102 normalizerMap = session.getDirectoryService().getRegistries()
103 .getAttributeTypeRegistry().getNormalizerMapping();
104 this.nexus = session.getDirectoryService().getPartitionNexus();
105 AttributeTypeRegistry attributeTypeRegistry = session.getDirectoryService()
106 .getRegistries().getAttributeTypeRegistry();
107 OidRegistry oidRegistry = session.getDirectoryService().getRegistries().getOidRegistry();
108 NameComponentNormalizer ncn = new ConcreteNameComponentNormalizer( attributeTypeRegistry, oidRegistry );
109 aciParser = new ACIItemParser( ncn, normalizerMap );
110 prescriptiveAciAT = attributeTypeRegistry.lookup( SchemaConstants.PRESCRIPTIVE_ACI_AT );
111 initialize( session );
112 }
113
114
115 private LdapDN parseNormalized( String name ) throws NamingException
116 {
117 LdapDN dn = new LdapDN( name );
118 dn.normalize( normalizerMap );
119 return dn;
120 }
121
122
123 private void initialize( CoreSession session ) throws Exception
124 {
125
126
127
128 Iterator<String> suffixes = nexus.listSuffixes( null );
129
130 while ( suffixes.hasNext() )
131 {
132 String suffix = suffixes.next();
133 LdapDN baseDn = parseNormalized( suffix );
134 ExprNode filter = new EqualityNode<String>( SchemaConstants.OBJECT_CLASS_AT,
135 new ClientStringValue( SchemaConstants.ACCESS_CONTROL_SUBENTRY_OC ) );
136 SearchControls ctls = new SearchControls();
137 ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
138 EntryFilteringCursor results = nexus.search( new SearchOperationContext( session,
139 baseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, ctls ) );
140
141 while ( results.next() )
142 {
143 ServerEntry result = results.get();
144 LdapDN subentryDn = result.getDn().normalize( normalizerMap );
145 EntryAttribute aci = result.get( prescriptiveAciAT );
146
147 if ( aci == null )
148 {
149 LOG.warn( "Found accessControlSubentry '" + subentryDn + "' without any "
150 + SchemaConstants.PRESCRIPTIVE_ACI_AT );
151 continue;
152 }
153
154 subentryAdded( subentryDn, result );
155 }
156
157 results.close();
158 }
159 }
160
161
162 private boolean hasPrescriptiveACI( ServerEntry entry ) throws NamingException
163 {
164
165 EntryAttribute aci = entry.get( prescriptiveAciAT );
166
167 if ( aci == null )
168 {
169 if ( entry.contains( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.ACCESS_CONTROL_SUBENTRY_OC )
170 || entry.contains( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.ACCESS_CONTROL_SUBENTRY_OC_OID ) )
171 {
172
173
174
175 throw new LdapSchemaViolationException( "", ResultCodeEnum.OBJECT_CLASS_VIOLATION );
176 }
177 else
178 {
179 return false;
180 }
181 }
182
183 return true;
184 }
185
186
187 public void subentryAdded( LdapDN normName, ServerEntry entry ) throws NamingException
188 {
189
190 EntryAttribute aciAttr = entry.get( prescriptiveAciAT );
191
192 if ( !hasPrescriptiveACI( entry ) )
193 {
194 return;
195 }
196
197 List<ACITuple> entryTuples = new ArrayList<ACITuple>();
198
199 for ( Value<?> value : aciAttr )
200 {
201 String aci = ( String ) value.get();
202 ACIItem item = null;
203
204 try
205 {
206 item = aciParser.parse( aci );
207 entryTuples.addAll( item.toTuples() );
208 }
209 catch ( ParseException e )
210 {
211 String msg = "ACIItem parser failure on \n'" + item + "'\ndue to syntax error. "
212 + "Cannnot add ACITuples to TupleCache.\n"
213 + "Check that the syntax of the ACI item is correct. \nUntil this error "
214 + "is fixed your security settings will not be as expected.";
215 LOG.error( msg, e );
216
217
218
219 }
220 }
221
222 tuples.put( normName.toNormName(), entryTuples );
223 }
224
225
226 public void subentryDeleted( LdapDN normName, ServerEntry entry ) throws NamingException
227 {
228 if ( !hasPrescriptiveACI( entry ) )
229 {
230 return;
231 }
232
233 tuples.remove( normName.toString() );
234 }
235
236
237 public void subentryModified( LdapDN normName, List<Modification> mods, ServerEntry entry ) throws NamingException
238 {
239 if ( !hasPrescriptiveACI( entry ) )
240 {
241 return;
242 }
243
244 for ( Modification mod : mods )
245 {
246 if ( ( ( ServerAttribute ) mod.getAttribute() ).instanceOf( SchemaConstants.PRESCRIPTIVE_ACI_AT ) )
247 {
248 subentryDeleted( normName, entry );
249 subentryAdded( normName, entry );
250 }
251 }
252 }
253
254
255 public void subentryModified( LdapDN normName, ServerEntry mods, ServerEntry entry ) throws NamingException
256 {
257 if ( !hasPrescriptiveACI( entry ) )
258 {
259 return;
260 }
261
262 if ( mods.get( prescriptiveAciAT ) != null )
263 {
264 subentryDeleted( normName, entry );
265 subentryAdded( normName, entry );
266 }
267 }
268
269
270 @SuppressWarnings("unchecked")
271 public List<ACITuple> getACITuples( String subentryDn )
272 {
273 List aciTuples = tuples.get( subentryDn );
274 if ( aciTuples == null )
275 {
276 return Collections.EMPTY_LIST;
277 }
278 return Collections.unmodifiableList( aciTuples );
279 }
280
281
282 public void subentryRenamed( LdapDN oldName, LdapDN newName )
283 {
284 tuples.put( newName.toString(), tuples.remove( oldName.toString() ) );
285 }
286 }