]> source.dussan.org Git - archiva.git/blob
b2242394ef1b2b3439a3094ddbfa3d47f6639227
[archiva.git] /
1 package org.apache.archiva.redback.struts2.action;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import org.apache.archiva.redback.keys.AuthenticationKey;
23 import org.apache.archiva.redback.policy.AccountLockedException;
24 import org.apache.archiva.redback.users.User;
25 import org.apache.struts2.ServletActionContext;
26 import org.apache.archiva.redback.authentication.AuthenticationConstants;
27 import org.apache.archiva.redback.authentication.AuthenticationDataSource;
28 import org.apache.archiva.redback.authentication.AuthenticationException;
29 import org.apache.archiva.redback.authentication.AuthenticationResult;
30 import org.apache.archiva.redback.authentication.PasswordBasedAuthenticationDataSource;
31 import org.apache.archiva.redback.authentication.TokenBasedAuthenticationDataSource;
32 import org.apache.archiva.redback.configuration.UserConfiguration;
33 import org.apache.archiva.redback.keys.KeyManagerException;
34 import org.apache.archiva.redback.keys.KeyNotFoundException;
35 import org.apache.archiva.redback.policy.MustChangePasswordException;
36 import org.apache.archiva.redback.system.SecuritySession;
37 import org.apache.archiva.redback.system.SecuritySystem;
38 import org.apache.archiva.redback.users.UserNotFoundException;
39 import org.codehaus.plexus.util.StringUtils;
40 import org.apache.archiva.redback.integration.interceptor.SecureActionBundle;
41 import org.apache.archiva.redback.integration.interceptor.SecureActionException;
42 import org.apache.archiva.redback.integration.util.AutoLoginCookies;
43 import org.springframework.context.annotation.Scope;
44 import org.springframework.stereotype.Controller;
45
46 import javax.inject.Inject;
47 import java.util.Arrays;
48 import java.util.Date;
49
50 /**
51  * LoginAction
52  *
53  * @author Jesse McConnell <jmcconnell@apache.org>
54  * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
55  * @version $Id$
56  */
57 @Controller( "redback-login" )
58 @Scope( "prototype" )
59 public class LoginAction
60     extends AbstractSecurityAction
61     implements CancellableAction
62 {
63     private static final String LOGIN_SUCCESS = "security-login-success";
64
65     private static final String PASSWORD_CHANGE = "security-must-change-password";
66
67     private static final String ACCOUNT_LOCKED = "security-login-locked";
68
69     // ------------------------------------------------------------------
70     //  Component Requirements
71     // ------------------------------------------------------------------
72
73     /**
74      *
75      */
76     @Inject
77     protected SecuritySystem securitySystem;
78
79     private String username;
80
81     private String password;
82
83     private String validateMe;
84
85     private String resetPassword;
86
87     private boolean rememberMe;
88
89     /**
90      *
91      */
92     @Inject
93     private AutoLoginCookies autologinCookies;
94
95     /**
96      *
97      */
98     @Inject
99     private UserConfiguration config;
100
101     // ------------------------------------------------------------------
102     // Action Entry Points - (aka Names)
103     // ------------------------------------------------------------------
104
105     public String show()
106     {
107         return INPUT;
108     }
109
110     /**
111      * 1) check if this is a validation authentication action
112      * 2) check if this is a reset password authentication action
113      * 3) sets up a password based authentication and passes on to webLogin()
114      *
115      * @return
116      */
117     public String login()
118     {
119         if ( StringUtils.isNotEmpty( validateMe ) )
120         {
121             // Process a login / validate request.
122             return validated();
123         }
124
125         if ( StringUtils.isNotEmpty( resetPassword ) )
126         {
127             // Process a login / reset password request.
128             return resetPassword();
129         }
130
131         if ( StringUtils.isEmpty( username ) )
132         {
133             addFieldError( "username", getText( "username.required" ) );
134             return ERROR;
135         }
136
137         PasswordBasedAuthenticationDataSource authdatasource = new PasswordBasedAuthenticationDataSource();
138         authdatasource.setPrincipal( username );
139         authdatasource.setPassword( password );
140
141         return webLogin( authdatasource, rememberMe );
142     }
143
144     /**
145      * 1) sets up a token based authentication
146      * 2) forces a password change requirement to the user
147      * 3) passes on to webLogin()
148      *
149      * @return
150      */
151     public String resetPassword()
152     {
153         if ( StringUtils.isEmpty( resetPassword ) )
154         {
155             addActionError( getText( "reset.password.missing" ) );
156             return ERROR;
157         }
158
159         try
160         {
161             AuthenticationKey authkey = securitySystem.getKeyManager().findKey( resetPassword );
162
163             User user = securitySystem.getUserManager().findUser( authkey.getForPrincipal() );
164
165             user.setPasswordChangeRequired( true );
166             user.setEncodedPassword( "" );
167
168             TokenBasedAuthenticationDataSource authsource = new TokenBasedAuthenticationDataSource();
169             authsource.setPrincipal( user.getPrincipal().toString() );
170             authsource.setToken( authkey.getKey() );
171             authsource.setEnforcePasswordChange( false );
172
173             securitySystem.getUserManager().updateUser( user );
174
175             AuditEvent event = new AuditEvent( getText( "log.password.change" ) );
176             event.setAffectedUser( username );
177             event.log();
178
179             return webLogin( authsource, false );
180         }
181         catch ( KeyNotFoundException e )
182         {
183             log.info( "Invalid key requested: {}", resetPassword );
184             addActionError( getText( "cannot.find.key" ) );
185             return ERROR;
186         }
187         catch ( KeyManagerException e )
188         {
189             addActionError( getText( "cannot.find.key.at.the.moment" ) );
190             log.warn( "Key Manager error: ", e );
191             return ERROR;
192         }
193         catch ( UserNotFoundException e )
194         {
195             addActionError( getText( "cannot.find.user" ) );
196             return ERROR;
197         }
198     }
199
200     /**
201      * 1) sets up a token based authentication
202      * 2) forces a password change requirement to the user
203      * 3) passes on to webLogin()
204      *
205      * @return
206      */
207     public String validated()
208     {
209         if ( StringUtils.isEmpty( validateMe ) )
210         {
211             addActionError( getText( "validation.failure.key.missing" ) );
212             return ERROR;
213         }
214
215         try
216         {
217             AuthenticationKey authkey = securitySystem.getKeyManager().findKey( validateMe );
218
219             User user = securitySystem.getUserManager().findUser( authkey.getForPrincipal() );
220
221             user.setValidated( true );
222             user.setLocked( false );
223             user.setPasswordChangeRequired( true );
224             user.setEncodedPassword( "" );
225
226             TokenBasedAuthenticationDataSource authsource = new TokenBasedAuthenticationDataSource();
227             authsource.setPrincipal( user.getPrincipal().toString() );
228             authsource.setToken( authkey.getKey() );
229             authsource.setEnforcePasswordChange( false );
230
231             securitySystem.getUserManager().updateUser( user );
232             String currentUser = getCurrentUser();
233
234             AuditEvent event = new AuditEvent( getText( "log.account.validation" ) );
235             event.setAffectedUser( username );
236             event.setCurrentUser( currentUser );
237             event.log();
238
239             return webLogin( authsource, false );
240         }
241         catch ( KeyNotFoundException e )
242         {
243             log.info( "Invalid key requested: {}", validateMe );
244             addActionError( getText( "cannot.find.key" ) );
245             return ERROR;
246         }
247         catch ( KeyManagerException e )
248         {
249             addActionError( getText( "cannot.find.key.at.the.momment" ) );
250             return ERROR;
251         }
252         catch ( UserNotFoundException e )
253         {
254             addActionError( getText( "cannot.find.user" ) );
255             return ERROR;
256         }
257     }
258
259     public String cancel()
260     {
261         return CANCEL;
262     }
263
264     public String getUsername()
265     {
266         return username;
267     }
268
269     public void setUsername( String username )
270     {
271         this.username = username;
272     }
273
274     public String getPassword()
275     {
276         return password;
277     }
278
279     public void setPassword( String password )
280     {
281         this.password = password;
282     }
283
284     public String getValidateMe()
285     {
286         return validateMe;
287     }
288
289     public void setValidateMe( String validateMe )
290     {
291         this.validateMe = validateMe;
292     }
293
294     public SecureActionBundle initSecureActionBundle()
295         throws SecureActionException
296     {
297         return SecureActionBundle.OPEN;
298     }
299
300     public String getResetPassword()
301     {
302         return resetPassword;
303     }
304
305     public void setResetPassword( String resetPassword )
306     {
307         this.resetPassword = resetPassword;
308     }
309
310     public boolean isRememberMe()
311     {
312         return rememberMe;
313     }
314
315     public void setRememberMe( boolean rememberMe )
316     {
317         this.rememberMe = rememberMe;
318     }
319
320
321     /**
322      * 1) attempts to authentication based on the passed in data source
323      * 2) if successful sets cookies and returns LOGIN_SUCCESS
324      * 3) if failure then check what kinda failure and return error
325      *
326      * @param authdatasource
327      * @param rememberMe
328      * @return
329      */
330     private String webLogin( AuthenticationDataSource authdatasource, boolean rememberMe )
331     {
332         // An attempt should log out your authentication tokens first!
333         setAuthTokens( null );
334
335         clearErrorsAndMessages();
336
337         // TODO: share this section with AutoLoginInterceptor
338         try
339         {
340             SecuritySession securitySession = securitySystem.authenticate( authdatasource );
341
342             if ( securitySession.isAuthenticated() )
343             {
344                 // Success!  Create tokens.
345                 setAuthTokens( securitySession );
346
347                 if ( securitySystem.getPolicy().getUserValidationSettings().isEmailValidationRequired() )
348                 {
349                     if ( !securitySession.getUser().getUsername().equals(
350                         config.getString( "redback.default.admin" ) ) )
351                     {
352                         if ( !securitySession.getUser().isValidated() )
353                         {
354                             setAuthTokens( null );
355                             // NOTE: this text is the same as incorrect.username.password to avoid exposing actual account existence
356                             addActionError( getText( "account.validation.required" ) );
357                             return ERROR;
358                         }
359                     }
360                 }
361
362                 setCookies( authdatasource, rememberMe );
363
364                 AuditEvent event = new AuditEvent( getText( "log.login.success" ) );
365                 event.setAffectedUser( username );
366                 event.log();
367
368                 User user = securitySession.getUser();
369                 user.setLastLoginDate( new Date() );
370                 securitySystem.getUserManager().updateUser( user );
371
372                 if ( StringUtils.isNotEmpty( validateMe ) )
373                 {
374                     try
375                     {
376                         //REDBACK-146: delete key after validating so user won't be able to use it the second time around
377                         securitySystem.getKeyManager().deleteKey( validateMe );
378                     }
379                     catch ( KeyManagerException e )
380                     {
381                         addActionError( getText( "cannot.find.key.at.the.momment" ) );
382                         return ERROR;
383                     }
384                 }
385
386                 return LOGIN_SUCCESS;
387             }
388             else
389             {
390                 log.debug( "Login Action failed against principal : {}",
391                            securitySession.getAuthenticationResult().getPrincipal(),
392                            securitySession.getAuthenticationResult().getException() );
393
394                 AuthenticationResult result = securitySession.getAuthenticationResult();
395                 if ( result.getExceptionsMap() != null && !result.getExceptionsMap().isEmpty() )
396                 {
397                     if ( result.getExceptionsMap().get( AuthenticationConstants.AUTHN_NO_SUCH_USER ) != null )
398                     {
399                         addActionError( getText( "incorrect.username.password" ) );
400                     }
401                     else
402                     {
403                         addActionError( getText( "authentication.failed" ) );
404                     }
405                 }
406                 else
407                 {
408                     addActionError( getText( "authentication.failed" ) );
409                 }
410
411                 AuditEvent event = new AuditEvent( getText( "log.login.fail" ) );
412                 event.setAffectedUser( username );
413                 event.log();
414
415                 return ERROR;
416             }
417         }
418         catch ( AuthenticationException ae )
419         {
420             addActionError( getText( "authentication.exception", Arrays.asList( (Object) ae.getMessage() ) ) );
421             return ERROR;
422         }
423         catch ( UserNotFoundException ue )
424         {
425             addActionError(
426                 getText( "user.not.found.exception", Arrays.asList( (Object) username, ue.getMessage() ) ) );
427
428             AuditEvent event = new AuditEvent( getText( "log.login.fail" ) );
429             event.setAffectedUser( username );
430             event.log();
431             return ERROR;
432         }
433         catch ( AccountLockedException e )
434         {
435             addActionError( getText( "account.locked" ) );
436
437             AuditEvent event = new AuditEvent( getText( "log.login.fail.locked" ) );
438             event.setAffectedUser( username );
439             event.log();
440             return ACCOUNT_LOCKED;
441         }
442         catch ( MustChangePasswordException e )
443         {
444             // TODO: preferably we would not set the cookies for this "partial" login state
445             setCookies( authdatasource, rememberMe );
446
447             AuditEvent event = new AuditEvent( getText( "log.login.fail.locked" ) );
448             event.setAffectedUser( username );
449             event.log();
450             return PASSWORD_CHANGE;
451         }
452     }
453
454     private void setCookies( AuthenticationDataSource authdatasource, boolean rememberMe )
455     {
456         if ( rememberMe )
457         {
458             autologinCookies.setRememberMeCookie( authdatasource.getPrincipal(), ServletActionContext.getResponse(),
459                                                   ServletActionContext.getRequest() );
460         }
461         autologinCookies.setSignonCookie( authdatasource.getPrincipal(), ServletActionContext.getResponse(),
462                                           ServletActionContext.getRequest() );
463     }
464 }