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/09 12:55:14 UTC

[syncope] branch master updated: [SYNCOPE-1421] added captcha as last step of the wizard

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 36d4847  [SYNCOPE-1421] added captcha as last step of the wizard
36d4847 is described below

commit 36d4847df677ab5391ff673143392551c461e84c
Author: Andrea Patricelli <an...@apache.org>
AuthorDate: Tue Apr 9 14:40:12 2019 +0200

    [SYNCOPE-1421] added captcha as last step of the wizard
---
 .../enduser/wizards/any/AbstractCaptchaPanel.java  | 89 ++++++++++++++++++++++
 .../enduser/wizards/any/AnyWizardBuilder.java      |  9 +++
 .../client/enduser/wizards/any/Captcha.java        | 55 +++++++++++++
 .../client/enduser/wizards/any/CaptchaPanel.java   | 60 +++++++++++++++
 .../enduser/wizards/any/UserWizardBuilder.java     |  7 ++
 .../enduser/SyncopeWebApplication.properties       |  3 +
 .../enduser/SyncopeWebApplication_it.properties    |  3 +
 .../enduser/SyncopeWebApplication_ja.properties    |  2 +
 .../enduser/SyncopeWebApplication_pt_BR.properties |  2 +
 .../enduser/SyncopeWebApplication_ru.properties    |  2 +
 .../enduser/wizards/any/AbstractCaptchaPanel.html  | 24 ++++++
 .../wizards/any/AbstractCaptchaPanel.properties    | 17 +----
 .../client/enduser/wizards/any/Captcha.html        | 25 ++++++
 .../client/enduser/wizards/any/CaptchaPanel.html   | 40 ++++++++++
 .../syncope/client/ui/commons/Constants.java       |  2 +
 .../client/ui/commons/wizards/AjaxWizard.java      |  9 +++
 .../exception/CaptchaNotMatchingException.java     | 28 +++++++
 .../src/test/resources/enduser.properties          |  2 +-
 18 files changed, 362 insertions(+), 17 deletions(-)

diff --git a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/AbstractCaptchaPanel.java b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/AbstractCaptchaPanel.java
new file mode 100644
index 0000000..deb52c0
--- /dev/null
+++ b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/AbstractCaptchaPanel.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.client.enduser.wizards.any;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.extensions.markup.html.captcha.CaptchaImageResource;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.form.RequiredTextField;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.PropertyModel;
+
+public abstract class AbstractCaptchaPanel<T> extends Panel {
+
+    private static final long serialVersionUID = -4310189409064713307L;
+
+    protected String randomText;
+
+    protected String captchaText;
+
+    protected final CaptchaImageResource captchaImageResource;
+
+    public AbstractCaptchaPanel(final String id) {
+        super(id);
+        this.setOutputMarkupId(true);
+
+        captchaImageResource = createCaptchaImageResource();
+        final Image captchaImage = new Image("image", captchaImageResource);
+        captchaImage.setOutputMarkupId(true);
+        add(captchaImage);
+
+        AjaxButton realoadCaptchaButton = new AjaxButton("reloadButton") {
+
+            private static final long serialVersionUID = -957948639666058749L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target) {
+                captchaImageResource.invalidate();
+                target.add(captchaImage);
+            }
+
+        };
+        realoadCaptchaButton.setDefaultFormProcessing(false);
+        add(realoadCaptchaButton);
+
+        add(new RequiredTextField<String>("captcha",
+                new PropertyModel<>(AbstractCaptchaPanel.this, "captchaText"), String.class) {
+
+            private static final long serialVersionUID = -5918382907429502528L;
+
+            @Override
+            protected void onComponentTag(final ComponentTag tag) {
+                super.onComponentTag(tag);
+                // clear the field after each render
+                tag.put("value", "");
+            }
+
+        });
+    }
+
+    public String getRandomText() {
+        return randomText;
+    }
+
+    public String getCaptchaText() {
+        return captchaText;
+    }
+
+    protected abstract CaptchaImageResource createCaptchaImageResource();
+
+    protected abstract void reload();
+}
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 22e1b3b..0cb432d 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
@@ -42,6 +42,8 @@ public abstract class AnyWizardBuilder extends AbstractAnyWizardBuilder<UserTO>
 
     protected UserFormLayoutInfo formLayoutInfo;
 
+    protected Captcha captcha;
+
     /**
      * Construct.
      *
@@ -127,6 +129,13 @@ public abstract class AnyWizardBuilder extends AbstractAnyWizardBuilder<UserTO>
             wizardModel.add(new Resources(modelObject));
         }
 
+        if (SyncopeWebApplication.get().isCaptchaEnabled()) {
+            // add captcha
+            captcha = new Captcha();
+            captcha.setOutputMarkupId(true);
+            wizardModel.add(captcha);
+        }
+
         return wizardModel;
     }
 
diff --git a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/Captcha.java b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/Captcha.java
new file mode 100644
index 0000000..d0a1243
--- /dev/null
+++ b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/Captcha.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.client.enduser.wizards.any;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.enduser.SyncopeWebApplication;
+import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.extensions.wizard.WizardStep;
+
+public class Captcha extends WizardStep implements WizardModel.ICondition {
+
+    private static final long serialVersionUID = 702900610508752856L;
+
+    private final CaptchaPanel<Void> captchaPanel;
+
+    public Captcha() {
+        captchaPanel = new CaptchaPanel<>("captchaPanel");
+        captchaPanel.setOutputMarkupId(true);
+        add(captchaPanel);
+    }
+
+    public boolean captchaCheck() {
+        final String captchaText = captchaPanel.getCaptchaText();
+        final String randomText = captchaPanel.getRandomText();
+        return StringUtils.isBlank(captchaText) || StringUtils.isBlank(randomText)
+                ? false
+                : captchaText.equals(randomText);
+    }
+
+    public void reload() {
+        captchaPanel.reload();
+    }
+
+    @Override
+    public boolean evaluate() {
+        return SyncopeWebApplication.get().isCaptchaEnabled();
+    }
+
+}
diff --git a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/CaptchaPanel.java b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/CaptchaPanel.java
new file mode 100644
index 0000000..63158f7
--- /dev/null
+++ b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/CaptchaPanel.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.client.enduser.wizards.any;
+
+import java.security.SecureRandom;
+import org.apache.commons.text.RandomStringGenerator;
+import org.apache.wicket.extensions.markup.html.captcha.CaptchaImageResource;
+
+public class CaptchaPanel<T> extends AbstractCaptchaPanel<T> {
+
+    private static final long serialVersionUID = 1169850573252481471L;
+
+    private static final SecureRandom RANDOM = new SecureRandom();
+
+    private static final RandomStringGenerator RANDOM_LETTERS = new RandomStringGenerator.Builder().
+            usingRandom(RANDOM::nextInt).
+            withinRange('a', 'z').
+            build();
+
+    public CaptchaPanel(final String id) {
+        super(id);
+    }
+
+    @Override
+    protected CaptchaImageResource createCaptchaImageResource() {
+        return new CaptchaImageResource() {
+
+            private static final long serialVersionUID = 2436829189992948005L;
+
+            @Override
+            protected byte[] render() {
+                randomText = RANDOM_LETTERS.generate(6);
+                getChallengeIdModel().setObject(randomText);
+                return super.render();
+            }
+        };
+    }
+
+    @Override
+    protected void reload() {
+        this.captchaImageResource.invalidate();
+    }
+
+}
diff --git a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/UserWizardBuilder.java b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/UserWizardBuilder.java
index 9346bf4..4caecec 100644
--- a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/UserWizardBuilder.java
+++ b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/wizards/any/UserWizardBuilder.java
@@ -26,6 +26,7 @@ import org.apache.syncope.client.enduser.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.enduser.rest.UserSelfRestClient;
 import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper;
 import org.apache.syncope.client.ui.commons.wizards.any.UserWrapper;
+import org.apache.syncope.client.ui.commons.wizards.exception.CaptchaNotMatchingException;
 import org.apache.syncope.common.lib.AnyOperations;
 import org.apache.syncope.common.lib.EntityTOUtils;
 import org.apache.syncope.common.lib.request.PasswordPatch;
@@ -77,6 +78,12 @@ public class UserWizardBuilder extends AnyWizardBuilder implements UserForm {
 
     @Override
     protected Serializable onApplyInternal(final AnyWrapper<UserTO> modelObject) {
+        // captcha check
+        if (captcha != null && captcha.evaluate() && !captcha.captchaCheck()) {
+//            sendError("Entered captcha is not matching");
+            // force captcha redrawing
+            throw new CaptchaNotMatchingException();
+        }
         UserTO inner = modelObject.getInnerObject();
 
         ProvisioningResult<UserTO> result;
diff --git a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication.properties b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication.properties
index ecefc58..43860b2 100644
--- a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication.properties
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication.properties
@@ -75,3 +75,6 @@ timeout=Operation is taking to long: it will be executed in background. Please c
 security=Security
 before=Before
 after=After
+
+captcha_error=Captcha entered does not match
+
diff --git a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_it.properties b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_it.properties
index 4480641..1dde420 100644
--- a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_it.properties
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_it.properties
@@ -74,3 +74,6 @@ timeout=L'operazione sta durando troppo: sar\u00e0 eseguita in background. Verif
 security=Sicurezza
 before=Prima
 after=Dopo
+
+captcha_error=Il Captcha inserito non \u00e8 corretto
+
diff --git a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_ja.properties b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_ja.properties
index 4433d8a..149353a 100644
--- a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_ja.properties
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_ja.properties
@@ -72,3 +72,5 @@ timeout=\u64cd\u4f5c\u306b\u9577\u6642\u9593\u304b\u304b\u3063\u3066\u3044\u307e
 security=Security
 before=Before
 after=After
+
+captcha_error=Captcha entered does not match
diff --git a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_pt_BR.properties b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_pt_BR.properties
index 4926204..98531d6 100644
--- a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_pt_BR.properties
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_pt_BR.properties
@@ -74,3 +74,5 @@ timeout=Operation is taking to long: it will be executed in background. Please c
 security=Security
 before=Before
 after=After
+
+captcha_error=Captcha entered does not match
diff --git a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_ru.properties b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_ru.properties
index c1cef7c..46723d9 100644
--- a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_ru.properties
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/SyncopeWebApplication_ru.properties
@@ -73,3 +73,5 @@ timeout=Operation is taking to long: it will be executed in background. Please c
 security=Security
 before=Before
 after=After
+
+captcha_error=Captcha entered does not match
diff --git a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/AbstractCaptchaPanel.html b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/AbstractCaptchaPanel.html
new file mode 100644
index 0000000..c3164b1
--- /dev/null
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/AbstractCaptchaPanel.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <wicket:child/>
+  </wicket:panel>
+</html>
\ No newline at end of file
diff --git a/fit/enduser-reference/src/test/resources/enduser.properties b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/AbstractCaptchaPanel.properties
similarity index 76%
copy from fit/enduser-reference/src/test/resources/enduser.properties
copy to client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/AbstractCaptchaPanel.properties
index 7387c0d..1d2b1df 100644
--- a/fit/enduser-reference/src/test/resources/enduser.properties
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/AbstractCaptchaPanel.properties
@@ -14,19 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-enduser.directory=${conf.directory}
-
-domain=Master
-
-anonymousUser=${anonymousUser}
-anonymousKey=${anonymousKey}
-adminUser=${adminUser}
-useGZIPCompression=true
-
-scheme=http
-host=localhost
-port=9080
-rootPath=/syncope/rest/
-
-captcha=false
-xsrf=false
+captcha.message=Please enter the code displayed within the image.
diff --git a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/Captcha.html b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/Captcha.html
new file mode 100644
index 0000000..9593914
--- /dev/null
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/Captcha.html
@@ -0,0 +1,25 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div class="box-body">
+      <span wicket:id="captchaPanel">[CAPTCHA]</span>
+    </div>
+  </wicket:panel>
+</html>
\ No newline at end of file
diff --git a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/CaptchaPanel.html b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/CaptchaPanel.html
new file mode 100644
index 0000000..e45fdf5
--- /dev/null
+++ b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/wizards/any/CaptchaPanel.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <wicket:extend>
+      <div id="captchaButtons">
+        <img wicket:id="image" />
+      </div>
+      <div>
+        <button wicket:id="reloadButton" id="refresh" type="button" class="btn btn-default btn-xs fa fa-refresh" 
+                title="Refresh Captcha"></button>
+        <button id="infoLink" class="btn btn-default btn-xs fa fa-question-circle" title="What is this?"
+                onclick="window.open('https://it.wikipedia.org/wiki/CAPTCHA')"></button>
+      </div>
+      <div>
+        <input wicket:id="captcha" type="text" size="28" />
+      </div>
+      <div>
+        <wicket:message key="captcha.message">[CAPTCHA_MESSAGE]</wicket:message>
+      </div>
+    </wicket:extend>
+  </wicket:panel>
+</html>
diff --git a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java
index bf10b42..6128a01 100644
--- a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java
+++ b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java
@@ -66,6 +66,8 @@ public final class Constants {
     public static final String OPERATION_SUCCEEDED = "operation_succeeded";
 
     public static final String OPERATION_ERROR = "operation_error";
+    
+    public static final String CAPTCHA_ERROR = "captcha_error";
 
     public static final String SEARCH_ERROR = "search_error";
 
diff --git a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizard.java b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizard.java
index cbe2582..475cda2 100644
--- a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizard.java
+++ b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizard.java
@@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.client.ui.commons.Constants;
 import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.event.Broadcast;
@@ -45,6 +46,7 @@ import org.slf4j.LoggerFactory;
 import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
 import org.apache.syncope.client.ui.commons.panels.SubmitableModalPanel;
 import org.apache.syncope.client.ui.commons.panels.WizardModalPanel;
+import org.apache.syncope.client.ui.commons.wizards.exception.CaptchaNotMatchingException;
 import org.apache.wicket.Application;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.Session;
@@ -216,6 +218,10 @@ public abstract class AjaxWizard<T extends Serializable> extends Wizard
             }
             sendWarning(getString("timeout"));
             ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
+        } catch (CaptchaNotMatchingException ce) {
+            LOG.error("Wizard error on finish: captcha not matching");
+            sendError(getString(Constants.CAPTCHA_ERROR));
+            ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
         } catch (Exception e) {
             LOG.error("Wizard error on finish", e);
             sendError(StringUtils.isBlank(e.getMessage())
@@ -397,6 +403,9 @@ public abstract class AjaxWizard<T extends Serializable> extends Wizard
 
             return res.getRight();
         } catch (InterruptedException | ExecutionException e) {
+            if (e.getCause() instanceof CaptchaNotMatchingException) {
+                throw (CaptchaNotMatchingException) e.getCause();
+            }
             throw new RuntimeException(e);
         }
     }
diff --git a/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/exception/CaptchaNotMatchingException.java b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/exception/CaptchaNotMatchingException.java
new file mode 100644
index 0000000..1223723
--- /dev/null
+++ b/client/idrepo/ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/exception/CaptchaNotMatchingException.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.client.ui.commons.wizards.exception;
+
+public class CaptchaNotMatchingException extends RuntimeException {
+
+    private static final long serialVersionUID = -7735150705166393254L;
+
+    public CaptchaNotMatchingException() {
+    }
+
+}
diff --git a/fit/enduser-reference/src/test/resources/enduser.properties b/fit/enduser-reference/src/test/resources/enduser.properties
index 7387c0d..ad59927 100644
--- a/fit/enduser-reference/src/test/resources/enduser.properties
+++ b/fit/enduser-reference/src/test/resources/enduser.properties
@@ -28,5 +28,5 @@ host=localhost
 port=9080
 rootPath=/syncope/rest/
 
-captcha=false
+captcha=true
 xsrf=false