1 package org.apache.archiva.redback.authentication.ldap;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
22 import org.apache.archiva.redback.common.ldap.UserMapper;
23 import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory;
24 import org.apache.archiva.redback.configuration.UserConfiguration;
25 import org.apache.commons.lang.StringUtils;
26 import org.apache.archiva.redback.authentication.AuthenticationDataSource;
27 import org.apache.archiva.redback.authentication.AuthenticationException;
28 import org.apache.archiva.redback.authentication.AuthenticationResult;
29 import org.apache.archiva.redback.authentication.Authenticator;
30 import org.apache.archiva.redback.authentication.PasswordBasedAuthenticationDataSource;
31 import org.apache.archiva.redback.common.ldap.connection.LdapConnection;
32 import org.apache.archiva.redback.common.ldap.connection.LdapException;
33 import org.apache.archiva.redback.users.ldap.service.LdapCacheService;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.springframework.stereotype.Service;
38 import javax.inject.Inject;
39 import javax.inject.Named;
40 import javax.naming.NamingEnumeration;
41 import javax.naming.NamingException;
42 import javax.naming.directory.DirContext;
43 import javax.naming.directory.SearchControls;
44 import javax.naming.directory.SearchResult;
47 * LdapBindAuthenticator:
49 * @author: Jesse McConnell <jesse@codehaus.org>
51 @Service( "authenticator#ldap" )
52 public class LdapBindAuthenticator
53 implements Authenticator
56 private Logger log = LoggerFactory.getLogger( getClass() );
59 @Named( value = "userMapper#ldap" )
60 private UserMapper mapper;
63 @Named( value = "ldapConnectionFactory#configurable" )
64 private LdapConnectionFactory connectionFactory;
67 @Named( value = "userConfiguration" )
68 private UserConfiguration config;
71 private LdapCacheService ldapCacheService;
75 return "LdapBindAuthenticator";
78 public AuthenticationResult authenticate( AuthenticationDataSource s )
79 throws AuthenticationException
81 PasswordBasedAuthenticationDataSource source = (PasswordBasedAuthenticationDataSource) s;
83 if ( !config.getBoolean( "ldap.bind.authenticator.enabled" ) || (
84 !config.getBoolean( "ldap.bind.authenticator.allowEmptyPasswords", false ) && StringUtils.isEmpty(
85 source.getPassword() ) ) )
87 return new AuthenticationResult( false, source.getPrincipal(), null );
90 SearchControls ctls = new SearchControls();
92 ctls.setCountLimit( 1 );
94 ctls.setDerefLinkFlag( true );
95 ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
97 String filter = "(&(objectClass=" + mapper.getUserObjectClass() + ")"
98 + ( mapper.getUserFilter() != null ? mapper.getUserFilter() : "" ) + "(" + mapper.getUserIdAttribute() + "="
99 + source.getPrincipal() + "))";
101 log.info( "Searching for users with filter: \'{}\'" + " from base dn: {}", filter, mapper.getUserBaseDn() );
103 LdapConnection ldapConnection = getLdapConnection();
104 LdapConnection authLdapConnection = null;
105 NamingEnumeration<SearchResult> results = null;
108 // check the cache for user's userDn in the ldap server
109 String userDn = ldapCacheService.getLdapUserDn( source.getPrincipal() );
113 log.debug( "userDn for user {} not found in cache. Retrieving from ldap server..", source.getPrincipal() );
115 DirContext context = ldapConnection.getDirContext();
117 results = context.search( mapper.getUserBaseDn(), filter, ctls );
119 log.info( "Found user?: {}", results.hasMoreElements() );
121 if ( results.hasMoreElements() )
123 SearchResult result = results.nextElement();
125 userDn = result.getNameInNamespace();
127 log.debug( "Adding userDn {} for user {} to the cache..", userDn, source.getPrincipal() );
129 // REDBACK-289/MRM-1488 cache the ldap user's userDn to lessen calls to ldap server
130 ldapCacheService.addLdapUserDn( source.getPrincipal(), userDn );
134 return new AuthenticationResult( false, source.getPrincipal(), null );
138 log.info( "Attempting Authenication: + {}", userDn );
140 authLdapConnection = connectionFactory.getConnection( userDn, source.getPassword() );
142 return new AuthenticationResult( true, source.getPrincipal(), null );
144 catch ( LdapException e )
146 return new AuthenticationResult( false, source.getPrincipal(), e );
148 catch ( NamingException e )
150 return new AuthenticationResult( false, source.getPrincipal(), e );
154 closeNamingEnumeration( results );
155 closeLdapConnection( ldapConnection );
156 if ( authLdapConnection != null )
158 closeLdapConnection( authLdapConnection );
163 public boolean supportsDataSource( AuthenticationDataSource source )
165 return ( source instanceof PasswordBasedAuthenticationDataSource );
168 private LdapConnection getLdapConnection()
172 return connectionFactory.getConnection();
174 catch ( LdapException e )
176 log.warn( "failed to get a ldap connection " + e.getMessage(), e );
177 throw new RuntimeException( "failed to get a ldap connection " + e.getMessage(), e );
181 private void closeLdapConnection( LdapConnection ldapConnection )
183 if ( ldapConnection != null )
185 ldapConnection.close();
189 private void closeNamingEnumeration( NamingEnumeration<SearchResult> results )
193 if ( results != null )
198 catch ( NamingException e )
200 log.warn( "skip exception closing naming search result " + e.getMessage() );