Search in sources :

Example 21 with JWSInput

use of org.keycloak.jose.jws.JWSInput in project keycloak by keycloak.

the class OAuthProofKeyForCodeExchangeTest method expectSuccessfulResponseFromTokenEndpoint.

private void expectSuccessfulResponseFromTokenEndpoint(String codeId, String sessionId, String code) throws Exception {
    OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
    assertEquals(200, response.getStatusCode());
    Assert.assertThat(response.getExpiresIn(), allOf(greaterThanOrEqualTo(250), lessThanOrEqualTo(300)));
    Assert.assertThat(response.getRefreshExpiresIn(), allOf(greaterThanOrEqualTo(1750), lessThanOrEqualTo(1800)));
    assertEquals("Bearer", response.getTokenType());
    String expectedKid = oauth.doCertsRequest("test").getKeys()[0].getKeyId();
    JWSHeader header = new JWSInput(response.getAccessToken()).getHeader();
    assertEquals("RS256", header.getAlgorithm().name());
    assertEquals("JWT", header.getType());
    assertEquals(expectedKid, header.getKeyId());
    assertNull(header.getContentType());
    header = new JWSInput(response.getIdToken()).getHeader();
    assertEquals("RS256", header.getAlgorithm().name());
    assertEquals("JWT", header.getType());
    assertEquals(expectedKid, header.getKeyId());
    assertNull(header.getContentType());
    header = new JWSInput(response.getRefreshToken()).getHeader();
    assertEquals("HS256", header.getAlgorithm().name());
    assertEquals("JWT", header.getType());
    assertNull(header.getContentType());
    AccessToken token = oauth.verifyToken(response.getAccessToken());
    assertEquals(findUserByUsername(adminClient.realm("test"), "test-user@localhost").getId(), token.getSubject());
    Assert.assertNotEquals("test-user@localhost", token.getSubject());
    assertEquals(sessionId, token.getSessionState());
    assertEquals(2, token.getRealmAccess().getRoles().size());
    assertTrue(token.getRealmAccess().isUserInRole("user"));
    assertEquals(1, token.getResourceAccess(oauth.getClientId()).getRoles().size());
    assertTrue(token.getResourceAccess(oauth.getClientId()).isUserInRole("customer-user"));
    EventRepresentation event = events.expectCodeToToken(codeId, sessionId).assertEvent();
    assertEquals(token.getId(), event.getDetails().get(Details.TOKEN_ID));
    assertEquals(oauth.parseRefreshToken(response.getRefreshToken()).getId(), event.getDetails().get(Details.REFRESH_TOKEN_ID));
    assertEquals(sessionId, token.getSessionState());
    // make sure PKCE does not affect token refresh on Token Endpoint
    String refreshTokenString = response.getRefreshToken();
    RefreshToken refreshToken = oauth.parseRefreshToken(refreshTokenString);
    Assert.assertNotNull(refreshTokenString);
    Assert.assertThat(token.getExpiration() - getCurrentTime(), allOf(greaterThanOrEqualTo(200), lessThanOrEqualTo(350)));
    int actual = refreshToken.getExpiration() - getCurrentTime();
    Assert.assertThat(actual, allOf(greaterThanOrEqualTo(1799 - RefreshTokenTest.ALLOWED_CLOCK_SKEW), lessThanOrEqualTo(1800 + RefreshTokenTest.ALLOWED_CLOCK_SKEW)));
    assertEquals(sessionId, refreshToken.getSessionState());
    setTimeOffset(2);
    OAuthClient.AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(refreshTokenString, "password");
    AccessToken refreshedToken = oauth.verifyToken(refreshResponse.getAccessToken());
    RefreshToken refreshedRefreshToken = oauth.parseRefreshToken(refreshResponse.getRefreshToken());
    assertEquals(200, refreshResponse.getStatusCode());
    assertEquals(sessionId, refreshedToken.getSessionState());
    assertEquals(sessionId, refreshedRefreshToken.getSessionState());
    Assert.assertThat(refreshResponse.getExpiresIn(), allOf(greaterThanOrEqualTo(250), lessThanOrEqualTo(300)));
    Assert.assertThat(refreshedToken.getExpiration() - getCurrentTime(), allOf(greaterThanOrEqualTo(250 - RefreshTokenTest.ALLOWED_CLOCK_SKEW), lessThanOrEqualTo(300 + RefreshTokenTest.ALLOWED_CLOCK_SKEW)));
    Assert.assertThat(refreshedToken.getExpiration() - token.getExpiration(), allOf(greaterThanOrEqualTo(1), lessThanOrEqualTo(10)));
    Assert.assertThat(refreshedRefreshToken.getExpiration() - refreshToken.getExpiration(), allOf(greaterThanOrEqualTo(1), lessThanOrEqualTo(10)));
    Assert.assertNotEquals(token.getId(), refreshedToken.getId());
    Assert.assertNotEquals(refreshToken.getId(), refreshedRefreshToken.getId());
    assertEquals("Bearer", refreshResponse.getTokenType());
    assertEquals(findUserByUsername(adminClient.realm("test"), "test-user@localhost").getId(), refreshedToken.getSubject());
    Assert.assertNotEquals("test-user@localhost", refreshedToken.getSubject());
    assertEquals(2, refreshedToken.getRealmAccess().getRoles().size());
    Assert.assertTrue(refreshedToken.getRealmAccess().isUserInRole("user"));
    assertEquals(1, refreshedToken.getResourceAccess(oauth.getClientId()).getRoles().size());
    Assert.assertTrue(refreshedToken.getResourceAccess(oauth.getClientId()).isUserInRole("customer-user"));
    EventRepresentation refreshEvent = events.expectRefresh(event.getDetails().get(Details.REFRESH_TOKEN_ID), sessionId).assertEvent();
    Assert.assertNotEquals(event.getDetails().get(Details.TOKEN_ID), refreshEvent.getDetails().get(Details.TOKEN_ID));
    Assert.assertNotEquals(event.getDetails().get(Details.REFRESH_TOKEN_ID), refreshEvent.getDetails().get(Details.UPDATED_REFRESH_TOKEN_ID));
    setTimeOffset(0);
}
Also used : RefreshToken(org.keycloak.representations.RefreshToken) OAuthClient(org.keycloak.testsuite.util.OAuthClient) AccessToken(org.keycloak.representations.AccessToken) EventRepresentation(org.keycloak.representations.idm.EventRepresentation) JWSInput(org.keycloak.jose.jws.JWSInput) JWSHeader(org.keycloak.jose.jws.JWSHeader)

Example 22 with JWSInput

use of org.keycloak.jose.jws.JWSInput in project keycloak by keycloak.

the class OIDCIdentityProvider method extractIdentity.

protected BrokeredIdentityContext extractIdentity(AccessTokenResponse tokenResponse, String accessToken, JsonWebToken idToken) throws IOException {
    String id = idToken.getSubject();
    BrokeredIdentityContext identity = new BrokeredIdentityContext(id);
    String name = (String) idToken.getOtherClaims().get(IDToken.NAME);
    String givenName = (String) idToken.getOtherClaims().get(IDToken.GIVEN_NAME);
    String familyName = (String) idToken.getOtherClaims().get(IDToken.FAMILY_NAME);
    String preferredUsername = (String) idToken.getOtherClaims().get(getusernameClaimNameForIdToken());
    String email = (String) idToken.getOtherClaims().get(IDToken.EMAIL);
    if (!getConfig().isDisableUserInfoService()) {
        String userInfoUrl = getUserInfoUrl();
        if (userInfoUrl != null && !userInfoUrl.isEmpty()) {
            if (accessToken != null) {
                SimpleHttp.Response response = executeRequest(userInfoUrl, SimpleHttp.doGet(userInfoUrl, session).header("Authorization", "Bearer " + accessToken));
                String contentType = response.getFirstHeader(HttpHeaders.CONTENT_TYPE);
                MediaType contentMediaType;
                try {
                    contentMediaType = MediaType.valueOf(contentType);
                } catch (IllegalArgumentException ex) {
                    contentMediaType = null;
                }
                if (contentMediaType == null || contentMediaType.isWildcardSubtype() || contentMediaType.isWildcardType()) {
                    throw new RuntimeException("Unsupported content-type [" + contentType + "] in response from [" + userInfoUrl + "].");
                }
                JsonNode userInfo;
                if (MediaType.APPLICATION_JSON_TYPE.isCompatible(contentMediaType)) {
                    userInfo = response.asJson();
                } else if (APPLICATION_JWT_TYPE.isCompatible(contentMediaType)) {
                    JWSInput jwsInput;
                    try {
                        jwsInput = new JWSInput(response.asString());
                    } catch (JWSInputException cause) {
                        throw new RuntimeException("Failed to parse JWT userinfo response", cause);
                    }
                    if (verify(jwsInput)) {
                        userInfo = JsonSerialization.readValue(jwsInput.getContent(), JsonNode.class);
                    } else {
                        throw new RuntimeException("Failed to verify signature of userinfo response from [" + userInfoUrl + "].");
                    }
                } else {
                    throw new RuntimeException("Unsupported content-type [" + contentType + "] in response from [" + userInfoUrl + "].");
                }
                id = getJsonProperty(userInfo, "sub");
                name = getJsonProperty(userInfo, "name");
                givenName = getJsonProperty(userInfo, IDToken.GIVEN_NAME);
                familyName = getJsonProperty(userInfo, IDToken.FAMILY_NAME);
                preferredUsername = getUsernameFromUserInfo(userInfo);
                email = getJsonProperty(userInfo, "email");
                AbstractJsonUserAttributeMapper.storeUserProfileForMapper(identity, userInfo, getConfig().getAlias());
            }
        }
    }
    identity.getContextData().put(VALIDATED_ID_TOKEN, idToken);
    identity.setId(id);
    if (givenName != null) {
        identity.setFirstName(givenName);
    }
    if (familyName != null) {
        identity.setLastName(familyName);
    }
    if (givenName == null && familyName == null) {
        identity.setName(name);
    }
    identity.setEmail(email);
    identity.setBrokerUserId(getConfig().getAlias() + "." + id);
    if (preferredUsername == null) {
        preferredUsername = email;
    }
    if (preferredUsername == null) {
        preferredUsername = id;
    }
    identity.setUsername(preferredUsername);
    if (tokenResponse != null && tokenResponse.getSessionState() != null) {
        identity.setBrokerSessionId(getConfig().getAlias() + "." + tokenResponse.getSessionState());
    }
    if (tokenResponse != null)
        identity.getContextData().put(FEDERATED_ACCESS_TOKEN_RESPONSE, tokenResponse);
    if (tokenResponse != null)
        processAccessTokenResponse(identity, tokenResponse);
    return identity;
}
Also used : SimpleHttp(org.keycloak.broker.provider.util.SimpleHttp) MediaType(javax.ws.rs.core.MediaType) JWSInputException(org.keycloak.jose.jws.JWSInputException) JsonNode(com.fasterxml.jackson.databind.JsonNode) JWSInput(org.keycloak.jose.jws.JWSInput) BrokeredIdentityContext(org.keycloak.broker.provider.BrokeredIdentityContext)

Example 23 with JWSInput

use of org.keycloak.jose.jws.JWSInput in project keycloak by keycloak.

the class AbstractGroupTest method login.

AccessToken login(String login, String clientId, String clientSecret, String userId) throws Exception {
    AccessTokenResponse tokenResponse = oauth.doGrantAccessTokenRequest("test", login, "password", null, clientId, clientSecret);
    String accessToken = tokenResponse.getAccessToken();
    String refreshToken = tokenResponse.getRefreshToken();
    PublicKey publicKey = PemUtils.decodePublicKey(ApiUtil.findActiveSigningKey(adminClient.realm("test")).getPublicKey());
    AccessToken accessTokenRepresentation = RSATokenVerifier.verifyToken(accessToken, publicKey, getAuthServerContextRoot() + "/auth/realms/test");
    JWSInput jws = new JWSInput(refreshToken);
    RefreshToken refreshTokenRepresentation = jws.readJsonContent(RefreshToken.class);
    events.expectLogin().client(clientId).user(userId).detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD).detail(Details.TOKEN_ID, accessTokenRepresentation.getId()).detail(Details.REFRESH_TOKEN_ID, refreshTokenRepresentation.getId()).detail(Details.USERNAME, login).removeDetail(Details.CODE_ID).removeDetail(Details.REDIRECT_URI).removeDetail(Details.CONSENT).assertEvent();
    return accessTokenRepresentation;
}
Also used : RefreshToken(org.keycloak.representations.RefreshToken) PublicKey(java.security.PublicKey) AccessToken(org.keycloak.representations.AccessToken) JWSInput(org.keycloak.jose.jws.JWSInput) AccessTokenResponse(org.keycloak.testsuite.util.OAuthClient.AccessTokenResponse)

Example 24 with JWSInput

use of org.keycloak.jose.jws.JWSInput in project keycloak by keycloak.

the class AuthorizationAPITest method testResourceServerAsAudience.

public void testResourceServerAsAudience(String clientId, String resourceServerClientId, String authzConfigFile) throws Exception {
    AuthzClient authzClient = getAuthzClient(authzConfigFile);
    PermissionRequest request = new PermissionRequest();
    request.setResourceId("Resource A");
    String accessToken = new OAuthClient().realm("authz-test").clientId(clientId).doGrantAccessTokenRequest("secret", "marta", "password").getAccessToken();
    String ticket = authzClient.protection().permission().create(request).getTicket();
    // Ticket is opaque to client or resourceServer. The audience should be just an authorization server itself
    JsonWebToken ticketDecoded = JsonSerialization.readValue(new JWSInput(ticket).getContent(), JsonWebToken.class);
    Assert.assertFalse(ticketDecoded.hasAudience(clientId));
    Assert.assertFalse(ticketDecoded.hasAudience(resourceServerClientId));
    AuthorizationResponse response = authzClient.authorization(accessToken).authorize(new AuthorizationRequest(ticket));
    assertNotNull(response.getToken());
    AccessToken rpt = toAccessToken(response.getToken());
    assertEquals(resourceServerClientId, rpt.getAudience()[0]);
}
Also used : PermissionRequest(org.keycloak.representations.idm.authorization.PermissionRequest) AuthzClient(org.keycloak.authorization.client.AuthzClient) AuthorizationRequest(org.keycloak.representations.idm.authorization.AuthorizationRequest) OAuthClient(org.keycloak.testsuite.util.OAuthClient) AccessToken(org.keycloak.representations.AccessToken) JWSInput(org.keycloak.jose.jws.JWSInput) JsonWebToken(org.keycloak.representations.JsonWebToken) AuthorizationResponse(org.keycloak.representations.idm.authorization.AuthorizationResponse)

Example 25 with JWSInput

use of org.keycloak.jose.jws.JWSInput in project keycloak by keycloak.

the class LoginTest method loginSuccessRealmSigningAlgorithms.

@Test
public void loginSuccessRealmSigningAlgorithms() throws JWSInputException {
    ContainerAssume.assumeAuthServerSSL();
    loginPage.open();
    loginPage.login("login-test", "password");
    Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
    Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
    events.expectLogin().user(userId).detail(Details.USERNAME, "login-test").assertEvent();
    driver.navigate().to(getAuthServerContextRoot() + "/auth/realms/test/");
    String keycloakIdentity = driver.manage().getCookieNamed("KEYCLOAK_IDENTITY").getValue();
    // Check identity cookie is signed with HS256
    String algorithm = new JWSInput(keycloakIdentity).getHeader().getAlgorithm().name();
    assertEquals("HS256", algorithm);
    try {
        TokenSignatureUtil.changeRealmTokenSignatureProvider(adminClient, Algorithm.ES256);
        oauth.openLoginForm();
        Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
        driver.navigate().to(getAuthServerContextRoot() + "/auth/realms/test/");
        keycloakIdentity = driver.manage().getCookieNamed("KEYCLOAK_IDENTITY").getValue();
        // Check identity cookie is still signed with HS256
        algorithm = new JWSInput(keycloakIdentity).getHeader().getAlgorithm().name();
        assertEquals("HS256", algorithm);
        // Check identity cookie still works
        oauth.openLoginForm();
        Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
    } finally {
        TokenSignatureUtil.changeRealmTokenSignatureProvider(adminClient, Algorithm.RS256);
    }
}
Also used : Matchers.containsString(org.hamcrest.Matchers.containsString) JWSInput(org.keycloak.jose.jws.JWSInput) Test(org.junit.Test) AbstractTestRealmKeycloakTest(org.keycloak.testsuite.AbstractTestRealmKeycloakTest)

Aggregations

JWSInput (org.keycloak.jose.jws.JWSInput)62 AccessToken (org.keycloak.representations.AccessToken)29 OAuthClient (org.keycloak.testsuite.util.OAuthClient)20 JWSInputException (org.keycloak.jose.jws.JWSInputException)16 Test (org.junit.Test)15 JWSHeader (org.keycloak.jose.jws.JWSHeader)11 Response (javax.ws.rs.core.Response)10 RefreshToken (org.keycloak.representations.RefreshToken)10 EventRepresentation (org.keycloak.representations.idm.EventRepresentation)9 ClientRepresentation (org.keycloak.representations.idm.ClientRepresentation)8 IOException (java.io.IOException)7 VerificationException (org.keycloak.common.VerificationException)7 JsonWebToken (org.keycloak.representations.JsonWebToken)7 JsonNode (com.fasterxml.jackson.databind.JsonNode)5 PublicKey (java.security.PublicKey)5 AccessTokenResponse (org.keycloak.representations.AccessTokenResponse)5 Client (javax.ws.rs.client.Client)4 IDToken (org.keycloak.representations.IDToken)4 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)3 List (java.util.List)3