keycloak-memoizeit

KEYCLOAK-8490: Direct grants returns invalid credentials

10/5/2018 5:36:43 AM

Details

diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index 4641702..872fd4c 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -555,7 +555,7 @@ public class TokenEndpoint {
         UserModel user = authSession.getAuthenticatedUser();
         if (user.getRequiredActions() != null && user.getRequiredActions().size() > 0) {
             event.error(Errors.RESOLVE_REQUIRED_ACTIONS);
-            throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Invalid user credentials", Response.Status.UNAUTHORIZED);
+            throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Account is not fully set up", Response.Status.BAD_REQUEST);
 
         }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index 23bc245..167cbf4 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -615,10 +615,23 @@ public class AccessTokenTest extends AbstractKeycloakTest {
                 userResource.update(userRepresentation);
             }
 
+            // good password is 400 => Account is not fully set up
+            try (Response response = executeGrantAccessTokenRequest(grantTarget)) {
+                assertEquals(400, response.getStatus());
+                ObjectMapper objectMapper = new ObjectMapper();
+                JsonNode jsonNode = objectMapper.readTree(response.readEntity(String.class));
+                assertEquals("invalid_grant", jsonNode.get("error").asText());
+                assertEquals("Account is not fully set up", jsonNode.get("error_description").asText());
+            }
 
-            Response response = executeGrantAccessTokenRequest(grantTarget);
-            assertEquals(401, response.getStatus());
-            response.close();
+            // wrong password is 401 => Invalid user credentials
+            try (Response response = executeGrantAccessTokenRequestWrongPassword(grantTarget)) {
+                assertEquals(401, response.getStatus());
+                ObjectMapper objectMapper = new ObjectMapper();
+                JsonNode jsonNode = objectMapper.readTree(response.readEntity(String.class));
+                assertEquals("invalid_grant", jsonNode.get("error").asText());
+                assertEquals("Invalid user credentials", jsonNode.get("error_description").asText());
+            }
 
             {
                 UserResource userResource = findUserByUsernameId(adminClient.realm("test"), "test-user@localhost");
@@ -1018,6 +1031,10 @@ public class AccessTokenTest extends AbstractKeycloakTest {
         return executeGrantRequest(grantTarget, username, password);
     }
 
+    protected Response executeGrantAccessTokenRequestWrongPassword(WebTarget grantTarget) {
+        return executeGrantRequest(grantTarget, "test-user@localhost", "bad-password");
+    }
+
     protected Response executeGrantRequest(WebTarget grantTarget, String username, String password) {
         String header = BasicAuthHelper.createHeader("test-app", "password");
         Form form = new Form();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
index e84dbce..aa2f072 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
@@ -331,10 +331,10 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT
 
         OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "password");
 
-        assertEquals(401, response.getStatusCode());
+        assertEquals(400, response.getStatusCode());
 
         assertEquals("invalid_grant", response.getError());
-        assertEquals("Invalid user credentials", response.getErrorDescription());
+        assertEquals("Account is not fully set up", response.getErrorDescription());
 
         events.expectLogin()
                 .client("resource-owner")
@@ -348,6 +348,36 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT
         UserManager.realm(realmResource).username("test-user@localhost").removeRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL.toString());
 
     }
+    
+    @Test
+    public void grantAccessTokenVerifyEmailInvalidPassword() throws Exception {
+
+        RealmResource realmResource = adminClient.realm("test");
+        RealmManager.realm(realmResource).verifyEmail(true);
+
+        oauth.clientId("resource-owner");
+
+        OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "bad-password");
+
+        assertEquals(401, response.getStatusCode());
+
+        assertEquals("invalid_grant", response.getError());
+        assertEquals("Invalid user credentials", response.getErrorDescription());
+
+        events.expectLogin()
+                .client("resource-owner")
+                .session((String) null)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
+                .removeDetail(Details.CODE_ID)
+                .removeDetail(Details.REDIRECT_URI)
+                .removeDetail(Details.CONSENT)
+                .error(Errors.INVALID_USER_CREDENTIALS)
+                .assertEvent();
+
+        RealmManager.realm(realmResource).verifyEmail(false);
+        UserManager.realm(realmResource).username("test-user@localhost").removeRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL.toString());
+
+    }
 
     @Test
     public void grantAccessTokenExpiredPassword() throws Exception {
@@ -362,10 +392,10 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT
 
             OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "password");
 
-            assertEquals(401, response.getStatusCode());
+            assertEquals(400, response.getStatusCode());
 
             assertEquals("invalid_grant", response.getError());
-            assertEquals("Invalid user credentials", response.getErrorDescription());
+            assertEquals("Account is not fully set up", response.getErrorDescription());
 
             setTimeOffset(0);
 
@@ -382,6 +412,40 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT
                     .removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString());
         }
     }
+    
+    @Test
+    public void grantAccessTokenExpiredPasswordInvalidPassword() throws Exception {
+
+        RealmResource realmResource = adminClient.realm("test");
+        RealmManager.realm(realmResource).passwordPolicy("forceExpiredPasswordChange(1)");
+
+        try {
+            setTimeOffset(60 * 60 * 48);
+
+            oauth.clientId("resource-owner");
+
+            OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "bad-password");
+
+            assertEquals(401, response.getStatusCode());
+
+            assertEquals("invalid_grant", response.getError());
+            assertEquals("Invalid user credentials", response.getErrorDescription());
+
+            events.expectLogin()
+                    .client("resource-owner")
+                    .session((String) null)
+                    .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
+                    .removeDetail(Details.CODE_ID)
+                    .removeDetail(Details.REDIRECT_URI)
+                    .removeDetail(Details.CONSENT)
+                    .error(Errors.INVALID_USER_CREDENTIALS)
+                    .assertEvent();
+        } finally {
+            RealmManager.realm(realmResource).passwordPolicy("");
+            UserManager.realm(realmResource).username("test-user@localhost")
+                    .removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString());
+        }
+    }
 
     @Test
     public void grantAccessTokenInvalidUserCredentials() throws Exception {
@@ -392,6 +456,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT
         assertEquals(401, response.getStatusCode());
 
         assertEquals("invalid_grant", response.getError());
+        assertEquals("Invalid user credentials", response.getErrorDescription());
 
         events.expectLogin()
                 .client("resource-owner")