]> source.dussan.org Git - archiva.git/blob
0d04fa3658adff04a4cacdc79e79558b884d08fd
[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.UserManagerException;
38 import org.apache.archiva.redback.users.UserNotFoundException;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.context.ApplicationContext;
42 import org.springframework.stereotype.Service;
43
44 import javax.annotation.PostConstruct;
45 import javax.inject.Inject;
46 import java.util.ArrayList;
47 import java.util.List;
48
49 /**
50  * @author Olivier Lamy
51  * @since 1.4-M4
52  */
53 @Service("authenticator#archiva")
54 public class ArchivaUserManagerAuthenticator
55     extends AbstractAuthenticator
56     implements Authenticator
57 {
58     private Logger log = LoggerFactory.getLogger( getClass() );
59
60     @Inject
61     private UserSecurityPolicy securityPolicy;
62
63     @Inject
64     private ApplicationContext applicationContext;
65
66     @Inject
67     private RedbackRuntimeConfigurationAdmin redbackRuntimeConfigurationAdmin;
68
69     private List<UserManager> userManagers;
70
71     @PostConstruct
72     @Override
73     public void initialize()
74         throws AuthenticationException
75     {
76         try
77         {
78             List<String> userManagerImpls =
79                 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration().getUserManagerImpls();
80
81             userManagers = new ArrayList<UserManager>( userManagerImpls.size() );
82
83             for ( String beanId : userManagerImpls )
84             {
85                 userManagers.add( applicationContext.getBean( "userManager#" + beanId, UserManager.class ) );
86             }
87         }
88         catch ( RepositoryAdminException e )
89         {
90             throw new AuthenticationException( e.getMessage(), e );
91         }
92     }
93
94
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<AuthenticationFailureCause>();
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() ) );
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() + "." ) );
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 {} failed. user not found.", source.getUsername() );
198                 resultException = e;
199                 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER,
200                                                                        "Login for user " + source.getUsername()
201                                                                            + " failed. user not found." ) );
202             }
203             catch ( Exception e )
204             {
205                 log.warn( "Login for user {} failed, message: {}", source.getUsername(), e.getMessage() );
206                 resultException = e;
207                 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_RUNTIME_EXCEPTION,
208                                                                        "Login for user " + source.getUsername()
209                                                                            + " failed, message: " + e.getMessage() ) );
210             }
211         }
212         return new AuthenticationResult( authenticationSuccess, username, resultException, authnResultErrors );
213     }
214
215     public boolean supportsDataSource( AuthenticationDataSource source )
216     {
217         return ( source instanceof PasswordBasedAuthenticationDataSource );
218     }
219
220     public String getId()
221     {
222         return "ArchivaUserManagerAuthenticator";
223     }
224 }