package org.ngbw.web.actions; import edu.sdsc.globusauth.util.OauthConstants; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.sql.SQLException; import java.util.Calendar; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; import org.apache.log4j.Logger; import org.apache.struts2.ServletActionContext; import org.ngbw.sdk.UserAuthenticationException; import org.ngbw.sdk.Workbench; import org.ngbw.sdk.WorkbenchSession; import org.ngbw.sdk.clients.Client; import org.ngbw.sdk.common.util.StringUtils; import org.ngbw.sdk.common.util.ValidationResult; import org.ngbw.sdk.database.TomcatSessionService; import org.ngbw.sdk.database.User; import org.ngbw.sdk.foldershare.ProvisionCipresShareUser; import org.ngbw.sdk.phoenix.CipresPhoenixUserAccountManager; import org.ngbw.sdk.tool.CipresNotifier; import org.ngbw.web.controllers.SessionController; /** * Struts action class to process all session-related requests in the NGBW * web application. * * @author Jeremy Carver * @author Tony Chen */ @SuppressWarnings("serial") public class SessionManager extends NgbwSupport { private static final Logger logger = Logger.getLogger(SessionManager.class); // navigation constants public static final String TAB = "tab"; public static final String SHIB_HEADERS = "shibHeaders"; // parameter attribute key constants public static final String USER = "user"; public static final String CODE = "code"; // default password for automatic reset public static final String DEFAULT_PASSWORD = "changeme"; public static final String GLOBUS_TRANSFER="globusTransfer"; public static final String SEP = "^"; // controller private SessionController controller; // registration form properties private String username; private String newPassword = null; private String confirmNewPassword = null; private String firstName; private String lastName; private String email; private String confirmEmail; private String institution; private String country; private String account; // login form properties private String currentPassword; private int updatingPassword = 0; /** * There are a number of different ways that a user can be "effectively" logged in. For example, * by explicitly logging in, logging in via iplant, registering, or responding to a password * change confirmation email. In all cases, this method will be called once the user's * credentials have been validated. In some cases (eg. registration) this may be called more * than once - I'm not sure. * @return */ public boolean finalizeLogin () { // Store the WorkbenchSession object in the http session. try { WorkbenchSession wbSession = getController().getWorkbenchSession(); if (wbSession == null) { throw new Exception("WorkbenchSession is null."); } HttpServletRequest req = ServletActionContext.getRequest(); String userAgent = req.getHeader(NgbwSupport.USER_AGENT); wbSession.setSessionAttribute(NgbwSupport.USER_AGENT, userAgent); setWorkbenchSession(getController().getWorkbenchSession()); refreshCurrentFolder(); User user = getController().getAuthenticatedUser(); if (StringUtils.isNullOrEmpty(user.getCountry(), true) || !Workbench.getInstance().isValidCountryCode(user.getCountry())) { final String countryCode = Workbench.getInstance().getCountryCodeFromIP(super.getClientIp()); if (null == countryCode) { CipresNotifier.emailSysAdmin( "User Country Code Error", String.format( "User [%d, %s]\n\n" + "Unable to find country code of IP %s.", user.getUserId(), user.getUsername(), super.getClientIp()), false); } else if (!Workbench.getInstance().isValidCountryCode(countryCode)) { CipresNotifier.emailSysAdmin( "User Country Code Error", String.format( "User [%d, %s]\n\n" + "Return country code of IP %s is %s which could not be found in db.", user.getUserId(), user.getUsername(), super.getClientIp(), countryCode), false); } else { user.setCountry(countryCode); } } if (StringUtils.hasHtml4Chars(user.getFirstName())) { user.setFirstName(StringUtils.unescapeHtml4(user.getFirstName())); } if (StringUtils.hasHtml4Chars(user.getLastName())) { user.setLastName(StringUtils.unescapeHtml4(user.getLastName())); } if (StringUtils.hasHtml4Chars(user.getInstitution())) { user.setInstitution(StringUtils.unescapeHtml4(user.getInstitution())); } if (userAgent != null && !userAgent.isEmpty()) { String currentComment = user.getComment(); String newComment = getComment(userAgent); if (currentComment == null || currentComment.isEmpty() || !currentComment.contains(newComment)) { user.setComment(getFullNewComment(currentComment, newComment)); } } user.setLastLogin(Calendar.getInstance().getTime()); user.save(); checkUserDataSize(user); } catch ( Throwable e ) { logger.error(reportUserError(e, "Internal Error completing the login process.")); return false; } // addActionMessage( // String.format( // "User \"%s\" successfully logged in.", // getController().getAuthenticatedUsername())); return true; } public String register () throws NoSuchAlgorithmException { logger.trace("BEGIN: register()::String"); // validate user input - if passed, attempt to register new user if (validateUserRegistrationInputs()) { try { if (User.findUser(getUsername().trim(), getEmail().trim(), false, true) != null) { addActionError("Sorry, either the username or email you choose already exists in our database."); return INPUT; } else if (Workbench.getInstance().hasInvalidChars(getNewPassword(), false)) { super.addActionError( "Your password contains one or more unsupported characters. " + "Supported characters are " + NgbwSupport.ALPHANUMERIC_MSG + " and " + NgbwSupport.SPECIAL_CHARS_MSG); return INPUT; } } catch (Exception ex) { logger.error(ex); } HttpServletRequest req = ServletActionContext.getRequest(); String userAgent = req.getHeader(NgbwSupport.USER_AGENT); String comment = null; if (userAgent != null && !userAgent.isEmpty()) comment = getComment(userAgent); logger.info("register() comment = " + comment); ValidationResult result = getController() .registerUser( getUsername(), getNewPassword(), getEmail(), getFirstName(), getLastName(), getInstitution(), getCountry(), comment, super.getHttpSession()); logger.debug( String.format( "New user registered; user=[%s - %s]", getUsername(), getEmail())); if (result == null) { addActionError("Sorry, there was an error creating your account."); return INPUT; } else if (!result.isValid()) { logger.error(reportUserError("Sorry, there was an error creating your account:")); for (String error : result.getErrors()) { logger.error(reportUserError(error)); } if (result.getWarnings()!= null ) { for (String warning : result.getWarnings()) { sendEmailFromAdmin2(NgbwSupport.EMAIL_SENDER2, "Attempt to create multiple accounts", warning); } } return INPUT; } else { try { User user = getController().getAuthenticatedUser(); String activationCode = Client.makeActivationCode(getUsername()); user.setActivation(activationCode); user.save(); sendActivationEmail(user, activationCode); //sendWelcomeEmail(user); addActionMessage( String.format( "Your account \"%s\" has been created successfully. " + "We have sent an email to %s. Please open it to activate your account.\n" + "If you don't receive the activation email within 15 minutes, please check your email " + "'Spam' folder first. If you don't see it under your Spam folder, please contact " + "cipresadmin@sdsc.edu for help.", getUsername().trim(), getEmail())); // Call 'CIPRES Share' new user provision endpoint. try { final Response response = ProvisionCipresShareUser.provision(user); } catch ( Throwable t ) { logger.error(t.getMessage(), t); } } catch (Exception ex) { logger.error(reportUserError("Error saving activation code for " + getUsername())); logger.error(ex); } logout(); } } else { logger.warn("Register Form validation failed."); } logger.trace("END: register()::String"); return INPUT; } /** * @deprecated * @return */ public String guestLogin () { logger.debug("BEGIN: guestLogin()::String"); // Tony: // As of Dec. 1st, 2018, we no longer allow guest account. // String retval = INPUT; addActionError("Sorry, guest accounts are not allowed anymore."); // // Register guest user // SessionController cntrller = getController(); // ValidationResult result = cntrller.registerGuestUser(); // // if (result == null) // { // addActionError("Sorry, there was an error logging in as a guest."); // retval = INPUT; // } // else if (!result.isValid()) // { // logger.error(reportUserError("Sorry, there was an error logging in as a guest:")); // // for (String error : result.getErrors()) // { // logger.error(reportUserError(error)); // } // // retval = INPUT; // } // else // { // addActionMessage("Guest user \"" + cntrller.getAuthenticatedUsername() + "\" successfully logged in."); // // setSessionAttribute(TAB, "home"); // // if (finalizeLogin()) // { // retval = SUCCESS; // } // } logger.debug("END: guestLogin()::String"); return retval; } private String cyverseToCipresLogin ( User user, String cyverseUsername ) { logger.trace("BEGIN: cyverseToCipresLogin(User, String)::String"); WorkbenchSession session = null; String retVal = INPUT; try { session = getController().loginWithCyVerseCredential( user.getUsername(), cyverseUsername, super.getHttpSession()); if (session == null) { logger.error(reportUserError("There was an error authenticating your information.")); retVal = INPUT; } if (finalizeLogin()) { retVal = SUCCESS; } } catch ( UserAuthenticationException error ) { logger.error(reportUserError(error.getMessage())); retVal = INPUT; } logger.trace(String.format("RetVal=[%s]", retVal)); logger.trace("END: cyverseToCipresLogin(User, String)::String"); return retVal; } public String login () { logger.trace("BEGIN: login()::String"); String retval = INPUT; // This just means that the user entered a username and password, not that they're valid. if (validateLoginInputs()) { // getUsername() may return either username or email address // because users are allowed to log in with their username or email. String usernameOrEmail = getUsername(); logger.debug(String.format("User attemps to login with username/email=[%s]", usernameOrEmail)); try { if (!StringUtils.isNullOrEmpty(usernameOrEmail, true)) { // Username can contain char '@', // find the user account with 'username' or 'email' User user = User.findUser(usernameOrEmail.trim(), usernameOrEmail.trim(), true, true); if (user == null) { if (null == User.findUser(usernameOrEmail.trim(), usernameOrEmail.trim(), false, true)) { logger.error(reportUserError("There was an error authenticating your information.")); } else { logger.error( reportUserError( "Before your first login, please activate your account through the activation " + "email which was sent to you right after your registration.\nIf you never " + "receive the activation email, please contact cipresadmin@sdsc.edu for help.")); } retval = INPUT; } else { WorkbenchSession wbSession = getController().login( user.getUsername(), getCurrentPassword(), super.getHttpSession()); // If it is still null, throw an error. if (wbSession == null) { logger.error(reportUserError("There was an error authenticating your information.")); retval = INPUT; } else { clearSessionAttribute(SESSION_ERROR_MESSAGE); if (finalizeLogin()) { // Clean up other sessions info of the user. TomcatSessionService.deleteSessions(user); // After login is successful, populate/update record in 'tomcat_sessions' table. TomcatSessionService.persistSession(super.getHttpSession(), user); response.addCookie(buildUserNameCookie(user)); if (Workbench.getInstance().hasInvalidChars(getCurrentPassword(), false)) { logger.error("Password contains one or more unsupported chars!"); addActionError( "Your password contains one or more unsupported characters. " + "Supported characters are " + NgbwSupport.ALPHANUMERIC_MSG + " and " + NgbwSupport.SPECIAL_CHARS_MSG); addActionError("Please update your password."); logger.debug("Setting " + NgbwSupport.REQ_PASSWORD_CHANGE + " into the HttpSession ..."); wbSession.setSessionAttribute(NgbwSupport.REQ_PASSWORD_CHANGE, Boolean.TRUE); final Object obj = wbSession.getSessionAttribute(NgbwSupport.REQ_PASSWORD_CHANGE); logger.debug( String.format( "Attribute [%s] added to HttpSession with value=[%s].", NgbwSupport.REQ_PASSWORD_CHANGE, (null == obj? "???" : ((Boolean) obj).toString()))); retval = "updatePassword"; } else { if (Workbench.getInstance().isPhoenixApiModuleEnabled(Boolean.FALSE)) { try { // Sync with Phoenix Bioinformatics if necessary. CipresPhoenixUserAccountManager syncManager = new CipresPhoenixUserAccountManager( user, getCurrentPassword()); syncManager.sync(Boolean.FALSE); } catch ( Throwable t ) { logger.error(t.getMessage(), t); } } retval = SUCCESS; wbSession.clearSessionAttribute(NgbwSupport.REQ_PASSWORD_CHANGE); } } } } } else { logger.error(reportUserError("There was an error authenticating your information.")); retval = INPUT; } } catch ( IOException | SQLException exp ) { logger.error("Error authenticating user \"" + getUsername() + "\"", exp); logger.error(reportUserError("There was an error authenticating your information.")); retval = INPUT; } catch ( UserAuthenticationException error ) { logger.error(reportUserError(error.getMessage())); retval = INPUT; } } logger.trace("END: login()::String"); return retval; } /** * We only get there when there is an error on One Time Coordination or the * user bails out of it. * * @return */ public String getMeOutOfHere () { logger.trace("In getMeOutOfHere"); String retval = logout(); /* * if (retval.equals(IPLANT_LOGOUT)) { return "localLogout"; } */ return retval; } public String logout () { logger.trace("BEGIN: logout()::String"); if (request != null && request.getParameter("finallogout") == null) { if (getSession().get(OauthConstants.IS_AUTHENTICATED)==null || ((boolean)getSession().get(OauthConstants.IS_AUTHENTICATED) == false)) { logger.info("User is not logged in to Globus"); } else { logger.info("User is logged in to Globus"); return GLOBUS_TRANSFER; } } String retVal = SUCCESS; try { removeIplantCookies(); clearSessionAttribute(SHIB_HEADERS); String isIplantUser = (String) getSessionAttribute(IPLANT_USER); if (isIplantUser != null) { retVal = SUCCESS; // IPLANT_LOGOUT; //logger.debug("iPlant user logged out successfully."); } //logger.debug("Calling SessionController.logout() ..."); getController().logout(); //logger.debug("Calling SessionController.logout() ... done."); if (super.getHttpSession() != null) { //logger.debug("Calling invalidateSession() ..."); invalidateSession(); //logger.debug("Calling invalidateSession() ... done."); //logger.debug("Invalidating the HttpSession ..."); super.getHttpSession().invalidate(); //logger.debug("HttpSession invalided!"); } } catch ( Throwable e ) { logger.error(e.getMessage(), e); retVal = SUCCESS; } this.removeAllCookies(); logger.trace("END: logout()::String"); return retVal; } // This is CAS specific. private void removeIplantCookies () { logger.trace("BEGIN: removeIplantCookies()::void"); Cookie[] cookies = this.request.getCookies(); if (cookies != null) for (Cookie cookie : cookies) { if (cookie.getName().equalsIgnoreCase("MOD_AUTH_CAS")) { logger.debug("Have cookie MOD_AUTH_CAS, deleting it in response. "); cookie.setMaxAge(0); response.addCookie(cookie); } if (cookie.getName().equalsIgnoreCase("MOD_AUTH_CAS_S")) { logger.debug("Have cookie MOD_AUTH_CAS_S, deleting it in response. "); cookie.setMaxAge(0); response.addCookie(cookie); } } logger.trace("END: removeIplantCookies()::void"); } public String sendPasswordReset () throws Throwable { String usernameOrEmail = getUsername(); if (null != usernameOrEmail && !usernameOrEmail.trim().isEmpty()) { // The 'username' can be actual username or email address. usernameOrEmail = usernameOrEmail.trim(); User user = (usernameOrEmail.contains("@"))? User.findUserByEmail(usernameOrEmail) : User.findUser(usernameOrEmail); if (null == user) { String username = usernameOrEmail; String email = usernameOrEmail; if (usernameOrEmail.contains("@")) username = null; else email = null; user = User.findUser ( username, email, false, false ); if (null == user) addActionError("No registered user was found."); else addActionError( String.format( "Account associated with %s hasn't been activated yet. " + "We have sent an email to you after registration. Please open it to activate your account.\n" + "If you don't receive the activation email, please check your email " + "'Spam' folder first. If you still don't see it under your Spam folder, please contact " + "cipresadmin@sdsc.edu for help.", usernameOrEmail)); return INPUT; } else if (sendPasswordResetEmail(user)) { reportUserMessage("Password reset confirmation email successfully sent."); setUsername(null); setEmail(null); return SUCCESS; } else { addActionError("There was an error sending the password reset confirmation email."); return SUCCESS; } } else { addActionError("You must enter either your registered username or email address."); return INPUT; } } // I think we get here when user clicks on the link in the password // reset email we sent him. If he isn't already logged in, this effectively // logs him in. public String activateAccount () { logger.trace("BEGIN: activeAccount()::String"); try { String username = getRequestParameter(USER); String code = getRequestParameter(CODE); if (StringUtils.isNullOrEmpty(username, true) || StringUtils.isNullOrEmpty(code, true)) { logger.error("user/code is missing from the request."); return INPUT; } //SessionController controller = getController(); User user = User.findUser(username, null, false, true); if (null == user) { logger.error("No registered user was found with that username: " + username); return INPUT; } else if (null == user.getActivationCode()) { return SUCCESS; } else if (user.getActivationCode().equals(code)) { user.setActivationCode(null); user.save(); return SUCCESS; } } catch ( Exception ex ) { logger.error("There was an error activating account: " + username); logger.error(ex); } logger.trace("END: activeAccount()::String"); return INPUT; } public String confirmPasswordReset () throws Throwable { final SessionController sessCntrller = getController(); final String username = getRequestParameter(USER); final String encryptedPassword = getRequestParameter(CODE); User user = User.findUser(username); if (null == username) { addActionError("You must provide your username to reset your password."); return INPUT; } else if (null == user) { addActionError("No registered user was found with that username."); return INPUT; } else if (null == encryptedPassword || !encryptedPassword.equals(user.getPassword())) { addActionError("You must provide the correct confirmation code to reset your password."); return INPUT; } else if (!sessCntrller.changePassword(username, DEFAULT_PASSWORD)) { logger.error("Failed to change the user's, " + user.getUsername() + ",' password to DEFAULT_PASSWORD."); addActionError("There was an error updating your password."); return INPUT; } WorkbenchSession session = null; try { user = User.findUser(user.getUserId()); session = sessCntrller.getActiveSession(username, user.getPassword()); } catch ( IOException | SQLException | UserAuthenticationException error ) { logger.error("Unable to retrieve active session for user " + user.getUsername()); logger.error(error.getMessage(), error); addActionError("There was an error updating your password."); return INPUT; } if (session == null) { try { session = sessCntrller.login(username, DEFAULT_PASSWORD, super.getHttpSession()); } catch ( UserAuthenticationException error ) { logger.error("Unable to login the user " + user.getUsername()); logger.error(error.getMessage(), error); addActionError("There was an error updating your password."); return INPUT; } } if (session == null) { addActionError("There was an error updating your password."); return INPUT; } reportUserMessage("Your password was successfully reset."); if (finalizeLogin()) { return SUCCESS; } return INPUT; } public SessionController getController () { if (controller == null) { WorkbenchSession session = getWorkbenchSession(); controller = (session == null)? new SessionController() : new SessionController(session); } return controller; } public String getUsername () { return username; } public void setUsername ( String username ) { this.username = username; } public String getCurrentPassword () { return currentPassword; } public void setCurrentPassword ( String currentPassword ) { this.currentPassword = currentPassword; } public String getNewPassword () { return newPassword; } public void setNewPassword ( String newPassword ) { this.newPassword = newPassword; } public String getConfirmNewPassword () { return confirmNewPassword; } public void setConfirmNewPassword ( String confirmNewPassword ) { this.confirmNewPassword = confirmNewPassword; } public String getFirstName () { return firstName; } public void setFirstName ( String firstName ) { this.firstName = firstName; } public String getLastName () { return lastName; } public void setLastName ( String lastName ) { this.lastName = lastName; } public String getEmail () { return email; } public void setEmail ( String email ) { this.email = email; } public String getConfirmEmail () { return confirmEmail; } public void setConfirmEmail ( String confirmEmail ) { this.confirmEmail = confirmEmail; } public String getInstitution () { return institution; } public void setInstitution ( String institution ) { this.institution = institution; } public String getCountry () { return country; } public void setCountry ( String country ) { this.country = country; } public String getAccount () { return account; } public void setAccount ( String account ) { if (account == null || account.trim().equals("")) { this.account = null; return; } this.account = account; } /** * Function will check user data size and if it exceeds max, will set user preference, unless * user preference is already set to OVERRIDE. If not over max, will clear user preference. Also * if exceed warning or max size, will display respective warning message. @param User * @param user */ protected void checkUserDataSize ( User user ) { if (user == null) { logger.error("Invalid arguments received in checkUserDataSize(User)."); return; } long userDataSize = user.getDataSize(); SessionController controller = getController(); String delete = StringUtils.getDataSizeForDisplay(userDataSize - DATA_SIZE_MAX); String max = StringUtils.getDataSizeForDisplay(DATA_SIZE_MAX); if (userDataSize >= DATA_SIZE_MAX) { String user_preference = controller.getUserPreference(User.DATA_SIZE_EXCEEDS_MAX); if (user_preference != null && user_preference.equals("OVERRIDE")) { logger.error(reportUserError( "Warning, your current total storage size exceeds our maximum limit of " + max + ". However, you have been given a TEMPORARY override to continue job submission. Please deleted at least " + delete + " as soon as you can.")); } else { controller.setUserPreference(User.DATA_SIZE_EXCEEDS_MAX, "TRUE"); logger.error(reportUserError( "Warning, your current total storage size exceeds our maximum limit of " + max + ". You will not be allowed to submit more jobs until you have deleted more than " + delete + ".")); } } else { controller.clearUserPreference(User.DATA_SIZE_EXCEEDS_MAX); if (userDataSize >= DATA_SIZE_WARN) { logger.error(reportUserError( "Warning, you are getting close to our maximum storage size of " + max + ".")); } } return; } /** * Function will re-query user data size from the database and if it exceeds max, will set user * preference, unless preference is already set to OVERRIDE. If not over max, will clear user * preference. Also if exceed max size, will display warning message. @param User * @param user */ protected void refreshUserDataSize ( User user ) { if (user == null) { logger.error("Invalid arguments received in refreshUserDataSize(Uesr)"); return; } long userDataSize = 0; try { userDataSize = user.queryDataSize(); } catch ( Exception e ) { } SessionController controller = getController(); String delete = StringUtils.getDataSizeForDisplay(userDataSize - DATA_SIZE_MAX); String max = StringUtils.getDataSizeForDisplay(DATA_SIZE_MAX); if (userDataSize >= DATA_SIZE_MAX) { String user_preference = controller.getUserPreference(User.DATA_SIZE_EXCEEDS_MAX); if (user_preference != null && user_preference.equals("OVERRIDE")) { logger.error(reportUserError( "Warning, your current total storage size exceeds our maximum limit of " + max + ". However, you have been given a TEMPORARY override to continue job submission. Please deleted at least " + delete + " as soon as you can.")); } else { String[] tmp = delete.split("\\s"); controller.setUserPreference(User.DATA_SIZE_EXCEEDS_MAX, "TRUE"); logger.error(reportUserError( "You need to delete " + tmp[0] + " more " + tmp[1] + " to be below our maximum storage limit.")); } } else { controller.clearUserPreference(User.DATA_SIZE_EXCEEDS_MAX); } return; } protected boolean validateLoginInputs () { if (getUsername() == null || getUsername().trim().isEmpty()) { addFieldError("username", "Username is required."); logger.error("SessionManager.validateLogin(): username is null"); } if (getCurrentPassword() == null || getCurrentPassword().trim().isEmpty()) { addFieldError("currentPassword", "Password is required."); logger.error("SessionManager.validateLogin(): password is null"); } return !hasFieldErrors(); } protected boolean validateUserRegistrationInputs () { String input = null; logger.trace("Checking username ..."); input = StringUtils.unescapeHtml4(getUsername()); setUsername(input); if (StringUtils.isNullOrEmpty(input, true)) { logger.error("Username is required."); addFieldError("username", "Username is required."); } else if (input.length() < StringUtils.MIN_USERNAME_LENGTH || input.length() > StringUtils.MAX_USERNAME_LENGTH) { logger.error( String.format( "Username must be %d - %d characters long.", StringUtils.MIN_USERNAME_LENGTH, StringUtils.MAX_USERNAME_LENGTH)); addFieldError( "username", String.format( "Username must be %d - %d characters long.", StringUtils.MIN_USERNAME_LENGTH, StringUtils.MAX_USERNAME_LENGTH)); } else if (Workbench.getInstance().hasInvalidChars(input, false)) { addFieldError( "username", "Username format is incorrect. Username can only contain letters, " + "numbers, underscores, and hyphens. Other characters are not allowed."); } else if (!StringUtils.hasPattern(input, StringUtils.USERNAME_PATTERN)) // check the pattern { addFieldError( "username", "Username format is incorrect. Username can only contain letters, " + "numbers, underscores, and hyphens. Other characters are not allowed."); } logger.trace("Checking password ..."); input = StringUtils.unescapeHtml4(getNewPassword()); setNewPassword(input); if (StringUtils.isNullOrEmpty(input, true)) { addFieldError("newPassword", "Password is required."); } else if (input.length() < StringUtils.MIN_PASSWORD_LENGTH) { addFieldError( "newPassword", String.format( "Password must be %d characters or longer.", StringUtils.MIN_PASSWORD_LENGTH)); } else if (Workbench.getInstance().hasInvalidChars(input, false)) { addFieldError( "newPassword", "Password contains one or more unsupported characters. " + "Supported characters are " + NgbwSupport.ALPHANUMERIC_MSG + " and " + NgbwSupport.SPECIAL_CHARS_MSG); } else if (!StringUtils.hasPattern(input, StringUtils.PASSWORD_PATTERN)) { addFieldError( "newPassword", "Password format is incorrect. Password must contain at least one lower case letter, " + "one upper case letter, one number, and one special character."); } else if (StringUtils.isNullOrEmpty(getConfirmNewPassword(), true)) { addFieldError("confirmNewPassword", "Confirm (retype) the password."); } else if (!getNewPassword().equals(getConfirmNewPassword())) { addFieldError( "confirmNewPassword", "Sorry, two passwords you entered are not identical. Please try again."); } // final String SUPPORTED_CHARS_MSG = // //"The %s contains one or more unsupported characters. " + // "Supported characters are alphanumeric (A-Z, a-z, 0-9) and " + // "special characters - and '"; logger.trace("Checking Firstname ..."); input = StringUtils.unescapeHtml4(getFirstName()); setFirstName(input); if (StringUtils.isNullOrEmpty(input, true)) { addFieldError("firstName", "First name is required."); } else if (Workbench.getInstance().hasInvalidLetters(input, true)) { addFieldError( "firstName", "First name contains one or more unsupported characters. " + "Supported characters are " + NgbwSupport.LETTERS_MSG ); } logger.trace("Checking Lastname ..."); input = StringUtils.unescapeHtml4(getLastName()); setLastName(input); if (StringUtils.isNullOrEmpty(input, true)) { addFieldError("lastName", "Last name is required."); } else if (Workbench.getInstance().hasInvalidLetters(input, true)) { addFieldError( "lastName", "Last name contains one or more unsupported characters. " + "Supported characters are " + NgbwSupport.LETTERS_MSG ); } logger.trace("Checking Email ..."); input = StringUtils.unescapeHtml4(getEmail()); setEmail(input); if (StringUtils.isNullOrEmpty(input, true)) { addFieldError("email", "Email is required."); } else if (StringUtils.isNullOrEmpty(getConfirmEmail(), true)) { addFieldError("confirmEmail", "Confirm (retype) the email address."); } else if (!input.equals(getConfirmEmail())) { addFieldError("confirmEmail", "Sorry, the two email addresses you entered are not identical. Please try again."); } else if (!input.contains("@")) { addFieldError("email", "Sorry, the email address you entered is invalid"); } else { String strArr[] = input.trim().split("@"); if (strArr.length < 2) { addFieldError("email", "Sorry, the email address you entered is invalid"); } } logger.trace("Checking Institution ..."); input = StringUtils.unescapeHtml4(getInstitution()); setInstitution(input); if (StringUtils.isNullOrEmpty(input, true) || (input.length()< 4)) { addFieldError("institution", "Institution is required and the length should be at least 4 characters."); } else if (Workbench.getInstance().hasInvalidLettersWithSpecialChars(input, true)) { addFieldError( "institution", "Institution name contains one or more unsupported characters. " + "Supported characters are " + NgbwSupport.LETTERS_MSG + " and " + NgbwSupport.LIMIT_SPECIAL_CHARS_MSG); } // Get the country from IP address. logger.trace("Checking Country ..."); /* String countryCode = null; try { countryCode = Workbench.getInstance().getCountryCodeFromIP(super.getClientIp()); } catch ( Throwable t ) { countryCode = null; logger.error(t.getMessage(), t); } if (null == countryCode) { addFieldError("country", "Country is required."); } else if (!Workbench.getInstance().isValidCountryCode(countryCode)) { addFieldError("country", "Invalid Country: " + countryCode); } else { setCountry(countryCode); }*/ if (null == getCountry()) { final String countryCode = Workbench.getInstance() .getCountryCodeFromIP(super.getClientIp()); if (null == countryCode || countryCode.trim().isEmpty()) { addFieldError("country", "Sorry, please select your country " + "from the Country list below."); // Add the flag "countryCodeManualInput" to the Session with value "1". super.addCountryCodeManualInputRequirement(); } else if (!Workbench.getInstance().isValidCountryCode(countryCode)) { addFieldError("country", "The country you entered, " + countryCode + "' is invalid."); // Add the flag "countryCodeManualInput" to the Session with value "1". super.addCountryCodeManualInputRequirement(); } else { setCountry(countryCode.trim()); // Remove the flag "countryCodeManualInput" in the Session. super.removeCountryCodeManualInputRequirement(); } } else { // Remove the flag "countryCodeManualInput" in the Session. super.removeCountryCodeManualInputRequirement(); } return !hasFieldErrors(); } private boolean sendPasswordResetEmail ( final User user ) { String subject = "CIPRES Science Gateway Password Reset Confirmation"; String body = "A request was recently received to reset the password for your " + "registered account '" + user.getUsername().trim() + "' on the CIPRES Science Gateway." + "

" + "To confirm that you wish to reset your password for " + "this account, please click on the link at the bottom of this email. Your " + "password will NOT be reset unless you click the link below." + "

" + "By clicking this link, you authorize CIPRES to reset your password to " + "\"" + DEFAULT_PASSWORD + "\"." + "You will then be able to log into your account with this temporary password, " + "and from there you can change your password to your own one. " + "When you try to change to a new password, you will be prompted for your old password. " + "Enter \"" + DEFAULT_PASSWORD + "\" for your " + "old password." + "

"; // return sendEmailWithUserAndCode( // Workbench.getInstance().getEmailReplyAddress(), // user, // user.getPassword().trim(), // subject, // body, // "resetPassword.action", // true); return sendEmailWithUserAndCode( Workbench.getInstance().getEmailReplyAddress(), user, user.getPassword().trim(), subject, body, "resetPassword.action", true); //return sendActivationEmail(user, user.getPassword().trim()); } private boolean sendActivationEmail ( final User user, final String code ) { String subject = "CIPRES Science Gateway Account Activation"; String body = "Dear " + user.getUsername().trim() + ":\n\n" + "Please click the link at the bottom of this email to activate your CIPRES account.\n\n" + "Thank you!\n\n"; return sendEmailWithUserAndCode( NgbwSupport.EMAIL_SENDER2, user, code, subject, body, "activateAccount.action", false); } private boolean sendWelcomeEmail ( final User user ) { String subject = "Welcome to CIPRES Science Gateway"; String body = "Dear CIPRES User " + user.getUsername().trim() + ",

" + "Thank you for creating a new CIPRES account. Your registration provides a free six month trial of CIPRES, with 1,000 hours of compute time and 150 GB of storage on the NSF-funded Expanse supercomputer at UC San Diego. Each CIPRES code is benchmarked to run efficiently for your data set, for maximum impact of your compute time. " + "Additional compute time can be purchased at our web site.

" + "If you need help getting started, please visit our help page. Each code has an information page with example data sets and results files, so you can try out individual codes. We also have a Google Group for timely help and advice. Please let us know if you encounter any issues in using your account.

" + "Sincerely,

" + "Mark Miller


CIPRES Project Lead

\"\""; return CipresNotifier.emailUser(NgbwSupport.EMAIL_SENDER2, user, subject, body, true); } private boolean sendEmailWithUserAndCode ( final String senderEmail, final User user, final String code, final String subject, final String body, final String action, final boolean htmlContent ) { if (null == user || StringUtils.isNullOrEmpty(code, true)) { logger.error("Error sending password reset email: One or more arguments were null or empty."); return false; } else { // Modified by Tony C. // HTTP protocol should not be hardcoded. Either HTTP or HTTPS is determined from // HttpServletRequest.isSecure() method. //+ "http://" + request.getServerName() + "/" + portalAppName + "/resetPassword.action?user=" + username //+ "&code=" + code; HttpServletRequest req = ServletActionContext.getRequest(); int port = req.getServerPort(); String url = (req.isSecure())? "https://" : "http://"; url += req.getServerName(); // include the port if it is a non-conventional one such as 8080 or 8443. url += (port != 80 && port != 443)? (":" + port) : ""; url += req.getContextPath() + "/" + action; url += "?user=" + user.getUsername().trim() + "&code=" + code; if (htmlContent) { url = String.format("%s", url, url); } // append it to the main body. String emailBody = body + url; return CipresNotifier.emailUser(senderEmail, user, subject, emailBody, htmlContent); } } protected void removeAllCookies () { Cookie[] cookies = super.getServletRequest().getCookies(); logger.info(String.format("removeAllCookies: length of Cookie array is: [%d]", cookies == null? 0:cookies.length)); if (null != cookies && cookies.length > 0) { for (Cookie cookie : cookies) { cookie.setValue(""); cookie.setPath("/"); cookie.setMaxAge(0); super.getServletResponse().addCookie(cookie); } } } private String getComment(String userAgent) { return (super.getClientIp() + "|" + userAgent + SEP); } private String getFullNewComment(String currentComment, String newComment) { int itemSize = 5; if (currentComment == null || currentComment.isEmpty()) return newComment; String[] crs = currentComment.split("\\"+SEP); if (crs != null) { for (String s : crs) logger.info("getFullNewComment = " + s); } if (crs != null && crs.length < itemSize) return (currentComment + newComment); else if (crs != null && crs.length >= itemSize) { StringBuffer sb = new StringBuffer(); for (int i = 1; i < crs.length; ++i) { sb.append(crs[i]); sb.append(SEP); } sb.append(newComment); return sb.toString(); } return newComment; } private Cookie buildUserNameCookie ( User user ) { Cookie cookie = new Cookie("CIPRES_LOGGED_IN_USER_NAME", user.getUsername()); cookie.setPath("/"); cookie.setSecure(Boolean.FALSE); return cookie; } public boolean isUpdatingPassword () { return (updatingPassword == 1); } public int getUpdatingPassword () { return updatingPassword; } public void setUpdatingPassword ( int value ) { this.updatingPassword = value; logger.debug(String.format("'updatingPassword set to [%d]", updatingPassword)); } }