Search in sources :

Example 1 with UserInfoRequestContext

use of org.keycloak.services.clientpolicy.context.UserInfoRequestContext in project keycloak by keycloak.

the class UserInfoEndpoint method issueUserInfo.

private Response issueUserInfo(String tokenString) {
    cors = Cors.add(request).auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
    try {
        session.clientPolicy().triggerOnEvent(new UserInfoRequestContext(tokenString));
    } catch (ClientPolicyException cpe) {
        throw new CorsErrorResponseException(cors.allowAllOrigins(), cpe.getError(), cpe.getErrorDetail(), cpe.getErrorStatus());
    }
    EventBuilder event = new EventBuilder(realm, session, clientConnection).event(EventType.USER_INFO_REQUEST).detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN);
    if (tokenString == null) {
        event.error(Errors.INVALID_TOKEN);
        throw new CorsErrorResponseException(cors.allowAllOrigins(), OAuthErrorException.INVALID_REQUEST, "Token not provided", Response.Status.BAD_REQUEST);
    }
    AccessToken token;
    ClientModel clientModel = null;
    try {
        TokenVerifier<AccessToken> verifier = TokenVerifier.create(tokenString, AccessToken.class).withDefaultChecks().realmUrl(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
        SignatureVerifierContext verifierContext = session.getProvider(SignatureProvider.class, verifier.getHeader().getAlgorithm().name()).verifier(verifier.getHeader().getKeyId());
        verifier.verifierContext(verifierContext);
        token = verifier.verify().getToken();
        clientModel = realm.getClientByClientId(token.getIssuedFor());
        if (clientModel == null) {
            event.error(Errors.CLIENT_NOT_FOUND);
            throw new CorsErrorResponseException(cors.allowAllOrigins(), OAuthErrorException.INVALID_REQUEST, "Client not found", Response.Status.BAD_REQUEST);
        }
        cors.allowedOrigins(session, clientModel);
        TokenVerifier.createWithoutSignature(token).withChecks(NotBeforeCheck.forModel(clientModel), new TokenManager.TokenRevocationCheck(session)).verify();
    } catch (VerificationException e) {
        if (clientModel == null) {
            cors.allowAllOrigins();
        }
        event.error(Errors.INVALID_TOKEN);
        throw newUnauthorizedErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Token verification failed");
    }
    if (!clientModel.getProtocol().equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
        event.error(Errors.INVALID_CLIENT);
        throw new CorsErrorResponseException(cors, Errors.INVALID_CLIENT, "Wrong client protocol.", Response.Status.BAD_REQUEST);
    }
    session.getContext().setClient(clientModel);
    event.client(clientModel);
    if (!clientModel.isEnabled()) {
        event.error(Errors.CLIENT_DISABLED);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_REQUEST, "Client disabled", Response.Status.BAD_REQUEST);
    }
    UserSessionModel userSession = findValidSession(token, event, clientModel);
    UserModel userModel = userSession.getUser();
    if (userModel == null) {
        event.error(Errors.USER_NOT_FOUND);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_REQUEST, "User not found", Response.Status.BAD_REQUEST);
    }
    event.user(userModel).detail(Details.USERNAME, userModel.getUsername());
    // https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-3
    if (OIDCAdvancedConfigWrapper.fromClientModel(clientModel).isUseMtlsHokToken()) {
        if (!MtlsHoKTokenUtil.verifyTokenBindingWithClientCertificate(token, request, session)) {
            event.error(Errors.NOT_ALLOWED);
            throw newUnauthorizedErrorResponseException(OAuthErrorException.UNAUTHORIZED_CLIENT, "Client certificate missing, or its thumbprint and one in the refresh token did NOT match");
        }
    }
    // Existence of authenticatedClientSession for our client already handled before
    AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(clientModel.getId());
    // Retrieve by latest scope parameter
    ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession, session);
    AccessToken userInfo = new AccessToken();
    tokenManager.transformUserInfoAccessToken(session, userInfo, userSession, clientSessionCtx);
    Map<String, Object> claims = tokenManager.generateUserInfoClaims(userInfo, userModel);
    Response.ResponseBuilder responseBuilder;
    OIDCAdvancedConfigWrapper cfg = OIDCAdvancedConfigWrapper.fromClientModel(clientModel);
    if (cfg.isUserInfoSignatureRequired()) {
        String issuerUrl = Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName());
        String audience = clientModel.getClientId();
        claims.put("iss", issuerUrl);
        claims.put("aud", audience);
        String signatureAlgorithm = session.tokens().signatureAlgorithm(TokenCategory.USERINFO);
        SignatureProvider signatureProvider = session.getProvider(SignatureProvider.class, signatureAlgorithm);
        SignatureSignerContext signer = signatureProvider.signer();
        String signedUserInfo = new JWSBuilder().type("JWT").jsonContent(claims).sign(signer);
        responseBuilder = Response.ok(signedUserInfo).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JWT);
        event.detail(Details.SIGNATURE_REQUIRED, "true");
        event.detail(Details.SIGNATURE_ALGORITHM, cfg.getUserInfoSignedResponseAlg().toString());
    } else {
        responseBuilder = Response.ok(claims).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
        event.detail(Details.SIGNATURE_REQUIRED, "false");
    }
    event.success();
    return cors.builder(responseBuilder).build();
}
Also used : UserSessionModel(org.keycloak.models.UserSessionModel) SignatureVerifierContext(org.keycloak.crypto.SignatureVerifierContext) OIDCAdvancedConfigWrapper(org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper) SignatureSignerContext(org.keycloak.crypto.SignatureSignerContext) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) JWSBuilder(org.keycloak.jose.jws.JWSBuilder) UserModel(org.keycloak.models.UserModel) Response(javax.ws.rs.core.Response) HttpResponse(org.jboss.resteasy.spi.HttpResponse) ClientModel(org.keycloak.models.ClientModel) SignatureProvider(org.keycloak.crypto.SignatureProvider) UserInfoRequestContext(org.keycloak.services.clientpolicy.context.UserInfoRequestContext) EventBuilder(org.keycloak.events.EventBuilder) DefaultClientSessionContext(org.keycloak.services.util.DefaultClientSessionContext) ClientSessionContext(org.keycloak.models.ClientSessionContext) AccessToken(org.keycloak.representations.AccessToken) VerificationException(org.keycloak.common.VerificationException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException)

Aggregations

Response (javax.ws.rs.core.Response)1 HttpResponse (org.jboss.resteasy.spi.HttpResponse)1 VerificationException (org.keycloak.common.VerificationException)1 SignatureProvider (org.keycloak.crypto.SignatureProvider)1 SignatureSignerContext (org.keycloak.crypto.SignatureSignerContext)1 SignatureVerifierContext (org.keycloak.crypto.SignatureVerifierContext)1 EventBuilder (org.keycloak.events.EventBuilder)1 JWSBuilder (org.keycloak.jose.jws.JWSBuilder)1 AuthenticatedClientSessionModel (org.keycloak.models.AuthenticatedClientSessionModel)1 ClientModel (org.keycloak.models.ClientModel)1 ClientSessionContext (org.keycloak.models.ClientSessionContext)1 UserModel (org.keycloak.models.UserModel)1 UserSessionModel (org.keycloak.models.UserSessionModel)1 OIDCAdvancedConfigWrapper (org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper)1 AccessToken (org.keycloak.representations.AccessToken)1 CorsErrorResponseException (org.keycloak.services.CorsErrorResponseException)1 ClientPolicyException (org.keycloak.services.clientpolicy.ClientPolicyException)1 UserInfoRequestContext (org.keycloak.services.clientpolicy.context.UserInfoRequestContext)1 DefaultClientSessionContext (org.keycloak.services.util.DefaultClientSessionContext)1