You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by an...@apache.org on 2019/04/16 10:54:20 UTC

[syncope] branch master updated: [SYNCOPE-1421] added password strength meter, wizard bugfixing

This is an automated email from the ASF dual-hosted git repository.

andreapatricelli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/master by this push:
     new 0399306  [SYNCOPE-1421] added password strength meter, wizard bugfixing
0399306 is described below

commit 03993064cbdbb3e005f8c3715e518d4f61038b28
Author: Andrea Patricelli <an...@apache.org>
AuthorDate: Fri Apr 12 17:30:12 2019 +0200

    [SYNCOPE-1421] added password strength meter, wizard bugfixing
---
 .../apache/syncope/client/enduser/pages/Self.java  |   9 +-
 .../enduser/wizards/any/AnyWizardBuilder.java      | 138 +++++++++++++++++++++
 .../client/enduser/wizards/any/UserDetails.java    |  29 +++--
 .../markup/html/form/AjaxPasswordFieldPanel.html   |   4 +-
 .../markup/html/form/AjaxPasswordFieldPanel.java   |  14 ++-
 .../ui/commons/wizards/AjaxWizardBuilder.java      |   2 +-
 .../ui/commons/wizards/AjaxWizardMgtButtonBar.java |   2 +-
 .../ui/commons/wizards/any/PasswordPanel.java      |  17 ++-
 8 files changed, 194 insertions(+), 21 deletions(-)

diff --git a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/pages/Self.java b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/pages/Self.java
index eef84d5..071f630 100644
--- a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/pages/Self.java
+++ b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/pages/Self.java
@@ -45,7 +45,10 @@ public class Self extends BaseEnduserWebPage implements IEventSource {
 
         body.add(buildWizard(SyncopeEnduserSession.get().isAuthenticated()
                 ? SyncopeEnduserSession.get().getSelfTO()
-                : buildNewUserTO()));
+                : buildNewUserTO(),
+                SyncopeEnduserSession.get().isAuthenticated()
+                ? AjaxWizard.Mode.EDIT
+                : AjaxWizard.Mode.CREATE));
     }
 
     @Override
@@ -67,7 +70,7 @@ public class Self extends BaseEnduserWebPage implements IEventSource {
         super.onEvent(event);
     }
 
-    protected final AjaxWizard<AnyWrapper<UserTO>> buildWizard(final UserTO userTO) {
+    protected final AjaxWizard<AnyWrapper<UserTO>> buildWizard(final UserTO userTO, final AjaxWizard.Mode mode) {
         userWizardBuilder = new UserWizardBuilder(
                 null,
                 userTO,
@@ -75,7 +78,7 @@ public class Self extends BaseEnduserWebPage implements IEventSource {
                 new UserFormLayoutInfo(),
                 this.getPageReference());
         userWizardBuilder.setItem(new UserWrapper(userTO));
-        return userWizardBuilder.build(WIZARD_ID, userTO == null ? AjaxWizard.Mode.CREATE : AjaxWizard.Mode.EDIT);
+        return userWizardBuilder.build(WIZARD_ID, mode);
     }
 
     private UserTO buildNewUserTO() {
diff --git a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/AnyWizardBuilder.java b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/AnyWizardBuilder.java
index 0cb432d..25c1cb0 100644
--- a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/AnyWizardBuilder.java
+++ b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/AnyWizardBuilder.java
@@ -27,11 +27,18 @@ import org.apache.syncope.client.enduser.SyncopeWebApplication;
 import org.apache.syncope.client.enduser.SyncopeEnduserSession;
 import org.apache.syncope.client.enduser.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
+import org.apache.syncope.client.ui.commons.wizards.AjaxWizardMgtButtonBar;
 import org.apache.syncope.client.ui.commons.wizards.any.AbstractAnyWizardBuilder;
 import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper;
 import org.apache.syncope.client.ui.commons.wizards.any.UserWrapper;
 import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.wicket.Component;
 import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.wizard.FinishButton;
+import org.apache.wicket.extensions.wizard.IWizard;
+import org.apache.wicket.extensions.wizard.IWizardModel;
+import org.apache.wicket.extensions.wizard.IWizardStep;
 import org.apache.wicket.extensions.wizard.WizardModel;
 
 public abstract class AnyWizardBuilder extends AbstractAnyWizardBuilder<UserTO> {
@@ -159,4 +166,135 @@ public abstract class AnyWizardBuilder extends AbstractAnyWizardBuilder<UserTO>
             final Callable<Pair<Serializable, Serializable>> future) {
         return SyncopeEnduserSession.get().execute(future);
     }
+
+    @Override
+    public AjaxWizard<AnyWrapper<UserTO>> build(final String id, final AjaxWizard.Mode mode) {
+        this.mode = mode;
+
+        // get the specified item if available
+        final AnyWrapper<UserTO> modelObject = newModelObject();
+
+        return new AjaxWizard<AnyWrapper<UserTO>>(id, modelObject, buildModelSteps(modelObject, new WizardModel()),
+                mode, this.pageRef) {
+
+            private static final long serialVersionUID = 7770507663760640735L;
+
+            @Override
+            protected void onCancelInternal() {
+                AnyWizardBuilder.this.onCancelInternal(modelObject);
+            }
+
+            @Override
+            protected Pair<Serializable, Serializable> onApplyInternal(final AjaxRequestTarget target) {
+                Serializable res = AnyWizardBuilder.this.onApplyInternal(modelObject);
+
+                Serializable payload;
+                switch (mode) {
+                    case CREATE:
+                        payload = getCreateCustomPayloadEvent(res, target);
+                        break;
+                    case EDIT:
+                    case TEMPLATE:
+                        payload = getEditCustomPayloadEvent(res, target);
+                        break;
+                    default:
+                        payload = null;
+                }
+
+                return Pair.of(payload, res);
+            }
+
+            @Override
+            protected long getMaxWaitTimeInSeconds() {
+                return AnyWizardBuilder.this.getMaxWaitTimeInSeconds();
+            }
+
+            @Override
+            protected void sendError(final String message) {
+                AnyWizardBuilder.this.sendError(message);
+            }
+
+            @Override
+            protected void sendWarning(final String message) {
+                AnyWizardBuilder.this.sendWarning(message);
+            }
+
+            @Override
+            protected Future<Pair<Serializable, Serializable>> execute(
+                    final Callable<Pair<Serializable, Serializable>> future) {
+                return AnyWizardBuilder.this.execute(future);
+            }
+
+            @Override
+            protected Component newButtonBar(final String id) {
+                return new AjaxWizardMgtButtonBar<>(id, this, mode) {
+
+                    private static final long serialVersionUID = -3041152400413815333L;
+
+                    @Override
+                    protected FinishButton newFinishButton(final String id, final IWizard wizard) {
+                        return new FinishButton(id, wizard) {
+
+                            private static final long serialVersionUID = 864248301720764819L;
+
+                            @Override
+                            public boolean isEnabled() {
+                                switch (mode) {
+                                    case EDIT:
+                                    case TEMPLATE:
+                                        return true;
+                                    case READONLY:
+                                        return false;
+                                    default:
+                                        if (!completed) {
+                                            final IWizardStep activeStep = getWizardModel().getActiveStep();
+                                            completed = (activeStep != null)
+                                                    && getWizardModel().isLastStep(activeStep)
+                                                    && super.isEnabled();
+                                        }
+                                        return completed;
+                                }
+                            }
+
+                            @Override
+                            public boolean isVisible() {
+                                switch (mode) {
+                                    case READONLY:
+                                        return false;
+                                    default:
+                                        return true;
+                                }
+                            }
+
+                            @Override
+                            public void onClick() {
+                                IWizardModel wizardModel = getWizardModel();
+                                IWizardStep activeStep = wizardModel.getActiveStep();
+
+                                // let the step apply any state
+                                activeStep.applyState();
+
+                                // if the step completed after applying the state, notify the wizard
+                                if (activeStep.isComplete()
+                                        && SyncopeWebApplication.get().isCaptchaEnabled()
+                                        && !getWizardModel().isLastStep(activeStep)) {
+                                    // go to last step
+                                    getWizardModel().last();
+                                } else if (activeStep.isComplete()) {
+                                    getWizardModel().finish();
+                                } else {
+                                    error(getLocalizer().getString(
+                                            "org.apache.wicket.extensions.wizard.FinishButton.step.did.not.complete",
+                                            this));
+                                }
+                            }
+                        };
+                    }
+
+                };
+            }
+
+        }.setEventSink(eventSink).addOuterObject(outerObjects);
+    }
+
 }
diff --git a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/UserDetails.java b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/UserDetails.java
index 665f546..7323f33 100644
--- a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/UserDetails.java
+++ b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/UserDetails.java
@@ -18,6 +18,8 @@
  */
 package org.apache.syncope.client.enduser.wizards.any;
 
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.password.strength.PasswordStrengthBehavior;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.password.strength.PasswordStrengthConfig;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -68,7 +70,7 @@ public class UserDetails extends WizardStep {
 
     protected final UserTO userTO;
 
-    @SuppressWarnings({"unchecked", "rawtypes"})
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     public UserDetails(
             final UserWrapper wrapper,
             final boolean templateMode,
@@ -155,15 +157,6 @@ public class UserDetails extends WizardStep {
         // ------------------------
 
         // ------------------------
-        // Security Answer
-        // ------------------------
-        securityAnswer =
-                new AjaxTextFieldPanel("securityAnswer", "securityAnswer",
-                        new PropertyModel<>(userTO, "securityAnswer"), false);
-        add(securityAnswer.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true).setEnabled(false));
-        // ------------------------
-
-        // ------------------------
         // Security Question
         // ------------------------
         securityQuestion = new AjaxDropDownChoicePanel("securityQuestion", "securityQuestion", new PropertyModel<>(
@@ -210,6 +203,16 @@ public class UserDetails extends WizardStep {
 
         add(securityQuestion);
         // ------------------------
+
+        // ------------------------
+        // Security Answer
+        // ------------------------
+        securityAnswer =
+                new AjaxTextFieldPanel("securityAnswer", "securityAnswer",
+                        new PropertyModel<>(userTO, "securityAnswer"), false);
+        add(securityAnswer.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true).setEnabled(StringUtils.
+                isNotBlank(securityQuestion.getModelObject())));
+        // ------------------------
     }
 
     public static class EditUserPasswordPanel extends Panel {
@@ -223,7 +226,11 @@ public class UserDetails extends WizardStep {
             super(id);
             setOutputMarkupId(true);
             add(new Label("warning", new ResourceModel("password.change.warning")));
-            add(new PasswordPanel("passwordPanel", wrapper, templateMode));
+            add(new PasswordPanel("passwordPanel", wrapper, templateMode, new PasswordStrengthBehavior(
+                    new PasswordStrengthConfig()
+                            .withDebug(true)
+                            .withShowVerdictsInsideProgressBar(true)
+                            .withShowProgressBar(true))));
         }
 
     }
diff --git a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.html b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.html
index 2d22038..bddd03a 100644
--- a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.html
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.html
@@ -26,7 +26,9 @@ under the License.
         <label wicket:id="field-label">[LABEL]</label><span wicket:id="required"/>
         <span wicket:id="externalAction"/>
       </wicket:enclosure>
-      <fieldset class="input-group">
+      <!--to be restored and merged with password strength meter-->
+      <!--<fieldset class="input-group">-->
+      <fieldset>
         <input type="password" class="form-control" wicket:id="passwordField" />
       </fieldset>
     </wicket:extend>
diff --git a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java
index 58eeec3..91588fc 100644
--- a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java
+++ b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.client.ui.commons.markup.html.form;
 
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.password.strength.PasswordStrengthBehavior;
 import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
 import org.apache.syncope.client.ui.commons.Constants;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -30,14 +31,23 @@ public class AjaxPasswordFieldPanel extends FieldPanel<String> {
     private static final long serialVersionUID = -5490115280336667460L;
 
     public AjaxPasswordFieldPanel(final String id, final String name, final IModel<String> model) {
-        this(id, name, model, true);
+        this(id, name, model, true, null);
+    }
+
+    public AjaxPasswordFieldPanel(final String id, final String name, final IModel<String> model,
+            final boolean enableOnChange) {
+        this(id, name, model, enableOnChange, null);
     }
 
     public AjaxPasswordFieldPanel(
-            final String id, final String name, final IModel<String> model, final boolean enableOnChange) {
+            final String id, final String name, final IModel<String> model, final boolean enableOnChange,
+            final PasswordStrengthBehavior passwordStrengthBehavior) {
         super(id, name, model);
 
         field = new PasswordTextField("passwordField", model);
+        if (passwordStrengthBehavior != null) {
+            field.add(passwordStrengthBehavior);
+        }
         add(field.setLabel(new ResourceModel(name, name)).setRequired(false).setOutputMarkupId(true));
 
         if (enableOnChange && !isReadOnly()) {
diff --git a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardBuilder.java b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardBuilder.java
index a6ebaa7..ba9f1e0 100644
--- a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardBuilder.java
+++ b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardBuilder.java
@@ -40,7 +40,7 @@ public abstract class AjaxWizardBuilder<T extends Serializable> extends Abstract
 
     protected AjaxWizard.Mode mode = AjaxWizard.Mode.CREATE;
 
-    private final List<Component> outerObjects = new ArrayList<>();
+    protected final List<Component> outerObjects = new ArrayList<>();
 
     /**
      * Construct.
diff --git a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardMgtButtonBar.java b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardMgtButtonBar.java
index 74c239b..ce68be9 100644
--- a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardMgtButtonBar.java
+++ b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardMgtButtonBar.java
@@ -39,7 +39,7 @@ public class AjaxWizardMgtButtonBar<T extends Serializable> extends WizardButton
 
     private final AjaxWizard.Mode mode;
 
-    private boolean completed = false;
+    protected boolean completed = false;
 
     public AjaxWizardMgtButtonBar(final String id, final AjaxWizard<T> wizard, final AjaxWizard.Mode mode) {
         super(id, wizard);
diff --git a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/PasswordPanel.java b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/PasswordPanel.java
index d39cb13..6cf3087 100644
--- a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/PasswordPanel.java
+++ b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/PasswordPanel.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.client.ui.commons.wizards.any;
 
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.password.strength.PasswordStrengthBehavior;
 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPasswordFieldPanel;
 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
@@ -38,6 +39,14 @@ public class PasswordPanel extends Panel {
             final String id,
             final UserWrapper wrapper,
             final boolean templateMode) {
+        this(id, wrapper, templateMode, null);
+    }
+
+    public PasswordPanel(
+            final String id,
+            final UserWrapper wrapper,
+            final boolean templateMode,
+            final PasswordStrengthBehavior passwordStrengthBehavior) {
 
         super(id);
         setOutputMarkupId(true);
@@ -46,7 +55,7 @@ public class PasswordPanel extends Panel {
         add(form);
 
         FieldPanel<String> confirmPasswordField = new AjaxPasswordFieldPanel(
-                "confirmPassword", "confirmPassword", new Model<>(), false);
+                "confirmPassword", "confirmPassword", new Model<>(), false, null);
 
         confirmPasswordField.setMarkupId("confirmPassword");
         confirmPasswordField.setPlaceholder("confirmPassword");
@@ -66,7 +75,11 @@ public class PasswordPanel extends Panel {
             passwordField.enableJexlHelp();
         } else {
             AjaxPasswordFieldPanel passwordField = new AjaxPasswordFieldPanel(
-                    "password", "password", new PropertyModel<>(wrapper.getInnerObject(), "password"), false);
+                    "password",
+                    "password",
+                    new PropertyModel<>(wrapper.getInnerObject(), "password"),
+                    false,
+                    passwordStrengthBehavior);
             passwordField.setRequired(true);
             passwordField.setMarkupId("password");
             passwordField.setPlaceholder("password");