This project has retired. For details please refer to its Attic page.
LdapBindAuthenticator xref
View Javadoc

1   package org.apache.archiva.redback.authentication.ldap;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.archiva.redback.authentication.AbstractAuthenticator;
23  import org.apache.archiva.redback.common.ldap.connection.DefaultLdapConnection;
24  import org.apache.archiva.redback.common.ldap.connection.LdapConnection;
25  import org.apache.archiva.redback.common.ldap.user.UserMapper;
26  import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory;
27  import org.apache.archiva.redback.configuration.UserConfiguration;
28  import org.apache.archiva.redback.configuration.UserConfigurationKeys;
29  import org.apache.commons.lang.StringUtils;
30  import org.apache.archiva.redback.authentication.AuthenticationDataSource;
31  import org.apache.archiva.redback.authentication.AuthenticationException;
32  import org.apache.archiva.redback.authentication.AuthenticationResult;
33  import org.apache.archiva.redback.authentication.Authenticator;
34  import org.apache.archiva.redback.authentication.PasswordBasedAuthenticationDataSource;
35  import org.apache.archiva.redback.common.ldap.connection.LdapException;
36  import org.apache.archiva.redback.users.ldap.service.LdapCacheService;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  import org.springframework.stereotype.Service;
40  
41  import javax.inject.Inject;
42  import javax.inject.Named;
43  import javax.naming.NamingEnumeration;
44  import javax.naming.NamingException;
45  import javax.naming.directory.DirContext;
46  import javax.naming.directory.SearchControls;
47  import javax.naming.directory.SearchResult;
48  
49  /**
50   * LdapBindAuthenticator:
51   *
52   * @author: Jesse McConnell <jesse@codehaus.org>
53   */
54  @Service( "authenticator#ldap" )
55  public class LdapBindAuthenticator
56      extends AbstractAuthenticator
57      implements Authenticator
58  {
59  
60      private Logger log = LoggerFactory.getLogger( getClass() );
61  
62      @Inject
63      @Named( value = "userMapper#ldap" )
64      private UserMapper mapper;
65  
66      @Inject
67      @Named( value = "ldapConnectionFactory#configurable" )
68      private LdapConnectionFactory connectionFactory;
69  
70      @Inject
71      @Named( value = "userConfiguration#default" )
72      private UserConfiguration config;
73  
74      @Inject
75      private LdapCacheService ldapCacheService;
76  
77      public String getId()
78      {
79          return "LdapBindAuthenticator";
80      }
81  
82      public AuthenticationResult authenticate( AuthenticationDataSource s )
83          throws AuthenticationException
84      {
85          PasswordBasedAuthenticationDataSource source = (PasswordBasedAuthenticationDataSource) s;
86  
87          if ( !config.getBoolean( UserConfigurationKeys.LDAP_BIND_AUTHENTICATOR_ENABLED ) || (
88              !config.getBoolean( UserConfigurationKeys.LDAP_BIND_AUTHENTICATOR_ALLOW_EMPTY_PASSWORDS, false )
89                  && StringUtils.isEmpty( source.getPassword() ) ) )
90          {
91              return new AuthenticationResult( false, source.getUsername(), null );
92          }
93  
94          SearchControls ctls = new SearchControls();
95  
96          ctls.setCountLimit( 1 );
97  
98          ctls.setDerefLinkFlag( true );
99          ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
100 
101         String filter = "(&(objectClass=" + mapper.getUserObjectClass() + ")" + ( mapper.getUserFilter() != null
102             ? mapper.getUserFilter()
103             : "" ) + "(" + mapper.getUserIdAttribute() + "=" + source.getUsername() + "))";
104 
105         log.debug( "Searching for users with filter: '{}' from base dn: {}", filter, mapper.getUserBaseDn() );
106 
107         LdapConnection ldapConnection = null;
108         LdapConnection authLdapConnection = null;
109         NamingEnumeration<SearchResult> results = null;
110         try
111         {
112             ldapConnection = getLdapConnection();
113             // check the cache for user's userDn in the ldap server
114             String userDn = ldapCacheService.getLdapUserDn( source.getUsername() );
115 
116             if ( userDn == null )
117             {
118                 log.debug( "userDn for user {} not found in cache. Retrieving from ldap server..",
119                            source.getUsername() );
120 
121                 DirContext context = ldapConnection.getDirContext();
122 
123                 results = context.search( mapper.getUserBaseDn(), filter, ctls );
124 
125                 log.debug( "Found user '{}': {}", source.getUsername(), results.hasMoreElements() );
126 
127                 if ( results.hasMoreElements() )
128                 {
129                     SearchResult result = results.nextElement();
130 
131                     userDn = result.getNameInNamespace();
132 
133                     log.debug( "Adding userDn {} for user {} to the cache..", userDn, source.getUsername() );
134 
135                     // REDBACK-289/MRM-1488 cache the ldap user's userDn to lessen calls to ldap server
136                     ldapCacheService.addLdapUserDn( source.getUsername(), userDn );
137                 }
138                 else
139                 {
140                     return new AuthenticationResult( false, source.getUsername(), null );
141                 }
142             }
143 
144             log.debug( "Attempting Authenication: {}", userDn );
145 
146             authLdapConnection = connectionFactory.getConnection( userDn, source.getPassword() );
147 
148             log.info( "user '{}' authenticated", source.getUsername() );
149 
150             return new AuthenticationResult( true, source.getUsername(), null );
151         }
152         catch ( LdapException e )
153         {
154             return new AuthenticationResult( false, source.getUsername(), e );
155         }
156         catch ( NamingException e )
157         {
158             return new AuthenticationResult( false, source.getUsername(), e );
159         }
160         finally
161         {
162             closeNamingEnumeration( results );
163             closeLdapConnection( ldapConnection );
164             if ( authLdapConnection != null )
165             {
166                 closeLdapConnection( authLdapConnection );
167             }
168         }
169     }
170 
171     public boolean supportsDataSource( AuthenticationDataSource source )
172     {
173         return ( source instanceof PasswordBasedAuthenticationDataSource );
174     }
175 
176     private LdapConnection getLdapConnection()
177         throws LdapException
178     {
179         return connectionFactory.getConnection();
180     }
181 
182     private void closeLdapConnection( LdapConnection ldapConnection )
183     {
184         if ( ldapConnection != null )
185         {
186             ldapConnection.close();
187         }
188     }
189 
190     private void closeNamingEnumeration( NamingEnumeration<SearchResult> results )
191     {
192         try
193         {
194             if ( results != null )
195             {
196                 results.close();
197             }
198         }
199         catch ( NamingException e )
200         {
201             log.warn( "skip exception closing naming search result " + e.getMessage() );
202         }
203     }
204 }