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 javax.naming.Context;
21  import javax.naming.NamingException;
22  import javax.naming.directory.Attribute;
23  import javax.naming.directory.Attributes;
24  
25  import org.apache.ldap.common.exception.LdapAuthenticationException;
26  import org.apache.ldap.common.name.LdapName;
27  import org.apache.ldap.common.util.ArrayUtils;
28  import org.apache.ldap.common.aci.AuthenticationLevel;
29  import org.apache.ldap.server.jndi.ServerContext;
30  import org.apache.ldap.server.partition.DirectoryPartitionNexus;
31  import org.apache.ldap.server.partition.DirectoryPartitionNexusProxy;
32  import org.apache.ldap.server.invocation.Invocation;
33  import org.apache.ldap.server.invocation.InvocationStack;
34  
35  import java.util.HashSet;
36  import java.util.Collections;
37  import java.util.Set;
38  import java.util.Collection;
39  
40  
41  /***
42   * A simple {@link Authenticator} that authenticates clear text passwords
43   * contained within the <code>userPassword</code> attribute in DIT.
44   *
45   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
46   */
47  public class SimpleAuthenticator extends AbstractAuthenticator
48  {
49      private static final Collection USERLOOKUP_BYPASS;
50  
51      static
52      {
53          Set c = new HashSet();
54          c.add( "authenticationService" );
55          c.add( "authorizationService" );
56          c.add( "oldAuthorizationService" );
57          c.add( "schemaService" );
58          c.add( "subentryService" );
59          c.add( "operationalAttributeService" );
60          c.add( "eventService" );
61          USERLOOKUP_BYPASS = Collections.unmodifiableCollection( c );
62      }
63  
64  
65      /***
66       * Creates a new instance.
67       */
68      public SimpleAuthenticator( )
69      {
70          super( "simple" );
71      }
72  
73  
74      /***
75       * Looks up <tt>userPassword</tt> attribute of the entry whose name is
76       * the value of {@link Context#SECURITY_PRINCIPAL} environment variable,
77       * and authenticates a user with the plain-text password.
78       */
79      public LdapPrincipal authenticate( ServerContext ctx ) throws NamingException
80      {
81          // ---- extract password from JNDI environment
82  
83          Object creds = ctx.getEnvironment().get( Context.SECURITY_CREDENTIALS );
84  
85          if ( creds == null )
86          {
87              creds = ArrayUtils.EMPTY_BYTE_ARRAY;
88          }
89          else if ( creds instanceof String )
90          {
91              creds = ( ( String ) creds ).getBytes();
92          }
93  
94          // ---- extract principal from JNDI environment
95  
96          String principal;
97  
98          if ( ! ctx.getEnvironment().containsKey( Context.SECURITY_PRINCIPAL ) )
99          {
100             throw new LdapAuthenticationException();
101         }
102         else
103         {
104             principal = ( String ) ctx.getEnvironment().get( Context.SECURITY_PRINCIPAL );
105 
106             if ( principal == null )
107             {
108                 throw new LdapAuthenticationException();
109             }
110         }
111 
112         // ---- lookup the principal entry's userPassword attribute
113 
114         LdapName principalDn = new LdapName( principal );
115         Invocation invocation = InvocationStack.getInstance().peek();
116         DirectoryPartitionNexusProxy proxy = invocation.getProxy();
117         Attributes userEntry;
118 
119         try
120         {
121             userEntry = proxy.lookup( principalDn, new String[] {"userPassword"}, USERLOOKUP_BYPASS );
122             if ( userEntry == null )
123             {
124                 throw new LdapAuthenticationException( "Failed to lookup user for authentication: " + principal );
125             }
126         }
127         catch( Exception cause )
128         {
129             LdapAuthenticationException e = new LdapAuthenticationException();
130             e.setRootCause( e );
131             throw e;
132         }
133 
134 
135         Object userPassword;
136 
137         Attribute userPasswordAttr = userEntry.get( "userPassword" );
138 
139         // ---- assert that credentials match
140 
141         if ( userPasswordAttr == null )
142         {
143             userPassword = ArrayUtils.EMPTY_BYTE_ARRAY;
144         }
145         else
146         {
147             userPassword = userPasswordAttr.get();
148 
149             if ( userPassword instanceof String )
150             {
151                 userPassword = ( ( String ) userPassword ).getBytes();
152             }
153         }
154 
155         if ( ! ArrayUtils.isEquals( creds, userPassword ) )
156         {
157             throw new LdapAuthenticationException();
158         }
159 
160         return new LdapPrincipal( principalDn, AuthenticationLevel.SIMPLE );
161     }
162 }