keycloak-memoizeit

Details

diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index 112f6e6..f11a2b4 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -108,7 +108,7 @@ public class TokenManager {
         RefreshToken refreshToken = null;
         try {
             if (!RSAProvider.verify(jws, realm.getPublicKey())) {
-                throw new RuntimeException("Invalid refresh token");
+                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token");
             }
             refreshToken = jws.readJsonContent(RefreshToken.class);
         } catch (IOException e) {
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index d964906..7b182d2 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -244,7 +244,7 @@ public class TokenService {
         }
         event.detail(Details.USERNAME, username);
 
-        UserModel user = session.users().getUserByUsername(username, realm);
+        UserModel user = KeycloakModelUtils.findUserByNameOrEmail(session, realm, username);
         if (user != null) event.user(user);
 
         ClientModel client = authorizeClient(authorizationHeader, form, event);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
index 0dd893b..9fcceb5 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -8,10 +8,10 @@ import org.junit.Assert;
 import org.junit.rules.TestRule;
 import org.junit.runners.model.Statement;
 import org.keycloak.Config;
-import org.keycloak.events.EventListenerProvider;
-import org.keycloak.events.EventListenerProviderFactory;
 import org.keycloak.events.Details;
 import org.keycloak.events.Event;
+import org.keycloak.events.EventListenerProvider;
+import org.keycloak.events.EventListenerProviderFactory;
 import org.keycloak.events.EventType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
@@ -277,6 +277,11 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
             return this;
         }
 
+        public ExpectedEvent clearDetails() {
+            if (details != null) details.clear();
+            return this;
+        }
+
         public ExpectedEvent error(String error) {
             expected.setError(error);
             return this;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
index 924eae4..568ddf2 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
@@ -33,9 +33,11 @@ import org.keycloak.enums.SslRequired;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.RefreshToken;
 import org.keycloak.services.resources.TokenService;
+import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.OAuthClient;
 import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
@@ -56,6 +58,8 @@ import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import java.net.URI;
+import java.security.PrivateKey;
+import java.security.PublicKey;
 
 import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.assertEquals;
@@ -175,6 +179,54 @@ public class RefreshTokenTest {
         Assert.assertNotEquals(tokenEvent.getDetails().get(Details.REFRESH_TOKEN_ID), refreshEvent.getDetails().get(Details.UPDATED_REFRESH_TOKEN_ID));
     }
 
+    PrivateKey privateKey;
+    PublicKey publicKey;
+
+    @Test
+    public void refreshTokenRealmKeysChanged() throws Exception {
+        oauth.doLogin("test-user@localhost", "password");
+
+        Event loginEvent = events.expectLogin().assertEvent();
+
+        String sessionId = loginEvent.getSessionId();
+        String codeId = loginEvent.getDetails().get(Details.CODE_ID);
+
+        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+
+        AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
+        String refreshTokenString = response.getRefreshToken();
+        RefreshToken refreshToken = oauth.verifyRefreshToken(refreshTokenString);
+
+        events.expectCodeToToken(codeId, sessionId).assertEvent();
+
+        try {
+            keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+                @Override
+                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                    privateKey = appRealm.getPrivateKey();
+                    publicKey = appRealm.getPublicKey();
+                    KeycloakModelUtils.generateRealmKeys(appRealm);
+                }
+            });
+
+            response = oauth.doRefreshTokenRequest(refreshTokenString, "password");
+
+            assertEquals(400, response.getStatusCode());
+            assertEquals("invalid_grant", response.getError());
+
+            events.expectRefresh(refreshToken.getId(), sessionId).user((String) null).session((String) null).clearDetails().error(Errors.INVALID_TOKEN).assertEvent();
+        } finally {
+            keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+                @Override
+                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                    appRealm.setPrivateKey(privateKey);
+                    appRealm.setPublicKey(publicKey);
+                }
+            });
+
+        }
+    }
+
     @Test
     public void refreshTokenUserSessionExpired() {
         oauth.doLogin("test-user@localhost", "password");
@@ -417,5 +469,4 @@ public class RefreshTokenTest {
     }
 
 
-
 }
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 f59c8ef..f172dec 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
@@ -8,6 +8,8 @@ import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.RefreshToken;
 import org.keycloak.services.managers.RealmManager;
@@ -32,6 +34,14 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
             ApplicationModel app = appRealm.addApplication("resource-owner");
             app.setSecret("secret");
             appRealm.setPasswordCredentialGrantAllowed(true);
+
+            UserModel user = session.users().addUser(appRealm, "direct-login");
+            user.setEmail("direct-login@localhost");
+            user.setEnabled(true);
+
+            userId = user.getId();
+
+            session.users().updateCredential(appRealm, user, UserCredentialModel.password("password"));
         }
     });
 
@@ -47,11 +57,22 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
     @WebResource
     protected OAuthClient oauth;
 
+    private static String userId;
+
     @Test
-    public void grantAccessToken() throws Exception {
+    public void grantAccessTokenUsername() throws Exception {
+        grantAccessToken("direct-login");
+    }
+
+    @Test
+    public void grantAccessTokenEmail() throws Exception {
+        grantAccessToken("direct-login@localhost");
+    }
+
+    private void grantAccessToken(String login) throws Exception {
         oauth.clientId("resource-owner");
 
-        OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "password");
+        OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", login, "password");
 
         assertEquals(200, response.getStatusCode());
 
@@ -60,11 +81,13 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
 
         events.expectLogin()
                 .client("resource-owner")
+                .user(userId)
                 .session(accessToken.getSessionState())
                 .detail(Details.AUTH_METHOD, "oauth_credentials")
                 .detail(Details.RESPONSE_TYPE, "token")
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
+                .detail(Details.USERNAME, login)
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
                 .assertEvent();
@@ -79,7 +102,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
         assertEquals(accessToken.getSessionState(), refreshedAccessToken.getSessionState());
         assertEquals(accessToken.getSessionState(), refreshedRefreshToken.getSessionState());
 
-        events.expectRefresh(refreshToken.getId(), refreshToken.getSessionState()).client("resource-owner").assertEvent();
+        events.expectRefresh(refreshToken.getId(), refreshToken.getSessionState()).user(userId).client("resource-owner").assertEvent();
     }
 
     @Test
@@ -187,4 +210,27 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
                 .assertEvent();
     }
 
+    @Test
+    public void grantAccessTokenUserNotFound() throws Exception {
+        oauth.clientId("resource-owner");
+
+        OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "invalid", "invalid");
+
+        assertEquals(400, response.getStatusCode());
+
+        assertEquals("invalid_grant", response.getError());
+
+        events.expectLogin()
+                .client("resource-owner")
+                .user((String) null)
+                .session((String) null)
+                .detail(Details.AUTH_METHOD, "oauth_credentials")
+                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.USERNAME, "invalid")
+                .removeDetail(Details.CODE_ID)
+                .removeDetail(Details.REDIRECT_URI)
+                .error(Errors.INVALID_USER_CREDENTIALS)
+                .assertEvent();
+    }
+
 }