1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ldap.server.authn;
18
19
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.Map;
25
26 import javax.naming.Context;
27 import javax.naming.Name;
28 import javax.naming.NamingEnumeration;
29 import javax.naming.NamingException;
30 import javax.naming.directory.Attributes;
31 import javax.naming.directory.ModificationItem;
32 import javax.naming.directory.SearchControls;
33
34 import org.apache.ldap.common.exception.LdapAuthenticationException;
35 import org.apache.ldap.common.exception.LdapAuthenticationNotSupportedException;
36 import org.apache.ldap.common.filter.ExprNode;
37 import org.apache.ldap.common.message.ResultCodeEnum;
38 import org.apache.ldap.common.util.StringTools;
39 import org.apache.ldap.server.configuration.AuthenticatorConfiguration;
40 import org.apache.ldap.server.configuration.InterceptorConfiguration;
41 import org.apache.ldap.server.interceptor.Interceptor;
42 import org.apache.ldap.server.interceptor.NextInterceptor;
43 import org.apache.ldap.server.invocation.InvocationStack;
44 import org.apache.ldap.server.jndi.ContextFactoryConfiguration;
45 import org.apache.ldap.server.jndi.ServerContext;
46
47
48 /***
49 * An {@link Interceptor} that authenticates users.
50 *
51 * @author Apache Directory Project (dev@directory.apache.org)
52 * @author Alex Karasulu (akarasulu@apache.org)
53 * @author Trustin Lee (trustin@apache.org)
54 * @version $Rev: 226451 $, $Date: 2005-07-29 20:54:58 -0400 (Fri, 29 Jul 2005) $
55 */
56 public class AuthenticationService implements Interceptor
57 {
58 /*** authenticators **/
59 public Map authenticators = new HashMap();
60
61 private ContextFactoryConfiguration factoryCfg;
62
63 /***
64 * Creates an authentication service interceptor.
65 */
66 public AuthenticationService()
67 {
68 }
69
70 /***
71 * Registers and initializes all {@link Authenticator}s to this service.
72 */
73 public void init( ContextFactoryConfiguration factoryCfg, InterceptorConfiguration cfg ) throws NamingException
74 {
75 this.factoryCfg = factoryCfg;
76
77
78 Iterator i = factoryCfg.getStartupConfiguration().getAuthenticatorConfigurations().iterator();
79 while( i.hasNext() )
80 {
81 try
82 {
83 this.register( ( AuthenticatorConfiguration ) i.next() );
84 }
85 catch ( Exception e )
86 {
87 destroy();
88 throw ( NamingException ) new NamingException(
89 "Failed to register authenticator." ).initCause( e );
90 }
91 }
92 }
93
94 /***
95 * Deinitializes and deregisters all {@link Authenticator}s from this service.
96 */
97 public void destroy()
98 {
99 Iterator i = new ArrayList( authenticators.values() ).iterator();
100 while( i.hasNext() )
101 {
102 Iterator j = new ArrayList( ( Collection ) i.next() ).iterator();
103 while( j.hasNext() )
104 {
105 unregister( ( Authenticator ) j.next() );
106 }
107 }
108
109 authenticators.clear();
110 }
111
112 /***
113 * Initializes the specified {@link Authenticator} and registers it to
114 * this service.
115 */
116 private void register( AuthenticatorConfiguration cfg ) throws NamingException
117 {
118 cfg.getAuthenticator().init( factoryCfg, cfg );
119
120 Collection authenticatorList = getAuthenticators( cfg.getAuthenticator().getAuthenticatorType() );
121 if ( authenticatorList == null )
122 {
123 authenticatorList = new ArrayList();
124 authenticators.put( cfg.getAuthenticator().getAuthenticatorType(), authenticatorList );
125 }
126
127 authenticatorList.add( cfg.getAuthenticator() );
128 }
129
130 /***
131 * Deinitializes the specified {@link Authenticator} and deregisters it from
132 * this service.
133 */
134 private void unregister( Authenticator authenticator )
135 {
136 Collection authenticatorList = getAuthenticators( authenticator.getAuthenticatorType() );
137
138 if ( authenticatorList == null )
139 {
140 return;
141 }
142
143 authenticatorList.remove( authenticator );
144
145 try
146 {
147 authenticator.destroy();
148 }
149 catch( Throwable t )
150 {
151 t.printStackTrace();
152 }
153 }
154
155 /***
156 * Returns the list of {@link Authenticator}s with the specified type.
157 *
158 * @return <tt>null</tt> if no authenticator is found.
159 */
160 private Collection getAuthenticators( String type )
161 {
162 Collection result = ( Collection ) authenticators.get( type );
163 if( result != null && result.size() > 0 )
164 {
165 return result;
166 }
167 else
168 {
169 return null;
170 }
171 }
172
173
174 public void add( NextInterceptor next, String upName, Name normName, Attributes entry ) throws NamingException
175 {
176 authenticate();
177 next.add( upName, normName, entry );
178 }
179
180
181 public void delete( NextInterceptor next, Name name ) throws NamingException
182 {
183 authenticate();
184 next.delete( name );
185 }
186
187
188 public Name getMatchedName( NextInterceptor next, Name dn, boolean normalized ) throws NamingException
189 {
190 authenticate();
191 return next.getMatchedName( dn, normalized );
192 }
193
194
195 public Attributes getRootDSE( NextInterceptor next ) throws NamingException
196 {
197 authenticate();
198 return next.getRootDSE();
199 }
200
201
202 public Name getSuffix( NextInterceptor next, Name dn, boolean normalized ) throws NamingException
203 {
204 authenticate();
205 return next.getSuffix( dn, normalized );
206 }
207
208
209 public boolean hasEntry( NextInterceptor next, Name name ) throws NamingException
210 {
211 authenticate();
212 return next.hasEntry( name );
213 }
214
215
216 public boolean isSuffix( NextInterceptor next, Name name ) throws NamingException
217 {
218 authenticate();
219 return next.isSuffix( name );
220 }
221
222
223 public NamingEnumeration list( NextInterceptor next, Name base ) throws NamingException
224 {
225 authenticate();
226 return next.list( base );
227 }
228
229
230 public Iterator listSuffixes( NextInterceptor next, boolean normalized ) throws NamingException
231 {
232 authenticate();
233 return next.listSuffixes( normalized );
234 }
235
236
237 public Attributes lookup( NextInterceptor next, Name dn, String[] attrIds ) throws NamingException
238 {
239 authenticate();
240 return next.lookup( dn, attrIds );
241 }
242
243
244 public Attributes lookup( NextInterceptor next, Name name ) throws NamingException
245 {
246 authenticate();
247 return next.lookup( name );
248 }
249
250
251 public void modify( NextInterceptor next, Name name, int modOp, Attributes mods ) throws NamingException
252 {
253 authenticate();
254 next.modify( name, modOp, mods );
255 }
256
257
258 public void modify( NextInterceptor next, Name name, ModificationItem[] mods ) throws NamingException
259 {
260 authenticate();
261 next.modify( name, mods );
262 }
263
264
265 public void modifyRn( NextInterceptor next, Name name, String newRn, boolean deleteOldRn ) throws NamingException
266 {
267 authenticate();
268 next.modifyRn( name, newRn, deleteOldRn );
269 }
270
271
272 public void move( NextInterceptor next, Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn ) throws NamingException
273 {
274 authenticate();
275 next.move( oriChildName, newParentName, newRn, deleteOldRn );
276 }
277
278
279 public void move( NextInterceptor next, Name oriChildName, Name newParentName ) throws NamingException
280 {
281 authenticate();
282 next.move( oriChildName, newParentName );
283 }
284
285
286 public NamingEnumeration search( NextInterceptor next, Name base, Map env, ExprNode filter, SearchControls searchCtls ) throws NamingException
287 {
288 authenticate();
289 return next.search( base, env, filter, searchCtls );
290 }
291
292
293 private void authenticate() throws NamingException
294 {
295
296
297 ServerContext ctx =
298 ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
299
300 if ( ctx.getPrincipal() != null )
301 {
302 if ( ctx.getEnvironment().containsKey( Context.SECURITY_CREDENTIALS ) )
303 {
304 ctx.removeFromEnvironment( Context.SECURITY_CREDENTIALS );
305 }
306 return;
307 }
308
309 String authList = ( String ) ctx.getEnvironment().get( Context.SECURITY_AUTHENTICATION );
310
311 if ( authList == null )
312 {
313 if ( ctx.getEnvironment().containsKey( Context.SECURITY_CREDENTIALS ) )
314 {
315
316
317 authList = "simple";
318 }
319 else
320 {
321
322
323 authList = "none";
324 }
325
326 }
327
328 authList = StringTools.deepTrim( authList );
329
330 String[] auth = authList.split( " " );
331
332 Collection authenticators = null;
333
334
335
336 for ( int i=0; i<auth.length; i++)
337 {
338 authenticators = getAuthenticators( auth[i] );
339
340 if ( authenticators != null )
341 {
342 break;
343 }
344 }
345
346 if ( authenticators == null )
347 {
348 ctx.getEnvironment();
349
350 ResultCodeEnum rc = ResultCodeEnum.AUTHMETHODNOTSUPPORTED;
351
352 throw new LdapAuthenticationNotSupportedException( rc );
353 }
354
355
356 for ( Iterator i = authenticators.iterator(); i.hasNext(); )
357 {
358 try
359 {
360 Authenticator authenticator = ( Authenticator ) i.next();
361
362
363
364 LdapPrincipal authorizationId = authenticator.authenticate( ctx );
365
366
367
368 ctx.setPrincipal( new TrustedPrincipalWrapper( authorizationId ) );
369
370
371
372 ctx.removeFromEnvironment( Context.SECURITY_CREDENTIALS );
373 return;
374 }
375 catch ( LdapAuthenticationException e )
376 {
377
378 }
379 }
380
381 throw new LdapAuthenticationException();
382 }
383
384
385 /***
386 * FIXME This doesn't secure anything actually.
387 *
388 * Created this wrapper to pass to ctx.setPrincipal() which is public for added
389 * security. This adds more security because an instance of this class is not
390 * easily accessible whereas LdapPrincipals can be accessed easily from a context
391 * althought they cannot be instantiated outside of the authn package. Malicious
392 * code may not be able to set the principal to what they would like but they
393 * could switch existing principals using the now public ServerContext.setPrincipal()
394 * method. To avoid this we make sure that this metho takes a TrustedPrincipalWrapper
395 * as opposed to the LdapPrincipal. Only this service can create and call setPrincipal
396 * with a TrustedPrincipalWrapper.
397 */
398 public final class TrustedPrincipalWrapper
399 {
400 /*** the wrapped ldap principal */
401 private final LdapPrincipal principal;
402
403
404 /***
405 * Creates a TrustedPrincipalWrapper around an LdapPrincipal.
406 *
407 * @param principal the LdapPrincipal to wrap
408 */
409 private TrustedPrincipalWrapper( LdapPrincipal principal )
410 {
411 this.principal = principal;
412 }
413
414
415 /***
416 * Gets the LdapPrincipal this TrustedPrincipalWrapper wraps.
417 *
418 * @return the wrapped LdapPrincipal
419 */
420 public LdapPrincipal getPrincipal()
421 {
422 return principal;
423 }
424 }
425 }