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 java.io.IOException;
24 import java.util.HashSet;
25 import java.util.Set;
26
27 import javax.naming.NoPermissionException;
28
29 import org.apache.directory.api.ldap.model.entry.Attribute;
30 import org.apache.directory.api.ldap.model.entry.Entry;
31 import org.apache.directory.api.ldap.model.entry.Value;
32 import org.apache.directory.api.ldap.model.exception.LdapException;
33 import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
34 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
35 import org.apache.directory.api.ldap.model.name.Dn;
36 import org.apache.directory.server.constants.ServerDNConstants;
37 import org.apache.directory.server.core.api.CoreSession;
38 import org.apache.directory.server.core.api.DirectoryService;
39 import org.apache.directory.server.core.api.InterceptorEnum;
40 import org.apache.directory.server.core.api.filtering.EntryFilter;
41 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
42 import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
43 import org.apache.directory.server.core.api.interceptor.Interceptor;
44 import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
45 import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
46 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
47 import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
48 import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
49 import org.apache.directory.server.core.api.interceptor.context.OperationContext;
50 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
51 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
52 import org.apache.directory.server.core.api.partition.Partition;
53 import org.apache.directory.server.core.api.partition.PartitionNexus;
54 import org.apache.directory.server.core.api.partition.PartitionTxn;
55 import org.apache.directory.server.core.shared.partition.DefaultPartitionNexus;
56 import org.apache.directory.server.i18n.I18n;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60
61
62
63
64
65
66
67
68
69 public class DefaultAuthorizationInterceptor extends BaseInterceptor
70 {
71
72 private static final Logger LOG = LoggerFactory.getLogger( DefaultAuthorizationInterceptor.class );
73
74
75 private Dn adminSystemDn;
76
77
78 private Dn groupsBaseDn;
79
80
81 private Dn usersBaseDn;
82
83
84 private Dn adminGroupDn;
85
86 private Set<String> administrators = new HashSet<>( 2 );
87
88 private PartitionNexus nexus;
89
90
91
92
93 private class DefaultAuthorizationSearchFilter implements EntryFilter
94 {
95
96
97
98 public boolean accept( SearchOperationContext operation, Entry entry ) throws LdapException
99 {
100 return DefaultAuthorizationInterceptor.this.isSearchable( operation, entry );
101 }
102
103
104
105
106
107 public String toString( String tabs )
108 {
109 return tabs + "DefaultAuthorizationSearchFilter";
110 }
111 }
112
113
114
115
116
117 public DefaultAuthorizationInterceptor()
118 {
119 super( InterceptorEnum.DEFAULT_AUTHORIZATION_INTERCEPTOR );
120 }
121
122
123
124
125
126 @Override
127 public void init( DirectoryService directoryService ) throws LdapException
128 {
129 super.init( directoryService );
130
131 nexus = directoryService.getPartitionNexus();
132
133 adminSystemDn = dnFactory.create( ServerDNConstants.ADMIN_SYSTEM_DN );
134
135 groupsBaseDn = dnFactory.create( ServerDNConstants.GROUPS_SYSTEM_DN );
136
137 usersBaseDn = dnFactory.create( ServerDNConstants.USERS_SYSTEM_DN );
138
139 adminGroupDn = dnFactory.create( ServerDNConstants.ADMINISTRATORS_GROUP_DN );
140
141 loadAdministrators( directoryService );
142 }
143
144
145 private void loadAdministrators( DirectoryService directoryService ) throws LdapException
146 {
147
148 Set<String> newAdministrators = new HashSet<>( 2 );
149 CoreSession adminSession = directoryService.getAdminSession();
150 Partition partition = nexus.getPartition( adminGroupDn );
151 Entry adminGroup;
152
153 LookupOperationContexttor/context/LookupOperationContext.html#LookupOperationContext">LookupOperationContext lookupContext = new LookupOperationContext( adminSession, adminGroupDn );
154 lookupContext.setPartition( partition );
155
156 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
157 {
158 lookupContext.setTransaction( partitionTxn );
159 adminGroup = nexus.lookup( lookupContext );
160 }
161 catch ( IOException ioe )
162 {
163 throw new LdapOtherException( ioe.getMessage(), ioe );
164 }
165
166 if ( adminGroup == null )
167 {
168 return;
169 }
170
171 Attribute uniqueMember = adminGroup.get( directoryService.getAtProvider().getUniqueMember() );
172
173 for ( Value value : uniqueMember )
174 {
175 Dn memberDn = dnFactory.create( value.getString() );
176 newAdministrators.add( memberDn.getNormName() );
177 }
178
179 administrators = newAdministrators;
180 }
181
182
183
184
185
186
187
188
189 @Override
190 public void delete( DeleteOperationContext deleteContext ) throws LdapException
191 {
192 if ( deleteContext.getSession().getDirectoryService().isAccessControlEnabled() )
193 {
194 next( deleteContext );
195 return;
196 }
197
198 Dn dn = deleteContext.getDn();
199
200 if ( dn.isEmpty() )
201 {
202 String msg = I18n.err( I18n.ERR_12 );
203 LOG.error( msg );
204 throw new LdapNoPermissionException( msg );
205 }
206
207 if ( dn.equals( adminGroupDn ) )
208 {
209 String msg = I18n.err( I18n.ERR_13 );
210 LOG.error( msg );
211 throw new LdapNoPermissionException( msg );
212 }
213
214 Dn principalDn = getPrincipal( deleteContext ).getDn();
215
216 if ( dn.equals( adminSystemDn ) )
217 {
218 String msg = I18n.err( I18n.ERR_14, principalDn.getName() );
219 LOG.error( msg );
220 throw new LdapNoPermissionException( msg );
221 }
222
223 if ( dn.size() > 2 && !isAnAdministrator( principalDn ) )
224 {
225 if ( dn.isDescendantOf( adminSystemDn ) )
226 {
227 String msg = I18n.err( I18n.ERR_15, principalDn.getName(), dn.getName() );
228 LOG.error( msg );
229 throw new LdapNoPermissionException( msg );
230 }
231
232 if ( dn.isDescendantOf( groupsBaseDn ) )
233 {
234 String msg = I18n.err( I18n.ERR_16, principalDn.getName(), dn.getName() );
235 LOG.error( msg );
236 throw new LdapNoPermissionException( msg );
237 }
238
239 if ( dn.isDescendantOf( usersBaseDn ) )
240 {
241 String msg = I18n.err( I18n.ERR_16, principalDn.getName(), dn.getName() );
242 LOG.error( msg );
243 throw new LdapNoPermissionException( msg );
244 }
245 }
246
247 next( deleteContext );
248 }
249
250
251
252
253
254 @Override
255 public Entry lookup( LookupOperationContext lookupContext ) throws LdapException
256 {
257 CoreSession session = lookupContext.getSession();
258 Entry entry = next( lookupContext );
259
260 if ( session.getDirectoryService().isAccessControlEnabled() )
261 {
262 return entry;
263 }
264
265 protectLookUp( session.getEffectivePrincipal().getDn(), lookupContext.getDn() );
266
267 return entry;
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 @Override
284 public void modify( ModifyOperationContext modifyContext ) throws LdapException
285 {
286 if ( !modifyContext.getSession().getDirectoryService().isAccessControlEnabled() )
287 {
288 Dn dn = modifyContext.getDn();
289
290 protectModifyAlterations( modifyContext, dn );
291 next( modifyContext );
292
293
294 if ( dn.getNormName().equals( adminGroupDn.getNormName() ) )
295 {
296 loadAdministrators( modifyContext.getSession().getDirectoryService() );
297 }
298 }
299 else
300 {
301 next( modifyContext );
302 }
303 }
304
305
306
307
308
309 @Override
310 public void move( MoveOperationContext moveContext ) throws LdapException
311 {
312 if ( !moveContext.getSession().getDirectoryService().isAccessControlEnabled() )
313 {
314 protectDnAlterations( moveContext, moveContext.getDn() );
315 }
316
317 next( moveContext );
318 }
319
320
321
322
323
324 @Override
325 public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
326 {
327 if ( !moveAndRenameContext.getSession().getDirectoryService().isAccessControlEnabled() )
328 {
329 protectDnAlterations( moveAndRenameContext, moveAndRenameContext.getDn() );
330 }
331
332 next( moveAndRenameContext );
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346
347 @Override
348 public void rename( RenameOperationContext renameContext ) throws LdapException
349 {
350 if ( !renameContext.getSession().getDirectoryService().isAccessControlEnabled() )
351 {
352 protectDnAlterations( renameContext, renameContext.getDn() );
353 }
354
355 next( renameContext );
356 }
357
358
359
360
361
362 @Override
363 public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
364 {
365 EntryFilteringCursor cursor = next( searchContext );
366
367 if ( searchContext.getSession().getDirectoryService().isAccessControlEnabled() )
368 {
369 return cursor;
370 }
371
372 cursor.addEntryFilter( new DefaultAuthorizationSearchFilter() );
373
374 return cursor;
375 }
376
377
378 private boolean isTheAdministrator( Dn dn )
379 {
380 return dn.getNormName().equals( adminSystemDn.getNormName() );
381 }
382
383
384 private boolean isAnAdministrator( Dn dn )
385 {
386 return isTheAdministrator( dn ) || administrators.contains( dn.getNormName() );
387 }
388
389
390 private void protectModifyAlterations( OperationContext opCtx, Dn dn ) throws LdapException
391 {
392 Dn principalDn = getPrincipal( opCtx ).getDn();
393
394 if ( dn.isEmpty() )
395 {
396 String msg = I18n.err( I18n.ERR_17 );
397 LOG.error( msg );
398 throw new LdapNoPermissionException( msg );
399 }
400
401 if ( !isAnAdministrator( principalDn ) )
402 {
403
404 if ( dn.equals( getPrincipal( opCtx ).getDn() ) )
405 {
406 return;
407 }
408
409 if ( dn.equals( adminSystemDn ) )
410 {
411 String msg = I18n.err( I18n.ERR_18, principalDn.getName() );
412 LOG.error( msg );
413 throw new LdapNoPermissionException( msg );
414 }
415
416 if ( dn.size() > 2 )
417 {
418 if ( dn.isDescendantOf( adminSystemDn ) )
419 {
420 String msg = I18n.err( I18n.ERR_19, principalDn.getName(), dn.getName() );
421 LOG.error( msg );
422 throw new LdapNoPermissionException( msg );
423 }
424
425 if ( dn.isDescendantOf( groupsBaseDn ) )
426 {
427 String msg = I18n.err( I18n.ERR_20, principalDn.getName(), dn.getName() );
428 LOG.error( msg );
429 throw new LdapNoPermissionException( msg );
430 }
431
432 if ( dn.isDescendantOf( usersBaseDn ) )
433 {
434 String msg = I18n.err( I18n.ERR_20, principalDn.getName(), dn.getName() );
435 LOG.error( msg );
436 throw new LdapNoPermissionException( msg );
437 }
438 }
439 }
440 }
441
442
443 private void protectDnAlterations( OperationContext opCtx, Dn dn ) throws LdapException
444 {
445 Dn principalDn = getPrincipal( opCtx ).getDn();
446
447 if ( dn.isEmpty() )
448 {
449 String msg = I18n.err( I18n.ERR_234 );
450 LOG.error( msg );
451 throw new LdapNoPermissionException( msg );
452 }
453
454 if ( dn.equals( adminGroupDn ) )
455 {
456 String msg = I18n.err( I18n.ERR_21 );
457 LOG.error( msg );
458 throw new LdapNoPermissionException( msg );
459 }
460
461 if ( isTheAdministrator( dn ) )
462 {
463 String msg = I18n.err( I18n.ERR_22, principalDn.getName(), dn.getName() );
464 LOG.error( msg );
465 throw new LdapNoPermissionException( msg );
466 }
467
468 if ( ( dn.size() > 2 ) && !isAnAdministrator( principalDn ) )
469 {
470 if ( dn.isDescendantOf( adminSystemDn ) )
471 {
472 String msg = I18n.err( I18n.ERR_23, principalDn.getName(), dn.getName() );
473 LOG.error( msg );
474 throw new LdapNoPermissionException( msg );
475 }
476
477 if ( dn.isDescendantOf( groupsBaseDn ) )
478 {
479 String msg = I18n.err( I18n.ERR_24, principalDn.getName(), dn.getName() );
480 LOG.error( msg );
481 throw new LdapNoPermissionException( msg );
482 }
483
484 if ( dn.isDescendantOf( usersBaseDn ) )
485 {
486 String msg = I18n.err( I18n.ERR_24, principalDn.getName(), dn.getName() );
487 LOG.error( msg );
488 throw new LdapNoPermissionException( msg );
489 }
490 }
491 }
492
493
494 private void protectLookUp( Dn principalDn, Dn normalizedDn ) throws LdapException
495 {
496 if ( !isAnAdministrator( principalDn ) )
497 {
498 if ( normalizedDn.size() > 2 )
499 {
500 if ( normalizedDn.isDescendantOf( adminSystemDn ) )
501 {
502
503 if ( normalizedDn.equals( principalDn ) )
504 {
505 return;
506 }
507
508 String msg = I18n.err( I18n.ERR_25, normalizedDn.getName(), principalDn.getName() );
509 LOG.error( msg );
510 throw new LdapNoPermissionException( msg );
511 }
512
513 if ( normalizedDn.isDescendantOf( groupsBaseDn ) || normalizedDn.isDescendantOf( usersBaseDn ) )
514 {
515
516 if ( normalizedDn.equals( principalDn ) )
517 {
518 return;
519 }
520
521 String msg = I18n.err( I18n.ERR_26, normalizedDn.getName(), principalDn.getName() );
522 LOG.error( msg );
523 throw new LdapNoPermissionException( msg );
524 }
525 }
526
527 if ( isTheAdministrator( normalizedDn ) )
528 {
529
530 if ( normalizedDn.equals( principalDn ) )
531 {
532 return;
533 }
534
535 String msg = I18n.err( I18n.ERR_27, principalDn.getName() );
536 LOG.error( msg );
537 throw new LdapNoPermissionException( msg );
538 }
539 }
540 }
541
542
543
544 private boolean isSearchable( OperationContext opContext, Entry entry ) throws LdapException
545 {
546 Dn principalDn = opContext.getSession().getEffectivePrincipal().getDn();
547 Dn dn = entry.getDn();
548
549 if ( !dn.isSchemaAware() )
550 {
551 dn = new Dn( schemaManager, dn );
552 }
553
554
555 if ( isAnAdministrator( principalDn ) )
556 {
557 return true;
558 }
559
560
561 boolean isSelfRead = dn.equals( principalDn );
562
563 if ( isSelfRead )
564 {
565 return true;
566 }
567
568
569 if ( dn.size() >= 2 )
570 {
571
572
573
574 if ( dn.isDescendantOf( adminSystemDn ) || dn.isDescendantOf( groupsBaseDn )
575 || dn.isDescendantOf( usersBaseDn ) )
576 {
577 return false;
578 }
579 }
580
581
582 return !isTheAdministrator( dn );
583 }
584 }