keycloak-aplcache

Details

diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
index f29ad39..c94e8cb 100755
--- a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
+++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
@@ -18,10 +18,7 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import java.net.URI;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -116,6 +113,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
 
     private class ValidationContextImpl extends FormContextImpl implements ValidationContext {
         FormAction action;
+        String error;
 
         private ValidationContextImpl(AuthenticationExecutionModel executionModel, FormAction action) {
             super(executionModel);
@@ -131,6 +129,10 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
             this.formData = formData;
         }
 
+        public void error(String error) {
+            this.error = error;
+        }
+
         @Override
         public void success() {
            success = true;
@@ -145,6 +147,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
         Map<String, ClientSessionModel.ExecutionStatus> executionStatus = new HashMap<>();
         List<FormAction> requiredActions = new LinkedList<>();
         List<ValidationContextImpl> successes = new LinkedList<>();
+        List<ValidationContextImpl> errors = new LinkedList<>();
         for (AuthenticationExecutionModel formActionExecution : formActionExecutions) {
             if (!formActionExecution.isEnabled()) {
                 executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
@@ -183,10 +186,26 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
                 executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
                 successes.add(result);
             } else {
-                processor.logFailure();
                 executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
-                return renderForm(result.formData, result.errors);
+                errors.add(result);
+            }
+        }
+
+        if (!errors.isEmpty()) {
+            processor.logFailure();
+            List<FormMessage> messages = new LinkedList<>();
+            Set<String> fields = new HashSet<>();
+            for (ValidationContextImpl v : errors) {
+                for (FormMessage m : v.errors) {
+                    if (!fields.contains(m.getField())) {
+                        fields.add(m.getField());
+                        messages.add(m);
+                    }
+                }
             }
+            ValidationContextImpl first = errors.get(0);
+            first.getEvent().error(first.error);
+            return renderForm(first.formData, messages);
         }
 
         for (ValidationContextImpl context : successes) {
diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java
index ade4e00..ff2442f 100755
--- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java
+++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java
@@ -59,7 +59,7 @@ public class RegistrationPassword implements FormAction, FormActionFactory {
         }
 
         if (errors.size() > 0) {
-            context.getEvent().error(Errors.INVALID_REGISTRATION);
+            context.error(Errors.INVALID_REGISTRATION);
             formData.remove(RegistrationPage.FIELD_PASSWORD);
             formData.remove(RegistrationPage.FIELD_PASSWORD_CONFIRM);
             context.validationError(formData, errors);
diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java
index 2fd3c85..3baae6f 100755
--- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java
+++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java
@@ -56,15 +56,17 @@ public class RegistrationProfile implements FormAction, FormActionFactory {
         }
 
         String email = formData.getFirst(Validation.FIELD_EMAIL);
+        boolean emailValid = true;
         if (Validation.isBlank(email)) {
             errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.MISSING_EMAIL));
+            emailValid = false;
         } else if (!Validation.isEmailValid(email)) {
-            formData.remove(Validation.FIELD_EMAIL);
             context.getEvent().detail(Details.EMAIL, email);
             errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.INVALID_EMAIL));
+            emailValid = false;
         }
 
-        if (context.getSession().users().getUserByEmail(email, context.getRealm()) != null) {
+        if (emailValid && context.getSession().users().getUserByEmail(email, context.getRealm()) != null) {
             eventError = Errors.EMAIL_IN_USE;
             formData.remove(Validation.FIELD_EMAIL);
             context.getEvent().detail(Details.EMAIL, email);
@@ -72,7 +74,7 @@ public class RegistrationProfile implements FormAction, FormActionFactory {
         }
 
         if (errors.size() > 0) {
-            context.getEvent().error(eventError);
+            context.error(eventError);
             context.validationError(formData, errors);
             return;
 
diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java
index 3c1817c..eb10250 100755
--- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java
+++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java
@@ -108,7 +108,7 @@ public class RegistrationRecaptcha implements FormAction, FormActionFactory, Con
         } else {
             errors.add(new FormMessage(null, Messages.RECAPTCHA_FAILED));
             formData.remove(G_RECAPTCHA_RESPONSE);
-            context.getEvent().error(Errors.INVALID_REGISTRATION);
+            context.error(Errors.INVALID_REGISTRATION);
             context.validationError(formData, errors);
             return;
 
diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java
index 40d2fb0..dfc2a89 100755
--- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java
+++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java
@@ -56,9 +56,8 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory {
 
         String usernameField = RegistrationPage.FIELD_USERNAME;
         if (context.getRealm().isRegistrationEmailAsUsername()) {
-            username = email;
-            context.getEvent().detail(Details.USERNAME, username);
-            usernameField = RegistrationPage.FIELD_EMAIL;
+            context.getEvent().detail(Details.USERNAME, email);
+
             if (Validation.isBlank(email)) {
                 errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.MISSING_EMAIL));
             } else if (!Validation.isEmailValid(email)) {
@@ -66,33 +65,32 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory {
                 formData.remove(Validation.FIELD_EMAIL);
             }
             if (errors.size() > 0) {
-                context.getEvent().error(Errors.INVALID_REGISTRATION);
+                context.error(Errors.INVALID_REGISTRATION);
                 context.validationError(formData, errors);
                 return;
             }
             if (email != null && context.getSession().users().getUserByEmail(email, context.getRealm()) != null) {
-                context.getEvent().error(Errors.USERNAME_IN_USE);
+                context.error(Errors.EMAIL_IN_USE);
                 formData.remove(Validation.FIELD_EMAIL);
-                errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.USERNAME_EXISTS));
+                errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.EMAIL_EXISTS));
                 context.validationError(formData, errors);
                 return;
             }
         } else {
             if (Validation.isBlank(username)) {
-                context.getEvent().error(Errors.INVALID_REGISTRATION);
+                context.error(Errors.INVALID_REGISTRATION);
                 errors.add(new FormMessage(RegistrationPage.FIELD_USERNAME, Messages.MISSING_USERNAME));
                 context.validationError(formData, errors);
                 return;
             }
 
-        }
-        if (context.getSession().users().getUserByUsername(username, context.getRealm()) != null) {
-            context.getEvent().error(Errors.USERNAME_IN_USE);
-            errors.add(new FormMessage(usernameField, Messages.USERNAME_EXISTS));
-            formData.remove(Validation.FIELD_USERNAME);
-            formData.remove(Validation.FIELD_EMAIL);
-            context.validationError(formData, errors);
-            return;
+            if (context.getSession().users().getUserByUsername(username, context.getRealm()) != null) {
+                context.error(Errors.USERNAME_IN_USE);
+                errors.add(new FormMessage(usernameField, Messages.USERNAME_EXISTS));
+                formData.remove(Validation.FIELD_USERNAME);
+                context.validationError(formData, errors);
+                return;
+            }
 
         }
         context.success();
diff --git a/services/src/main/java/org/keycloak/authentication/ValidationContext.java b/services/src/main/java/org/keycloak/authentication/ValidationContext.java
index b0c456e..ce96b68 100755
--- a/services/src/main/java/org/keycloak/authentication/ValidationContext.java
+++ b/services/src/main/java/org/keycloak/authentication/ValidationContext.java
@@ -21,6 +21,8 @@ public interface ValidationContext extends FormContext {
      */
     void validationError(MultivaluedMap<String, String> formData, List<FormMessage> errors);
 
+    void error(String error);
+
     /**
      * Mark this validation as sucessful
      *
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
index 9c2852e..55c7e61 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
@@ -21,10 +21,7 @@
  */
 package org.keycloak.testsuite.forms;
 
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.*;
 import org.keycloak.events.Details;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.PasswordPolicy;
@@ -42,6 +39,8 @@ import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
 
+import static org.junit.Assert.assertEquals;
+
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
@@ -80,15 +79,15 @@ public class RegisterTest {
         registerPage.register("firstName", "lastName", "registerExistingUser@email", "test-user@localhost", "password", "password");
 
         registerPage.assertCurrent();
-        Assert.assertEquals("Username already exists.", registerPage.getError());
+        assertEquals("Username already exists.", registerPage.getError());
 
         // assert form keeps form fields on error
-        Assert.assertEquals("firstName", registerPage.getFirstName());
-        Assert.assertEquals("lastName", registerPage.getLastName());
-        Assert.assertEquals("", registerPage.getEmail());
-        Assert.assertEquals("", registerPage.getUsername());
-        Assert.assertEquals("", registerPage.getPassword());
-        Assert.assertEquals("", registerPage.getPasswordConfirm());
+        assertEquals("firstName", registerPage.getFirstName());
+        assertEquals("lastName", registerPage.getLastName());
+        assertEquals("registerExistingUser@email", registerPage.getEmail());
+        assertEquals("", registerPage.getUsername());
+        assertEquals("", registerPage.getPassword());
+        assertEquals("", registerPage.getPasswordConfirm());
 
         events.expectRegister("test-user@localhost", "registerExistingUser@email")
                 .removeDetail(Details.EMAIL)
@@ -104,15 +103,15 @@ public class RegisterTest {
         registerPage.register("firstName", "lastName", "registerUserInvalidPasswordConfirm@email", "registerUserInvalidPasswordConfirm", "password", "invalid");
 
         registerPage.assertCurrent();
-        Assert.assertEquals("Password confirmation doesn't match.", registerPage.getError());
+        assertEquals("Password confirmation doesn't match.", registerPage.getError());
 
         // assert form keeps form fields on error
-        Assert.assertEquals("firstName", registerPage.getFirstName());
-        Assert.assertEquals("lastName", registerPage.getLastName());
-        Assert.assertEquals("registerUserInvalidPasswordConfirm@email", registerPage.getEmail());
-        Assert.assertEquals("registerUserInvalidPasswordConfirm", registerPage.getUsername());
-        Assert.assertEquals("", registerPage.getPassword());
-        Assert.assertEquals("", registerPage.getPasswordConfirm());
+        assertEquals("firstName", registerPage.getFirstName());
+        assertEquals("lastName", registerPage.getLastName());
+        assertEquals("registerUserInvalidPasswordConfirm@email", registerPage.getEmail());
+        assertEquals("registerUserInvalidPasswordConfirm", registerPage.getUsername());
+        assertEquals("", registerPage.getPassword());
+        assertEquals("", registerPage.getPasswordConfirm());
 
         events.expectRegister("registerUserInvalidPasswordConfirm", "registerUserInvalidPasswordConfirm@email")
                 .removeDetail(Details.USERNAME)
@@ -129,7 +128,7 @@ public class RegisterTest {
         registerPage.register("firstName", "lastName", "registerUserMissingPassword@email", "registerUserMissingPassword", null, null);
 
         registerPage.assertCurrent();
-        Assert.assertEquals("Please specify password.", registerPage.getError());
+        assertEquals("Please specify password.", registerPage.getError());
 
         events.expectRegister("registerUserMissingPassword", "registerUserMissingPassword@email")
                 .removeDetail(Details.USERNAME)
@@ -154,7 +153,7 @@ public class RegisterTest {
             registerPage.register("firstName", "lastName", "registerPasswordPolicy@email", "registerPasswordPolicy", "pass", "pass");
 
             registerPage.assertCurrent();
-            Assert.assertEquals("Invalid password: minimum length 8.", registerPage.getError());
+            assertEquals("Invalid password: minimum length 8.", registerPage.getError());
 
             events.expectRegister("registerPasswordPolicy", "registerPasswordPolicy@email")
                     .removeDetail(Details.USERNAME)
@@ -162,7 +161,7 @@ public class RegisterTest {
                     .user((String) null).error("invalid_registration").assertEvent();
 
             registerPage.register("firstName", "lastName", "registerPasswordPolicy@email", "registerPasswordPolicy", "password", "password");
-            Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
+            assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
 
             String userId = events.expectRegister("registerPasswordPolicy", "registerPasswordPolicy@email").assertEvent().getUserId();
 
@@ -186,7 +185,29 @@ public class RegisterTest {
         registerPage.register("firstName", "lastName", "registerUserMissingUsername@email", null, "password", "password");
 
         registerPage.assertCurrent();
-        Assert.assertEquals("Please specify username.", registerPage.getError());
+        assertEquals("Please specify username.", registerPage.getError());
+
+        events.expectRegister(null, "registerUserMissingUsername@email")
+                .removeDetail(Details.USERNAME)
+                .removeDetail(Details.EMAIL)
+                .error("invalid_registration").assertEvent();
+    }
+
+    @Test
+    public void registerUserManyErrors() {
+        loginPage.open();
+        loginPage.clickRegister();
+        registerPage.assertCurrent();
+
+        registerPage.register(null, null, null, null, null, null);
+
+        registerPage.assertCurrent();
+
+        assertEquals("Please specify username.\n" +
+                "Please specify first name.\n" +
+                "Please specify last name.\n" +
+                "Please specify email.\n" +
+                "Please specify password.", registerPage.getError());
 
         events.expectRegister(null, "registerUserMissingUsername@email")
                 .removeDetail(Details.USERNAME)
@@ -195,21 +216,29 @@ public class RegisterTest {
     }
 
     @Test
-    public void registerUserMissingOrInvalidEmail() {
+    public void registerUserMissingEmail() {
         loginPage.open();
         loginPage.clickRegister();
         registerPage.assertCurrent();
 
         registerPage.register("firstName", "lastName", null, "registerUserMissingEmail", "password", "password");
         registerPage.assertCurrent();
-        Assert.assertEquals("Please specify email.", registerPage.getError());
+        assertEquals("Please specify email.", registerPage.getError());
         events.expectRegister("registerUserMissingEmail", null)
                 .removeDetail("email")
                 .error("invalid_registration").assertEvent();
+    }
+
+    @Test
+    public void registerUserInvalidEmail() {
+        loginPage.open();
+        loginPage.clickRegister();
+        registerPage.assertCurrent();
 
         registerPage.register("firstName", "lastName", "registerUserInvalidEmailemail", "registerUserInvalidEmail", "password", "password");
         registerPage.assertCurrent();
-        Assert.assertEquals("Invalid email address.", registerPage.getError());
+        assertEquals("registerUserInvalidEmailemail", registerPage.getEmail());
+        assertEquals("Invalid email address.", registerPage.getError());
         events.expectRegister("registerUserInvalidEmail", "registerUserInvalidEmailemail")
                 .error("invalid_registration").assertEvent();
     }
@@ -222,7 +251,7 @@ public class RegisterTest {
 
         registerPage.register("firstName", "lastName", "registerUserSuccess@email", "registerUserSuccess", "password", "password");
 
-        Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
+        assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
 
         String userId = events.expectRegister("registerUserSuccess", "registerUserSuccess@email").assertEvent().getUserId();
         events.expectLogin().detail("username", "registerusersuccess").user(userId).assertEvent();
@@ -233,10 +262,10 @@ public class RegisterTest {
         // test that timestamp is current with 10s tollerance
         Assert.assertTrue((System.currentTimeMillis() - user.getCreatedTimestamp()) < 10000);
         // test user info is set from form
-        Assert.assertEquals("registerusersuccess", user.getUsername());
-        Assert.assertEquals("registerusersuccess@email", user.getEmail());
-        Assert.assertEquals("firstName", user.getFirstName());
-        Assert.assertEquals("lastName", user.getLastName());
+        assertEquals("registerusersuccess", user.getUsername());
+        assertEquals("registerusersuccess@email", user.getEmail());
+        assertEquals("firstName", user.getFirstName());
+        assertEquals("lastName", user.getLastName());
     }
 
     protected UserModel getUser(String userId) {
@@ -261,9 +290,9 @@ public class RegisterTest {
             registerPage.registerWithEmailAsUsername("firstName", "lastName", "test-user@localhost", "password", "password");
 
             registerPage.assertCurrent();
-            Assert.assertEquals("Username already exists.", registerPage.getError());
+            assertEquals("Email already exists.", registerPage.getError());
 
-            events.expectRegister("test-user@localhost", "test-user@localhost").user((String) null).error("username_in_use").assertEvent();
+            events.expectRegister("test-user@localhost", "test-user@localhost").user((String) null).error("email_in_use").assertEvent();
         } finally {
             configureRelamRegistrationEmailAsUsername(false);
         }
@@ -280,12 +309,12 @@ public class RegisterTest {
 
             registerPage.registerWithEmailAsUsername("firstName", "lastName", null, "password", "password");
             registerPage.assertCurrent();
-            Assert.assertEquals("Please specify email.", registerPage.getError());
+            assertEquals("Please specify email.", registerPage.getError());
             events.expectRegister(null, null).removeDetail("username").removeDetail("email").error("invalid_registration").assertEvent();
 
             registerPage.registerWithEmailAsUsername("firstName", "lastName", "registerUserInvalidEmailemail", "password", "password");
             registerPage.assertCurrent();
-            Assert.assertEquals("Invalid email address.", registerPage.getError());
+            assertEquals("Invalid email address.", registerPage.getError());
             events.expectRegister("registerUserInvalidEmailemail", "registerUserInvalidEmailemail").error("invalid_registration").assertEvent();
         } finally {
             configureRelamRegistrationEmailAsUsername(false);
@@ -303,7 +332,7 @@ public class RegisterTest {
 
             registerPage.registerWithEmailAsUsername("firstName", "lastName", "registerUserSuccessE@email", "password", "password");
 
-            Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
+            assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
 
             String userId = events.expectRegister("registerUserSuccessE@email", "registerUserSuccessE@email").assertEvent().getUserId();
             events.expectLogin().detail("username", "registerusersuccesse@email").user(userId).assertEvent();