From 4f8669d668e7b226dd6bc1bff5282d9cf7f1397b Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Tue, 1 Mar 2016 09:05:02 +0100 Subject: [PATCH] KEYCLOAK-2513 Add test for direct grant with OTP --- .../org/keycloak/testsuite/OAuthClient.java | 4 ++ ...urceOwnerPasswordCredentialsGrantTest.java | 71 ++++++++++++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java index 46235ed11b..e53ebfbe70 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java @@ -205,6 +205,10 @@ public class OAuthClient { return doGrantAccessTokenRequest(realm, username, password, null, clientId, clientSecret); } + public AccessTokenResponse doGrantAccessTokenRequest(String clientSecret, String username, String password, String otp) throws Exception { + return doGrantAccessTokenRequest(realm, username, password, otp, clientId, clientSecret); + } + public AccessTokenResponse doGrantAccessTokenRequest(String realm, String username, String password, String totp, String clientId, String clientSecret) throws Exception { CloseableHttpClient client = new DefaultHttpClient(); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java index 0c93c0f9e7..5d8608526a 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java @@ -29,8 +29,10 @@ import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.models.*; import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.models.utils.TimeBasedOTP; import org.keycloak.representations.AccessToken; import org.keycloak.representations.RefreshToken; +import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.services.managers.RealmManager; import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.OAuthClient; @@ -63,9 +65,24 @@ public class ResourceOwnerPasswordCredentialsGrantTest { user.setEmail("direct-login@localhost"); user.setEnabled(true); + session.users().updateCredential(appRealm, user, UserCredentialModel.password("password")); + userId = user.getId(); - session.users().updateCredential(appRealm, user, UserCredentialModel.password("password")); + UserModel user2 = session.users().addUser(appRealm, "direct-login-otp"); + user2.setEnabled(true); + + UserCredentialModel credentials = new UserCredentialModel(); + credentials.setType(CredentialRepresentation.TOTP); + credentials.setValue("totpSecret"); + user2.updateCredential(credentials); + + user2.setOtpEnabled(true); + + session.users().updateCredential(appRealm, user2, UserCredentialModel.password("password")); + + userId2 = user2.getId(); + } }); @@ -83,6 +100,10 @@ public class ResourceOwnerPasswordCredentialsGrantTest { private static String userId; + private static String userId2; + + private TimeBasedOTP totp = new TimeBasedOTP(); + @Test public void grantAccessTokenUsername() throws Exception { grantAccessToken("direct-login", "resource-owner"); @@ -98,11 +119,57 @@ public class ResourceOwnerPasswordCredentialsGrantTest { grantAccessToken("direct-login", "resource-owner-public"); } + @Test + public void grantAccessTokenWithTotp() throws Exception { + grantAccessToken(userId2, "direct-login-otp", "resource-owner", totp.generateTOTP("totpSecret")); + } + + @Test + public void grantAccessTokenMissingTotp() throws Exception { + oauth.clientId("resource-owner"); + + OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "direct-login-otp", "password"); + + assertEquals(401, response.getStatusCode()); + + assertEquals("invalid_grant", response.getError()); + + events.expectLogin() + .client("resource-owner") + .session((String) null) + .clearDetails() + .error(Errors.INVALID_USER_CREDENTIALS) + .user(userId2) + .assertEvent(); + } + + @Test + public void grantAccessTokenInvalidTotp() throws Exception { + oauth.clientId("resource-owner"); + + OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "direct-login-otp", "password", totp.generateTOTP("totpSecret2")); + + assertEquals(401, response.getStatusCode()); + + assertEquals("invalid_grant", response.getError()); + + events.expectLogin() + .client("resource-owner") + .session((String) null) + .clearDetails() + .error(Errors.INVALID_USER_CREDENTIALS) + .user(userId2) + .assertEvent(); + } private void grantAccessToken(String login, String clientId) throws Exception { + grantAccessToken(userId, login, clientId, null); + } + + private void grantAccessToken(String userId, String login, String clientId, String otp) throws Exception { oauth.clientId(clientId); - OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", login, "password"); + OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", login, "password", otp); assertEquals(200, response.getStatusCode());