Verification of iss at refresh token request
Added iss checking using the existing TokenVerifier.RealmUrlCheck in the verifyRefreshToken method. Closes #22191
This commit is contained in:
parent
1bd6aca629
commit
84112f57b5
3 changed files with 49 additions and 8 deletions
|
@ -107,7 +107,7 @@ public class TokenVerifier<T extends JsonWebToken> {
|
|||
}
|
||||
|
||||
if (! this.realmUrl.equals(t.getIssuer())) {
|
||||
throw new VerificationException("Invalid token issuer. Expected '" + this.realmUrl + "', but was '" + t.getIssuer() + "'");
|
||||
throw new VerificationException("Invalid token issuer. Expected '" + this.realmUrl + "'");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -78,6 +78,7 @@ import org.keycloak.representations.LogoutToken;
|
|||
import org.keycloak.representations.RefreshToken;
|
||||
import org.keycloak.representations.dpop.DPoP;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.Urls;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.AuthenticationSessionManager;
|
||||
import org.keycloak.services.managers.UserSessionCrossDCManager;
|
||||
|
@ -477,15 +478,18 @@ public class TokenManager {
|
|||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token");
|
||||
}
|
||||
|
||||
TokenVerifier<RefreshToken> tokenVerifier = TokenVerifier.createWithoutSignature(refreshToken)
|
||||
.withChecks(new TokenVerifier.RealmUrlCheck(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName())));
|
||||
|
||||
if (checkExpiration) {
|
||||
tokenVerifier.withChecks(NotBeforeCheck.forModel(realm), TokenVerifier.IS_ACTIVE);
|
||||
}
|
||||
|
||||
try {
|
||||
TokenVerifier.createWithoutSignature(refreshToken)
|
||||
.withChecks(NotBeforeCheck.forModel(realm), TokenVerifier.IS_ACTIVE)
|
||||
.verify();
|
||||
tokenVerifier.verify();
|
||||
} catch (VerificationException e) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (!client.getClientId().equals(refreshToken.getIssuedFor())) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token. Token client and authorized client don't match");
|
||||
|
|
|
@ -60,6 +60,7 @@ import org.keycloak.services.managers.AuthenticationSessionManager;
|
|||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.arquillian.undertow.lb.SimpleUndertowLoadBalancer;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
|
||||
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
||||
|
@ -107,6 +108,7 @@ import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
|||
import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername;
|
||||
import static org.keycloak.testsuite.util.OAuthClient.AUTH_SERVER_ROOT;
|
||||
import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_SSL_REQUIRED;
|
||||
import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getHttpAuthServerContextRoot;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
|
@ -284,6 +286,41 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
|
|||
assertEquals("123456", refreshedToken.getNonce());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshTokenWithDifferentIssuer() throws Exception {
|
||||
final String proxyHost = "proxy.kc.127.0.0.1.nip.io";
|
||||
final int httpPort = 8666;
|
||||
final int httpsPort = 8667;
|
||||
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
EventRepresentation loginEvent = events.expectLogin().assertEvent();
|
||||
|
||||
String sessionId = loginEvent.getSessionId();
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
|
||||
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||
String refreshTokenString = response.getRefreshToken();
|
||||
|
||||
events.expectCodeToToken(codeId, sessionId).assertEvent();
|
||||
|
||||
SimpleUndertowLoadBalancer proxy = new SimpleUndertowLoadBalancer(proxyHost, httpPort, httpsPort, "node1=" + getHttpAuthServerContextRoot() + "/auth");
|
||||
proxy.start();
|
||||
|
||||
oauth.baseUrl(String.format("http://%s:%s", proxyHost, httpPort));
|
||||
|
||||
response = oauth.doRefreshTokenRequest(refreshTokenString, "password");
|
||||
|
||||
Assert.assertEquals(400, response.getStatusCode());
|
||||
events.expect(EventType.REFRESH_TOKEN).error(Errors.INVALID_TOKEN).user((String) null).assertEvent();
|
||||
|
||||
proxy.stop();
|
||||
|
||||
oauth.baseUrl(AUTH_SERVER_ROOT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshTokenWithAccessToken() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
|
Loading…
Reference in a new issue