| package org.apache.archiva.web.security; |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.apache.archiva.admin.model.RepositoryAdminException; |
| import org.apache.archiva.admin.model.runtime.RedbackRuntimeConfigurationAdmin; |
| import org.apache.archiva.redback.authentication.AbstractAuthenticator; |
| import org.apache.archiva.redback.authentication.AuthenticationConstants; |
| import org.apache.archiva.redback.authentication.AuthenticationDataSource; |
| import org.apache.archiva.redback.authentication.AuthenticationException; |
| import org.apache.archiva.redback.authentication.AuthenticationFailureCause; |
| import org.apache.archiva.redback.authentication.AuthenticationResult; |
| import org.apache.archiva.redback.authentication.Authenticator; |
| import org.apache.archiva.redback.authentication.PasswordBasedAuthenticationDataSource; |
| import org.apache.archiva.redback.policy.AccountLockedException; |
| import org.apache.archiva.redback.policy.MustChangePasswordException; |
| import org.apache.archiva.redback.policy.PasswordEncoder; |
| import org.apache.archiva.redback.policy.UserSecurityPolicy; |
| import org.apache.archiva.redback.users.User; |
| import org.apache.archiva.redback.users.UserManager; |
| import org.apache.archiva.redback.users.UserNotFoundException; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.springframework.context.ApplicationContext; |
| import org.springframework.stereotype.Service; |
| |
| import javax.annotation.PostConstruct; |
| import javax.inject.Inject; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * @author Olivier Lamy |
| * @since 1.4-M4 |
| */ |
| @Service("authenticator#archiva") |
| public class ArchivaUserManagerAuthenticator |
| extends AbstractAuthenticator |
| implements Authenticator |
| { |
| private Logger log = LoggerFactory.getLogger( getClass() ); |
| |
| @Inject |
| private UserSecurityPolicy securityPolicy; |
| |
| @Inject |
| private ApplicationContext applicationContext; |
| |
| @Inject |
| private RedbackRuntimeConfigurationAdmin redbackRuntimeConfigurationAdmin; |
| |
| private List<UserManager> userManagers; |
| |
| private boolean valid = false; |
| |
| @PostConstruct |
| @Override |
| public void initialize() |
| throws AuthenticationException |
| { |
| try |
| { |
| List<String> userManagerImpls = |
| redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration().getUserManagerImpls(); |
| |
| userManagers = new ArrayList<>( userManagerImpls.size() ); |
| |
| for ( String beanId : userManagerImpls ) |
| { |
| userManagers.add( applicationContext.getBean( "userManager#" + beanId, UserManager.class ) ); |
| } |
| valid=true; |
| } |
| catch ( RepositoryAdminException e ) |
| { |
| log.error("Error during repository initialization "+e.getMessage(),e); |
| // throw new AuthenticationException( e.getMessage(), e ); |
| } |
| } |
| |
| |
| @Override |
| public AuthenticationResult authenticate( AuthenticationDataSource ds ) |
| throws AuthenticationException, AccountLockedException, MustChangePasswordException |
| { |
| boolean authenticationSuccess = false; |
| String username = null; |
| Exception resultException = null; |
| PasswordBasedAuthenticationDataSource source = (PasswordBasedAuthenticationDataSource) ds; |
| List<AuthenticationFailureCause> authnResultErrors = new ArrayList<>(); |
| |
| for ( UserManager userManager : userManagers ) |
| { |
| try |
| { |
| log.debug( "Authenticate: {} with userManager: {}", source, userManager.getId() ); |
| User user = userManager.findUser( source.getUsername() ); |
| username = user.getUsername(); |
| |
| if ( user.isLocked() ) |
| { |
| //throw new AccountLockedException( "Account " + source.getUsername() + " is locked.", user ); |
| AccountLockedException e = |
| new AccountLockedException( "Account " + source.getUsername() + " is locked.", user ); |
| log.warn( "{}", e.getMessage() ); |
| resultException = e; |
| authnResultErrors.add( |
| new AuthenticationFailureCause( AuthenticationConstants.AUTHN_LOCKED_USER_EXCEPTION, |
| e.getMessage() ) ); |
| } |
| |
| if ( user.isPasswordChangeRequired() && source.isEnforcePasswordChange() ) |
| { |
| //throw new MustChangePasswordException( "Password expired.", user ); |
| MustChangePasswordException e = new MustChangePasswordException( "Password expired.", user ); |
| log.warn( "{}", e.getMessage() ); |
| resultException = e; |
| authnResultErrors.add( |
| new AuthenticationFailureCause( AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION, |
| e.getMessage() ) ); |
| } |
| |
| PasswordEncoder encoder = securityPolicy.getPasswordEncoder(); |
| log.debug( "PasswordEncoder: {}", encoder.getClass().getName() ); |
| |
| boolean isPasswordValid = encoder.isPasswordValid( user.getEncodedPassword(), source.getPassword() ); |
| if ( isPasswordValid ) |
| { |
| log.debug( "User {} provided a valid password", source.getUsername() ); |
| |
| try |
| { |
| securityPolicy.extensionPasswordExpiration( user ); |
| |
| authenticationSuccess = true; |
| |
| //REDBACK-151 do not make unnessesary updates to the user object |
| if ( user.getCountFailedLoginAttempts() > 0 ) |
| { |
| user.setCountFailedLoginAttempts( 0 ); |
| if ( !userManager.isReadOnly() ) |
| { |
| userManager.updateUser( user ); |
| } |
| } |
| |
| return new AuthenticationResult( true, source.getUsername(), null ); |
| } |
| catch ( MustChangePasswordException e ) |
| { |
| user.setPasswordChangeRequired( true ); |
| //throw e; |
| resultException = e; |
| authnResultErrors.add( new AuthenticationFailureCause( |
| AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION, e.getMessage() ).user( user ) ); |
| } |
| } |
| else |
| { |
| log.warn( "Password is Invalid for user {} and userManager '{}'.", source.getUsername(), |
| userManager.getId() ); |
| authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER, |
| "Password is Invalid for user " |
| + source.getUsername() + "." ).user( user ) ); |
| |
| try |
| { |
| |
| securityPolicy.extensionExcessiveLoginAttempts( user ); |
| |
| } |
| finally |
| { |
| if ( !userManager.isReadOnly() ) |
| { |
| userManager.updateUser( user ); |
| } |
| } |
| |
| //return new AuthenticationResult( false, source.getUsername(), null, authnResultExceptionsMap ); |
| } |
| } |
| catch ( UserNotFoundException e ) |
| { |
| log.warn( "Login for user {} and userManager {} failed. user not found.", source.getUsername(), |
| userManager.getId() ); |
| resultException = e; |
| authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER, |
| "Login for user " + source.getUsername() |
| + " failed. user not found." ) ); |
| } |
| catch ( Exception e ) |
| { |
| log.warn( "Login for user {} and userManager {} failed, message: {}", source.getUsername(), |
| userManager.getId(), e.getMessage() ); |
| resultException = e; |
| authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_RUNTIME_EXCEPTION, |
| "Login for user " + source.getUsername() |
| + " failed, message: " + e.getMessage() ) ); |
| } |
| } |
| return new AuthenticationResult( authenticationSuccess, username, resultException, authnResultErrors ); |
| } |
| |
| @Override |
| public boolean supportsDataSource( AuthenticationDataSource source ) |
| { |
| return ( source instanceof PasswordBasedAuthenticationDataSource ); |
| } |
| |
| @Override |
| public String getId() |
| { |
| return "ArchivaUserManagerAuthenticator"; |
| } |
| |
| public boolean isValid() { |
| return valid; |
| } |
| } |