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/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 {
}
-
}