Search in sources :

Example 1 with SignatureProvider

use of org.keycloak.crypto.SignatureProvider 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)

Example 2 with SignatureProvider

use of org.keycloak.crypto.SignatureProvider in project keycloak by keycloak.

the class DefaultTokenManager method decode.

@Override
public <T extends Token> T decode(String token, Class<T> clazz) {
    if (token == null) {
        return null;
    }
    try {
        JWSInput jws = new JWSInput(token);
        String signatureAlgorithm = jws.getHeader().getAlgorithm().name();
        SignatureProvider signatureProvider = session.getProvider(SignatureProvider.class, signatureAlgorithm);
        if (signatureProvider == null) {
            return null;
        }
        String kid = jws.getHeader().getKeyId();
        // Backwards compatibility. Old offline tokens and cookies didn't have KID in the header
        if (kid == null) {
            logger.debugf("KID is null in token. Using the realm active key to verify token signature.");
            kid = session.keys().getActiveKey(session.getContext().getRealm(), KeyUse.SIG, signatureAlgorithm).getKid();
        }
        boolean valid = signatureProvider.verifier(kid).verify(jws.getEncodedSignatureInput().getBytes("UTF-8"), jws.getSignature());
        return valid ? jws.readJsonContent(clazz) : null;
    } catch (Exception e) {
        logger.debug("Failed to decode token", e);
        return null;
    }
}
Also used : SignatureProvider(org.keycloak.crypto.SignatureProvider) JWEException(org.keycloak.jose.jwe.JWEException) IOException(java.io.IOException) UnsupportedEncodingException(java.io.UnsupportedEncodingException)

Example 3 with SignatureProvider

use of org.keycloak.crypto.SignatureProvider in project keycloak by keycloak.

the class DefaultTokenManager method encode.

@Override
public String encode(Token token) {
    String signatureAlgorithm = signatureAlgorithm(token.getCategory());
    SignatureProvider signatureProvider = session.getProvider(SignatureProvider.class, signatureAlgorithm);
    SignatureSignerContext signer = signatureProvider.signer();
    String encodedToken = new JWSBuilder().type("JWT").jsonContent(token).sign(signer);
    return encodedToken;
}
Also used : SignatureProvider(org.keycloak.crypto.SignatureProvider) SignatureSignerContext(org.keycloak.crypto.SignatureSignerContext)

Example 4 with SignatureProvider

use of org.keycloak.crypto.SignatureProvider in project keycloak by keycloak.

the class CIBAAuthenticationRequest method serialize.

/**
 * Serializes this instance to a JWE.
 *
 * @param session the session
 * @return the JWE
 */
public String serialize(KeycloakSession session) {
    try {
        SignatureProvider signatureProvider = session.getProvider(SignatureProvider.class, Algorithm.HS256);
        SignatureSignerContext signer = signatureProvider.signer();
        String encodedJwt = new JWSBuilder().type("JWT").jsonContent(this).sign(signer);
        SecretKey aesKey = session.keys().getActiveKey(session.getContext().getRealm(), KeyUse.ENC, Algorithm.AES).getSecretKey();
        SecretKey hmacKey = session.keys().getActiveKey(session.getContext().getRealm(), KeyUse.SIG, Algorithm.HS256).getSecretKey();
        return TokenUtil.jweDirectEncode(aesKey, hmacKey, encodedJwt.getBytes("UTF-8"));
    } catch (JWEException | UnsupportedEncodingException e) {
        throw new RuntimeException("Error encoding auth_req_id.", e);
    }
}
Also used : SignatureProvider(org.keycloak.crypto.SignatureProvider) SecretKey(javax.crypto.SecretKey) SignatureSignerContext(org.keycloak.crypto.SignatureSignerContext) JWEException(org.keycloak.jose.jwe.JWEException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) JWSBuilder(org.keycloak.jose.jws.JWSBuilder)

Aggregations

SignatureProvider (org.keycloak.crypto.SignatureProvider)4 SignatureSignerContext (org.keycloak.crypto.SignatureSignerContext)3 UnsupportedEncodingException (java.io.UnsupportedEncodingException)2 JWEException (org.keycloak.jose.jwe.JWEException)2 JWSBuilder (org.keycloak.jose.jws.JWSBuilder)2 IOException (java.io.IOException)1 SecretKey (javax.crypto.SecretKey)1 Response (javax.ws.rs.core.Response)1 HttpResponse (org.jboss.resteasy.spi.HttpResponse)1 VerificationException (org.keycloak.common.VerificationException)1 SignatureVerifierContext (org.keycloak.crypto.SignatureVerifierContext)1 EventBuilder (org.keycloak.events.EventBuilder)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