Search in sources :

Example 1 with BackchannelTokenRequestContext

use of org.keycloak.protocol.oidc.grants.ciba.clientpolicy.context.BackchannelTokenRequestContext in project keycloak by keycloak.

the class CibaGrantType method cibaGrant.

public Response cibaGrant() {
    ProfileHelper.requireFeature(Profile.Feature.CIBA);
    if (!realm.getCibaPolicy().isOIDCCIBAGrantEnabled(client)) {
        event.error(Errors.NOT_ALLOWED);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Client not allowed OIDC CIBA Grant", Response.Status.BAD_REQUEST);
    }
    String jwe = formParams.getFirst(AUTH_REQ_ID);
    if (jwe == null) {
        event.error(Errors.INVALID_CODE);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_REQUEST, "Missing parameter: " + AUTH_REQ_ID, Response.Status.BAD_REQUEST);
    }
    logger.tracev("CIBA Grant :: authReqId = {0}", jwe);
    CIBAAuthenticationRequest request;
    try {
        request = CIBAAuthenticationRequest.deserialize(session, jwe);
    } catch (Exception e) {
        logger.warnf("illegal format of auth_req_id : e.getMessage() = %s", e.getMessage());
        // Auth Req ID has not put onto cache, no need to remove Auth Req ID.
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Invalid Auth Req ID", Response.Status.BAD_REQUEST);
    }
    request.setClient(client);
    try {
        session.clientPolicy().triggerOnEvent(new BackchannelTokenRequestContext(request, formParams));
    } catch (ClientPolicyException cpe) {
        event.error(cpe.getError());
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
    }
    OAuth2DeviceTokenStoreProvider store = session.getProvider(OAuth2DeviceTokenStoreProvider.class);
    OAuth2DeviceCodeModel deviceCode = store.getByDeviceCode(realm, request.getId());
    if (deviceCode == null) {
        // Auth Req ID has not put onto cache, no need to remove Auth Req ID.
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Invalid " + AUTH_REQ_ID, Response.Status.BAD_REQUEST);
    }
    if (!request.getIssuedFor().equals(client.getClientId())) {
        logDebug("invalid client.", request);
        // the client sending this Auth Req ID does not match the client to which keycloak had issued Auth Req ID.
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "unauthorized client", Response.Status.BAD_REQUEST);
    }
    if (deviceCode.isExpired()) {
        logDebug("expired.", request);
        throw new CorsErrorResponseException(cors, OAuthErrorException.EXPIRED_TOKEN, "authentication timed out", Response.Status.BAD_REQUEST);
    }
    if (!store.isPollingAllowed(deviceCode)) {
        logDebug("pooling.", request);
        throw new CorsErrorResponseException(cors, OAuthErrorException.SLOW_DOWN, "too early to access", Response.Status.BAD_REQUEST);
    }
    if (deviceCode.isDenied()) {
        logDebug("denied.", request);
        throw new CorsErrorResponseException(cors, OAuthErrorException.ACCESS_DENIED, "not authorized", Response.Status.BAD_REQUEST);
    }
    // get corresponding Authentication Channel Result entry
    if (deviceCode.isPending()) {
        logDebug("not yet authenticated by Authentication Device or auth_req_id has already been used to get tokens.", request);
        throw new CorsErrorResponseException(cors, OAuthErrorException.AUTHORIZATION_PENDING, "The authorization request is still pending as the end-user hasn't yet been authenticated.", Response.Status.BAD_REQUEST);
    }
    UserSessionModel userSession = createUserSession(request, deviceCode.getAdditionalParams());
    UserModel user = userSession.getUser();
    store.removeDeviceCode(realm, request.getId());
    // Compute client scopes again from scope parameter. Check if user still has them granted
    // (but in code-to-token request, it could just theoretically happen that they are not available)
    String scopeParam = request.getScope();
    if (!TokenManager.verifyConsentStillAvailable(session, user, client, TokenManager.getRequestedClientScopes(scopeParam, client))) {
        event.error(Errors.NOT_ALLOWED);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user", Response.Status.BAD_REQUEST);
    }
    ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(userSession.getAuthenticatedClientSessionByClient(client.getId()), scopeParam, session);
    int authTime = Time.currentTime();
    userSession.setNote(AuthenticationManager.AUTH_TIME, String.valueOf(authTime));
    return tokenEndpoint.createTokenResponse(user, userSession, clientSessionCtx, scopeParam, true);
}
Also used : OAuth2DeviceTokenStoreProvider(org.keycloak.models.OAuth2DeviceTokenStoreProvider) UserModel(org.keycloak.models.UserModel) UserSessionModel(org.keycloak.models.UserSessionModel) DefaultClientSessionContext(org.keycloak.services.util.DefaultClientSessionContext) ClientSessionContext(org.keycloak.models.ClientSessionContext) OAuth2DeviceCodeModel(org.keycloak.models.OAuth2DeviceCodeModel) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) BackchannelTokenRequestContext(org.keycloak.protocol.oidc.grants.ciba.clientpolicy.context.BackchannelTokenRequestContext) CIBAAuthenticationRequest(org.keycloak.protocol.oidc.grants.ciba.channel.CIBAAuthenticationRequest) OAuthErrorException(org.keycloak.OAuthErrorException) ErrorResponseException(org.keycloak.services.ErrorResponseException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) CibaRootEndpoint(org.keycloak.protocol.oidc.grants.ciba.endpoints.CibaRootEndpoint) TokenEndpoint(org.keycloak.protocol.oidc.endpoints.TokenEndpoint) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException)

Aggregations

OAuthErrorException (org.keycloak.OAuthErrorException)1 ClientSessionContext (org.keycloak.models.ClientSessionContext)1 OAuth2DeviceCodeModel (org.keycloak.models.OAuth2DeviceCodeModel)1 OAuth2DeviceTokenStoreProvider (org.keycloak.models.OAuth2DeviceTokenStoreProvider)1 UserModel (org.keycloak.models.UserModel)1 UserSessionModel (org.keycloak.models.UserSessionModel)1 TokenEndpoint (org.keycloak.protocol.oidc.endpoints.TokenEndpoint)1 CIBAAuthenticationRequest (org.keycloak.protocol.oidc.grants.ciba.channel.CIBAAuthenticationRequest)1 BackchannelTokenRequestContext (org.keycloak.protocol.oidc.grants.ciba.clientpolicy.context.BackchannelTokenRequestContext)1 CibaRootEndpoint (org.keycloak.protocol.oidc.grants.ciba.endpoints.CibaRootEndpoint)1 CorsErrorResponseException (org.keycloak.services.CorsErrorResponseException)1 ErrorResponseException (org.keycloak.services.ErrorResponseException)1 ClientPolicyException (org.keycloak.services.clientpolicy.ClientPolicyException)1 DefaultClientSessionContext (org.keycloak.services.util.DefaultClientSessionContext)1