1 package org.apache.archiva.web.security;
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
21 import org.apache.archiva.admin.model.RepositoryAdminException;
22 import org.apache.archiva.admin.model.runtime.RedbackRuntimeConfigurationAdmin;
23 import org.apache.archiva.redback.authentication.AbstractAuthenticator;
24 import org.apache.archiva.redback.authentication.AuthenticationConstants;
25 import org.apache.archiva.redback.authentication.AuthenticationDataSource;
26 import org.apache.archiva.redback.authentication.AuthenticationException;
27 import org.apache.archiva.redback.authentication.AuthenticationFailureCause;
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.policy.AccountLockedException;
32 import org.apache.archiva.redback.policy.MustChangePasswordException;
33 import org.apache.archiva.redback.policy.PasswordEncoder;
34 import org.apache.archiva.redback.policy.UserSecurityPolicy;
35 import org.apache.archiva.redback.users.User;
36 import org.apache.archiva.redback.users.UserManager;
37 import org.apache.archiva.redback.users.UserNotFoundException;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.springframework.context.ApplicationContext;
41 import org.springframework.stereotype.Service;
43 import javax.annotation.PostConstruct;
44 import javax.inject.Inject;
45 import java.util.ArrayList;
46 import java.util.List;
49 * @author Olivier Lamy
52 @Service("authenticator#archiva")
53 public class ArchivaUserManagerAuthenticator
54 extends AbstractAuthenticator
55 implements Authenticator
57 private Logger log = LoggerFactory.getLogger( getClass() );
60 private UserSecurityPolicy securityPolicy;
63 private ApplicationContext applicationContext;
66 private RedbackRuntimeConfigurationAdmin redbackRuntimeConfigurationAdmin;
68 private List<UserManager> userManagers;
70 private boolean valid = false;
74 public void initialize()
75 throws AuthenticationException
79 List<String> userManagerImpls =
80 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration().getUserManagerImpls();
82 userManagers = new ArrayList<>( userManagerImpls.size() );
84 for ( String beanId : userManagerImpls )
86 userManagers.add( applicationContext.getBean( "userManager#" + beanId, UserManager.class ) );
90 catch ( RepositoryAdminException e )
92 log.error("Error during repository initialization "+e.getMessage(),e);
93 // throw new AuthenticationException( e.getMessage(), e );
99 public AuthenticationResult authenticate( AuthenticationDataSource ds )
100 throws AuthenticationException, AccountLockedException, MustChangePasswordException
102 boolean authenticationSuccess = false;
103 String username = null;
104 Exception resultException = null;
105 PasswordBasedAuthenticationDataSource source = (PasswordBasedAuthenticationDataSource) ds;
106 List<AuthenticationFailureCause> authnResultErrors = new ArrayList<>();
108 for ( UserManager userManager : userManagers )
112 log.debug( "Authenticate: {} with userManager: {}", source, userManager.getId() );
113 User user = userManager.findUser( source.getUsername() );
114 username = user.getUsername();
116 if ( user.isLocked() )
118 //throw new AccountLockedException( "Account " + source.getUsername() + " is locked.", user );
119 AccountLockedException e =
120 new AccountLockedException( "Account " + source.getUsername() + " is locked.", user );
121 log.warn( "{}", e.getMessage() );
123 authnResultErrors.add(
124 new AuthenticationFailureCause( AuthenticationConstants.AUTHN_LOCKED_USER_EXCEPTION,
128 if ( user.isPasswordChangeRequired() && source.isEnforcePasswordChange() )
130 //throw new MustChangePasswordException( "Password expired.", user );
131 MustChangePasswordException e = new MustChangePasswordException( "Password expired.", user );
132 log.warn( "{}", e.getMessage() );
134 authnResultErrors.add(
135 new AuthenticationFailureCause( AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION,
139 PasswordEncoder encoder = securityPolicy.getPasswordEncoder();
140 log.debug( "PasswordEncoder: {}", encoder.getClass().getName() );
142 boolean isPasswordValid = encoder.isPasswordValid( user.getEncodedPassword(), source.getPassword() );
143 if ( isPasswordValid )
145 log.debug( "User {} provided a valid password", source.getUsername() );
149 securityPolicy.extensionPasswordExpiration( user );
151 authenticationSuccess = true;
153 //REDBACK-151 do not make unnessesary updates to the user object
154 if ( user.getCountFailedLoginAttempts() > 0 )
156 user.setCountFailedLoginAttempts( 0 );
157 if ( !userManager.isReadOnly() )
159 userManager.updateUser( user );
163 return new AuthenticationResult( true, source.getUsername(), null );
165 catch ( MustChangePasswordException e )
167 user.setPasswordChangeRequired( true );
170 authnResultErrors.add( new AuthenticationFailureCause(
171 AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION, e.getMessage() ).user( user ) );
176 log.warn( "Password is Invalid for user {} and userManager '{}'.", source.getUsername(),
177 userManager.getId() );
178 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER,
179 "Password is Invalid for user "
180 + source.getUsername() + "." ).user( user ) );
185 securityPolicy.extensionExcessiveLoginAttempts( user );
190 if ( !userManager.isReadOnly() )
192 userManager.updateUser( user );
196 //return new AuthenticationResult( false, source.getUsername(), null, authnResultExceptionsMap );
199 catch ( UserNotFoundException e )
201 log.warn( "Login for user {} and userManager {} failed. user not found.", source.getUsername(),
202 userManager.getId() );
204 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER,
205 "Login for user " + source.getUsername()
206 + " failed. user not found." ) );
208 catch ( Exception e )
210 log.warn( "Login for user {} and userManager {} failed, message: {}", source.getUsername(),
211 userManager.getId(), e.getMessage() );
214 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_RUNTIME_EXCEPTION,
215 "Login for user " + source.getUsername()
216 + " failed, message: " + e.getMessage() ) );
219 return new AuthenticationResult( authenticationSuccess, username, resultException, authnResultErrors );
223 public boolean supportsDataSource( AuthenticationDataSource source )
225 return ( source instanceof PasswordBasedAuthenticationDataSource );
229 public String getId()
231 return "ArchivaUserManagerAuthenticator";
234 public boolean isValid() {