1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ldap.server.authz;
18
19
20 import java.util.Map;
21
22 import javax.naming.Name;
23 import javax.naming.NamingEnumeration;
24 import javax.naming.NamingException;
25 import javax.naming.NoPermissionException;
26 import javax.naming.directory.Attributes;
27 import javax.naming.directory.ModificationItem;
28 import javax.naming.directory.SearchControls;
29 import javax.naming.directory.SearchResult;
30 import javax.naming.ldap.LdapContext;
31
32 import org.apache.ldap.common.exception.LdapNoPermissionException;
33 import org.apache.ldap.common.filter.ExprNode;
34 import org.apache.ldap.common.name.DnParser;
35 import org.apache.ldap.server.DirectoryServiceConfiguration;
36 import org.apache.ldap.server.configuration.InterceptorConfiguration;
37 import org.apache.ldap.server.enumeration.SearchResultFilteringEnumeration;
38 import org.apache.ldap.server.enumeration.SearchResultFilter;
39 import org.apache.ldap.server.interceptor.BaseInterceptor;
40 import org.apache.ldap.server.interceptor.Interceptor;
41 import org.apache.ldap.server.interceptor.NextInterceptor;
42 import org.apache.ldap.server.invocation.InvocationStack;
43 import org.apache.ldap.server.invocation.Invocation;
44 import org.apache.ldap.server.jndi.ServerContext;
45 import org.apache.ldap.server.partition.DirectoryPartitionNexus;
46 import org.apache.ldap.server.schema.AttributeTypeRegistry;
47 import org.apache.ldap.server.schema.ConcreteNameComponentNormalizer;
48
49
50 /***
51 * An {@link Interceptor} that controls access to {@link DirectoryPartitionNexus}.
52 * If a user tries to perform any operations that requires
53 * permission he or she doesn't have, {@link NoPermissionException} will be
54 * thrown and therefore the current invocation chain will terminate.
55 *
56 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
57 * @version $Rev: 201550 $, $Date: 2005-06-23 23:08:31 -0400 (Thu, 23 Jun 2005) $
58 */
59 public class OldAuthorizationService extends BaseInterceptor
60 {
61 /***
62 * the administrator's distinguished {@link Name}
63 */
64 private static final Name ADMIN_DN = DirectoryPartitionNexus.getAdminName();
65
66 /***
67 * the base distinguished {@link Name} for all users
68 */
69 private static final Name USER_BASE_DN = DirectoryPartitionNexus.getUsersBaseName();
70
71 /***
72 * the base distinguished {@link Name} for all groups
73 */
74 private static final Name GROUP_BASE_DN = DirectoryPartitionNexus.getGroupsBaseName();
75
76 /***
77 * the name parser used by this service
78 */
79 private DnParser dnParser;
80 private boolean enabled = true;
81
82
83
84 /***
85 * Creates a new instance.
86 */
87 public OldAuthorizationService()
88 {
89 }
90
91
92 public void init( DirectoryServiceConfiguration factoryCfg, InterceptorConfiguration cfg ) throws NamingException
93 {
94 AttributeTypeRegistry atr = factoryCfg.getGlobalRegistries().getAttributeTypeRegistry();
95 dnParser = new DnParser( new ConcreteNameComponentNormalizer( atr ) );
96
97
98 enabled = ! factoryCfg.getStartupConfiguration().isAccessControlEnabled();
99 }
100
101
102
103
104
105
106 public void delete( NextInterceptor nextInterceptor, Name name ) throws NamingException
107 {
108 if ( !enabled )
109 {
110 nextInterceptor.delete( name );
111 return;
112 }
113
114 Name principalDn = getPrincipal().getJndiName();
115
116 if ( name.toString().equals( "" ) )
117 {
118 String msg = "The rootDSE cannot be deleted!";
119 throw new LdapNoPermissionException( msg );
120 }
121
122 if ( name == ADMIN_DN || name.equals( ADMIN_DN ) )
123 {
124 String msg = "User " + principalDn;
125 msg += " does not have permission to delete the admin account.";
126 msg += " No one not even the admin can delete this account!";
127 throw new LdapNoPermissionException( msg );
128 }
129
130 if ( name.size() > 2 && name.startsWith( USER_BASE_DN )
131 && !principalDn.equals( ADMIN_DN ) )
132 {
133 String msg = "User " + principalDn;
134 msg += " does not have permission to delete the user account: ";
135 msg += name + ". Only the admin can delete user accounts.";
136 throw new LdapNoPermissionException( msg );
137 }
138
139 if ( name.size() > 2 && name.startsWith( GROUP_BASE_DN )
140 && !principalDn.equals( ADMIN_DN ) )
141 {
142 String msg = "User " + principalDn;
143 msg += " does not have permission to delete the group entry: ";
144 msg += name + ". Only the admin can delete groups.";
145 throw new LdapNoPermissionException( msg );
146 }
147
148 nextInterceptor.delete( name );
149 }
150
151
152 /***
153 * Note that we do nothing here. First because this is not an externally
154 * exposed function via the JNDI interfaces. It is used internally by
155 * the provider for optimization purposes so there is no reason for us to
156 * start to constrain it.
157 */
158 public boolean hasEntry( NextInterceptor nextInterceptor, Name name ) throws NamingException
159 {
160 return super.hasEntry( nextInterceptor, name );
161 }
162
163
164
165
166
167
168
169 /***
170 * This policy needs to be really tight too because some attributes may take
171 * part in giving the user permissions to protected resources. We do not want
172 * users to self access these resources. As far as we're concerned no one but
173 * the admin needs access.
174 */
175 public void modify( NextInterceptor nextInterceptor, Name name, int modOp, Attributes attrs ) throws NamingException
176 {
177 if ( enabled )
178 {
179 protectModifyAlterations( name );
180 }
181
182 nextInterceptor.modify( name, modOp, attrs );
183 }
184
185
186 /***
187 * This policy needs to be really tight too because some attributes may take part
188 * in giving the user permissions to protected resources. We do not want users to
189 * self access these resources. As far as we're concerned no one but the admin
190 * needs access.
191 */
192 public void modify( NextInterceptor nextInterceptor, Name name, ModificationItem[] items ) throws NamingException
193 {
194 if ( enabled )
195 {
196 protectModifyAlterations( name );
197 }
198 nextInterceptor.modify( name, items );
199 }
200
201
202 private void protectModifyAlterations( Name dn ) throws LdapNoPermissionException
203 {
204 Name principalDn = getPrincipal().getJndiName();
205
206 if ( dn.toString().equals( "" ) )
207 {
208 String msg = "The rootDSE cannot be modified!";
209 throw new LdapNoPermissionException( msg );
210 }
211
212 if ( !principalDn.equals( ADMIN_DN ) )
213 {
214 if ( dn.equals( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) )
215 {
216 String msg = "User " + principalDn;
217 msg += " does not have permission to modify the account of the";
218 msg += " admin user.";
219 throw new LdapNoPermissionException( msg );
220 }
221
222 if ( dn.size() > 2 && dn.startsWith( USER_BASE_DN ) )
223 {
224 String msg = "User " + principalDn;
225 msg += " does not have permission to modify the account of the";
226 msg += " user " + dn + ".\nEven the owner of an account cannot";
227 msg += " modify it.\nUser accounts can only be modified by the";
228 msg += " administrator.";
229 throw new LdapNoPermissionException( msg );
230 }
231
232 if ( dn.size() > 2 && dn.startsWith( GROUP_BASE_DN ) )
233 {
234 String msg = "User " + principalDn;
235 msg += " does not have permission to modify the group entry ";
236 msg += dn + ".\nGroups can only be modified by the admin.";
237 throw new LdapNoPermissionException( msg );
238 }
239 }
240 }
241
242
243
244
245
246
247
248
249
250
251
252
253 public void modifyRn( NextInterceptor nextInterceptor, Name name, String newRn, boolean deleteOldRn ) throws NamingException
254 {
255 if ( enabled )
256 {
257 protectDnAlterations( name );
258 }
259 nextInterceptor.modifyRn( name, newRn, deleteOldRn );
260 }
261
262
263 public void move( NextInterceptor nextInterceptor, Name oriChildName, Name newParentName ) throws NamingException
264 {
265 if ( enabled )
266 {
267 protectDnAlterations( oriChildName );
268 }
269 nextInterceptor.move( oriChildName, newParentName );
270 }
271
272
273 public void move( NextInterceptor nextInterceptor,
274 Name oriChildName, Name newParentName, String newRn,
275 boolean deleteOldRn ) throws NamingException
276 {
277 if ( enabled )
278 {
279 protectDnAlterations( oriChildName );
280 }
281 nextInterceptor.move( oriChildName, newParentName, newRn, deleteOldRn );
282 }
283
284
285 private void protectDnAlterations( Name dn ) throws LdapNoPermissionException
286 {
287 Name principalDn = getPrincipal().getJndiName();
288
289 if ( dn.toString().equals( "" ) )
290 {
291 String msg = "The rootDSE cannot be moved or renamed!";
292 throw new LdapNoPermissionException( msg );
293 }
294
295 if ( dn == ADMIN_DN || dn.equals( ADMIN_DN ) )
296 {
297 String msg = "User '" + principalDn;
298 msg += "' does not have permission to move or rename the admin";
299 msg += " account. No one not even the admin can move or";
300 msg += " rename " + dn + "!";
301 throw new LdapNoPermissionException( msg );
302 }
303
304 if ( dn.size() > 2 && dn.startsWith( USER_BASE_DN ) && !principalDn.equals( ADMIN_DN ) )
305 {
306 String msg = "User '" + principalDn;
307 msg += "' does not have permission to move or rename the user";
308 msg += " account: " + dn + ". Only the admin can move or";
309 msg += " rename user accounts.";
310 throw new LdapNoPermissionException( msg );
311 }
312
313 if ( dn.size() > 2 && dn.startsWith( GROUP_BASE_DN ) && !principalDn.equals( ADMIN_DN ) )
314 {
315 String msg = "User " + principalDn;
316 msg += " does not have permission to move or rename the group entry ";
317 msg += dn + ".\nGroups can only be moved or renamed by the admin.";
318 throw new LdapNoPermissionException( msg );
319 }
320 }
321
322
323 public Attributes lookup( NextInterceptor nextInterceptor, Name name ) throws NamingException
324 {
325 Attributes attributes = nextInterceptor.lookup( name );
326 if ( ! enabled || attributes == null )
327 {
328 return attributes;
329 }
330
331 protectLookUp( name );
332 return attributes;
333 }
334
335
336 public Attributes lookup( NextInterceptor nextInterceptor, Name name, String[] attrIds ) throws NamingException
337 {
338 Attributes attributes = nextInterceptor.lookup( name, attrIds );
339 if ( ! enabled || attributes == null )
340 {
341 return attributes;
342 }
343
344 protectLookUp( name );
345 return attributes;
346 }
347
348
349 private void protectLookUp( Name dn ) throws NamingException
350 {
351 LdapContext ctx =
352 ( LdapContext ) InvocationStack.getInstance().peek().getCaller();
353 Name principalDn = ( ( ServerContext ) ctx ).getPrincipal().getJndiName();
354
355 if ( !principalDn.equals( ADMIN_DN ) )
356 {
357 if ( dn.size() > 2 && dn.startsWith( USER_BASE_DN ) )
358 {
359
360 if ( dn.toString().equals( principalDn.toString() ) )
361 {
362 return;
363 }
364
365 String msg = "Access to user account '" + dn + "' not permitted";
366 msg += " for user '" + principalDn + "'. Only the admin can";
367 msg += " access user account information";
368 throw new LdapNoPermissionException( msg );
369 }
370
371 if ( dn.size() > 2 && dn.startsWith( GROUP_BASE_DN ) )
372 {
373
374 if ( dn.toString().equals( principalDn.toString() ) )
375 {
376 return;
377 }
378
379 String msg = "Access to group '" + dn + "' not permitted";
380 msg += " for user '" + principalDn + "'. Only the admin can";
381 msg += " access group information";
382 throw new LdapNoPermissionException( msg );
383 }
384
385 if ( dn.equals( ADMIN_DN ) )
386 {
387
388 if ( dn.toString().equals( principalDn.toString() ) )
389 {
390 return;
391 }
392
393 String msg = "Access to admin account not permitted for user '";
394 msg += principalDn + "'. Only the admin can";
395 msg += " access admin account information";
396 throw new LdapNoPermissionException( msg );
397 }
398 }
399 }
400
401
402 public NamingEnumeration search( NextInterceptor nextInterceptor,
403 Name base, Map env, ExprNode filter,
404 SearchControls searchCtls ) throws NamingException
405 {
406 NamingEnumeration e = nextInterceptor.search( base, env, filter, searchCtls );
407 if ( !enabled )
408 {
409 return e;
410 }
411
412
413
414
415
416 Invocation invocation = InvocationStack.getInstance().peek();
417 return new SearchResultFilteringEnumeration( e, searchCtls, invocation,
418 new SearchResultFilter()
419 {
420 public boolean accept( Invocation invocation, SearchResult result, SearchControls controls )
421 throws NamingException
422 {
423 return OldAuthorizationService.this.isSearchable( invocation, result );
424 }
425 });
426 }
427
428
429 public NamingEnumeration list( NextInterceptor nextInterceptor, Name base ) throws NamingException
430 {
431 NamingEnumeration e = nextInterceptor.list( base );
432 if ( !enabled )
433 {
434 return e;
435 }
436
437 Invocation invocation = InvocationStack.getInstance().peek();
438 return new SearchResultFilteringEnumeration( e, null, invocation,
439 new SearchResultFilter()
440 {
441 public boolean accept( Invocation invocation, SearchResult result, SearchControls controls )
442 throws NamingException
443 {
444 return OldAuthorizationService.this.isSearchable( invocation, result );
445 }
446 } );
447 }
448
449
450 private boolean isSearchable( Invocation invocataion, SearchResult result )
451 throws NamingException
452 {
453 Name dn;
454
455 synchronized ( dnParser )
456 {
457 dn = dnParser.parse( result.getName() );
458 }
459
460 Name principalDn = ( ( ServerContext ) invocataion.getCaller() ).getPrincipal().getJndiName();
461 if ( !principalDn.equals( ADMIN_DN ) )
462 {
463 if ( dn.size() > 2 )
464 {
465 if ( dn.startsWith( USER_BASE_DN ) || dn.startsWith( GROUP_BASE_DN ) )
466 {
467 return false;
468 }
469 }
470
471 if ( dn.equals( ADMIN_DN ) )
472 {
473 return false;
474 }
475
476 }
477
478 return true;
479 }
480 }