/* * Copyright (c) 2010-2016 Evolveum * * Licensed under the Apache 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.apache.org/licenses/LICENSE-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 com.evolveum.midpoint.gui.api.component.password; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.markup.html.form.PasswordTextField; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.validation.IValidatable; import org.apache.wicket.validation.IValidator; import org.apache.wicket.validation.ValidationError; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.prism.InputPanel; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; /** * @author lazyman */ public class PasswordPanel extends InputPanel { private static final long serialVersionUID = 1L; private static final String ID_LINK_CONTAINER = "linkContainer"; private static final String ID_PASSWORD_SET = "passwordSet"; private static final String ID_PASSWORD_REMOVE = "passwordRemove"; private static final String ID_CHANGE_PASSWORD_LINK = "changePasswordLink"; private static final String ID_REMOVE_PASSWORD_LINK = "removePasswordLink"; private static final String ID_REMOVE_BUTTON_CONTAINER = "removeButtonContainer"; private static final String ID_INPUT_CONTAINER = "inputContainer"; private static final String ID_PASSWORD_ONE = "password1"; private static final String ID_PASSWORD_TWO = "password2"; private static final Trace LOGGER = TraceManager.getTrace(PasswordPanel.class); private boolean passwordInputVisble; public PasswordPanel(String id, IModel<ProtectedStringType> model) { this(id, model, false, false); } public PasswordPanel(String id, IModel<ProtectedStringType> model, boolean isReadOnly, boolean showRemoveButton) { super(id); this.passwordInputVisble = model.getObject() == null; initLayout(model, isReadOnly, showRemoveButton); } public PasswordPanel(String id, IModel<ProtectedStringType> model, boolean isReadOnly, boolean isInputVisible, boolean showRemoveButton) { super(id); this.passwordInputVisble = isInputVisible; initLayout(model, isReadOnly, showRemoveButton); } private void initLayout(final IModel<ProtectedStringType> model, final boolean isReadOnly, boolean showRemoveButton) { setOutputMarkupId(true); final WebMarkupContainer inputContainer = new WebMarkupContainer(ID_INPUT_CONTAINER) { @Override public boolean isVisible() { return passwordInputVisble; } }; inputContainer.setOutputMarkupId(true); add(inputContainer); final PasswordTextField password1 = new PasswordTextField(ID_PASSWORD_ONE, new PasswordModel(model)); password1.setRequired(false); password1.setResetPassword(false); password1.setOutputMarkupId(true); password1.add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); inputContainer.add(password1); final PasswordTextField password2 = new PasswordTextField(ID_PASSWORD_TWO, new Model<String>()); password2.setRequired(false); password2.setResetPassword(false); password2.setOutputMarkupId(true); password2.add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); inputContainer.add(password2); password1.add(new AjaxFormComponentUpdatingBehavior("change") { @Override protected void onUpdate(AjaxRequestTarget target) { boolean required = !StringUtils.isEmpty(password1.getModel().getObject()); password2.setRequired(required); //fix of MID-2463 // target.add(password2); // target.appendJavaScript("$(\"#"+ password2.getMarkupId() +"\").focus()"); } }); password2.add(new PasswordValidator(password1, password2)); final WebMarkupContainer linkContainer = new WebMarkupContainer(ID_LINK_CONTAINER) { @Override public boolean isVisible() { return !passwordInputVisble; } }; inputContainer.setOutputMarkupId(true); linkContainer.setOutputMarkupId(true); add(linkContainer); final Label passwordSetLabel = new Label(ID_PASSWORD_SET, new ResourceModel("passwordPanel.passwordSet")); linkContainer.add(passwordSetLabel); final Label passwordRemoveLabel = new Label(ID_PASSWORD_REMOVE, new ResourceModel("passwordPanel.passwordRemoveLabel")); passwordRemoveLabel.setVisible(false); linkContainer.add(passwordRemoveLabel); AjaxLink link = new AjaxLink(ID_CHANGE_PASSWORD_LINK) { @Override public void onClick(AjaxRequestTarget target) { onLinkClick(target); } @Override public boolean isVisible() { return !passwordInputVisble; } }; link.add(new VisibleEnableBehaviour() { @Override public boolean isVisible() { return !isReadOnly; } }); link.setBody(new ResourceModel("passwordPanel.passwordChange")); link.setOutputMarkupId(true); linkContainer.add(link); final WebMarkupContainer removeButtonContainer = new WebMarkupContainer(ID_REMOVE_BUTTON_CONTAINER); AjaxLink removePassword = new AjaxLink(ID_REMOVE_PASSWORD_LINK) { @Override public void onClick(AjaxRequestTarget target) { onRemovePassword(model, target); } }; removePassword.setVisible(showRemoveButton); removePassword.setBody(new ResourceModel("passwordPanel.passwordRemove")); removePassword.setOutputMarkupId(true); removeButtonContainer.add(removePassword); add(removeButtonContainer); } private void onLinkClick(AjaxRequestTarget target) { passwordInputVisble = true; target.add(this); } private void onRemovePassword(IModel<ProtectedStringType> model, AjaxRequestTarget target) { get(ID_LINK_CONTAINER).get(ID_PASSWORD_SET).setVisible(false); get(ID_LINK_CONTAINER).get(ID_PASSWORD_REMOVE).setVisible(true); passwordInputVisble = false; target.add(this); model.setObject(null); } @Override public List<FormComponent> getFormComponents() { List<FormComponent> list = new ArrayList<FormComponent>(); list.add((FormComponent) get(ID_INPUT_CONTAINER + ":" + ID_PASSWORD_ONE)); list.add((FormComponent) get(ID_INPUT_CONTAINER + ":" + ID_PASSWORD_TWO)); return list; } @Override public FormComponent getBaseFormComponent() { return (FormComponent) get(ID_INPUT_CONTAINER + ":" + ID_PASSWORD_ONE); } private static class PasswordValidator implements IValidator<String> { private PasswordTextField p1; private PasswordTextField p2; private PasswordValidator(PasswordTextField p1, PasswordTextField p2) { Validate.notNull(p1, "Password field one must not be null."); Validate.notNull(p2, "Password field two must not be null."); this.p1 = p1; this.p2 = p2; } @Override public void validate(IValidatable<String> validatable) { String s1 = p1.getValue(); String s2 = p2.getValue(); if (StringUtils.isEmpty(s1) && StringUtils.isEmpty(s2)) { return; } boolean equal = s1 != null ? s1.equals(s2) : s2 == null; if (!equal) { validatable = p1.newValidatable(); ValidationError err = new ValidationError(); err.addKey("passwordPanel.error"); validatable.error(err); } } } private static class EmptyOnBlurAjaxFormUpdatingBehaviour extends AjaxFormComponentUpdatingBehavior { public EmptyOnBlurAjaxFormUpdatingBehaviour() { super("blur"); } @Override protected void onUpdate(AjaxRequestTarget target) { } } private class PasswordModel implements IModel<String> { IModel<ProtectedStringType> psModel; PasswordModel(IModel<ProtectedStringType> psModel) { this.psModel = psModel; } @Override public void detach() { // Nothing to do } @Override public String getObject() { if (psModel.getObject() == null) { return null; } else { return psModel.getObject().getClearValue(); } } @Override public void setObject(String object) { if (object == null) { psModel.setObject(null); } else { if (psModel.getObject() == null) { psModel.setObject(new ProtectedStringType()); } psModel.getObject().setClearValue(object); } } } }