/* * Databinder: a simple bridge from Wicket to Hibernate * Copyright (C) 2006 Nathan Hamblen nathan@technically.us * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package net.databinder.auth.components; import java.util.HashMap; import java.util.Map; import net.databinder.auth.AuthSession; import net.databinder.auth.AuthApplication; import net.databinder.auth.components.DataSignInPageBase.ReturnPage; import net.databinder.auth.data.DataUser; import net.databinder.auth.valid.EqualPasswordConvertedInputValidator; import net.databinder.components.NullPlug; import net.databinder.models.BindingModel; import org.apache.wicket.Application; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; import org.apache.wicket.Session; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.border.Border; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.RequiredTextField; import org.apache.wicket.markup.html.form.SimpleFormComponentLabel; import org.apache.wicket.markup.html.form.validation.FormComponentFeedbackBorder; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IChainingModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.protocol.http.WebSession; import org.apache.wicket.validation.IValidatable; import org.apache.wicket.validation.validator.StringValidator; /** * Registration with username, password, and password confirmation. * Replaceable String resources: <pre> * data.auth.username * data.auth.password * data.auth.passwordConfirm * data.auth.remember * data.auth.register * data.auth.update * data.auth.username.taken * </pre> * Must be overriden in a containing page * or a subclass of this panel. */ public abstract class DataProfilePanelBase<T extends DataUser> extends Panel { private ReturnPage returnPage; private Form<T> form; private RequiredTextField<String> username; private RSAPasswordTextField password, passwordConfirm; private CheckBox rememberMe; /** @return component used in base page, if needed in subclass */ protected RequiredTextField getUsername() { return username; } /** @return component used in base page, if needed in subclass */ protected RSAPasswordTextField getPassword() { return password; } /** @return component used in base page, if needed in subclass */ protected RSAPasswordTextField getPasswordConfirm() { return passwordConfirm; } /** @return component used in base page, if needed in subclass */ protected CheckBox getRememberMe() { return rememberMe; } /** @return form used in base page, if needed elsewhere */ public Form<T> getForm() { return form; } public DataProfilePanelBase(String id, ReturnPage returnPage) { super(id); this.returnPage = returnPage; add(form = profileForm("registerForm", getAuthSession().getUserModel())); form.add(new Profile("profile")); } /** @return new form component to be used within this panel */ protected abstract Form<T> profileForm(String id, IModel<T> userModel); /** @return user from form component */ protected T getUser() { return form.getModelObject(); } /** @return true if form is bound to existing user, is not registration form */ @SuppressWarnings("unchecked") protected boolean existing() { BindingModel model = ((BindingModel<T>)((IChainingModel<T>)form.getModel()).getChainedModel()); return model != null && model.isBound(); } /** Contents of the profile form. */ protected class Profile extends WebMarkupContainer { public Profile(String id) { super(id); add(highFormSocket("highFormSocket")); add(feedbackBorder("username-border") .add(username = new RequiredTextField<String>("username"))); username.add(new UsernameValidator()); username.setLabel(new ResourceModel("data.auth.username", "Username")); add(new SimpleFormComponentLabel("username-label", username)); add(feedbackBorder("password-border") .add(password = new RSAPasswordTextField("password", new Model<String>(), form) { public boolean isRequired() { return !existing(); } })); password.setLabel(new ResourceModel("data.auth.password", "Password")); add(new SimpleFormComponentLabel("password-label", password)); add(feedbackBorder("passwordConfirm-border") .add(passwordConfirm = new RSAPasswordTextField("passwordConfirm", new Model<String>(), form) { public boolean isRequired() { return !existing(); } @Override protected void onModelChanged() { setPassword((String) getModelObject()); } })); form.add(new EqualPasswordConvertedInputValidator(password, passwordConfirm)); passwordConfirm.setLabel(new ResourceModel("data.auth.passwordConfirm", "Retype Password")); add(new SimpleFormComponentLabel("passwordConfirm-label", passwordConfirm)); add(new WebMarkupContainer("rememberMeRow") { public boolean isVisible() { return !existing(); } }.add( rememberMe = new CheckBox("rememberMe", new Model<Boolean>(Boolean.TRUE)) ).add( new Label("text", new ResourceModel("data.auth.remember", "Always sign in automatically")) )); add(lowFormSocket("lowFormSocket")); add(new Button("submit") { }.add(new AttributeModifier("value", new AbstractReadOnlyModel() { public Object getObject() { return existing() ? getString("auth.data.update", null, "Update Account") : getString("data.auth.register", null, "Register"); } }))); } } protected void setPassword(String password) { if (password != null) getUser().getPassword().change(password); } /** Subclasses call this after form submission. Returns user to prior page if possible, otherwise home. */ protected void afterSubmit() { getAuthSession().signIn(getUser(), (Boolean) rememberMe.getModelObject()); if (returnPage == null) { if (!continueToOriginalDestination()) setResponsePage(getApplication().getHomePage()); } else setResponsePage(returnPage.get()); } /** @return true if username is available (can not load via AuthApplication, or is current user). */ public static boolean isAvailable(String username) { AuthApplication authSettings = (AuthApplication)Application.get(); DataUser found = (DataUser) authSettings.getUser(username), current = ((AuthSession)WebSession.get()).getUser(); return found == null || found.equals(current); } /** Username is valid if isAvailable(username) returns true */ public static class UsernameValidator extends StringValidator { @Override protected void onValidate(IValidatable validatable) { String username = (String) validatable.getValue(); if (username != null && !isAvailable(username)) { Map<String, Object> m = new HashMap<String, Object>(1); m.put("username", username); error(validatable,"data.auth.username.taken", m); } } } /** @return content to appear above form, base class returns feedback panel */ protected Component highFormSocket(String id) { return new FeedbackPanel(id) .add(new AttributeModifier("class", true, new Model<String>("feedback"))); } /** @return content to appear below form, base class returns blank */ protected Component lowFormSocket(String id) { return new NullPlug(id); } /** @return border to go around each form component, base returns FormComponentFeedbackBorder. */ protected Border feedbackBorder(String id) { return new FormComponentFeedbackBorder(id); } /** @return casted session */ protected AuthSession<T> getAuthSession() { return (AuthSession<T>) Session.get(); } }