Java tutorial
/** * $Id: MainProducer.java 105078 2012-02-24 23:00:38Z ottenhoff@longsight.com $ * $URL: https://source.sakaiproject.org/svn/reset-pass/trunk/account-validator-tool/src/java/org/sakaiproject/accountvalidator/tool/producers/MainProducer.java $ * DeveloperHelperService.java - entity-broker - Apr 13, 2008 5:42:38 PM - azeckoski ************************************************************************** * Copyright (c) 2008, 2009 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sakaiproject.accountvalidator.tool.producers; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.joda.time.Period; import org.joda.time.format.PeriodFormat; import org.joda.time.format.PeriodFormatter; import org.sakaiproject.accountvalidator.model.ValidationAccount; import org.sakaiproject.entitybroker.EntityReference; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserNotDefinedException; import uk.org.ponder.localeutil.LocaleGetter; import uk.org.ponder.messageutil.TargettedMessage; import uk.org.ponder.rsf.components.*; import uk.org.ponder.rsf.flow.ActionResultInterceptor; import uk.org.ponder.rsf.view.ComponentChecker; import uk.org.ponder.rsf.view.ViewComponentProducer; import uk.org.ponder.rsf.viewstate.ViewParameters; import java.util.Locale; /** * Produces passwordReset.html - builds a form containing nothing more than the a password and confirm password field * @author bbailla2 */ public class PasswordResetProducer extends BaseValidationProducer implements ViewComponentProducer, ActionResultInterceptor { private static Log log = LogFactory.getLog(PasswordResetProducer.class); public static final String VIEW_ID = "passwordReset"; private static final String MAX_PASSWORD_RESET_MINUTES = "accountValidator.maxPasswordResetMinutes"; private static LocaleGetter localeGetter; public void setLocaleGetter(LocaleGetter localeGetter) { this.localeGetter = localeGetter; } private Locale getLocale() { return localeGetter.get(); } public String getViewID() { return VIEW_ID; } public void init() { } public void fillComponents(UIContainer tofill, ViewParameters viewparams, ComponentChecker checker) { Object[] args = new Object[] { serverConfigurationService.getString("ui.service", "Sakai") }; UIMessage.make(tofill, "welcome1", "validate.welcome1.reset", args); ValidationAccount va = getValidationAccount(viewparams, tml); if (va == null) { //handled by getValidationAccount return; } else if (!va.getAccountStatus().equals(ValidationAccount.ACCOUNT_STATUS_PASSWORD_RESET)) { //this is not a password reset args = new Object[] { va.getValidationToken() }; //no such validation of the required account status tml.addMessage(new TargettedMessage("msg.noSuchValidation", args, TargettedMessage.SEVERITY_ERROR)); return; } else if (ValidationAccount.STATUS_CONFIRMED.equals(va.getStatus())) { args = new Object[] { va.getValidationToken() }; tml.addMessage(new TargettedMessage("msg.alreadyValidated", args, TargettedMessage.SEVERITY_ERROR)); addResetPassLink(tofill, va); return; } else if (ValidationAccount.STATUS_EXPIRED.equals(va.getStatus())) { /* * If accountValidator.maxPasswordResetMinutes is configured, * we give them an approrpiate message, otherwise we give them the default */ TargettedMessage message = getExpirationMessage(); if (message == null) { //give them the default args = new Object[] { va.getValidationToken() }; tml.addMessage( new TargettedMessage("msg.expiredValidation", args, TargettedMessage.SEVERITY_ERROR)); addResetPassLink(tofill, va); } else { tml.addMessage(message); } return; } else if (sendLegacyLinksEnabled()) { redirectToLegacyLink(tofill, va); return; } else { /* * Password resets should go quickly. If it takes longer than accountValidator.maxPasswordResetMinutes, * it could be an intruder who stumbled on an old validation token. */ //Only do this check if accountValidator.maxPasswordResetMinutes is configured correctly String strMinutes = serverConfigurationService.getString(MAX_PASSWORD_RESET_MINUTES); if (strMinutes != null && !"".equals(strMinutes)) { if (va.getAccountStatus() != null) { try { //get the time limit and convert to millis long maxMillis = Long.parseLong(strMinutes); maxMillis *= 60 * 1000; //the time when the validation token was sent to the email server long sentTime = va.getValidationSent().getTime(); if (System.currentTimeMillis() - sentTime > maxMillis) { //it's been too long, so invalide the token and stop the user va.setStatus(ValidationAccount.STATUS_EXPIRED); //get a nice expiration meesage TargettedMessage expirationMessage = getExpirationMessage(); if (expirationMessage == null) { //should never happen args = new Object[] { va.getValidationToken() }; tml.addMessage(new TargettedMessage("msg.expiredValidation", args, TargettedMessage.SEVERITY_ERROR)); return; } tml.addMessage(expirationMessage); addResetPassLink(tofill, va); return; } } catch (NumberFormatException nfe) { log.error("accountValidator.maxPasswordResetMinutes is not configured correctly"); } } } } User u = null; try { u = userDirectoryService.getUser(EntityReference.getIdFromRef(va.getUserId())); } catch (UserNotDefinedException e) { } if (u == null) { log.error("user ID does not exist for ValidationAccount with tokenId: " + va.getValidationToken()); tml.addMessage(new TargettedMessage("validate.userNotDefined", new Object[] {}, TargettedMessage.SEVERITY_ERROR)); return; } String resetMinutes = serverConfigurationService.getString(MAX_PASSWORD_RESET_MINUTES); if (resetMinutes != null && !"".equals(resetMinutes)) { try { int minutes = Integer.parseInt(resetMinutes); UIMessage.make(tofill, "welcome2", "validate.expirationtime", new Object[] { getFormattedMinutes(minutes) }); } catch (NumberFormatException nfe) { log.error("accountValidator.maxPasswordResetMinutes is not configured correctly"); } } //the form UIForm detailsForm = UIForm.make(tofill, "setDetailsForm"); UICommand.make(detailsForm, "addDetailsSub", UIMessage.make("submit.new.reset"), "accountValidationLocator.validateAccount"); String otp = "accountValidationLocator." + va.getId(); UIMessage.make(detailsForm, "username.new", "username.new.reset", args); UIOutput.make(detailsForm, "eid", u.getDisplayId()); boolean passwordPolicyEnabled = (userDirectoryService.getPasswordPolicy() != null); String passwordPolicyEnabledJavaScript = "VALIDATOR.isPasswordPolicyEnabled = " + Boolean.toString(passwordPolicyEnabled) + ";"; UIVerbatim.make(tofill, "passwordPolicyEnabled", passwordPolicyEnabledJavaScript); UIBranchContainer row1 = UIBranchContainer.make(detailsForm, "passrow1:"); UIInput.make(row1, "password1", otp + ".password"); UIBranchContainer row2 = UIBranchContainer.make(detailsForm, "passrow2:"); UIInput.make(row2, "password2", otp + ".password2"); detailsForm.parameters.add(new UIELBinding(otp + ".userId", va.getUserId())); } /** * Converts some number of minutes into a presentable String' * ie for English: * 122 minutes -> 2 hours 2 minutes * 121 minutes -> 2 hours 1 minute * 120 minutes -> 2 hours * 62 minutes -> 1 hour 2 minutes * 61 minutes -> 1 hour 1 minute * 60 minutes -> 1 hour * 2 minutes -> 2 minutes * 1 minutes -> 1 minute * 0 minutes -> 0 minutes * Works with other languages too. * @param totalMinutes some number of minutes * @return a presentable String representation of totalMinutes */ public String getFormattedMinutes(int totalMinutes) { // Create a joda time period (takes milliseconds) Period period = new Period(totalMinutes * 60 * 1000); // format the period for the locale /* * Covers English, Danish, Dutch, French, German, Japanese, Portuguese, and Spanish. * To translate into others, see http://joda-time.sourceforge.net/apidocs/org/joda/time/format/PeriodFormat.html#wordBased(java.util.Locale) * (ie. put the properties mentioned in http://joda-time.sourceforge.net/apidocs/src-html/org/joda/time/format/PeriodFormat.html#line.94 into the classpath resource bundle) */ PeriodFormatter periodFormatter = PeriodFormat.wordBased(getLocale()); return periodFormatter.print(period); } /** * Adds a link to the page for the user to request another validation token * @param tofill the parent of the link */ private void addResetPassLink(UIContainer toFill, ValidationAccount va) { if (toFill == null || va == null) { // enforce method contract throw new IllegalArgumentException("null passed to addResetPassLink()"); } //the url to reset-pass - assume it's on the gateway. Otherwise, we don't render a link and we log a warning String url = null; try { //get the link target url = developerHelperService.getToolViewURL("sakai.resetpass", null, null, developerHelperService.getStartingLocationReference()); } catch (IllegalArgumentException e) { log.warn("Couldn't create a link to reset-pass; no instance of reset-pass found on the gateway"); } if (url != null) { //add the container UIBranchContainer requestAnotherContainer = UIBranchContainer.make(toFill, "requestAnotherContainer:"); //add a label UIMessage.make(requestAnotherContainer, "request.another.label", "validate.requestanother.label"); //add the link to reset-pass String requestAnother = null; if (ValidationAccount.ACCOUNT_STATUS_PASSWORD_RESET == va.getAccountStatus()) { requestAnother = messageLocator.getMessage("validate.requestanother.reset"); } else { requestAnother = messageLocator.getMessage("validate.requestanother"); } UILink.make(requestAnotherContainer, "request.another", requestAnother, url); } //else - there is no reset pass instance on the gateway, but the user sees an appropriate message regardless (handled by a targetted message) } /** * When a user's validation token expires (by accountValidator.maxPasswordResetMinutes elapsing) * this returns an appropriate TargettedMessage * @return an approrpiate TargettedMessage when a validaiton token has expired, * null if accountValidator.maxPasswordResetMinutes isn't configured correctly */ private TargettedMessage getExpirationMessage() { //get the time limit (iff possible) String strMinutes = serverConfigurationService.getString(MAX_PASSWORD_RESET_MINUTES); if (strMinutes != null && !"".equals(strMinutes)) { try { int totalMinutes = Integer.parseInt(strMinutes); //get a formatted string representation of the time limit, and create the return value String formattedTime = getFormattedMinutes(totalMinutes); Object[] args = new Object[] { formattedTime }; return new TargettedMessage("msg.expiredValidationRealTime", args, TargettedMessage.SEVERITY_ERROR); } catch (NumberFormatException e) { log.warn("accountValidator.maxPasswordResetMinutes is not configured properly"); } } return null; } }