Search in sources :

Example 76 with AccessToken

use of org.keycloak.representations.AccessToken in project keycloak by keycloak.

the class TokenEndpoint method createTokenResponse.

public Response createTokenResponse(UserModel user, UserSessionModel userSession, ClientSessionContext clientSessionCtx, String scopeParam, boolean code) {
    AccessToken token = tokenManager.createClientAccessToken(session, realm, client, user, userSession, clientSessionCtx);
    TokenManager.AccessTokenResponseBuilder responseBuilder = tokenManager.responseBuilder(realm, client, event, session, userSession, clientSessionCtx).accessToken(token);
    if (OIDCAdvancedConfigWrapper.fromClientModel(client).isUseRefreshToken()) {
        responseBuilder.generateRefreshToken();
    }
    checkMtlsHoKToken(responseBuilder, OIDCAdvancedConfigWrapper.fromClientModel(client).isUseRefreshToken());
    if (TokenUtil.isOIDCRequest(scopeParam)) {
        responseBuilder.generateIDToken().generateAccessTokenHash();
    }
    AccessTokenResponse res = null;
    if (code) {
        try {
            res = responseBuilder.build();
        } catch (RuntimeException re) {
            if ("can not get encryption KEK".equals(re.getMessage())) {
                throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_REQUEST, "can not get encryption KEK", Response.Status.BAD_REQUEST);
            } else {
                throw re;
            }
        }
    } else {
        res = responseBuilder.build();
    }
    event.success();
    return cors.builder(Response.ok(res).type(MediaType.APPLICATION_JSON_TYPE)).build();
}
Also used : AccessToken(org.keycloak.representations.AccessToken) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) TokenManager(org.keycloak.protocol.oidc.TokenManager) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse)

Example 77 with AccessToken

use of org.keycloak.representations.AccessToken in project keycloak by keycloak.

the class TokenManager method validateToken.

public TokenValidation validateToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, RefreshToken oldToken, HttpHeaders headers) throws OAuthErrorException {
    UserSessionModel userSession = null;
    boolean offline = TokenUtil.TOKEN_TYPE_OFFLINE.equals(oldToken.getType());
    if (offline) {
        UserSessionManager sessionManager = new UserSessionManager(session);
        userSession = sessionManager.findOfflineUserSession(realm, oldToken.getSessionState());
        if (userSession != null) {
            // Revoke timeouted offline userSession
            if (!AuthenticationManager.isOfflineSessionValid(realm, userSession)) {
                sessionManager.revokeOfflineUserSession(userSession);
                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Offline session not active", "Offline session not active");
            }
        } else {
            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Offline user session not found", "Offline user session not found");
        }
    } else {
        // Find userSession regularly for online tokens
        userSession = session.sessions().getUserSession(realm, oldToken.getSessionState());
        if (!AuthenticationManager.isSessionValid(realm, userSession)) {
            AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
        }
    }
    UserModel user = userSession.getUser();
    if (user == null) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown user");
    }
    if (!user.isEnabled()) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "User disabled", "User disabled");
    }
    if (oldToken.isIssuedBeforeSessionStart(userSession.getStarted())) {
        logger.debug("Refresh toked issued before the user session started");
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh toked issued before the user session started");
    }
    ClientModel client = session.getContext().getClient();
    AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
    // Can theoretically happen in cross-dc environment. Try to see if userSession with our client is available in remoteCache
    if (clientSession == null) {
        userSession = new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, userSession.getId(), offline, client.getId());
        if (userSession != null) {
            clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
        } else {
            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session doesn't have required client", "Session doesn't have required client");
        }
    }
    if (oldToken.isIssuedBeforeSessionStart(clientSession.getStarted())) {
        logger.debug("Refresh toked issued before the client session started");
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh toked issued before the client session started");
    }
    if (!client.getClientId().equals(oldToken.getIssuedFor())) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients");
    }
    try {
        TokenVerifier.createWithoutSignature(oldToken).withChecks(NotBeforeCheck.forModel(client), NotBeforeCheck.forModel(session, realm, user)).verify();
    } catch (VerificationException e) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token");
    }
    // Setup clientScopes from refresh token to the context
    String oldTokenScope = oldToken.getScope();
    // Case when offline token is migrated from previous version
    if (oldTokenScope == null && userSession.isOffline()) {
        logger.debugf("Migrating offline token of user '%s' for client '%s' of realm '%s'", user.getUsername(), client.getClientId(), realm.getName());
        MigrationUtils.migrateOldOfflineToken(session, realm, client, user);
        oldTokenScope = OAuth2Constants.OFFLINE_ACCESS;
    }
    ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, oldTokenScope, session);
    // Check user didn't revoke granted consent
    if (!verifyConsentStillAvailable(session, user, client, clientSessionCtx.getClientScopesStream())) {
        throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user");
    }
    clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, oldToken.getNonce());
    // recreate token.
    AccessToken newToken = createClientAccessToken(session, realm, client, user, userSession, clientSessionCtx);
    return new TokenValidation(user, userSession, clientSessionCtx, newToken);
}
Also used : UserSessionModel(org.keycloak.models.UserSessionModel) OAuthErrorException(org.keycloak.OAuthErrorException) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) UserSessionCrossDCManager(org.keycloak.services.managers.UserSessionCrossDCManager) UserSessionManager(org.keycloak.services.managers.UserSessionManager) UserModel(org.keycloak.models.UserModel) ClientModel(org.keycloak.models.ClientModel) DefaultClientSessionContext(org.keycloak.services.util.DefaultClientSessionContext) ClientSessionContext(org.keycloak.models.ClientSessionContext) AccessToken(org.keycloak.representations.AccessToken) VerificationException(org.keycloak.common.VerificationException)

Example 78 with AccessToken

use of org.keycloak.representations.AccessToken in project keycloak by keycloak.

the class DefaultTokenExchangeProvider method tokenExchange.

protected Response tokenExchange() {
    UserModel tokenUser = null;
    UserSessionModel tokenSession = null;
    AccessToken token = null;
    String subjectToken = formParams.getFirst(OAuth2Constants.SUBJECT_TOKEN);
    if (subjectToken != null) {
        String subjectTokenType = formParams.getFirst(OAuth2Constants.SUBJECT_TOKEN_TYPE);
        String realmIssuerUrl = Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName());
        String subjectIssuer = formParams.getFirst(OAuth2Constants.SUBJECT_ISSUER);
        if (subjectIssuer == null && OAuth2Constants.JWT_TOKEN_TYPE.equals(subjectTokenType)) {
            try {
                JWSInput jws = new JWSInput(subjectToken);
                JsonWebToken jwt = jws.readJsonContent(JsonWebToken.class);
                subjectIssuer = jwt.getIssuer();
            } catch (JWSInputException e) {
                event.detail(Details.REASON, "unable to parse jwt subject_token");
                event.error(Errors.INVALID_TOKEN);
                throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_TOKEN, "Invalid token type, must be access token", Response.Status.BAD_REQUEST);
            }
        }
        if (subjectIssuer != null && !realmIssuerUrl.equals(subjectIssuer)) {
            event.detail(OAuth2Constants.SUBJECT_ISSUER, subjectIssuer);
            return exchangeExternalToken(subjectIssuer, subjectToken);
        }
        if (subjectTokenType != null && !subjectTokenType.equals(OAuth2Constants.ACCESS_TOKEN_TYPE)) {
            event.detail(Details.REASON, "subject_token supports access tokens only");
            event.error(Errors.INVALID_TOKEN);
            throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_TOKEN, "Invalid token type, must be access token", Response.Status.BAD_REQUEST);
        }
        AuthenticationManager.AuthResult authResult = AuthenticationManager.verifyIdentityToken(session, realm, session.getContext().getUri(), clientConnection, true, true, null, false, subjectToken, headers);
        if (authResult == null) {
            event.detail(Details.REASON, "subject_token validation failure");
            event.error(Errors.INVALID_TOKEN);
            throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_TOKEN, "Invalid token", Response.Status.BAD_REQUEST);
        }
        tokenUser = authResult.getUser();
        tokenSession = authResult.getSession();
        token = authResult.getToken();
    }
    String requestedSubject = formParams.getFirst(OAuth2Constants.REQUESTED_SUBJECT);
    if (requestedSubject != null) {
        event.detail(Details.REQUESTED_SUBJECT, requestedSubject);
        UserModel requestedUser = session.users().getUserByUsername(realm, requestedSubject);
        if (requestedUser == null) {
            requestedUser = session.users().getUserById(realm, requestedSubject);
        }
        if (requestedUser == null) {
            // We always returned access denied to avoid username fishing
            event.detail(Details.REASON, "requested_subject not found");
            event.error(Errors.NOT_ALLOWED);
            throw new CorsErrorResponseException(cors, OAuthErrorException.ACCESS_DENIED, "Client not allowed to exchange", Response.Status.FORBIDDEN);
        }
        if (token != null) {
            event.detail(Details.IMPERSONATOR, tokenUser.getUsername());
            // for this case, the user represented by the token, must have permission to impersonate.
            AdminAuth auth = new AdminAuth(realm, token, tokenUser, client);
            if (!AdminPermissions.evaluator(session, realm, auth).users().canImpersonate(requestedUser)) {
                event.detail(Details.REASON, "subject not allowed to impersonate");
                event.error(Errors.NOT_ALLOWED);
                throw new CorsErrorResponseException(cors, OAuthErrorException.ACCESS_DENIED, "Client not allowed to exchange", Response.Status.FORBIDDEN);
            }
        } else {
            // to impersonate
            if (client.isPublicClient()) {
                event.detail(Details.REASON, "public clients not allowed");
                event.error(Errors.NOT_ALLOWED);
                throw new CorsErrorResponseException(cors, OAuthErrorException.ACCESS_DENIED, "Client not allowed to exchange", Response.Status.FORBIDDEN);
            }
            if (!AdminPermissions.management(session, realm).users().canClientImpersonate(client, requestedUser)) {
                event.detail(Details.REASON, "client not allowed to impersonate");
                event.error(Errors.NOT_ALLOWED);
                throw new CorsErrorResponseException(cors, OAuthErrorException.ACCESS_DENIED, "Client not allowed to exchange", Response.Status.FORBIDDEN);
            }
        }
        tokenSession = session.sessions().createUserSession(realm, requestedUser, requestedUser.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
        if (tokenUser != null) {
            tokenSession.setNote(IMPERSONATOR_ID.toString(), tokenUser.getId());
            tokenSession.setNote(IMPERSONATOR_USERNAME.toString(), tokenUser.getUsername());
        }
        tokenUser = requestedUser;
    }
    String requestedIssuer = formParams.getFirst(OAuth2Constants.REQUESTED_ISSUER);
    if (requestedIssuer == null) {
        return exchangeClientToClient(tokenUser, tokenSession);
    } else {
        try {
            return exchangeToIdentityProvider(tokenUser, tokenSession, requestedIssuer);
        } finally {
            if (subjectToken == null) {
                // we are naked! So need to clean up user session
                try {
                    session.sessions().removeUserSession(realm, tokenSession);
                } catch (Exception ignore) {
                }
            }
        }
    }
}
Also used : UserModel(org.keycloak.models.UserModel) AuthenticationManager(org.keycloak.services.managers.AuthenticationManager) AdminAuth(org.keycloak.services.resources.admin.AdminAuth) UserSessionModel(org.keycloak.models.UserSessionModel) AccessToken(org.keycloak.representations.AccessToken) JWSInputException(org.keycloak.jose.jws.JWSInputException) JWSInput(org.keycloak.jose.jws.JWSInput) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) JsonWebToken(org.keycloak.representations.JsonWebToken) OAuthErrorException(org.keycloak.OAuthErrorException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) JWSInputException(org.keycloak.jose.jws.JWSInputException)

Example 79 with AccessToken

use of org.keycloak.representations.AccessToken in project keycloak by keycloak.

the class TokenManager method createClientAccessToken.

public AccessToken createClientAccessToken(KeycloakSession session, RealmModel realm, ClientModel client, UserModel user, UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
    AccessToken token = initToken(realm, client, user, userSession, clientSessionCtx, session.getContext().getUri());
    token = transformAccessToken(session, token, userSession, clientSessionCtx);
    return token;
}
Also used : AccessToken(org.keycloak.representations.AccessToken)

Example 80 with AccessToken

use of org.keycloak.representations.AccessToken in project keycloak by keycloak.

the class AccessTokenIntrospectionProvider method introspect.

public Response introspect(String token) {
    try {
        AccessToken accessToken = verifyAccessToken(token);
        ObjectNode tokenMetadata;
        if (accessToken != null) {
            tokenMetadata = JsonSerialization.createObjectNode(accessToken);
            tokenMetadata.put("client_id", accessToken.getIssuedFor());
            if (!tokenMetadata.has("username")) {
                if (accessToken.getPreferredUsername() != null) {
                    tokenMetadata.put("username", accessToken.getPreferredUsername());
                } else {
                    UserModel userModel = session.users().getUserById(realm, accessToken.getSubject());
                    if (userModel != null) {
                        tokenMetadata.put("username", userModel.getUsername());
                    }
                }
            }
        } else {
            tokenMetadata = JsonSerialization.createObjectNode();
        }
        tokenMetadata.put("active", accessToken != null);
        return Response.ok(JsonSerialization.writeValueAsBytes(tokenMetadata)).type(MediaType.APPLICATION_JSON_TYPE).build();
    } catch (Exception e) {
        throw new RuntimeException("Error creating token introspection response.", e);
    }
}
Also used : UserModel(org.keycloak.models.UserModel) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) AccessToken(org.keycloak.representations.AccessToken) VerificationException(org.keycloak.common.VerificationException)

Aggregations

AccessToken (org.keycloak.representations.AccessToken)230 Test (org.junit.Test)129 OAuthClient (org.keycloak.testsuite.util.OAuthClient)104 AbstractKeycloakTest (org.keycloak.testsuite.AbstractKeycloakTest)54 RefreshToken (org.keycloak.representations.RefreshToken)45 AuthorizationResponse (org.keycloak.representations.idm.authorization.AuthorizationResponse)37 JWSInput (org.keycloak.jose.jws.JWSInput)29 Permission (org.keycloak.representations.idm.authorization.Permission)28 EventRepresentation (org.keycloak.representations.idm.EventRepresentation)27 Response (javax.ws.rs.core.Response)26 ClientResource (org.keycloak.admin.client.resource.ClientResource)22 VerificationException (org.keycloak.common.VerificationException)19 ClientRepresentation (org.keycloak.representations.idm.ClientRepresentation)19 AccessTokenResponse (org.keycloak.representations.AccessTokenResponse)18 IDToken (org.keycloak.representations.IDToken)18 AuthorizationRequest (org.keycloak.representations.idm.authorization.AuthorizationRequest)17 IOException (java.io.IOException)15 AuthzClient (org.keycloak.authorization.client.AuthzClient)15 ResourceRepresentation (org.keycloak.representations.idm.authorization.ResourceRepresentation)14 ArrayList (java.util.ArrayList)13