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.authn;
21
22
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.apache.directory.server.core.CoreSession;
32 import org.apache.directory.server.core.DefaultCoreSession;
33 import org.apache.directory.server.core.DirectoryService;
34 import org.apache.directory.server.core.entry.ClonedServerEntry;
35 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
36 import org.apache.directory.server.core.interceptor.BaseInterceptor;
37 import org.apache.directory.server.core.interceptor.Interceptor;
38 import org.apache.directory.server.core.interceptor.NextInterceptor;
39 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
40 import org.apache.directory.server.core.interceptor.context.BindOperationContext;
41 import org.apache.directory.server.core.interceptor.context.CompareOperationContext;
42 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
43 import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
44 import org.apache.directory.server.core.interceptor.context.GetMatchedNameOperationContext;
45 import org.apache.directory.server.core.interceptor.context.GetRootDSEOperationContext;
46 import org.apache.directory.server.core.interceptor.context.GetSuffixOperationContext;
47 import org.apache.directory.server.core.interceptor.context.ListOperationContext;
48 import org.apache.directory.server.core.interceptor.context.ListSuffixOperationContext;
49 import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
50 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
51 import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
52 import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
53 import org.apache.directory.server.core.interceptor.context.OperationContext;
54 import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
55 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
56 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
57 import org.apache.directory.shared.ldap.exception.LdapAuthenticationException;
58 import org.apache.directory.shared.ldap.exception.LdapNoPermissionException;
59 import org.apache.directory.shared.ldap.exception.LdapOperationNotSupportedException;
60 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
61 import org.apache.directory.shared.ldap.name.LdapDN;
62 import org.apache.directory.shared.ldap.util.StringTools;
63
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67
68
69
70
71
72
73
74
75 public class AuthenticationInterceptor extends BaseInterceptor
76 {
77 private static final Logger LOG = LoggerFactory.getLogger( AuthenticationInterceptor.class );
78
79
80
81
82 private static final boolean IS_DEBUG = LOG.isDebugEnabled();
83
84 private Set<Authenticator> authenticators;
85 private final Map<String, Collection<Authenticator>> authenticatorsMapByType =
86 new HashMap<String, Collection<Authenticator>>();
87
88 private DirectoryService directoryService;
89
90
91
92
93
94 public AuthenticationInterceptor()
95 {
96 }
97
98
99
100
101
102 public void init( DirectoryService directoryService ) throws Exception
103 {
104 this.directoryService = directoryService;
105
106 if ( authenticators == null )
107 {
108 setDefaultAuthenticators();
109 }
110
111 for ( Authenticator authenticator : authenticators )
112 {
113 register( authenticator, directoryService );
114 }
115 }
116
117
118 private void setDefaultAuthenticators()
119 {
120 Set<Authenticator> set = new HashSet<Authenticator>();
121 set.add( new AnonymousAuthenticator() );
122 set.add( new SimpleAuthenticator() );
123 set.add( new StrongAuthenticator() );
124
125 setAuthenticators( set );
126 }
127
128
129 public Set<Authenticator> getAuthenticators()
130 {
131 return authenticators;
132 }
133
134
135
136
137
138
139 public void setAuthenticators( Set<Authenticator> authenticators )
140 {
141 this.authenticators = authenticators;
142 }
143
144
145
146
147
148 public void destroy()
149 {
150 authenticatorsMapByType.clear();
151 Set<Authenticator> copy = new HashSet<Authenticator>( authenticators );
152 authenticators = null;
153 for ( Authenticator authenticator : copy )
154 {
155 authenticator.destroy();
156 }
157 }
158
159
160
161
162
163
164
165
166
167
168 private void register( Authenticator authenticator, DirectoryService directoryService ) throws Exception
169 {
170 authenticator.init( directoryService );
171
172 Collection<Authenticator> authenticatorList = getAuthenticators( authenticator.getAuthenticatorType() );
173
174 if ( authenticatorList == null )
175 {
176 authenticatorList = new ArrayList<Authenticator>();
177 authenticatorsMapByType.put( authenticator.getAuthenticatorType(), authenticatorList );
178 }
179
180 authenticatorList.add( authenticator );
181 }
182
183
184
185
186
187
188
189
190 private Collection<Authenticator> getAuthenticators( String type )
191 {
192 Collection<Authenticator> result = authenticatorsMapByType.get( type );
193
194 if ( ( result != null ) && ( result.size() > 0 ) )
195 {
196 return result;
197 }
198 else
199 {
200 return null;
201 }
202 }
203
204
205 public void add( NextInterceptor next, AddOperationContext opContext ) throws Exception
206 {
207 if ( IS_DEBUG )
208 {
209 LOG.debug( "Operation Context: {}", opContext );
210 }
211
212 checkAuthenticated( opContext );
213 next.add( opContext );
214 }
215
216
217 public void delete( NextInterceptor next, DeleteOperationContext opContext ) throws Exception
218 {
219 if ( IS_DEBUG )
220 {
221 LOG.debug( "Operation Context: {}", opContext );
222 }
223
224 checkAuthenticated( opContext );
225 next.delete( opContext );
226 invalidateAuthenticatorCaches( opContext.getDn() );
227 }
228
229
230 public LdapDN getMatchedName( NextInterceptor next, GetMatchedNameOperationContext opContext ) throws Exception
231 {
232 if ( IS_DEBUG )
233 {
234 LOG.debug( "Operation Context: {}", opContext );
235 }
236
237 checkAuthenticated( opContext );
238 return next.getMatchedName( opContext );
239 }
240
241
242 public ClonedServerEntry getRootDSE( NextInterceptor next, GetRootDSEOperationContext opContext ) throws Exception
243 {
244 if ( IS_DEBUG )
245 {
246 LOG.debug( "Operation Context: {}", opContext );
247 }
248
249 checkAuthenticated( opContext );
250 return next.getRootDSE( opContext );
251 }
252
253
254 public LdapDN getSuffix( NextInterceptor next, GetSuffixOperationContext opContext ) throws Exception
255 {
256 if ( IS_DEBUG )
257 {
258 LOG.debug( "Operation Context: {}", opContext );
259 }
260
261 checkAuthenticated( opContext );
262 return next.getSuffix( opContext );
263 }
264
265
266 public boolean hasEntry( NextInterceptor next, EntryOperationContext opContext ) throws Exception
267 {
268 if ( IS_DEBUG )
269 {
270 LOG.debug( "Operation Context: {}", opContext );
271 }
272
273 checkAuthenticated( opContext );
274 return next.hasEntry( opContext );
275 }
276
277
278 public EntryFilteringCursor list( NextInterceptor next, ListOperationContext opContext ) throws Exception
279 {
280 if ( IS_DEBUG )
281 {
282 LOG.debug( "Operation Context: {}", opContext );
283 }
284
285 checkAuthenticated( opContext );
286 return next.list( opContext );
287 }
288
289
290 public Iterator<String> listSuffixes( NextInterceptor next, ListSuffixOperationContext opContext ) throws Exception
291 {
292 if ( IS_DEBUG )
293 {
294 LOG.debug( "Operation Context: {}", opContext );
295 }
296
297 checkAuthenticated( opContext );
298 return next.listSuffixes( opContext );
299 }
300
301
302 public ClonedServerEntry lookup( NextInterceptor next, LookupOperationContext opContext ) throws Exception
303 {
304 if ( IS_DEBUG )
305 {
306 LOG.debug( "Operation Context: {}", opContext );
307 }
308
309 checkAuthenticated( opContext );
310 return next.lookup( opContext );
311 }
312
313
314 private void invalidateAuthenticatorCaches( LdapDN principalDn )
315 {
316 for ( String authMech : authenticatorsMapByType.keySet() )
317 {
318 Collection<Authenticator> authenticators = getAuthenticators( authMech );
319
320
321 for ( Authenticator authenticator : authenticators )
322 {
323 authenticator.invalidateCache( principalDn );
324 }
325 }
326 }
327
328
329 public void modify( NextInterceptor next, ModifyOperationContext opContext ) throws Exception
330 {
331 if ( IS_DEBUG )
332 {
333 LOG.debug( "Operation Context: {}", opContext );
334 }
335
336 checkAuthenticated( opContext );
337 next.modify( opContext );
338 invalidateAuthenticatorCaches( opContext.getDn() );
339 }
340
341
342 public void rename( NextInterceptor next, RenameOperationContext opContext ) throws Exception
343 {
344 if ( IS_DEBUG )
345 {
346 LOG.debug( "Operation Context: {}", opContext );
347 }
348
349 checkAuthenticated( opContext );
350 next.rename( opContext );
351 invalidateAuthenticatorCaches( opContext.getDn() );
352 }
353
354
355 public boolean compare( NextInterceptor next, CompareOperationContext opContext ) throws Exception
356 {
357 if ( IS_DEBUG )
358 {
359 LOG.debug( "Operation Context: {}", opContext );
360 }
361
362 checkAuthenticated( opContext );
363 boolean result = next.compare( opContext );
364 invalidateAuthenticatorCaches( opContext.getDn() );
365 return result;
366 }
367
368
369 public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext opContext )
370 throws Exception
371 {
372 if ( IS_DEBUG )
373 {
374 LOG.debug( "Operation Context: {}", opContext );
375 }
376
377 checkAuthenticated( opContext );
378 next.moveAndRename( opContext );
379 invalidateAuthenticatorCaches( opContext.getDn() );
380 }
381
382
383 public void move( NextInterceptor next, MoveOperationContext opContext ) throws Exception
384 {
385 if ( IS_DEBUG )
386 {
387 LOG.debug( "Operation Context: {}", opContext );
388 }
389
390 checkAuthenticated( opContext );
391 next.move( opContext );
392 invalidateAuthenticatorCaches( opContext.getDn() );
393 }
394
395
396 public EntryFilteringCursor search( NextInterceptor next, SearchOperationContext opContext ) throws Exception
397 {
398 if ( IS_DEBUG )
399 {
400 LOG.debug( "Operation Context: {}", opContext );
401 }
402
403 checkAuthenticated( opContext );
404 return next.search( opContext );
405 }
406
407
408
409
410
411
412
413
414
415 private void checkAuthenticated( OperationContext operation ) throws Exception
416 {
417 if ( operation.getSession().isAnonymous() && !directoryService.isAllowAnonymousAccess()
418 && !operation.getDn().isEmpty() )
419 {
420 LOG.error( "Attempted operation {} by unauthenticated caller.", operation.getName() );
421 throw new LdapNoPermissionException( "Attempted operation by unauthenticated caller." );
422 }
423 }
424
425
426 public void bind( NextInterceptor next, BindOperationContext opContext ) throws Exception
427 {
428 if ( IS_DEBUG )
429 {
430 LOG.debug( "Operation Context: {}", opContext );
431 }
432
433 if ( opContext.getSession() != null && opContext.getSession().getEffectivePrincipal() != null )
434 {
435
436 opContext.setCredentials( null );
437 }
438
439
440 AuthenticationLevel level = opContext.getAuthenticationLevel();
441
442 if ( level == AuthenticationLevel.UNAUTHENT )
443 {
444
445
446 throw new LdapOperationNotSupportedException( "Cannot Bind for DN " + opContext.getDn().getUpName(), ResultCodeEnum.UNWILLING_TO_PERFORM );
447 }
448
449 Collection<Authenticator> authenticators = getAuthenticators( level.getName() );
450
451 if ( authenticators == null )
452 {
453 LOG.debug( "No authenticators found, delegating bind to the nexus." );
454
455
456 next.bind( opContext );
457
458 LOG.debug( "Nexus succeeded on bind operation." );
459
460
461
462 LdapPrincipal principal = new LdapPrincipal( opContext.getDn(), AuthenticationLevel.SIMPLE );
463 CoreSession session = new DefaultCoreSession( principal, directoryService );
464 opContext.setSession( session );
465
466
467 opContext.setCredentials( null );
468 return;
469 }
470
471
472
473 for ( Authenticator authenticator : authenticators )
474 {
475 try
476 {
477
478 LdapPrincipal principal = authenticator.authenticate( opContext );
479
480 LdapPrincipal clonedPrincipal = (LdapPrincipal)(principal.clone());
481
482
483 opContext.setCredentials( null );
484 clonedPrincipal.setUserPassword( StringTools.EMPTY_BYTES );
485
486
487 CoreSession session = new DefaultCoreSession( clonedPrincipal, directoryService );
488 opContext.setSession( session );
489
490 return;
491 }
492 catch ( LdapAuthenticationException e )
493 {
494
495 if ( LOG.isInfoEnabled() )
496 {
497 LOG.info( "Authenticator {} failed to authenticate: {}", authenticator, opContext );
498 }
499 }
500 catch ( Exception e )
501 {
502
503 if ( LOG.isWarnEnabled() )
504 {
505 LOG.info( "Unexpected failure for Authenticator {} : {}", authenticator, opContext );
506 }
507 }
508 }
509
510 if ( LOG.isInfoEnabled() )
511 {
512 LOG.info( "Cannot bind to the server " );
513 }
514
515 LdapDN dn = opContext.getDn();
516 String upDn = ( dn == null ? "" : dn.getUpName() );
517 throw new LdapAuthenticationException( "Cannot authenticate user " + upDn );
518 }
519 }