Search in sources :

Example 6 with CorsErrorResponseException

use of org.keycloak.services.CorsErrorResponseException in project keycloak by keycloak.

the class LogoutEndpoint method authorizeClient.

private ClientModel authorizeClient() {
    ClientModel client = AuthorizeClientUtil.authorizeClient(session, event, cors).getClient();
    cors.allowedOrigins(session, client);
    if (client.isBearerOnly()) {
        throw new CorsErrorResponseException(cors, Errors.INVALID_CLIENT, "Bearer-only not allowed", Response.Status.BAD_REQUEST);
    }
    return client;
}
Also used : ClientModel(org.keycloak.models.ClientModel) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException)

Example 7 with CorsErrorResponseException

use of org.keycloak.services.CorsErrorResponseException in project keycloak by keycloak.

the class TokenEndpoint method permissionGrant.

public Response permissionGrant() {
    event.detail(Details.AUTH_METHOD, "oauth_credentials");
    String accessTokenString = null;
    String authorizationHeader = headers.getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
    if (authorizationHeader != null && authorizationHeader.toLowerCase().startsWith("bearer")) {
        accessTokenString = new AppAuthManager().extractAuthorizationHeaderToken(headers);
    }
    // public clients don't have secret and should be able to obtain a RPT by providing an access token previously issued by the server
    if (accessTokenString != null) {
        AccessToken accessToken = Tokens.getAccessToken(session);
        if (accessToken == null) {
            try {
                // In case the access token is invalid because it's expired or the user is disabled, identify the client
                // from the access token anyway in order to set correct CORS headers.
                AccessToken invalidToken = new JWSInput(accessTokenString).readJsonContent(AccessToken.class);
                ClientModel client = realm.getClientByClientId(invalidToken.getIssuedFor());
                cors.allowedOrigins(session, client);
                event.client(client);
            } catch (JWSInputException ignore) {
            }
            event.error(Errors.INVALID_TOKEN);
            throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Invalid bearer token", Status.UNAUTHORIZED);
        }
        ClientModel client = realm.getClientByClientId(accessToken.getIssuedFor());
        session.getContext().setClient(client);
        cors.allowedOrigins(session, client);
        event.client(client);
    }
    String claimToken = null;
    // claim_token is optional, if provided we just grab it from the request
    if (formParams.containsKey("claim_token")) {
        claimToken = formParams.get("claim_token").get(0);
    }
    String claimTokenFormat = formParams.getFirst("claim_token_format");
    if (claimToken != null && claimTokenFormat == null) {
        claimTokenFormat = AuthorizationTokenService.CLAIM_TOKEN_FORMAT_ID_TOKEN;
    }
    String subjectToken = formParams.getFirst("subject_token");
    if (accessTokenString == null) {
        // in case no bearer token is provided, we force client authentication
        checkClient();
        // if a claim token is provided, we check if the format is a OpenID Connect IDToken and assume the token represents the identity asking for permissions
        if (AuthorizationTokenService.CLAIM_TOKEN_FORMAT_ID_TOKEN.equalsIgnoreCase(claimTokenFormat)) {
            accessTokenString = claimToken;
        } else if (subjectToken != null) {
            accessTokenString = subjectToken;
        } else {
            // Clients need to authenticate in order to obtain a RPT from the server.
            // In order to support cases where the client is obtaining permissions on its on behalf, we issue a temporary access token
            accessTokenString = AccessTokenResponse.class.cast(clientCredentialsGrant().getEntity()).getToken();
        }
    }
    AuthorizationTokenService.KeycloakAuthorizationRequest authorizationRequest = new AuthorizationTokenService.KeycloakAuthorizationRequest(session.getProvider(AuthorizationProvider.class), tokenManager, event, this.request, cors, clientConnection);
    authorizationRequest.setTicket(formParams.getFirst("ticket"));
    authorizationRequest.setClaimToken(claimToken);
    authorizationRequest.setClaimTokenFormat(claimTokenFormat);
    authorizationRequest.setPct(formParams.getFirst("pct"));
    String rpt = formParams.getFirst("rpt");
    if (rpt != null) {
        AccessToken accessToken = session.tokens().decode(rpt, AccessToken.class);
        if (accessToken == null) {
            event.error(Errors.INVALID_REQUEST);
            throw new CorsErrorResponseException(cors, "invalid_rpt", "RPT signature is invalid", Status.FORBIDDEN);
        }
        authorizationRequest.setRpt(accessToken);
    }
    authorizationRequest.setScope(formParams.getFirst("scope"));
    String audienceParam = formParams.getFirst("audience");
    authorizationRequest.setAudience(audienceParam);
    authorizationRequest.setSubjectToken(accessTokenString);
    event.detail(Details.AUDIENCE, audienceParam);
    String submitRequest = formParams.getFirst("submit_request");
    authorizationRequest.setSubmitRequest(submitRequest == null ? true : Boolean.valueOf(submitRequest));
    // permissions have a format like RESOURCE#SCOPE1,SCOPE2
    List<String> permissions = formParams.get("permission");
    if (permissions != null) {
        event.detail(Details.PERMISSION, String.join("|", permissions));
        for (String permission : permissions) {
            String[] parts = permission.split("#");
            String resource = parts[0];
            if (parts.length == 1) {
                authorizationRequest.addPermission(resource);
            } else {
                String[] scopes = parts[1].split(",");
                authorizationRequest.addPermission(parts[0], scopes);
            }
        }
    }
    Metadata metadata = new Metadata();
    String responseIncludeResourceName = formParams.getFirst("response_include_resource_name");
    if (responseIncludeResourceName != null) {
        metadata.setIncludeResourceName(Boolean.parseBoolean(responseIncludeResourceName));
    }
    String responsePermissionsLimit = formParams.getFirst("response_permissions_limit");
    if (responsePermissionsLimit != null) {
        metadata.setLimit(Integer.parseInt(responsePermissionsLimit));
    }
    metadata.setResponseMode(formParams.getFirst("response_mode"));
    authorizationRequest.setMetadata(metadata);
    Response authorizationResponse = AuthorizationTokenService.instance().authorize(authorizationRequest);
    event.success();
    return authorizationResponse;
}
Also used : AuthorizationProvider(org.keycloak.authorization.AuthorizationProvider) Metadata(org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata) JWSInputException(org.keycloak.jose.jws.JWSInputException) JWSInput(org.keycloak.jose.jws.JWSInput) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse) Response(javax.ws.rs.core.Response) HttpResponse(org.jboss.resteasy.spi.HttpResponse) ClientModel(org.keycloak.models.ClientModel) AuthorizationTokenService(org.keycloak.authorization.authorization.AuthorizationTokenService) AccessToken(org.keycloak.representations.AccessToken) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse) AppAuthManager(org.keycloak.services.managers.AppAuthManager)

Example 8 with CorsErrorResponseException

use of org.keycloak.services.CorsErrorResponseException 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 9 with CorsErrorResponseException

use of org.keycloak.services.CorsErrorResponseException in project keycloak by keycloak.

the class TokenEndpoint method clientCredentialsGrant.

public Response clientCredentialsGrant() {
    if (client.isBearerOnly()) {
        event.error(Errors.INVALID_CLIENT);
        throw new CorsErrorResponseException(cors, OAuthErrorException.UNAUTHORIZED_CLIENT, "Bearer-only client not allowed to retrieve service account", Response.Status.UNAUTHORIZED);
    }
    if (client.isPublicClient()) {
        event.error(Errors.INVALID_CLIENT);
        throw new CorsErrorResponseException(cors, OAuthErrorException.UNAUTHORIZED_CLIENT, "Public client not allowed to retrieve service account", Response.Status.UNAUTHORIZED);
    }
    if (!client.isServiceAccountsEnabled()) {
        event.error(Errors.INVALID_CLIENT);
        throw new CorsErrorResponseException(cors, OAuthErrorException.UNAUTHORIZED_CLIENT, "Client not enabled to retrieve service account", Response.Status.UNAUTHORIZED);
    }
    UserModel clientUser = session.users().getServiceAccount(client);
    if (clientUser == null || client.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER) == null) {
        // May need to handle bootstrap here as well
        logger.debugf("Service account user for client '%s' not found or default protocol mapper for service account not found. Creating now", client.getClientId());
        new ClientManager(new RealmManager(session)).enableServiceAccount(client);
        clientUser = session.users().getServiceAccount(client);
    }
    String clientUsername = clientUser.getUsername();
    event.detail(Details.USERNAME, clientUsername);
    event.user(clientUser);
    if (!clientUser.isEnabled()) {
        event.error(Errors.USER_DISABLED);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_REQUEST, "User '" + clientUsername + "' disabled", Response.Status.UNAUTHORIZED);
    }
    String scope = getRequestedScopes();
    RootAuthenticationSessionModel rootAuthSession = new AuthenticationSessionManager(session).createAuthenticationSession(realm, false);
    AuthenticationSessionModel authSession = rootAuthSession.createAuthenticationSession(client);
    authSession.setAuthenticatedUser(clientUser);
    authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
    authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
    authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
    // persisting of userSession by default
    UserSessionModel.SessionPersistenceState sessionPersistenceState = UserSessionModel.SessionPersistenceState.PERSISTENT;
    boolean useRefreshToken = OIDCAdvancedConfigWrapper.fromClientModel(client).isUseRefreshTokenForClientCredentialsGrant();
    if (!useRefreshToken) {
        // we don't want to store a session hence we mark it as transient, see KEYCLOAK-9551
        sessionPersistenceState = UserSessionModel.SessionPersistenceState.TRANSIENT;
    }
    UserSessionModel userSession = session.sessions().createUserSession(authSession.getParentSession().getId(), realm, clientUser, clientUsername, clientConnection.getRemoteAddr(), ServiceAccountConstants.CLIENT_AUTH, false, null, null, sessionPersistenceState);
    event.session(userSession);
    AuthenticationManager.setClientScopesInSession(authSession);
    ClientSessionContext clientSessionCtx = TokenManager.attachAuthenticationSession(session, userSession, authSession);
    // Notes about client details
    userSession.setNote(ServiceAccountConstants.CLIENT_ID, client.getClientId());
    userSession.setNote(ServiceAccountConstants.CLIENT_HOST, clientConnection.getRemoteHost());
    userSession.setNote(ServiceAccountConstants.CLIENT_ADDRESS, clientConnection.getRemoteAddr());
    try {
        session.clientPolicy().triggerOnEvent(new ServiceAccountTokenRequestContext(formParams, clientSessionCtx.getClientSession()));
    } catch (ClientPolicyException cpe) {
        event.error(cpe.getError());
        throw new CorsErrorResponseException(cors, cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
    }
    updateUserSessionFromClientAuth(userSession);
    TokenManager.AccessTokenResponseBuilder responseBuilder = tokenManager.responseBuilder(realm, client, event, session, userSession, clientSessionCtx).generateAccessToken();
    // Make refresh token generation optional, see KEYCLOAK-9551
    if (useRefreshToken) {
        responseBuilder = responseBuilder.generateRefreshToken();
    } else {
        responseBuilder.getAccessToken().setSessionState(null);
    }
    checkMtlsHoKToken(responseBuilder, useRefreshToken);
    String scopeParam = clientSessionCtx.getClientSession().getNote(OAuth2Constants.SCOPE);
    if (TokenUtil.isOIDCRequest(scopeParam)) {
        responseBuilder.generateIDToken().generateAccessTokenHash();
    }
    // TODO : do the same as codeToToken()
    AccessTokenResponse res = responseBuilder.build();
    event.success();
    return cors.builder(Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).build();
}
Also used : AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) UserSessionModel(org.keycloak.models.UserSessionModel) RealmManager(org.keycloak.services.managers.RealmManager) ServiceAccountTokenRequestContext(org.keycloak.services.clientpolicy.context.ServiceAccountTokenRequestContext) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) UserModel(org.keycloak.models.UserModel) AuthenticationSessionManager(org.keycloak.services.managers.AuthenticationSessionManager) DefaultClientSessionContext(org.keycloak.services.util.DefaultClientSessionContext) ClientSessionContext(org.keycloak.models.ClientSessionContext) ClientManager(org.keycloak.services.managers.ClientManager) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) TokenManager(org.keycloak.protocol.oidc.TokenManager) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse)

Example 10 with CorsErrorResponseException

use of org.keycloak.services.CorsErrorResponseException in project keycloak by keycloak.

the class TokenEndpoint method getRequestedScopes.

private String getRequestedScopes() {
    String scope = formParams.getFirst(OAuth2Constants.SCOPE);
    boolean validScopes;
    if (Profile.isFeatureEnabled(Profile.Feature.DYNAMIC_SCOPES)) {
        AuthorizationRequestContext authorizationRequestContext = AuthorizationContextUtil.getAuthorizationRequestContextFromScopes(session, scope);
        validScopes = TokenManager.isValidScope(scope, authorizationRequestContext, client);
    } else {
        validScopes = TokenManager.isValidScope(scope, client);
    }
    if (!validScopes) {
        event.error(Errors.INVALID_REQUEST);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_SCOPE, "Invalid scopes: " + scope, Status.BAD_REQUEST);
    }
    return scope;
}
Also used : AuthorizationRequestContext(org.keycloak.rar.AuthorizationRequestContext) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException)

Aggregations

CorsErrorResponseException (org.keycloak.services.CorsErrorResponseException)30 UserSessionModel (org.keycloak.models.UserSessionModel)13 UserModel (org.keycloak.models.UserModel)11 ClientSessionContext (org.keycloak.models.ClientSessionContext)10 ClientModel (org.keycloak.models.ClientModel)9 ClientPolicyException (org.keycloak.services.clientpolicy.ClientPolicyException)9 OAuthErrorException (org.keycloak.OAuthErrorException)8 AccessTokenResponse (org.keycloak.representations.AccessTokenResponse)8 DefaultClientSessionContext (org.keycloak.services.util.DefaultClientSessionContext)8 Response (javax.ws.rs.core.Response)7 AuthenticationSessionModel (org.keycloak.sessions.AuthenticationSessionModel)6 RootAuthenticationSessionModel (org.keycloak.sessions.RootAuthenticationSessionModel)6 AuthorizationProvider (org.keycloak.authorization.AuthorizationProvider)5 AuthenticatedClientSessionModel (org.keycloak.models.AuthenticatedClientSessionModel)5 TokenManager (org.keycloak.protocol.oidc.TokenManager)5 AccessToken (org.keycloak.representations.AccessToken)5 AuthenticationSessionManager (org.keycloak.services.managers.AuthenticationSessionManager)4 EventBuilder (org.keycloak.events.EventBuilder)3 JWSInput (org.keycloak.jose.jws.JWSInput)3 JWSInputException (org.keycloak.jose.jws.JWSInputException)3