]> source.dussan.org Git - archiva.git/blob
4d9325305e765a77f098498fb4a118cd02e5d583
[archiva.git] /
1 package org.apache.archiva.web.security;
2 /*
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
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
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
18  * under the License.
19  */
20
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;
42
43 import javax.annotation.PostConstruct;
44 import javax.inject.Inject;
45 import java.util.ArrayList;
46 import java.util.List;
47
48 /**
49  * @author Olivier Lamy
50  * @since 1.4-M4
51  */
52 @Service("authenticator#archiva")
53 public class ArchivaUserManagerAuthenticator
54     extends AbstractAuthenticator
55     implements Authenticator
56 {
57     private Logger log = LoggerFactory.getLogger( getClass() );
58
59     @Inject
60     private UserSecurityPolicy securityPolicy;
61
62     @Inject
63     private ApplicationContext applicationContext;
64
65     @Inject
66     private RedbackRuntimeConfigurationAdmin redbackRuntimeConfigurationAdmin;
67
68     private List<UserManager> userManagers;
69
70     @PostConstruct
71     @Override
72     public void initialize()
73         throws AuthenticationException
74     {
75         try
76         {
77             List<String> userManagerImpls =
78                 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration().getUserManagerImpls();
79
80             userManagers = new ArrayList<>( userManagerImpls.size() );
81
82             for ( String beanId : userManagerImpls )
83             {
84                 userManagers.add( applicationContext.getBean( "userManager#" + beanId, UserManager.class ) );
85             }
86         }
87         catch ( RepositoryAdminException e )
88         {
89             throw new AuthenticationException( e.getMessage(), e );
90         }
91     }
92
93
94     @Override
95     public AuthenticationResult authenticate( AuthenticationDataSource ds )
96         throws AuthenticationException, AccountLockedException, MustChangePasswordException
97     {
98         boolean authenticationSuccess = false;
99         String username = null;
100         Exception resultException = null;
101         PasswordBasedAuthenticationDataSource source = (PasswordBasedAuthenticationDataSource) ds;
102         List<AuthenticationFailureCause> authnResultErrors = new ArrayList<>();
103
104         for ( UserManager userManager : userManagers )
105         {
106             try
107             {
108                 log.debug( "Authenticate: {} with userManager: {}", source, userManager.getId() );
109                 User user = userManager.findUser( source.getUsername() );
110                 username = user.getUsername();
111
112                 if ( user.isLocked() )
113                 {
114                     //throw new AccountLockedException( "Account " + source.getUsername() + " is locked.", user );
115                     AccountLockedException e =
116                         new AccountLockedException( "Account " + source.getUsername() + " is locked.", user );
117                     log.warn( "{}", e.getMessage() );
118                     resultException = e;
119                     authnResultErrors.add(
120                         new AuthenticationFailureCause( AuthenticationConstants.AUTHN_LOCKED_USER_EXCEPTION,
121                                                         e.getMessage() ) );
122                 }
123
124                 if ( user.isPasswordChangeRequired() && source.isEnforcePasswordChange() )
125                 {
126                     //throw new MustChangePasswordException( "Password expired.", user );
127                     MustChangePasswordException e = new MustChangePasswordException( "Password expired.", user );
128                     log.warn( "{}", e.getMessage() );
129                     resultException = e;
130                     authnResultErrors.add(
131                         new AuthenticationFailureCause( AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION,
132                                                         e.getMessage() ) );
133                 }
134
135                 PasswordEncoder encoder = securityPolicy.getPasswordEncoder();
136                 log.debug( "PasswordEncoder: {}", encoder.getClass().getName() );
137
138                 boolean isPasswordValid = encoder.isPasswordValid( user.getEncodedPassword(), source.getPassword() );
139                 if ( isPasswordValid )
140                 {
141                     log.debug( "User {} provided a valid password", source.getUsername() );
142
143                     try
144                     {
145                         securityPolicy.extensionPasswordExpiration( user );
146
147                         authenticationSuccess = true;
148
149                         //REDBACK-151 do not make unnessesary updates to the user object
150                         if ( user.getCountFailedLoginAttempts() > 0 )
151                         {
152                             user.setCountFailedLoginAttempts( 0 );
153                             if ( !userManager.isReadOnly() )
154                             {
155                                 userManager.updateUser( user );
156                             }
157                         }
158
159                         return new AuthenticationResult( true, source.getUsername(), null );
160                     }
161                     catch ( MustChangePasswordException e )
162                     {
163                         user.setPasswordChangeRequired( true );
164                         //throw e;
165                         resultException = e;
166                         authnResultErrors.add( new AuthenticationFailureCause(
167                             AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION, e.getMessage() ).user( user ) );
168                     }
169                 }
170                 else
171                 {
172                     log.warn( "Password is Invalid for user {} and userManager '{}'.", source.getUsername(),
173                               userManager.getId() );
174                     authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER,
175                                                                            "Password is Invalid for user "
176                                                                                + source.getUsername() + "." ).user( user ) );
177
178                     try
179                     {
180
181                         securityPolicy.extensionExcessiveLoginAttempts( user );
182
183                     }
184                     finally
185                     {
186                         if ( !userManager.isReadOnly() )
187                         {
188                             userManager.updateUser( user );
189                         }
190                     }
191
192                     //return new AuthenticationResult( false, source.getUsername(), null, authnResultExceptionsMap );
193                 }
194             }
195             catch ( UserNotFoundException e )
196             {
197                 log.warn( "Login for user {} and userManager {} failed. user not found.", source.getUsername(),
198                           userManager.getId() );
199                 resultException = e;
200                 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER,
201                                                                        "Login for user " + source.getUsername()
202                                                                            + " failed. user not found." ) );
203             }
204             catch ( Exception e )
205             {
206                 log.warn( "Login for user {} and userManager {} failed, message: {}", source.getUsername(),
207                           userManager.getId(), e.getMessage() );
208                 resultException = e;
209                 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_RUNTIME_EXCEPTION,
210                                                                        "Login for user " + source.getUsername()
211                                                                            + " failed, message: " + e.getMessage() ) );
212             }
213         }
214         return new AuthenticationResult( authenticationSuccess, username, resultException, authnResultErrors );
215     }
216
217     @Override
218     public boolean supportsDataSource( AuthenticationDataSource source )
219     {
220         return ( source instanceof PasswordBasedAuthenticationDataSource );
221     }
222
223     @Override
224     public String getId()
225     {
226         return "ArchivaUserManagerAuthenticator";
227     }
228 }