]> source.dussan.org Git - archiva.git/blob
0a74e395bf693bdc672430eef8f49b2f3fc56665
[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     private boolean valid = false;
71
72     @PostConstruct
73     @Override
74     public void initialize()
75         throws AuthenticationException
76     {
77         try
78         {
79             List<String> userManagerImpls =
80                 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration().getUserManagerImpls();
81
82             userManagers = new ArrayList<>( userManagerImpls.size() );
83
84             for ( String beanId : userManagerImpls )
85             {
86                 userManagers.add( applicationContext.getBean( "userManager#" + beanId, UserManager.class ) );
87             }
88             valid=true;
89         }
90         catch ( RepositoryAdminException e )
91         {
92             log.error("Error during repository initialization "+e.getMessage(),e);
93             // throw new AuthenticationException( e.getMessage(), e );
94         }
95     }
96
97
98     @Override
99     public AuthenticationResult authenticate( AuthenticationDataSource ds )
100         throws AuthenticationException, AccountLockedException, MustChangePasswordException
101     {
102         boolean authenticationSuccess = false;
103         String username = null;
104         Exception resultException = null;
105         PasswordBasedAuthenticationDataSource source = (PasswordBasedAuthenticationDataSource) ds;
106         List<AuthenticationFailureCause> authnResultErrors = new ArrayList<>();
107
108         for ( UserManager userManager : userManagers )
109         {
110             try
111             {
112                 log.debug( "Authenticate: {} with userManager: {}", source, userManager.getId() );
113                 User user = userManager.findUser( source.getUsername() );
114                 username = user.getUsername();
115
116                 if ( user.isLocked() )
117                 {
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() );
122                     resultException = e;
123                     authnResultErrors.add(
124                         new AuthenticationFailureCause( AuthenticationConstants.AUTHN_LOCKED_USER_EXCEPTION,
125                                                         e.getMessage() ) );
126                 }
127
128                 if ( user.isPasswordChangeRequired() && source.isEnforcePasswordChange() )
129                 {
130                     //throw new MustChangePasswordException( "Password expired.", user );
131                     MustChangePasswordException e = new MustChangePasswordException( "Password expired.", user );
132                     log.warn( "{}", e.getMessage() );
133                     resultException = e;
134                     authnResultErrors.add(
135                         new AuthenticationFailureCause( AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION,
136                                                         e.getMessage() ) );
137                 }
138
139                 PasswordEncoder encoder = securityPolicy.getPasswordEncoder();
140                 log.debug( "PasswordEncoder: {}", encoder.getClass().getName() );
141
142                 boolean isPasswordValid = encoder.isPasswordValid( user.getEncodedPassword(), source.getPassword() );
143                 if ( isPasswordValid )
144                 {
145                     log.debug( "User {} provided a valid password", source.getUsername() );
146
147                     try
148                     {
149                         securityPolicy.extensionPasswordExpiration( user );
150
151                         authenticationSuccess = true;
152
153                         //REDBACK-151 do not make unnessesary updates to the user object
154                         if ( user.getCountFailedLoginAttempts() > 0 )
155                         {
156                             user.setCountFailedLoginAttempts( 0 );
157                             if ( !userManager.isReadOnly() )
158                             {
159                                 userManager.updateUser( user );
160                             }
161                         }
162
163                         return new AuthenticationResult( true, source.getUsername(), null );
164                     }
165                     catch ( MustChangePasswordException e )
166                     {
167                         user.setPasswordChangeRequired( true );
168                         //throw e;
169                         resultException = e;
170                         authnResultErrors.add( new AuthenticationFailureCause(
171                             AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION, e.getMessage() ).user( user ) );
172                     }
173                 }
174                 else
175                 {
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 ) );
181
182                     try
183                     {
184
185                         securityPolicy.extensionExcessiveLoginAttempts( user );
186
187                     }
188                     finally
189                     {
190                         if ( !userManager.isReadOnly() )
191                         {
192                             userManager.updateUser( user );
193                         }
194                     }
195
196                     //return new AuthenticationResult( false, source.getUsername(), null, authnResultExceptionsMap );
197                 }
198             }
199             catch ( UserNotFoundException e )
200             {
201                 log.warn( "Login for user {} and userManager {} failed. user not found.", source.getUsername(),
202                           userManager.getId() );
203                 resultException = e;
204                 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER,
205                                                                        "Login for user " + source.getUsername()
206                                                                            + " failed. user not found." ) );
207             }
208             catch ( Exception e )
209             {
210                 log.warn( "Login for user {} and userManager {} failed, message: {}", source.getUsername(),
211                           userManager.getId(), e.getMessage() );
212                 resultException = e;
213                 authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_RUNTIME_EXCEPTION,
214                                                                        "Login for user " + source.getUsername()
215                                                                            + " failed, message: " + e.getMessage() ) );
216             }
217         }
218         return new AuthenticationResult( authenticationSuccess, username, resultException, authnResultErrors );
219     }
220
221     @Override
222     public boolean supportsDataSource( AuthenticationDataSource source )
223     {
224         return ( source instanceof PasswordBasedAuthenticationDataSource );
225     }
226
227     @Override
228     public String getId()
229     {
230         return "ArchivaUserManagerAuthenticator";
231     }
232
233     public boolean isValid() {
234         return valid;
235     }
236 }