View Javadoc

1   /* ===================================================================
2    * Copyright 2002-04 SRI International.
3    * Released under the MOZILLA PUBLIC LICENSE Version 1.1
4    * which can be obtained at http://www.mozilla.org/MPL/MPL-1.1.html
5    * This software is distributed on an "AS IS"
6    * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
7    * See the License for the specific language governing rights and
8    * limitations under the License.
9    * =================================================================== */
10  package com.sri.common.controller;
11  
12  import com.jcorporate.expresso.core.ExpressoConstants;
13  import com.jcorporate.expresso.core.controller.ControllerException;
14  import com.jcorporate.expresso.core.controller.ErrorCollection;
15  import com.jcorporate.expresso.core.controller.ExpressoRequest;
16  import com.jcorporate.expresso.core.controller.ExpressoResponse;
17  import com.jcorporate.expresso.core.controller.Input;
18  import com.jcorporate.expresso.core.controller.NonHandleableException;
19  import com.jcorporate.expresso.core.controller.Output;
20  import com.jcorporate.expresso.core.controller.ServletControllerRequest;
21  import com.jcorporate.expresso.core.controller.State;
22  import com.jcorporate.expresso.core.controller.Transition;
23  import com.jcorporate.expresso.core.controller.session.PersistentSession;
24  import com.jcorporate.expresso.core.db.DBException;
25  import com.jcorporate.expresso.core.misc.SerializableString;
26  import com.jcorporate.expresso.core.misc.StringUtil;
27  import com.jcorporate.expresso.core.registry.MutableRequestRegistry;
28  import com.jcorporate.expresso.core.registry.RequestRegistry;
29  import com.jcorporate.expresso.core.security.User;
30  import com.jcorporate.expresso.services.controller.EditUserPreference;
31  import com.jcorporate.expresso.services.controller.LoginController;
32  import com.jcorporate.expresso.services.controller.SimpleLoginController;
33  import com.jcorporate.expresso.services.dbobj.DefaultUserInfo;
34  import com.jcorporate.expresso.services.dbobj.UserGroup;
35  import com.jcorporate.expresso.services.dbobj.UserPreference;
36  import com.jcorporate.expresso.services.dbobj.UserPreferenceDef;
37  import com.jcorporate.expresso.services.validation.AuthValidationException;
38  import com.jcorporate.expresso.services.validation.ChangePasswordValidator;
39  import com.jcorporate.expresso.services.validation.ValidationEntry;
40  import com.sri.common.taglib.InputTag;
41  import com.sri.emo.EmoSchema;
42  
43  import javax.servlet.http.HttpServletRequest;
44  import javax.servlet.http.HttpServletResponse;
45  import java.util.Iterator;
46  import java.util.List;
47  
48  
49  /***
50   * Extension of Expresso's SimpleLoginController for EMO customization.
51   *
52   * @author Larry Hamel
53   */
54  public class LoginAction extends SimpleLoginController {
55      /***
56  	 * 
57  	 */
58  	private static final long serialVersionUID = 1L;
59  
60  	/***
61       * Constant for state prompt login.
62       */
63      public static final String PROMPT_LOGIN = "promptLogin";
64  
65      /***
66       * Constant for state do login.
67       */
68      public static final String DO_LOGIN = "doLogin";
69  
70      /***
71       * Constant for state do logout.
72       */
73      public static final String DO_LOGOUT = "doLogout";
74  
75      /***
76       * Constant for state send password.
77       */
78      public static final String PROMPT_SEND_PASSWORD = "promptSendPassword";
79  
80      /***
81       * Constant for state do send password.
82       */
83      public static final String DO_SEND_PASSWORD = "doSendPassword";
84  
85      /***
86       * Constant for state prompt change preferences.
87       */
88      public static final String PROMPT_CHANGE_PREFS = "promptChangePrefs";
89  
90      /***
91       * Constant for state change preferences.
92       */
93      public static final String DO_CHANGE_PREFS = "doChangePrefs";
94  
95      /***
96       * Constant for state prompt change password.
97       */
98      public static final String PROMPT_CHANGE_PASSWORD = "promptChangePassword";
99  
100     /***
101      * Constant for state do change password.
102      */
103     public static final String DO_CHANGE_PASSWORD = "doChangePassword";
104 
105     /***
106      * Constant for Input 'new password'.
107      */
108     public static final String NEW_PASSWORD = "NEW_PASSWORD";
109 
110     /***
111      * Constant for Input 'password verify'.
112      */
113     public static final String PASS_VERIFY = "PASS_VERIFY";
114 
115     /***
116      * Minimum password length constant.
117      */
118     public static final int MIN_PASSWD_LENGTH = 6;
119 
120     public LoginAction() {
121         // used for message internationalization
122         setSchema(EmoSchema.class.getName());
123         addState(new State(PROMPT_LOGIN, "Prompt Login"));
124         addState(new State(DO_LOGIN, "Login"));
125         addState(new State(DO_LOGOUT, "Logout"));
126         addState(new State(PROMPT_SEND_PASSWORD, "Prompt Send Password"));
127         addState(new State(DO_SEND_PASSWORD, "Reset & Send Password"));
128         addState(new State(PROMPT_CHANGE_PASSWORD, "Prompt to Change Password"));
129         addState(new State(PROMPT_CHANGE_PREFS, "Prompt to Change Prefs"));
130         addState(new State(DO_CHANGE_PREFS, "Change Prefs"));
131         addState(new State(DO_CHANGE_PASSWORD, "Change Password"));
132 
133         setInitialState(PROMPT_LOGIN);
134     }
135 
136     protected void runPromptLoginState(final ExpressoRequest request,
137                                        final ExpressoResponse response) throws ControllerException, DBException {
138         //System.out.println(thisClass + "runPromptLoginState()");
139 
140         // Fill in the Login field with values in following priority: form-cache, cookie
141         Input loginName = new Input();
142         loginName.setName("LoginName");
143 
144         String loginNameStr = null;
145 
146         try {
147             loginNameStr = StringUtil.notNull(response.getFormCache("LoginName"));
148         } catch (Exception e) {
149             // no problem if there is no form in cache
150             loginNameStr = "";
151         }
152 
153         if (loginNameStr.equals("")) {
154             loginNameStr = RequestRegistry.getUser().getLoginName();
155         }
156 
157         // leave blank if user hasn't logged in
158         if (loginNameStr.equals("NONE")) {
159             loginNameStr = "";
160         }
161 
162         loginName.setDefaultValue(loginNameStr);
163         loginName.setDisplayLength(15);
164         loginName.setMaxLength(30);
165         loginName.setLabel("Login");
166         response.addInput(loginName);
167 
168         // password in a field too
169         Input password = new Input();
170         password.setName("Password");
171         password.setLabel("Password");
172         password.setDisplayLength(15);
173         password.setMaxLength(30);
174         password.setType(InputTag.TYPE_PASSWORD);
175         response.addInput(password);
176 
177         // Fill in the Remember field
178         //        Input remember = new Input("Remember");
179         //        remember.setLabel("Remember Login");
180         //
181         //        String rm = response.getFormCache("Remember");
182         //
183         //        if (rm == null) {
184         //            rm = "Y";
185         //        }
186         //
187         //        remember.setType(InputTag.TYPE_CHECKBOX);
188         //        remember.setDefaultValue(rm);
189         //        response.addInput(remember);
190         // Remember Login checkbox
191         Input remember = new Input("Remember");
192         remember.setLabel("Remember Login");
193         remember.setName("Remember");
194         remember.setType(InputTag.TYPE_CHECKBOX);
195 
196         String rememberStr = "";
197 
198         try {
199             rememberStr = response.getFormCache("Remember");
200         } catch (Exception e) {
201             // no problem if there is no form in cache
202             if (getLogger().isDebugEnabled()) {
203                 getLogger().debug("No problem: Form is not in cache", e);
204             }
205         }
206 
207         if (rememberStr.length() == 0) { // default true
208             rememberStr = "Y";
209         }
210 
211         remember.addValidValue("Y", "");
212         remember.setDefaultValue(rememberStr);
213         response.addInput(remember);
214 
215         if (loginNameStr.equals("")) {
216             // see if there is a login name specified in the destination url
217             PersistentSession session = request.getSession();
218 
219             if (session != null) {
220                 SerializableString originalURL = (SerializableString) session.
221                         getPersistentAttribute(ExpressoConstants.CONTROLLER_ORIGINAL_URL_KEY);
222 
223                 if (originalURL != null) {
224                     String destination = originalURL.toString();
225                     System.out.println(destination);
226 
227                     // look for LoginName in this destination parameter
228                     int loginNameStart = destination.indexOf("LoginName");
229 
230                     if (loginNameStart != -1) {
231                         // get the login name
232                         loginNameStr = destination.substring(loginNameStart +
233                                 10);
234 
235                         int loginNameEnd = destination.indexOf("&");
236 
237                         if (loginNameEnd != -1) {
238                             loginNameStr = loginNameStr.substring(0,
239                                     loginNameEnd);
240                         }
241 
242                         loginName.setDefaultValue(loginNameStr);
243                     }
244                 }
245             }
246         }
247 
248         Transition login = new Transition(DO_LOGIN, this);
249         response.add(login);
250 
251         Transition promptSendPassword = new Transition(PROMPT_SEND_PASSWORD,
252                 this);
253         response.add(promptSendPassword);
254 
255         Transition editPref = new Transition();
256         editPref.setName("editPreferences");
257         editPref.addParam("controller", EditUserPreference.class.getName());
258         editPref.addParam("state", "edit");
259         response.add(editPref);
260     }
261 
262     /***
263      * Process a login request.
264      *
265      * @param request  the <code>ExpressoRequest</code> object.
266      * @param response the <code>ExpressoResponse</code> object.
267      * @throws ControllerException    upon error.
268      * @throws NonHandleableException upon fatal error.
269      */
270     protected void runDoLoginState(final ExpressoRequest request,
271                                    final ExpressoResponse response) throws ControllerException, NonHandleableException {
272         runProcessLoginState(request, response);
273     }
274 
275     /***
276      * Process a logout request.
277      *
278      * @param request  the <code>ExpressoRequest</code> object.
279      * @param response the <code>ExpressoResponse</code> object.
280      * @throws ControllerException    upon error.
281      * @throws NonHandleableException upon fatal error.
282      * @throws DBException            upon database object error.
283      */
284     protected void runDoLogoutState(final ExpressoRequest request,
285                                     final ExpressoResponse response) throws ControllerException,
286             NonHandleableException, DBException {
287         runProcessLogoutState(request, response);
288 
289         Transition login = new Transition(PROMPT_LOGIN, "", LoginAction.class,
290                 PROMPT_LOGIN);
291         login.redirectTransition(request, response); // redirect to get a new session; old one was invalidated
292     }
293 
294     /***
295      * Returns the title of this controller.
296      *
297      * @return java.lang.String
298      */
299     public String getTitle() {
300         return ("Login Action");
301     }
302 
303 
304     /***
305      * @param request  the <code>ExpressoRequest</code> object.
306      * @param response the <code>ExpressoResponse</code> object.
307      * @throws ControllerException upon error.
308      */
309     protected void runPromptSendPasswordState(final ExpressoRequest request,
310                                               final ExpressoResponse response) throws ControllerException {
311 
312         Input email = new Input();
313         email.setName("Email");
314         email.setLabel("EMail Address");
315 
316         try {
317             String emailValue = StringUtil.notNull(response.getFormCache("Email"));
318             email.setDefaultValue(emailValue);
319         } catch (Exception e) {
320             getLogger().debug("cannot get form cache");
321         }
322 
323         email.setDisplayLength(45);
324         email.setMaxLength(60);
325         response.addInput(email);
326 
327         Transition submit = new Transition(DO_SEND_PASSWORD, this);
328         response.add(submit);
329 
330         Transition pl = new Transition(PROMPT_LOGIN, this);
331         response.add(pl);
332     }
333 
334     /***
335      * @param request  the <code>ExpressoRequest</code> object.
336      * @param response the <code>ExpressoResponse</code> object.
337      * @throws ControllerException upon error.
338      */
339     protected void runPromptChangePasswordState(final ExpressoRequest request,
340                                                 final ExpressoResponse response) throws ControllerException {
341         Input oldPassword = new Input(DefaultUserInfo.PASSWORD, "Old password");
342         String opw = StringUtil.notNull(response.getFormCache(DefaultUserInfo.
343                 PASSWORD));
344         oldPassword.setDefaultValue(opw);
345         oldPassword.setDisplayLength(15);
346         oldPassword.setMaxLength(30);
347         oldPassword.setType(InputTag.TYPE_PASSWORD);
348         response.add(oldPassword);
349 
350         Input password = new Input(NEW_PASSWORD, "New Password");
351         String pw = StringUtil.notNull(response.getFormCache(NEW_PASSWORD));
352         password.setDefaultValue(pw);
353         password.setDisplayLength(15);
354         password.setMaxLength(30);
355         password.setType(InputTag.TYPE_PASSWORD);
356         response.add(password);
357 
358         Input password_verify = new Input(PASS_VERIFY, "Password (confirm)");
359         String pwv = StringUtil.notNull(response.getFormCache(PASS_VERIFY));
360         password_verify.setDefaultValue(pwv);
361         password_verify.setDisplayLength(15);
362         password_verify.setMaxLength(30);
363         password_verify.setType(InputTag.TYPE_PASSWORD);
364         response.add(password_verify);
365 
366         Transition submit = new Transition(DO_CHANGE_PASSWORD, this);
367         response.add(submit);
368     }
369 
370     /***
371      * @param request  the <code>ExpressoRequest</code> object.
372      * @param response the <code>ExpressoResponse</code> object.
373      * @throws ControllerException upon error.
374      */
375     protected void runPromptChangePrefsState(final ExpressoRequest request,
376                                              final ExpressoResponse response) throws ControllerException {
377         User user;
378 
379         try {        	
380             user = new User();
381             user.setUid(RequestRegistry.getUser().getUid());
382 
383             if (!user.find()) {
384                 throw new ControllerException("cannot find user for id: " +
385                 		RequestRegistry.getUser().getUid());
386             }
387 
388             String emailValue = StringUtil.notNull(response.getFormCache(DefaultUserInfo.EMAIL_ADDRESS));
389 
390             if (emailValue.length() == 0) {
391                 emailValue = user.getEmail();
392             }
393 
394             Input emailAddr = new Input(DefaultUserInfo.EMAIL_ADDRESS,
395                     "Email address");
396             emailAddr.setType(InputTag.TYPE_TEXT);
397             emailAddr.setDefaultValue(emailValue);
398             emailAddr.setDisplayLength(45);
399             emailAddr.setMaxLength(60);
400             response.add(emailAddr);
401 
402             String fullname = StringUtil.notNull(response.getFormCache(DefaultUserInfo.FULL_NAME));
403 
404             if (fullname.length() == 0) {
405                 fullname = user.getDisplayName();
406             }
407 
408             Input displayname = new Input(DefaultUserInfo.FULL_NAME, "Full name");
409             displayname.setType(InputTag.TYPE_TEXT);
410             displayname.setDefaultValue(fullname);
411             displayname.setDisplayLength(45);
412             displayname.setMaxLength(60);
413             response.add(displayname);
414 
415             Input primaryGroupMenu = new Input(UserGroup.GROUP_NAME_FIELD,
416                     "Primary Group");
417             response.add(primaryGroupMenu);
418             primaryGroupMenu.setType(InputTag.TYPE_DROPDOWN);
419 
420             List list = user.getGroupsList();
421             boolean foundSelected = false;
422             String primGroupName = user.getPrimaryGroup();
423 
424             for (Iterator iter = list.iterator(); iter.hasNext();) {
425                 String groupname = (String) iter.next();
426 
427                 // i don't know why everyone is member of unknownusers group, but filter that out
428                 if (!UserGroup.UNKNOWN_USERS_GROUP.equals(groupname)) {
429                     UserGroup group = UserGroup.getGroup(groupname);
430                     primaryGroupMenu.addValidValue(group.getGroupName(),
431                             group.getGroupDescription());
432 
433                     if (group.getGroupName().equals(primGroupName)) {
434                         foundSelected = true;
435                         primaryGroupMenu.setDefaultValue(primGroupName);
436                     }
437                 }
438             }
439 
440             if (!foundSelected && (list.size() > 0)) {
441                 primaryGroupMenu.setDefaultValue((String) list.get(0));
442             }
443 
444             Transition submit = new Transition(DO_CHANGE_PREFS, this);
445             response.add(submit);
446 
447             Transition pass = new Transition(PROMPT_CHANGE_PASSWORD, this);
448             response.add(pass);
449         } catch (DBException e) {
450             throw new ControllerException(e);
451         }
452     }
453 
454     /***
455      * @param request  the <code>ExpressoRequest</code> object.
456      * @param response the <code>ExpressoResponse</code> object.
457      * @throws ControllerException upon error.
458      */
459     protected void runDoChangePrefsState(final ExpressoRequest request,
460                                          final ExpressoResponse response) throws ControllerException {
461         User user;
462 
463         try {
464             String emailValue = request.getParameter(DefaultUserInfo.
465                     EMAIL_ADDRESS);
466 
467             if ((emailValue == null) || (emailValue.length() == 0)) {
468                 response.addError("email address is a required parameter");
469             }
470 
471             String fullname = request.getParameter(DefaultUserInfo.FULL_NAME);
472 
473             if ((fullname == null) || (fullname.length() == 0)) {
474                 response.addError("fullname is a required parameter");
475             }
476 
477             user = new User();
478             user.setUid(RequestRegistry.getUser().getUid());
479 
480             if (!user.find()) {
481                 throw new ControllerException("cannot find user for id: " +
482                 		RequestRegistry.getUser().getUid());
483             }
484 
485             boolean updateUser = false;
486 
487             if (!emailValue.equals(user.getEmail())) {
488                 user.setEmail(emailValue);
489                 updateUser = true;
490             }
491 
492             if (!fullname.equals(user.getDisplayName())) {
493                 user.setDisplayName(fullname);
494                 updateUser = true;
495             }
496 
497             if (updateUser) {
498                 user.update();
499             }
500 
501             String primgroupname = request.getParameter(UserGroup.
502                     GROUP_NAME_FIELD);
503             UserGroup group = UserGroup.getGroup(primgroupname);
504 
505             if (group != null) {
506                 UserPreference pref = new UserPreference();
507                 pref.setDataContext(user.getDBName());
508                 pref.setField(UserPreference.PREF_CODE,
509                         UserPreferenceDef.PRIMARY_GROUP_PREF);
510                 pref.setField(UserPreference.CLASS_NAME,
511                         UserPreferenceDef.ANY_CLASS);
512                 pref.setField(UserPreference.EXPUID, user.getUid());
513                 pref.setField(UserPreference.PREF_VALUE, primgroupname);
514                 pref.addOrUpdate();
515             }
516 
517             Output output = new Output(DefaultUserInfo.FULL_NAME,
518                     user.getDisplayName());
519             response.add(output);
520             output = new Output(DefaultUserInfo.EMAIL_ADDRESS, user.getEmail());
521             response.add(output);
522 
523             output = new Output(UserGroup.GROUP_NAME_FIELD,
524                     group.getGroupDescription());
525             response.add(output);
526         } catch (DBException e) {
527             throw new ControllerException(e);
528         }
529     }
530 
531     /***
532      * @param request  the <code>ExpressoRequest</code> object.
533      * @param response the <code>ExpressoResponse</code> object.
534      * @throws ControllerException upon error.
535      */
536     protected void runDoChangePasswordState(final ExpressoRequest request,
537                                             final ExpressoResponse response) throws ControllerException {
538         User user;
539 
540         try {
541             user = new User();
542             user.setUid(RequestRegistry.getUser().getUid());
543 
544             if (!user.find()) {
545                 throw new ControllerException("cannot find user for id: " +
546                 		RequestRegistry.getUser().getUid());
547             }
548 
549             String oldpass = request.getParameter(DefaultUserInfo.PASSWORD);
550 
551             if (!user.passwordEquals(oldpass)) {
552                 response.addError("Old password does not match.");
553                 transition(PROMPT_CHANGE_PASSWORD, request, response);
554             }
555 
556             String pass = getPassword(request, response);
557             ErrorCollection errors = response.getErrors();
558 
559             if ((errors != null) && (errors.size() > 0)) {
560                 transition(PROMPT_CHANGE_PASSWORD, request, response);
561 
562                 return;
563             }
564 
565             if (pass != null) {
566                 user.setPassword(pass);
567                 user.update();
568             }
569         } catch (DBException e) {
570             throw new ControllerException(e);
571         } catch (NonHandleableException e) {
572             throw new ControllerException(e);
573         }
574     }
575 
576     /***
577      * Send an email to the user with a URL to click to get their new password
578      *
579      * @param request  the <code>ExpressoRequest</code> object.
580      * @param response the <code>ExpressoResponse</code> object.
581      * @throws ControllerException    upon error.
582      * @throws NonHandleableException upon fatal error.
583      */
584     protected void runDoSendPasswordState(final ExpressoRequest request,
585                                           final ExpressoResponse response) throws ControllerException,
586             NonHandleableException {
587         // Debugging text
588         if (getLogger().isDebugEnabled()) {
589             getLogger().debug("Common: runDoSendPasswordState()");
590         }
591 
592         ErrorCollection errors = new ErrorCollection();
593 
594         // user supplies email address that we will match
595         String email = request.getParameter("Email");
596 
597         if (email.equals("")) {
598             errors.addError("Please specify email address");
599         }
600 
601         response.add(new Transition(PROMPT_LOGIN, this));
602 
603         try {
604             // find user that matches email account
605             User myUser = new User();
606             myUser.setDBName(request.getDataContext());
607             myUser.setEmail(email);
608 
609             if (!myUser.find()) {
610                 errors.addError("No user found with this email");
611             }
612 
613             String loginName = myUser.getLoginName();
614 
615             if (errors.getErrorCount() <= 0 && !myUser.getAccountStatus().equals("A")) {
616                 // need active account
617                 getLogger().warn("User \"" + loginName +
618                         "\" attempted password reset, denied because account status is \"" +
619                         myUser.getAccountStatus() + "\"");
620                 errors.addError("Account matching this email is disabled, cannot send password now");
621             }
622 
623             // if any errors, go back to page and prompt user again for email
624             if (errors.getErrorCount() > 0) {
625                 response.saveErrors(errors);
626                 response.setFormCache();
627                 transition(PROMPT_SEND_PASSWORD, request, response);
628             } else {
629                 // mark user as having submitted a password request and send email
630                 myUser.setEmailValCode(myUser.getEmailAuthCode());
631                 myUser.update();
632 
633                 ServletControllerRequest sparams = (ServletControllerRequest)
634                         request;
635                 HttpServletRequest hreq = (HttpServletRequest) sparams.
636                         getServletRequest();
637 
638                 try {
639                     ValidationEntry ve = new ValidationEntry(request.
640                             getDataContext());
641                     ve.setValidationHandler(ChangePasswordValidator.class.
642                             getName());
643                     ve.setTitle("Change Password Validation");
644                     ve.setDesc("user=" + loginName + ", db=" +
645                             request.getDataContext());
646                     ve.setServer(hreq.getServerName());
647 
648                     ve.setPort(Integer.toString(hreq.getServerPort()));
649                     ve.setContextPath(hreq.getContextPath());
650                     ve.addParam("db", request.getDataContext());
651                     ve.addParam("UserName", loginName);
652                     ve.addParam("LoginController", getClass().getName());
653                     ve.submit();
654                 } catch (AuthValidationException avex) {
655                     throw new ControllerException("Validation framework problem",
656                             avex);
657                 }
658 
659                 // add the email address to the output for display
660                 // in the message telling the user their request has been accepted
661                 response.add(new Output("Email", email));
662             }
663         } catch (Exception dbe) {
664             throw new ControllerException(dbe);
665         }
666     }
667 
668     /***
669      * override to remove dep. on registration
670      * <p/>
671      * Logs a user out of the system and invalidates their session.
672      *
673      * @param request  The framework controller request
674      * @param response The framework ExpressoResponse object
675      * @throws ControllerException upon logic error
676      * @throws DBException         upon database object error.
677      */
678     protected void runProcessLogoutState(final ExpressoRequest request,
679                                          final ExpressoResponse response) throws ControllerException, DBException {
680         PersistentSession session = request.getSession();
681         String loginName = RequestRegistry.getUser().getLoginName();
682         String successMessage = loginName + " has been logged out";
683 
684         if (loginName.equals("")) {
685             successMessage = "You were not logged in anyway!";
686         }
687 
688         if (request instanceof ServletControllerRequest) {
689             ServletControllerRequest sreq = (ServletControllerRequest) request;
690             LoginController.setCookie(null, null,
691                     (HttpServletResponse) sreq.getServletResponse(), true,
692                     request.getDataContext());
693         }
694 
695         Output successOutput = new Output();
696         successOutput.setName("sucessMessage");
697         successOutput.setContent(successMessage);
698         response.add(successOutput);
699 
700         new MutableRequestRegistry(RequestRegistry.getDataContext(), User.getUserFromLogin(User.UNKNOWN_USER));
701 
702         Transition pl = new Transition("promptLogin", this);
703         pl.addParam("dbContext", request.getDataContext());
704         response.add(pl);
705 
706         session.setClientAttribute("UserName", "");
707         session.setClientAttribute("Password", "");
708         session.setClientAttribute("dbContext", "");
709         session.removePersistentAttribute("CurrentLogin");
710         session.invalidate();
711     }
712 
713     /***
714      * Retrieves a password from the request and error-checks it. Returns
715      * null if an invalid password is found. Does NOT trim the password.
716      *
717      * @param request  the <code>ExpressoRequest</code> object.
718      * @param response the <code>ExpressoResponse</code> object.
719      * @return The password
720      * @throws ControllerException    upon error.
721      * @throws NonHandleableException upon fatal error.
722      * @throws DBException            upon database access error
723      */
724     protected String getPassword(final ExpressoRequest request,
725                                  final ExpressoResponse response) throws ControllerException, DBException,
726             NonHandleableException {
727         // make sure password was specified and confirmation matches
728         String password = request.getParameter(NEW_PASSWORD);
729         String passwordConfirm = request.getParameter(PASS_VERIFY);
730 
731         if ((password == null) || (password.length() == 0)) {
732             response.addError("Please specify a non-blank password");
733             response.setFormCache();
734             password = null;
735         } else if (!password.equals(passwordConfirm)) {
736             response.addError("Password did not match the confirmation password");
737             response.setFormCache();
738             password = null;
739         } else if (password.length() < MIN_PASSWD_LENGTH) {
740             response.addError("Password must be at least " + MIN_PASSWD_LENGTH +
741                     " characters");
742             response.setFormCache();
743             password = null;
744         } else if (password.length() > DefaultUserInfo.PASSWORD_LENGTH) {
745             response.addError("Password must be no more than " +
746                     DefaultUserInfo.PASSWORD_LENGTH + " characters");
747             response.setFormCache();
748             password = null;
749         }
750 
751         return password;
752     }
753 
754     /***
755      * Override the normal stateAllowed method to always allow
756      * access to this controller for certain states - otherwise no-one can ever log in :-)
757      *
758      * @param newState the state to transition to.
759      * @param request  The controllerRequest object
760      * @return true if the state is allowed for the currently logged in user.
761      * @throws ControllerException if there is an error while looking up the sercurity permissions
762      */
763     public boolean stateAllowed(final String newState, final ExpressoRequest request)
764             throws ControllerException {
765         try {
766             if (newState.equals(PROMPT_CHANGE_PASSWORD) || newState.equals(PROMPT_CHANGE_PREFS)) {
767                 // must be logged in as normal user ( not as "guest") for these methods
768                 String username = RequestRegistry.getUser().getLoginName();
769 
770                 return !(username.equals(User.UNKNOWN_USER) || username.equals("guest"));
771 
772                 // must return early -- superclass would allow these methods to anyone
773             }
774 
775             if (newState.equals(PROMPT_CHANGE_PASSWORD) || newState.equals(PROMPT_CHANGE_PREFS)) {
776                 // must be logged in as normal user ( not as "guest") for these methods
777                 String username = RequestRegistry.getUser().getLoginName();
778 
779                 return !(username.equals(User.UNKNOWN_USER) || username.equals("guest"));
780 
781                 // must return early -- superclass would allow these methods to anyone
782             }
783 
784             return super.stateAllowed(newState, request);
785         } catch (DBException ex) {
786             throw new ControllerException("Error querying User object", ex);
787         }
788     }
789 }