Search in sources :

Example 1 with TokenVerifier

use of org.keycloak.TokenVerifier in project keycloak by keycloak.

the class PreAuthActionsHandler method verifyAdminRequest.

protected JWSInput verifyAdminRequest() throws Exception {
    if (!facade.getRequest().isSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) {
        log.warn("SSL is required for adapter admin action");
        facade.getResponse().sendError(403, "ssl required");
        return null;
    }
    String token = StreamUtil.readString(facade.getRequest().getInputStream());
    if (token == null) {
        log.warn("admin request failed, no token");
        facade.getResponse().sendError(403, "no token");
        return null;
    }
    try {
        // Check just signature. Other things checked in validateAction
        TokenVerifier tokenVerifier = AdapterTokenVerifier.createVerifier(token, deployment, false, JsonWebToken.class);
        tokenVerifier.verify();
        return new JWSInput(token);
    } catch (VerificationException ignore) {
        log.warn("admin request failed, unable to verify token: " + ignore.getMessage());
        if (log.isDebugEnabled()) {
            log.debug(ignore.getMessage(), ignore);
        }
        facade.getResponse().sendError(403, "token failed verification");
        return null;
    }
}
Also used : TokenVerifier(org.keycloak.TokenVerifier) AdapterTokenVerifier(org.keycloak.adapters.rotation.AdapterTokenVerifier) VerificationException(org.keycloak.common.VerificationException) JWSInput(org.keycloak.jose.jws.JWSInput)

Example 2 with TokenVerifier

use of org.keycloak.TokenVerifier in project keycloak by keycloak.

the class ClientRegistrationTokenUtils method verifyToken.

public static TokenVerification verifyToken(KeycloakSession session, RealmModel realm, String token) {
    if (token == null) {
        return TokenVerification.error(new RuntimeException("Missing token"));
    }
    String kid;
    JsonWebToken jwt;
    try {
        TokenVerifier<JsonWebToken> verifier = TokenVerifier.create(token, JsonWebToken.class).withChecks(new TokenVerifier.RealmUrlCheck(getIssuer(session, realm)), TokenVerifier.IS_ACTIVE);
        SignatureVerifierContext verifierContext = session.getProvider(SignatureProvider.class, verifier.getHeader().getAlgorithm().name()).verifier(verifier.getHeader().getKeyId());
        verifier.verifierContext(verifierContext);
        kid = verifierContext.getKid();
        verifier.verify();
        jwt = verifier.getToken();
    } catch (VerificationException e) {
        return TokenVerification.error(new RuntimeException("Failed decode token", e));
    }
    if (!(TokenUtil.TOKEN_TYPE_BEARER.equals(jwt.getType()) || TYPE_INITIAL_ACCESS_TOKEN.equals(jwt.getType()) || TYPE_REGISTRATION_ACCESS_TOKEN.equals(jwt.getType()))) {
        return TokenVerification.error(new RuntimeException("Invalid type of token"));
    }
    return TokenVerification.success(kid, jwt);
}
Also used : SignatureProvider(org.keycloak.crypto.SignatureProvider) SignatureVerifierContext(org.keycloak.crypto.SignatureVerifierContext) TokenVerifier(org.keycloak.TokenVerifier) VerificationException(org.keycloak.common.VerificationException) JsonWebToken(org.keycloak.representations.JsonWebToken)

Example 3 with TokenVerifier

use of org.keycloak.TokenVerifier in project keycloak by keycloak.

the class ClientTokenExchangeTest method testImpersonation.

@Test
@UncaughtServerErrorExpected
public void testImpersonation() throws Exception {
    testingClient.server().run(ClientTokenExchangeTest::setupRealm);
    oauth.realm(TEST);
    oauth.clientId("client-exchanger");
    Client httpClient = AdminClientUtil.createResteasyClient();
    WebTarget exchangeUrl = httpClient.target(OAuthClient.AUTH_SERVER_ROOT).path("/realms").path(TEST).path("protocol/openid-connect/token");
    System.out.println("Exchange url: " + exchangeUrl.getUri().toString());
    OAuthClient.AccessTokenResponse tokenResponse = oauth.doGrantAccessTokenRequest("secret", "user", "password");
    String accessToken = tokenResponse.getAccessToken();
    TokenVerifier<AccessToken> accessTokenVerifier = TokenVerifier.create(accessToken, AccessToken.class);
    AccessToken token = accessTokenVerifier.parse().getToken();
    Assert.assertEquals(token.getPreferredUsername(), "user");
    Assert.assertTrue(token.getRealmAccess() == null || !token.getRealmAccess().isUserInRole("example"));
    // client-exchanger can impersonate from token "user" to user "impersonated-user"
    {
        Response response = exchangeUrl.request().header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader("client-exchanger", "secret")).post(Entity.form(new Form().param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE).param(OAuth2Constants.SUBJECT_TOKEN, accessToken).param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE).param(OAuth2Constants.REQUESTED_SUBJECT, "impersonated-user")));
        org.junit.Assert.assertEquals(200, response.getStatus());
        AccessTokenResponse accessTokenResponse = response.readEntity(AccessTokenResponse.class);
        response.close();
        String exchangedTokenString = accessTokenResponse.getToken();
        TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
        AccessToken exchangedToken = verifier.parse().getToken();
        Assert.assertEquals("client-exchanger", exchangedToken.getIssuedFor());
        Assert.assertNull(exchangedToken.getAudience());
        Assert.assertEquals("impersonated-user", exchangedToken.getPreferredUsername());
        Assert.assertNull(exchangedToken.getRealmAccess());
        Object impersonatorRaw = exchangedToken.getOtherClaims().get("impersonator");
        Assert.assertThat(impersonatorRaw, instanceOf(Map.class));
        Map impersonatorClaim = (Map) impersonatorRaw;
        Assert.assertEquals(token.getSubject(), impersonatorClaim.get("id"));
        Assert.assertEquals("user", impersonatorClaim.get("username"));
    }
    // client-exchanger can impersonate from token "user" to user "impersonated-user" and to "target" client
    {
        Response response = exchangeUrl.request().header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader("client-exchanger", "secret")).post(Entity.form(new Form().param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE).param(OAuth2Constants.SUBJECT_TOKEN, accessToken).param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE).param(OAuth2Constants.REQUESTED_SUBJECT, "impersonated-user").param(OAuth2Constants.AUDIENCE, "target")));
        org.junit.Assert.assertEquals(200, response.getStatus());
        AccessTokenResponse accessTokenResponse = response.readEntity(AccessTokenResponse.class);
        response.close();
        String exchangedTokenString = accessTokenResponse.getToken();
        TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
        AccessToken exchangedToken = verifier.parse().getToken();
        Assert.assertEquals("client-exchanger", exchangedToken.getIssuedFor());
        Assert.assertEquals("target", exchangedToken.getAudience()[0]);
        Assert.assertEquals(exchangedToken.getPreferredUsername(), "impersonated-user");
        Assert.assertTrue(exchangedToken.getRealmAccess().isUserInRole("example"));
    }
}
Also used : OAuthClient(org.keycloak.testsuite.util.OAuthClient) Form(javax.ws.rs.core.Form) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse) Response(javax.ws.rs.core.Response) AccessToken(org.keycloak.representations.AccessToken) TokenVerifier(org.keycloak.TokenVerifier) WebTarget(javax.ws.rs.client.WebTarget) OAuthClient(org.keycloak.testsuite.util.OAuthClient) Client(javax.ws.rs.client.Client) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse) Map(java.util.Map) AbstractKeycloakTest(org.keycloak.testsuite.AbstractKeycloakTest) Test(org.junit.Test) UncaughtServerErrorExpected(org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected)

Example 4 with TokenVerifier

use of org.keycloak.TokenVerifier in project keycloak by keycloak.

the class LoginActionsService method handleActionToken.

protected <T extends JsonWebToken & ActionTokenKeyModel> Response handleActionToken(String tokenString, String execution, String clientId, String tabId) {
    T token;
    ActionTokenHandler<T> handler;
    ActionTokenContext<T> tokenContext;
    String eventError = null;
    String defaultErrorMessage = null;
    AuthenticationSessionModel authSession = null;
    // Setup client, so error page will contain "back to application" link
    ClientModel client = null;
    if (clientId != null) {
        client = realm.getClientByClientId(clientId);
    }
    AuthenticationSessionManager authenticationSessionManager = new AuthenticationSessionManager(session);
    if (client != null) {
        session.getContext().setClient(client);
        authSession = authenticationSessionManager.getCurrentAuthenticationSession(realm, client, tabId);
    }
    event.event(EventType.EXECUTE_ACTION_TOKEN);
    // First resolve action token handler
    try {
        if (tokenString == null) {
            throw new ExplainedTokenVerificationException(null, Errors.NOT_ALLOWED, Messages.INVALID_REQUEST);
        }
        TokenVerifier<DefaultActionTokenKey> tokenVerifier = TokenVerifier.create(tokenString, DefaultActionTokenKey.class);
        DefaultActionTokenKey aToken = tokenVerifier.getToken();
        event.detail(Details.TOKEN_ID, aToken.getId()).detail(Details.ACTION, aToken.getActionId()).user(aToken.getUserId());
        handler = resolveActionTokenHandler(aToken.getActionId());
        eventError = handler.getDefaultEventError();
        defaultErrorMessage = handler.getDefaultErrorMessage();
        if (!realm.isEnabled()) {
            throw new ExplainedTokenVerificationException(aToken, Errors.REALM_DISABLED, Messages.REALM_NOT_ENABLED);
        }
        if (!checkSsl()) {
            throw new ExplainedTokenVerificationException(aToken, Errors.SSL_REQUIRED, Messages.HTTPS_REQUIRED);
        }
        TokenVerifier<DefaultActionTokenKey> verifier = tokenVerifier.withChecks(// Token introspection checks
        TokenVerifier.IS_ACTIVE, new TokenVerifier.RealmUrlCheck(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName())), ACTION_TOKEN_BASIC_CHECKS);
        String kid = verifier.getHeader().getKeyId();
        String algorithm = verifier.getHeader().getAlgorithm().name();
        SignatureVerifierContext signatureVerifier = session.getProvider(SignatureProvider.class, algorithm).verifier(kid);
        verifier.verifierContext(signatureVerifier);
        verifier.verify();
        token = TokenVerifier.create(tokenString, handler.getTokenClass()).getToken();
    } catch (TokenNotActiveException ex) {
        if (authSession != null) {
            event.clone().error(Errors.EXPIRED_CODE);
            String flowPath = authSession.getClientNote(AuthorizationEndpointBase.APP_INITIATED_FLOW);
            if (flowPath == null) {
                flowPath = AUTHENTICATE_PATH;
            }
            AuthenticationProcessor.resetFlow(authSession, flowPath);
            // Process correct flow
            return processFlowFromPath(flowPath, authSession, Messages.EXPIRED_ACTION_TOKEN_SESSION_EXISTS);
        }
        return handleActionTokenVerificationException(null, ex, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION_TOKEN_NO_SESSION);
    } catch (ExplainedTokenVerificationException ex) {
        return handleActionTokenVerificationException(null, ex, ex.getErrorEvent(), ex.getMessage());
    } catch (ExplainedVerificationException ex) {
        return handleActionTokenVerificationException(null, ex, ex.getErrorEvent(), ex.getMessage());
    } catch (VerificationException ex) {
        return handleActionTokenVerificationException(null, ex, eventError, defaultErrorMessage);
    }
    // Now proceed with the verification and handle the token
    tokenContext = new ActionTokenContext(session, realm, session.getContext().getUri(), clientConnection, request, event, handler, execution, this::processFlow, this::brokerLoginFlow);
    try {
        String tokenAuthSessionCompoundId = handler.getAuthenticationSessionIdFromToken(token, tokenContext, authSession);
        if (tokenAuthSessionCompoundId != null) {
            // This can happen if the token contains ID but user opens the link in a new browser
            String sessionId = AuthenticationSessionCompoundId.encoded(tokenAuthSessionCompoundId).getRootSessionId();
            LoginActionsServiceChecks.checkNotLoggedInYet(tokenContext, authSession, sessionId);
        }
        if (authSession == null) {
            authSession = handler.startFreshAuthenticationSession(token, tokenContext);
            tokenContext.setAuthenticationSession(authSession, true);
        } else if (tokenAuthSessionCompoundId == null || !LoginActionsServiceChecks.doesAuthenticationSessionFromCookieMatchOneFromToken(tokenContext, authSession, tokenAuthSessionCompoundId)) {
            // There exists an authentication session but no auth session ID was received in the action token
            logger.debugf("Authentication session in progress but no authentication session ID was found in action token %s, restarting.", token.getId());
            authenticationSessionManager.removeAuthenticationSession(realm, authSession, false);
            authSession = handler.startFreshAuthenticationSession(token, tokenContext);
            tokenContext.setAuthenticationSession(authSession, true);
            processLocaleParam(authSession);
        }
        initLoginEvent(authSession);
        event.event(handler.eventType());
        LoginActionsServiceChecks.checkIsUserValid(token, tokenContext);
        LoginActionsServiceChecks.checkIsClientValid(token, tokenContext);
        session.getContext().setClient(authSession.getClient());
        TokenVerifier.createWithoutSignature(token).withChecks(handler.getVerifiers(tokenContext)).verify();
        authSession = tokenContext.getAuthenticationSession();
        event = tokenContext.getEvent();
        event.event(handler.eventType());
        if (!handler.canUseTokenRepeatedly(token, tokenContext)) {
            LoginActionsServiceChecks.checkTokenWasNotUsedYet(token, tokenContext);
            authSession.setAuthNote(AuthenticationManager.INVALIDATE_ACTION_TOKEN, token.serializeKey());
        }
        authSession.setAuthNote(DefaultActionTokenKey.ACTION_TOKEN_USER_ID, token.getUserId());
        authSession.setAuthNote(Constants.KEY, tokenString);
        return handler.handleToken(token, tokenContext);
    } catch (ExplainedTokenVerificationException ex) {
        return handleActionTokenVerificationException(tokenContext, ex, ex.getErrorEvent(), ex.getMessage());
    } catch (LoginActionsServiceException ex) {
        Response response = ex.getResponse();
        return response == null ? handleActionTokenVerificationException(tokenContext, ex, eventError, defaultErrorMessage) : response;
    } catch (VerificationException ex) {
        return handleActionTokenVerificationException(tokenContext, ex, eventError, defaultErrorMessage);
    }
}
Also used : TokenNotActiveException(org.keycloak.exceptions.TokenNotActiveException) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) SignatureVerifierContext(org.keycloak.crypto.SignatureVerifierContext) ExplainedVerificationException(org.keycloak.authentication.ExplainedVerificationException) ActionTokenContext(org.keycloak.authentication.actiontoken.ActionTokenContext) DefaultActionTokenKey(org.keycloak.authentication.actiontoken.DefaultActionTokenKey) AuthenticationSessionManager(org.keycloak.services.managers.AuthenticationSessionManager) Response(javax.ws.rs.core.Response) ClientModel(org.keycloak.models.ClientModel) SignatureProvider(org.keycloak.crypto.SignatureProvider) GET(javax.ws.rs.GET) POST(javax.ws.rs.POST) ExplainedTokenVerificationException(org.keycloak.authentication.actiontoken.ExplainedTokenVerificationException) TokenVerifier(org.keycloak.TokenVerifier) VerificationException(org.keycloak.common.VerificationException) ExplainedVerificationException(org.keycloak.authentication.ExplainedVerificationException) ExplainedTokenVerificationException(org.keycloak.authentication.actiontoken.ExplainedTokenVerificationException)

Example 5 with TokenVerifier

use of org.keycloak.TokenVerifier in project keycloak by keycloak.

the class ClientTokenExchangeTest method testExchange.

@Test
@UncaughtServerErrorExpected
public void testExchange() throws Exception {
    testingClient.server().run(ClientTokenExchangeTest::setupRealm);
    oauth.realm(TEST);
    oauth.clientId("client-exchanger");
    OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "user", "password");
    String accessToken = response.getAccessToken();
    TokenVerifier<AccessToken> accessTokenVerifier = TokenVerifier.create(accessToken, AccessToken.class);
    AccessToken token = accessTokenVerifier.parse().getToken();
    Assert.assertEquals(token.getPreferredUsername(), "user");
    Assert.assertTrue(token.getRealmAccess() == null || !token.getRealmAccess().isUserInRole("example"));
    {
        response = oauth.doTokenExchange(TEST, accessToken, "target", "client-exchanger", "secret");
        String exchangedTokenString = response.getAccessToken();
        TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
        AccessToken exchangedToken = verifier.parse().getToken();
        Assert.assertEquals("client-exchanger", exchangedToken.getIssuedFor());
        Assert.assertEquals("target", exchangedToken.getAudience()[0]);
        Assert.assertEquals(exchangedToken.getPreferredUsername(), "user");
        Assert.assertTrue(exchangedToken.getRealmAccess().isUserInRole("example"));
    }
    {
        response = oauth.doTokenExchange(TEST, accessToken, "target", "legal", "secret");
        String exchangedTokenString = response.getAccessToken();
        TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
        AccessToken exchangedToken = verifier.parse().getToken();
        Assert.assertEquals("legal", exchangedToken.getIssuedFor());
        Assert.assertEquals("target", exchangedToken.getAudience()[0]);
        Assert.assertEquals(exchangedToken.getPreferredUsername(), "user");
        Assert.assertTrue(exchangedToken.getRealmAccess().isUserInRole("example"));
    }
    {
        response = oauth.doTokenExchange(TEST, accessToken, "target", "illegal", "secret");
        Assert.assertEquals(403, response.getStatusCode());
    }
}
Also used : OAuthClient(org.keycloak.testsuite.util.OAuthClient) AccessToken(org.keycloak.representations.AccessToken) TokenVerifier(org.keycloak.TokenVerifier) AbstractKeycloakTest(org.keycloak.testsuite.AbstractKeycloakTest) Test(org.junit.Test) UncaughtServerErrorExpected(org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected)

Aggregations

TokenVerifier (org.keycloak.TokenVerifier)6 Response (javax.ws.rs.core.Response)3 Test (org.junit.Test)3 VerificationException (org.keycloak.common.VerificationException)3 AccessToken (org.keycloak.representations.AccessToken)3 AbstractKeycloakTest (org.keycloak.testsuite.AbstractKeycloakTest)3 UncaughtServerErrorExpected (org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected)3 OAuthClient (org.keycloak.testsuite.util.OAuthClient)3 Client (javax.ws.rs.client.Client)2 WebTarget (javax.ws.rs.client.WebTarget)2 Form (javax.ws.rs.core.Form)2 SignatureProvider (org.keycloak.crypto.SignatureProvider)2 SignatureVerifierContext (org.keycloak.crypto.SignatureVerifierContext)2 AccessTokenResponse (org.keycloak.representations.AccessTokenResponse)2 Map (java.util.Map)1 GET (javax.ws.rs.GET)1 POST (javax.ws.rs.POST)1 AdapterTokenVerifier (org.keycloak.adapters.rotation.AdapterTokenVerifier)1 ExplainedVerificationException (org.keycloak.authentication.ExplainedVerificationException)1 ActionTokenContext (org.keycloak.authentication.actiontoken.ActionTokenContext)1