View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server.authn;
18  
19  
20  import org.apache.ldap.common.exception.LdapAuthenticationException;
21  import org.apache.ldap.common.exception.LdapAuthenticationNotSupportedException;
22  import org.apache.ldap.common.message.ResultCodeEnum;
23  import org.apache.ldap.common.util.StringTools;
24  import org.apache.ldap.server.interceptor.Interceptor;
25  import org.apache.ldap.server.interceptor.InterceptorContext;
26  import org.apache.ldap.server.interceptor.NextInterceptor;
27  import org.apache.ldap.server.invocation.Invocation;
28  import org.apache.ldap.server.jndi.EnvKeys;
29  import org.apache.ldap.server.jndi.ServerContext;
30  import org.apache.ldap.server.jndi.ServerLdapContext;
31  
32  import javax.naming.Context;
33  import javax.naming.NamingException;
34  import java.lang.reflect.Constructor;
35  import java.util.*;
36  
37  
38  /***
39   * An {@link Interceptor} that authenticates users.
40   *
41   * @author Apache Directory Project (dev@directory.apache.org)
42   * @author Alex Karasulu (akarasulu@apache.org)
43   * @author Trustin Lee (trustin@apache.org)
44   * @version $Rev: 159259 $, $Date: 2005-03-28 12:00:29 -0500 (Mon, 28 Mar 2005) $
45   */
46  public class AuthenticationService implements Interceptor
47  {
48      /*** short for Context.SECURITY_AUTHENTICATION */
49      private static final String AUTH_TYPE = Context.SECURITY_AUTHENTICATION;
50  
51      /*** short for Context.SECURITY_CREDENTIALS */
52      private static final String CREDS = Context.SECURITY_CREDENTIALS;
53  
54      /*** authenticators **/
55      public Map authenticators = new LinkedHashMap();
56  
57  
58      /***
59       * Creates an authentication service interceptor.
60       */
61      public AuthenticationService()
62      {
63      }
64  
65      public void init( InterceptorContext ctx ) throws NamingException
66      {
67          /*
68           * Create and add the Authentication service interceptor to before
69           * interceptor chain.
70           */
71          boolean allowAnonymous = !ctx.getEnvironment().containsKey( EnvKeys.DISABLE_ANONYMOUS );
72  
73          // create authenticator context
74  
75          GenericAuthenticatorContext authenticatorContext = new GenericAuthenticatorContext();
76  
77          authenticatorContext.setPartitionNexus( ctx.getRootNexus() );
78  
79          authenticatorContext.setAllowAnonymous( allowAnonymous );
80  
81          try // initialize default authenticators
82          {
83              // create anonymous authenticator
84  
85              GenericAuthenticatorConfig authenticatorConfig = new GenericAuthenticatorConfig();
86  
87              authenticatorConfig.setAuthenticatorName( "none" );
88  
89              authenticatorConfig.setAuthenticatorContext( authenticatorContext );
90  
91              org.apache.ldap.server.authn.Authenticator authenticator = new AnonymousAuthenticator();
92  
93              authenticator.init( authenticatorConfig );
94  
95              this.register( authenticator );
96  
97              // create simple authenticator
98              authenticatorConfig = new GenericAuthenticatorConfig();
99  
100             authenticatorConfig.setAuthenticatorName( "simple" );
101 
102             authenticatorConfig.setAuthenticatorContext( authenticatorContext );
103 
104             authenticator = new SimpleAuthenticator();
105 
106             authenticator.init( authenticatorConfig );
107 
108             this.register( authenticator );
109         }
110         catch ( Exception e )
111         {
112             throw new NamingException( e.getMessage() );
113         }
114 
115         GenericAuthenticatorConfig[] configs = null;
116 
117         configs = AuthenticatorConfigBuilder.getAuthenticatorConfigs( new Hashtable( ctx.getEnvironment() ) );
118 
119         for ( int ii = 0; ii < configs.length; ii++ )
120         {
121             try
122             {
123                 configs[ii].setAuthenticatorContext( authenticatorContext );
124 
125                 String authenticatorClass = configs[ii].getAuthenticatorClass();
126 
127                 Class clazz = Class.forName( authenticatorClass );
128 
129                 Constructor constructor = clazz.getConstructor( new Class[] { } );
130 
131                 AbstractAuthenticator authenticator = ( AbstractAuthenticator ) constructor.newInstance( new Object[] { } );
132 
133                 authenticator.init( configs[ii] );
134 
135                 this.register( authenticator );
136             }
137             catch ( Exception e )
138             {
139                 e.printStackTrace();
140             }
141         }
142 
143     }
144     
145     public void destroy()
146     {
147         authenticators.clear();
148     }
149 
150     /***
151      * Registers an AuthenticationService with the AuthenticationService.  Called by each
152      * AuthenticationService implementation after it has started to register for
153      * authentication operation calls.
154      *
155      * @param authenticator AuthenticationService component to register with this
156      * AuthenticatorService.
157      */
158     public void register( org.apache.ldap.server.authn.Authenticator authenticator )
159     {
160         Collection authenticatorList = getAuthenticators( authenticator.getAuthenticatorType() );
161 
162         if ( authenticatorList == null )
163         {
164             authenticatorList = new ArrayList();
165 
166             authenticators.put( authenticator.getAuthenticatorType(), authenticatorList );
167         }
168 
169         authenticatorList.add( authenticator );
170     }
171 
172     /***
173      * Unregisters an AuthenticationService with the AuthenticationService.  Called for each
174      * registered AuthenticationService right before it is to be stopped.  This prevents
175      * protocol server calls from reaching the Backend and effectively puts
176      * the ContextPartition's naming context offline.
177      *
178      * @param authenticator AuthenticationService component to unregister with this
179      * AuthenticationService.
180      */
181     public void unregister( org.apache.ldap.server.authn.Authenticator authenticator )
182     {
183         Collection authenticatorList = getAuthenticators( authenticator.getAuthenticatorType() );
184 
185         if ( authenticatorList == null )
186         {
187             return;
188         }
189 
190         authenticatorList.remove( authenticator );
191     }
192 
193     /***
194      * Gets the authenticators with a specific type.
195      *
196      * @param type the authentication type
197      * @return the authenticators with the specified type
198      */
199     public Collection getAuthenticators( String type )
200     {
201         return ( Collection ) authenticators.get( type );
202     }
203     
204     public void process( NextInterceptor nextProcessor, Invocation call ) throws NamingException
205     {
206         // check if we are already authenticated and if so we return making
207         // sure first that the credentials are not exposed within context
208         ServerContext ctx = ( ServerLdapContext ) call.getContextStack().peek();
209 
210         if ( ctx.getPrincipal() != null )
211         {
212             if ( ctx.getEnvironment().containsKey( CREDS ) )
213             {
214                 ctx.removeFromEnvironment( CREDS );
215             }
216 
217             nextProcessor.process(call);
218 
219             return;
220         }
221 
222         String authList = ( String ) ctx.getEnvironment().get( AUTH_TYPE );
223 
224         if ( authList == null )
225         {
226             if ( ctx.getEnvironment().containsKey( CREDS ) )
227             {
228                 // authentication type is simple here
229 
230                 authList = "simple";
231             }
232             else
233             {
234                 // authentication type is anonymous
235 
236                 authList = "none";
237             }
238 
239         }
240 
241         authList = StringTools.deepTrim( authList );
242 
243         String[] auth = authList.split( " " );
244 
245         Collection authenticators = null;
246 
247         // pick the first matching authenticator type
248 
249         for ( int i=0; i<auth.length; i++)
250         {
251             authenticators = getAuthenticators( auth[i] );
252 
253             if ( authenticators != null )
254             {
255                 break;
256             }
257         }
258 
259         if ( authenticators == null )
260         {
261             ctx.getEnvironment(); // shut's up idea's yellow light
262 
263             ResultCodeEnum rc = ResultCodeEnum.AUTHMETHODNOTSUPPORTED;
264 
265             throw new LdapAuthenticationNotSupportedException( rc );
266         }
267 
268         // try each authenticators
269         for ( Iterator i = authenticators.iterator(); i.hasNext(); )
270         {
271             try
272             {
273                 Authenticator authenticator = ( Authenticator ) i.next();
274 
275                 // perform the authentication
276 
277                 LdapPrincipal authorizationId = authenticator.authenticate( ctx );
278 
279                 // authentication was successful
280 
281                 ctx.setPrincipal( new TrustedPrincipalWrapper( authorizationId ) );
282 
283                 // remove creds so there is no security risk
284 
285                 ctx.removeFromEnvironment( CREDS );
286 
287                 nextProcessor.process(call);
288 
289                 return;
290             }
291             catch ( LdapAuthenticationException e )
292             {
293                 // authentication failed, try the next authenticator
294             }
295         }
296 
297         throw new LdapAuthenticationException();
298     }
299 
300 
301     /***
302      * Created this wrapper to pass to ctx.setPrincipal() which is public for added
303      * security.  This adds more security because an instance of this class is not
304      * easily accessible whereas LdapPrincipals can be accessed easily from a context
305      * althought they cannot be instantiated outside of the authn package.  Malicious
306      * code may not be able to set the principal to what they would like but they
307      * could switch existing principals using the now public ServerContext.setPrincipal()
308      * method.  To avoid this we make sure that this metho takes a TrustedPrincipalWrapper
309      * as opposed to the LdapPrincipal.  Only this service can create and call setPrincipal
310      * with a TrustedPrincipalWrapper.
311      */
312     public final class TrustedPrincipalWrapper
313     {
314         /*** the wrapped ldap principal */
315         private final LdapPrincipal principal;
316 
317 
318         /***
319          * Creates a TrustedPrincipalWrapper around an LdapPrincipal.
320          *
321          * @param principal the LdapPrincipal to wrap
322          */
323         private TrustedPrincipalWrapper( LdapPrincipal principal )
324         {
325             this.principal = principal;
326         }
327 
328 
329         /***
330          * Gets the LdapPrincipal this TrustedPrincipalWrapper wraps.
331          *
332          * @return the wrapped LdapPrincipal
333          */
334         public LdapPrincipal getPrincipal()
335         {
336             return principal;
337         }
338     }
339 }