]> source.dussan.org Git - archiva.git/blob
58a68074ccff5f71e9119d918bd9912698bbbe88
[archiva.git] /
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.user.UserMapper;
24 import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory;
25 import org.apache.archiva.redback.configuration.UserConfiguration;
26 import org.apache.archiva.redback.configuration.UserConfigurationKeys;
27 import org.apache.commons.lang.StringUtils;
28 import org.apache.archiva.redback.authentication.AuthenticationDataSource;
29 import org.apache.archiva.redback.authentication.AuthenticationException;
30 import org.apache.archiva.redback.authentication.AuthenticationResult;
31 import org.apache.archiva.redback.authentication.Authenticator;
32 import org.apache.archiva.redback.authentication.PasswordBasedAuthenticationDataSource;
33 import org.apache.archiva.redback.common.ldap.connection.LdapConnection;
34 import org.apache.archiva.redback.common.ldap.connection.LdapException;
35 import org.apache.archiva.redback.users.ldap.service.LdapCacheService;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38 import org.springframework.stereotype.Service;
39
40 import javax.inject.Inject;
41 import javax.inject.Named;
42 import javax.naming.NamingEnumeration;
43 import javax.naming.NamingException;
44 import javax.naming.directory.DirContext;
45 import javax.naming.directory.SearchControls;
46 import javax.naming.directory.SearchResult;
47
48 /**
49  * LdapBindAuthenticator:
50  *
51  * @author: Jesse McConnell <jesse@codehaus.org>
52  */
53 @Service( "authenticator#ldap" )
54 public class LdapBindAuthenticator
55     extends AbstractAuthenticator
56     implements Authenticator
57 {
58
59     private Logger log = LoggerFactory.getLogger( getClass() );
60
61     @Inject
62     @Named( value = "userMapper#ldap" )
63     private UserMapper mapper;
64
65     @Inject
66     @Named( value = "ldapConnectionFactory#configurable" )
67     private LdapConnectionFactory connectionFactory;
68
69     @Inject
70     @Named( value = "userConfiguration#default" )
71     private UserConfiguration config;
72
73     @Inject
74     private LdapCacheService ldapCacheService;
75
76     public String getId()
77     {
78         return "LdapBindAuthenticator";
79     }
80
81     public AuthenticationResult authenticate( AuthenticationDataSource s )
82         throws AuthenticationException
83     {
84         PasswordBasedAuthenticationDataSource source = (PasswordBasedAuthenticationDataSource) s;
85
86         if ( !config.getBoolean( UserConfigurationKeys.LDAP_BIND_AUTHENTICATOR_ENABLED ) || (
87             !config.getBoolean( UserConfigurationKeys.LDAP_BIND_AUTHENTICATOR_ALLOW_EMPTY_PASSWORDS, false )
88                 && StringUtils.isEmpty( source.getPassword() ) ) )
89         {
90             return new AuthenticationResult( false, source.getPrincipal(), null );
91         }
92
93         SearchControls ctls = new SearchControls();
94
95         ctls.setCountLimit( 1 );
96
97         ctls.setDerefLinkFlag( true );
98         ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
99
100         String filter = "(&(objectClass=" + mapper.getUserObjectClass() + ")" + ( mapper.getUserFilter() != null
101             ? mapper.getUserFilter()
102             : "" ) + "(" + mapper.getUserIdAttribute() + "=" + source.getPrincipal() + "))";
103
104         log.debug( "Searching for users with filter: '{}' from base dn: {}", filter, mapper.getUserBaseDn() );
105
106         LdapConnection ldapConnection = null;
107         LdapConnection authLdapConnection = null;
108         NamingEnumeration<SearchResult> results = null;
109         try
110         {
111             ldapConnection = getLdapConnection();
112             // check the cache for user's userDn in the ldap server
113             String userDn = ldapCacheService.getLdapUserDn( source.getPrincipal() );
114
115             if ( userDn == null )
116             {
117                 log.debug( "userDn for user {} not found in cache. Retrieving from ldap server..",
118                            source.getPrincipal() );
119
120                 DirContext context = ldapConnection.getDirContext();
121
122                 results = context.search( mapper.getUserBaseDn(), filter, ctls );
123
124                 log.debug( "Found user '{}': {}", source.getPrincipal(), results.hasMoreElements() );
125
126                 if ( results.hasMoreElements() )
127                 {
128                     SearchResult result = results.nextElement();
129
130                     userDn = result.getNameInNamespace();
131
132                     log.debug( "Adding userDn {} for user {} to the cache..", userDn, source.getPrincipal() );
133
134                     // REDBACK-289/MRM-1488 cache the ldap user's userDn to lessen calls to ldap server
135                     ldapCacheService.addLdapUserDn( source.getPrincipal(), userDn );
136                 }
137                 else
138                 {
139                     return new AuthenticationResult( false, source.getPrincipal(), null );
140                 }
141             }
142
143             log.debug( "Attempting Authenication: {}", userDn );
144
145             authLdapConnection = connectionFactory.getConnection( userDn, source.getPassword() );
146
147             log.info( "user '{}' authenticated", source.getPrincipal() );
148
149             return new AuthenticationResult( true, source.getPrincipal(), null );
150         }
151         catch ( LdapException e )
152         {
153             return new AuthenticationResult( false, source.getPrincipal(), e );
154         }
155         catch ( NamingException e )
156         {
157             return new AuthenticationResult( false, source.getPrincipal(), e );
158         }
159         finally
160         {
161             closeNamingEnumeration( results );
162             closeLdapConnection( ldapConnection );
163             if ( authLdapConnection != null )
164             {
165                 closeLdapConnection( authLdapConnection );
166             }
167         }
168     }
169
170     public boolean supportsDataSource( AuthenticationDataSource source )
171     {
172         return ( source instanceof PasswordBasedAuthenticationDataSource );
173     }
174
175     private LdapConnection getLdapConnection()
176         throws LdapException
177     {
178         return connectionFactory.getConnection();
179     }
180
181     private void closeLdapConnection( LdapConnection ldapConnection )
182     {
183         if ( ldapConnection != null )
184         {
185             ldapConnection.close();
186         }
187     }
188
189     private void closeNamingEnumeration( NamingEnumeration<SearchResult> results )
190     {
191         try
192         {
193             if ( results != null )
194             {
195                 results.close();
196             }
197         }
198         catch ( NamingException e )
199         {
200             log.warn( "skip exception closing naming search result " + e.getMessage() );
201         }
202     }
203 }