1package org.apache.archiva.redback.authentication;
23/*4 * Licensed to the Apache Software Foundation (ASF) under one5 * or more contributor license agreements. See the NOTICE file6 * distributed with this work for additional information7 * regarding copyright ownership. The ASF licenses this file8 * to you under the Apache License, Version 2.0 (the9 * "License"); you may not use this file except in compliance10 * with the License. You may obtain a copy of the License at11 *12 * http://www.apache.org/licenses/LICENSE-2.013 *14 * Unless required by applicable law or agreed to in writing,15 * software distributed under the License is distributed on an16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY17 * KIND, either express or implied. See the License for the18 * specific language governing permissions and limitations19 * under the License.20 */2122import org.apache.archiva.redback.policy.AccountLockedException;
23import org.apache.archiva.redback.policy.MustChangePasswordException;
24import org.apache.archiva.redback.users.User;
25import org.apache.archiva.redback.users.UserManager;
26import org.apache.archiva.redback.users.UserManagerException;
27import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29import org.springframework.context.ApplicationContext;
30import org.springframework.stereotype.Service;
3132import javax.annotation.PostConstruct;
33import javax.inject.Inject;
34import javax.inject.Named;
35import java.util.ArrayList;
36import java.util.HashMap;
37import java.util.List;
38import java.util.Map;
394041/**42 * DefaultAuthenticationManager: the goal of the authentication manager is to act as a conduit for43 * authentication requests into different authentication schemes44 * <p/>45 * For example, the default implementation can be configured with any number of authenticators and will46 * sequentially try them for an authenticated result. This allows you to have the standard user/pass47 * auth procedure followed by authentication based on a known key for 'remember me' type functionality.48 *49 * @author: Jesse McConnell <jesse@codehaus.org>50 */51 @Service("authenticationManager")
52publicclassDefaultAuthenticationManager53implementsAuthenticationManager54 {
5556private Logger log = LoggerFactory.getLogger( getClass() );
5758private List<Authenticator> authenticators;
5960 @Inject
61private ApplicationContext applicationContext;
6263 @Inject
64 @Named( value = "userManager#default" )
65privateUserManager userManager;
6667 @SuppressWarnings( "unchecked" )
68 @PostConstruct
69publicvoid initialize()
70 {
71this.authenticators =
72new ArrayList<Authenticator>( applicationContext.getBeansOfType( Authenticator.class ).values() );
73 }
747576public String getId()
77 {
78return"Default Authentication Manager - " + this.getClass().getName() + " : managed authenticators - " +
79 knownAuthenticators();
80 }
8182publicAuthenticationResult authenticate( AuthenticationDataSource source )
83throws AccountLockedException, AuthenticationException, MustChangePasswordException84 {
85if ( authenticators == null || authenticators.size() == 0 )
86 {
87return ( new AuthenticationResult( false, null, new AuthenticationException(
88"no valid authenticators, can't authenticate" ) ) );
89 }
9091// put AuthenticationResult exceptions in a map92 List<AuthenticationFailureCause> authnResultErrors = new ArrayList<AuthenticationFailureCause>();
93for ( Authenticator authenticator : authenticators )
94 {
95if ( authenticator.supportsDataSource( source ) )
96 {
97AuthenticationResult authResult = authenticator.authenticate( source );
98 List<AuthenticationFailureCause> authenticationFailureCauses =
99 authResult.getAuthenticationFailureCauses();
100101if ( authResult.isAuthenticated() )
102 {
103//olamy: as we can chain various user managers with Archiva104// user manager authenticator can lock accounts in the following case :105// 2 user managers: ldap and jdo.106// ldap correctly find the user but cannot compare hashed password107// jdo reject password so increase loginAttemptCount108// now ldap bind authenticator work but loginAttemptCount has been increased.109// so we restore here loginAttemptCount to 0 if in authenticationFailureCauses110111for ( AuthenticationFailureCause authenticationFailureCause : authenticationFailureCauses )
112 {
113User user = authenticationFailureCause.getUser();
114if ( user != null )
115 {
116if ( user.getCountFailedLoginAttempts() > 0 )
117 {
118 user.setCountFailedLoginAttempts( 0 );
119if ( !userManager.isReadOnly() )
120 {
121try122 {
123 userManager.updateUser( user );
124 }
125catch ( UserManagerException e )
126 {
127 log.debug( e.getMessage(), e );
128 log.warn( "skip error updating user: {}", e.getMessage() );
129 }
130 }
131 }
132 }
133 }
134return authResult;
135 }
136137if ( authenticationFailureCauses != null )
138 {
139 authnResultErrors.addAll( authenticationFailureCauses );
140 }
141else142 {
143if ( authResult.getException() != null )
144 {
145 authnResultErrors.add(
146newAuthenticationFailureCause( AuthenticationConstants.AUTHN_RUNTIME_EXCEPTION,
147 authResult.getException().getMessage() ) );
148 }
149 }
150151152 }
153 }
154155return ( new AuthenticationResult( false, null, new AuthenticationException(
156"authentication failed on authenticators: " + knownAuthenticators() ), authnResultErrors ) );
157 }
158159public List<Authenticator> getAuthenticators()
160 {
161return authenticators;
162 }
163164private String knownAuthenticators()
165 {
166 StringBuilder strbuf = new StringBuilder();
167168for ( Authenticator authenticator : authenticators )
169 {
170 strbuf.append( '(' ).append( authenticator.getId() ).append( ") " );
171 }
172173return strbuf.toString();
174 }
175 }