package se.idega.idegaweb.commune.account.citizen.presentation; import java.rmi.RemoteException; import java.util.Calendar; import javax.ejb.CreateException; import javax.ejb.FinderException; import se.idega.idegaweb.commune.account.citizen.business.CitizenAccountBusiness; import se.idega.idegaweb.commune.presentation.CommuneBlock; import se.idega.util.PIDChecker; import com.idega.business.IBOLookup; import com.idega.core.accesscontrol.business.LoginDBHandler; import com.idega.core.accesscontrol.data.LoginRecord; import com.idega.core.accesscontrol.data.LoginRecordHome; import com.idega.core.accesscontrol.data.LoginTable; import com.idega.core.builder.data.ICPage; import com.idega.idegaweb.IWResourceBundle; import com.idega.presentation.IWContext; import com.idega.presentation.Table; import com.idega.presentation.text.Break; import com.idega.presentation.text.Link; import com.idega.presentation.text.Text; import com.idega.presentation.ui.Form; import com.idega.presentation.ui.SubmitButton; import com.idega.presentation.ui.TextInput; import com.idega.user.data.User; import com.idega.util.LocaleUtil; import com.idega.util.text.SocialSecurityNumber; /** * * * * Title: idegaWeb * Description: This class handles the case, when a user has forgotten his password. * The presentation provides a single input field for the personal id. * After submitting the input is checked. * If the inputfield is empty a warning dialog pops up. * If the input represents an impossible social security number (SSN) * an error message is returned (with the inputfield again). If the input is a * possible valid ssn the value is checked if this ssn can be found in the table * of already known citizen in the database. * If the ssn is unknown a link to the citizen application form is returned. * If the ssn is known it is checked if the citizen has already activated his account. * If the citizen has not an activated account yet again a link to to the citizen * application form is returned. * There are two different cases if the citizen has already an activated account: * If the user has never logged in you can not trust his registered email address. * Therefore a new password is generated and send by regular post * to the person. * If the the user has logged at some time a new password is generated and send by email. * * Copyright: Copyright (c) 2002 * Company: idega software * @author <a href="mailto:thomas@idega.is">Thomas Hilbig</a> * @version 1.0 */ public class CitizenAccountForgottenPassword extends CommuneBlock { private final static String SSN_KEY = "caf_ssn"; private final static String SSN_DEFAULT = "Personnummer"; private final static String PASSWORD_CREATED_KEY = "cafp_password_was_created"; private final static String PASSWORD_CREATED_DEFAULT = "A new password was generated."; private final static String LETTER_SENT_KEY = "cafp_letter_was_sent"; private final static String LETTER_SENT_DEFAULT = "A letter containing the new password is sent to you."; private final static String EMAIL_SENT_KEY = "cafp_email_was_sent"; private final static String EMAIL_SENT_DEFAULT = "An email containing the new password is sent to you."; private final static String ACCOUNT_APPLICATION_KEY = "cafp_go_to_citizen_account"; private final static String ACCOUNT_APPLICATION_DEFAULT = "You have not applied for a citizen account yet."; private final static String ACCOUNT_APPLICATION_LINK_KEY = "cafp_link_to_citizen_account_application"; private final static String ACCOUNT_APPLICATION_LINK_DEFAULT = "Apply for a citizen account!"; private final static String FORMAT_ERROR_KEY = "caa_format_error"; private final static String FORMAT_ERROR_DEFAULT = "Felaktigt inmatat v�rde"; private final static String FORM_SUBMIT_KEY = "cafp_form_submit_key"; private final static String FORM_SUBMIT_DEFAULT = "Forgot my password"; private final static String ERROR_FIELD_CAN_NOT_BE_EMPTY_DEFAULT = "F�ltet m�ste fyllas i"; private final static String ERROR_FIELD_CAN_NOT_BE_EMPTY_KEY = "caf_field_can_not_be_empty"; private final static String ACTION_VIEW_FORM = "action_view_form"; private final static String ACTION_FORM_SUBMIT = "action_form_submit"; /** The color of all messages shown. */ private final static String COLOR_RED = "#ff0000"; /** Contains the page where the user can apply for a new account. */ private ICPage citizenAccountApplicationPage; /** Used when an e-mail should always be sent and never a letter (unless user has no e-mail) */ private boolean alwaysSendEmail = false; private static final String hasAppliedForPsw = "has_applied_before"; /** Sets the page where a user can apply for a new account. * @param citizenAccountApplicationPage the page where the user can apply for a new account. */ public void setCitizenAccountApplicationPage(ICPage citizenAccountApplicationPage) { this.citizenAccountApplicationPage = citizenAccountApplicationPage; } public void main(final IWContext iwc) { setResourceBundle(getResourceBundle(iwc)); String action = parseAction(iwc); if (ACTION_VIEW_FORM.equals(action)) viewForm(iwc); else if (ACTION_FORM_SUBMIT.equals(action)) { submitForm(iwc); viewForm(iwc); } } /** * Handles the input. Checks if the input is a possible valid ssn and if the * user is known or unknown. * @param iwc */ private void submitForm(IWContext iwc) { String ssn = getSsn(SSN_KEY, iwc); // in does not represent a possible ssn number if (ssn == null) { // set error text and show input field again IWResourceBundle bundle = getResourceBundle(); String displayName = bundle.getLocalizedString(SSN_KEY, SSN_DEFAULT); String formatErrorString = bundle.getLocalizedString( FORMAT_ERROR_KEY , FORMAT_ERROR_DEFAULT); viewError(formatErrorString + ": " + displayName, iwc); return; } try { final CitizenAccountBusiness business = (CitizenAccountBusiness) IBOLookup.getServiceInstance(iwc, CitizenAccountBusiness.class); final User user = business.getUser(ssn, iwc.getApplicationSettings().getDefaultLocale()); if (user == null) // user unknown show link to "Citizen account application" viewCitizienAccountApplication(); else { // user is known handleKnownUser(user, iwc); } } catch (Exception ex) { viewError(ex.getMessage(),iwc); } } /** * Builds a presentation containing the link to the citizen application page. */ private void viewCitizienAccountApplication() { IWResourceBundle bundle = getResourceBundle(); Text text = new Text(bundle.getLocalizedString(ACCOUNT_APPLICATION_KEY,ACCOUNT_APPLICATION_DEFAULT),true, false, false); Text linkText = new Text(bundle.getLocalizedString(ACCOUNT_APPLICATION_LINK_KEY,ACCOUNT_APPLICATION_LINK_DEFAULT),true, false, false); text.setFontColor(COLOR_RED); add(text); add(Text.getBreak()); Link link = new Link(linkText); if (citizenAccountApplicationPage != null) link.setPage(citizenAccountApplicationPage); add(link); } /** * Handles the case if the user is a known user with or without an activated account. * @param user the known user. * @param iwc * @throws RemoteException * @throws CreateException */ private void handleKnownUser(User user, IWContext iwc) throws RemoteException, CreateException { if(iwc.getSessionAttribute(hasAppliedForPsw) != null) { add(getErrorText(localize("cafp_already_applied_for_password", "You have already asked for a new password!"))); add(new Break(2)); } else { int userID = ((Integer)user.getPrimaryKey()).intValue(); LoginTable loginTable = LoginDBHandler.getUserLogin(userID); if (loginTable == null) { viewCitizienAccountApplication(); return; } IWResourceBundle bundle = getResourceBundle(); // check if user has ever logged in int loginID = ((Integer)loginTable.getPrimaryKey()).intValue(); boolean lastLoginRecordWasFound; try { ((LoginRecordHome) com.idega.data.IDOLookup.getHomeLegacy(LoginRecord.class)).findByLoginID(loginID); // last login was found lastLoginRecordWasFound = true; } catch (FinderException ex) { // last login record was not found lastLoginRecordWasFound = false; } if (alwaysSendEmail) { lastLoginRecordWasFound = true; } String message; // different messages are returned depending on the result // if the user has ever logged in if (lastLoginRecordWasFound) { // email is sent handleKnownUserLoggedIn(loginTable, user, iwc); message = bundle.getLocalizedString(EMAIL_SENT_KEY, EMAIL_SENT_DEFAULT); } else { // letter is sent handleKnownUserNeverLoggedIn(loginTable, user, iwc); message = bundle.getLocalizedString(LETTER_SENT_KEY, LETTER_SENT_DEFAULT); } String password = bundle.getLocalizedString(PASSWORD_CREATED_KEY, PASSWORD_CREATED_DEFAULT); if (getParentPage() != null) { getParentPage().setAlertOnLoad(password); } else { Text textPassword = new Text(password, true, false, false); Text textMessage = new Text(message ,true, false, false); textPassword.setFontColor(COLOR_RED); textMessage.setFontColor(COLOR_RED); add(textPassword); add(Text.getBreak()); add(textMessage); } iwc.setSessionAttribute(hasAppliedForPsw, Boolean.TRUE.toString()); } } /** * Handles known user, that has logged in at some time. * Creates new password, stores it and send it by an email to the user. * @param loginTable login of the user * @param user user * @throws RemoteException * @throws CreateException */ private void handleKnownUserLoggedIn(LoginTable loginTable, User user, IWContext iwc) throws RemoteException, CreateException { String newPassword = createNewPassword(); CitizenAccountBusiness business = getBusiness(iwc); business.changePasswordAndSendLetterOrEmail(iwc,loginTable, user,newPassword, false); } /** * Handles known user, that has never logged in. * Creates new password, stores it and send it by a letter to the user. * @param loginTable * @param user * @param iwc * @throws RemoteException * @throws CreateException */ private void handleKnownUserNeverLoggedIn(LoginTable loginTable, User user, IWContext iwc) throws RemoteException, CreateException { // send a letter with the new password // create new password String newPassword = createNewPassword(); CitizenAccountBusiness business = getBusiness(iwc); business.changePasswordAndSendLetterOrEmail(iwc,loginTable, user,newPassword, true); } /** * Builds a presentation containing the form with input field and submit button. * @param iwc */ private void viewForm(final IWContext iwc) { final Table table = createTable(); addSimpleInputs(table, iwc); table.setHeight(table.getRows() + 1, 12); SubmitButton button = getSubmitButton(FORM_SUBMIT_KEY + "_button", FORM_SUBMIT_DEFAULT); table.add(button, 1, table.getRows() + 1); table.add(Text.getNonBrakingSpace(), 1, table.getRows()); table.add(getHelpButton("registration_help_key"), 1, table.getRows()); final Form accountForm = new Form(); accountForm.addParameter(FORM_SUBMIT_KEY, Boolean.TRUE.toString()); accountForm.add(table); accountForm.setToDisableOnSubmit(button, true); add(accountForm); } /** * Gets submit button. * @param submitId * @param defaultText * @return SubmitButton */ private SubmitButton getSubmitButton(final String submitId, final String defaultText) { return (SubmitButton) getButton(new SubmitButton(submitId, localize(submitId, defaultText))); } /** * Puts an input field for the social security number into the specified table. * @param table * @param iwc */ private void addSimpleInputs(Table table, IWContext iwc) { Text header = getSmallHeader(localize(SSN_KEY, SSN_DEFAULT)); table.add(header, 1, 1); table.add(getSingleInput(SSN_KEY, 12, true, iwc), 3, 1); } /** * Gets input field for the social security number. * @param iwc * @param paramID * @param maxLength * @param notEmpty * @return the input field */ private TextInput getSingleInput (final String paramId, final int maxLength, boolean notEmpty, IWContext iwc) { TextInput textInput = (TextInput) getStyledInterface (new TextInput(paramId)); textInput.setMaxlength(maxLength); if (notEmpty) { final String fieldCanNotBeEmpty = localize (ERROR_FIELD_CAN_NOT_BE_EMPTY_KEY, ERROR_FIELD_CAN_NOT_BE_EMPTY_DEFAULT); final String name = localize(paramId, paramId); textInput.setAsNotEmpty(fieldCanNotBeEmpty + ": " + name); } String param = iwc.getParameter(paramId); if (param != null) { textInput.setContent(param); } return textInput; } /** * Creates table. * @return the table */ private Table createTable() { final Table table = new Table(); table.setCellspacing(getCellpadding()); table.setCellpadding(0); table.setWidth(2, "12"); return table; } /** * Parses the parameter string. * @param iwc * @return either string for action "view form" * or string for action "form was submitted". */ private String parseAction(final IWContext iwc) { String action = ACTION_VIEW_FORM; if (iwc.isParameterSet(FORM_SUBMIT_KEY)) action = ACTION_FORM_SUBMIT; return action; } /** Builds a presentation containing an error message and the inputfield * @param errorMessage the message to be shown. * @param iwc */ private void viewError(String errorMessage, IWContext iwc) { final Text text = new Text(errorMessage, true, false, false); text.setFontColor(COLOR_RED); add(text); add(Text.getBreak()); viewForm(iwc); } /** * Gets social security number. Checks if the parameter * that corresponds to the specified key represents a possible * social security number. Returns the number without any non * digit characters. Returns null if the parameter does not represent * a possible social security number. This method does not check if the * social security number is a real existing one. * This method does not use any database access. * @param iwc * @param key the key of the social security number parameter. * @return a digit string representing a (possible) social security number else null. */ private String getSsn( final String key, final IWContext iwc) { final String rawInput = iwc.getParameter(key); if (rawInput == null) { return null; } final StringBuffer digitOnlyInput = new StringBuffer(); for (int i = 0; i < rawInput.length(); i++) { if (Character.isDigit(rawInput.charAt(i))) { digitOnlyInput.append(rawInput.charAt(i)); } } if (iwc.getApplicationSettings().getDefaultLocale().equals(LocaleUtil.getSwedishLocale())) { final Calendar rightNow = Calendar.getInstance(); final int currentYear = rightNow.get(Calendar.YEAR); if (digitOnlyInput.length() == 10) { final int inputYear = new Integer(digitOnlyInput.substring(0, 2)).intValue(); final int century = inputYear + 2000 > currentYear ? 19 : 20; digitOnlyInput.insert(0, century); } final PIDChecker pidChecker = PIDChecker.getInstance (); if (digitOnlyInput.length() != 12 || !pidChecker.isValid (digitOnlyInput.toString ())) { return null; } final int year = new Integer(digitOnlyInput.substring(0, 4)).intValue(); final int month = new Integer(digitOnlyInput.substring(4, 6)).intValue(); final int day = new Integer(digitOnlyInput.substring(6, 8)).intValue(); if (year < 1880 || year > currentYear || month < 1 || month > 12 || day < 1 || day > 31) { return null; } return digitOnlyInput.toString(); } else if (iwc.getApplicationSettings().getDefaultLocale().equals(LocaleUtil.getIcelandicLocale())) { if (SocialSecurityNumber.isValidIcelandicSocialSecurityNumber(digitOnlyInput.toString())) { return digitOnlyInput.toString(); } } return null; } /** * Looks up service bean citizen account business * @param iwc * @return a service bean CitizenAccountBusiness. */ private CitizenAccountBusiness getBusiness(IWContext iwc) throws RemoteException { return (CitizenAccountBusiness) IBOLookup.getServiceInstance(iwc, CitizenAccountBusiness.class); } /** * Creates a new unencrypted password. * @return an unencrypted password. */ private String createNewPassword() { return LoginDBHandler.getGeneratedPasswordForUser(); } /** * @param alwaysSendEmail The alwaysSendEmail to set. */ public void setAlwaysSendEmail(boolean alwaysSendEmail) { this.alwaysSendEmail = alwaysSendEmail; } /*private MessageSession getMessageSession(IWContext iwc) throws Exception { return (MessageSession) com.idega.business.IBOLookup.getSessionInstance(iwc, MessageSession.class); }*/ }