Search in sources :

Example 1 with CibaConfig

use of org.keycloak.models.CibaConfig in project keycloak by keycloak.

the class BackchannelAuthenticationCallbackEndpoint method processAuthenticationChannelResult.

@Path("/")
@POST
@NoCache
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response processAuthenticationChannelResult(AuthenticationChannelResponse response) {
    event.event(EventType.LOGIN);
    BackchannelAuthCallbackContext ctx = verifyAuthenticationRequest(httpRequest.getHttpHeaders());
    AccessToken bearerToken = ctx.bearerToken;
    OAuth2DeviceCodeModel deviceModel = ctx.deviceModel;
    Status status = response.getStatus();
    if (status == null) {
        event.error(Errors.INVALID_REQUEST);
        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Invalid authentication status", Response.Status.BAD_REQUEST);
    }
    switch(status) {
        case SUCCEED:
            approveRequest(bearerToken, response.getAdditionalParams());
            break;
        case CANCELLED:
        case UNAUTHORIZED:
            denyRequest(bearerToken, status);
            break;
    }
    // Call the notification endpoint
    ClientModel client = session.getContext().getClient();
    CibaConfig cibaConfig = realm.getCibaPolicy();
    if (cibaConfig.getBackchannelTokenDeliveryMode(client).equals(CibaConfig.CIBA_PING_MODE)) {
        sendClientNotificationRequest(client, cibaConfig, deviceModel);
    }
    return Response.ok(MediaType.APPLICATION_JSON_TYPE).build();
}
Also used : Status(org.keycloak.protocol.oidc.grants.ciba.channel.AuthenticationChannelResponse.Status) ClientModel(org.keycloak.models.ClientModel) OAuth2DeviceCodeModel(org.keycloak.models.OAuth2DeviceCodeModel) AccessToken(org.keycloak.representations.AccessToken) CibaConfig(org.keycloak.models.CibaConfig) ErrorResponseException(org.keycloak.services.ErrorResponseException) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) NoCache(org.jboss.resteasy.annotations.cache.NoCache)

Example 2 with CibaConfig

use of org.keycloak.models.CibaConfig in project keycloak by keycloak.

the class CibaClientValidation method validate.

public void validate() {
    ClientModel client = context.getObjectToValidate();
    // Check only ping mode and poll mode allowed
    CibaConfig cibaConfig = client.getRealm().getCibaPolicy();
    String cibaMode = cibaConfig.getBackchannelTokenDeliveryMode(client);
    if (!CibaConfig.CIBA_SUPPORTED_MODES.contains(cibaMode)) {
        context.addError("cibaBackchannelTokenDeliveryMode", "Unsupported requested CIBA Backchannel Token Delivery Mode", "invalidCibaBackchannelTokenDeliveryMode");
    }
    // Check clientNotificationEndpoint URL configured for ping mode
    if (CibaConfig.CIBA_PING_MODE.equals(cibaMode)) {
        if (cibaConfig.getBackchannelClientNotificationEndpoint(client) == null) {
            context.addError("cibaBackchannelClientNotificationEndpoint", "CIBA Backchannel Client Notification Endpoint must be set for the CIBA ping mode", "missingCibaBackchannelClientNotificationEndpoint");
        }
    }
    // Validate clientNotificationEndpoint URL itself
    try {
        checkUrl(client.getRealm().getSslRequired(), cibaConfig.getBackchannelClientNotificationEndpoint(client), "backchannel_client_notification_endpoint");
    } catch (RuntimeException re) {
        context.addError("cibaBackchannelClientNotificationEndpoint", re.getMessage(), "invalidBackchannelClientNotificationEndpoint");
    }
    Algorithm alg = cibaConfig.getBackchannelAuthRequestSigningAlg(client);
    if (alg != null && !isSupportedBackchannelAuthenticationRequestSigningAlg(context.getSession(), alg.name())) {
        context.addError("cibaBackchannelAuthRequestSigningAlg", "Unsupported requested CIBA Backchannel Authentication Request Signing Algorithm", "invalidCibaBackchannelAuthRequestSigningAlg");
    }
}
Also used : ClientModel(org.keycloak.models.ClientModel) CibaConfig(org.keycloak.models.CibaConfig) Algorithm(org.keycloak.jose.jws.Algorithm)

Example 3 with CibaConfig

use of org.keycloak.models.CibaConfig in project keycloak by keycloak.

the class BackchannelAuthenticationEndpoint method authorizeClient.

private CIBAAuthenticationRequest authorizeClient(MultivaluedMap<String, String> params) {
    ClientModel client = null;
    try {
        client = authenticateClient();
    } catch (WebApplicationException wae) {
        OAuth2ErrorRepresentation errorRep = (OAuth2ErrorRepresentation) wae.getResponse().getEntity();
        throw new ErrorResponseException(errorRep.getError(), errorRep.getErrorDescription(), Response.Status.UNAUTHORIZED);
    }
    BackchannelAuthenticationEndpointRequest endpointRequest = BackchannelAuthenticationEndpointRequestParserProcessor.parseRequest(event, session, client, params, realm.getCibaPolicy());
    UserModel user = resolveUser(endpointRequest, realm.getCibaPolicy().getAuthRequestedUserHint());
    CIBAAuthenticationRequest request = new CIBAAuthenticationRequest(session, user, client);
    request.setClient(client);
    String scope = endpointRequest.getScope();
    if (scope == null) {
        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "missing parameter : scope", Response.Status.BAD_REQUEST);
    }
    request.setScope(scope);
    // optional parameters
    if (endpointRequest.getBindingMessage() != null) {
        validateBindingMessage(endpointRequest.getBindingMessage());
        request.setBindingMessage(endpointRequest.getBindingMessage());
    }
    if (endpointRequest.getAcr() != null)
        request.setAcrValues(endpointRequest.getAcr());
    CibaConfig policy = realm.getCibaPolicy();
    // create JWE encoded auth_req_id from Auth Req ID.
    Integer expiresIn = Optional.ofNullable(endpointRequest.getRequestedExpiry()).orElse(policy.getExpiresIn());
    request.exp(request.getIat() + expiresIn.longValue());
    StringBuilder scopes = new StringBuilder(Optional.ofNullable(request.getScope()).orElse(""));
    client.getClientScopes(true).forEach((key, value) -> {
        if (value.isDisplayOnConsentScreen())
            scopes.append(" ").append(value.getName());
    });
    request.setScope(scopes.toString());
    if (endpointRequest.getClientNotificationToken() != null) {
        if (!policy.getBackchannelTokenDeliveryMode(client).equals(CibaConfig.CIBA_PING_MODE)) {
            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client Notification token supported only for the ping mode", Response.Status.BAD_REQUEST);
        }
        if (endpointRequest.getClientNotificationToken().length() > 1024) {
            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client Notification token length is limited to 1024 characters", Response.Status.BAD_REQUEST);
        }
        request.setClientNotificationToken(endpointRequest.getClientNotificationToken());
    }
    if (endpointRequest.getClientNotificationToken() == null && policy.getBackchannelTokenDeliveryMode(client).equals(CibaConfig.CIBA_PING_MODE)) {
        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client Notification token needs to be provided with the ping mode", Response.Status.BAD_REQUEST);
    }
    if (endpointRequest.getUserCode() != null) {
        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "User code not supported", Response.Status.BAD_REQUEST);
    }
    extractAdditionalParams(endpointRequest, request);
    try {
        session.clientPolicy().triggerOnEvent(new BackchannelAuthenticationRequestContext(endpointRequest, request, params));
    } catch (ClientPolicyException cpe) {
        throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
    }
    return request;
}
Also used : BackchannelAuthenticationRequestContext(org.keycloak.protocol.oidc.grants.ciba.clientpolicy.context.BackchannelAuthenticationRequestContext) WebApplicationException(javax.ws.rs.WebApplicationException) OAuth2ErrorRepresentation(org.keycloak.representations.idm.OAuth2ErrorRepresentation) CIBAAuthenticationRequest(org.keycloak.protocol.oidc.grants.ciba.channel.CIBAAuthenticationRequest) BackchannelAuthenticationEndpointRequest(org.keycloak.protocol.oidc.grants.ciba.endpoints.request.BackchannelAuthenticationEndpointRequest) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) UserModel(org.keycloak.models.UserModel) ClientModel(org.keycloak.models.ClientModel) CibaConfig(org.keycloak.models.CibaConfig) ErrorResponseException(org.keycloak.services.ErrorResponseException)

Example 4 with CibaConfig

use of org.keycloak.models.CibaConfig in project keycloak by keycloak.

the class BackchannelAuthenticationEndpoint method processGrantRequest.

@POST
@NoCache
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response processGrantRequest(@Context HttpRequest httpRequest) {
    CIBAAuthenticationRequest request = authorizeClient(httpRequest.getDecodedFormParameters());
    try {
        String authReqId = request.serialize(session);
        AuthenticationChannelProvider provider = session.getProvider(AuthenticationChannelProvider.class);
        if (provider == null) {
            throw new RuntimeException("Authentication Channel Provider not found.");
        }
        CIBALoginUserResolver resolver = session.getProvider(CIBALoginUserResolver.class);
        if (resolver == null) {
            throw new RuntimeException("CIBA Login User Resolver not setup properly.");
        }
        UserModel user = request.getUser();
        String infoUsedByAuthentication = resolver.getInfoUsedByAuthentication(user);
        if (provider.requestAuthentication(request, infoUsedByAuthentication)) {
            CibaConfig cibaPolicy = realm.getCibaPolicy();
            int poolingInterval = cibaPolicy.getPoolingInterval();
            storeAuthenticationRequest(request, cibaPolicy, authReqId);
            ObjectNode response = JsonSerialization.createObjectNode();
            response.put(CibaGrantType.AUTH_REQ_ID, authReqId).put(OAuth2Constants.EXPIRES_IN, cibaPolicy.getExpiresIn());
            if (poolingInterval > 0) {
                response.put(OAuth2Constants.INTERVAL, poolingInterval);
            }
            return Response.ok(JsonSerialization.writeValueAsBytes(response)).build();
        }
    } catch (Exception e) {
        throw new ErrorResponseException(OAuthErrorException.SERVER_ERROR, "Failed to send authentication request", Response.Status.SERVICE_UNAVAILABLE);
    }
    throw new ErrorResponseException(OAuthErrorException.SERVER_ERROR, "Unexpected response from authentication device", Response.Status.SERVICE_UNAVAILABLE);
}
Also used : UserModel(org.keycloak.models.UserModel) AuthenticationChannelProvider(org.keycloak.protocol.oidc.grants.ciba.channel.AuthenticationChannelProvider) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) CIBALoginUserResolver(org.keycloak.protocol.oidc.grants.ciba.resolvers.CIBALoginUserResolver) CibaConfig(org.keycloak.models.CibaConfig) ErrorResponseException(org.keycloak.services.ErrorResponseException) CIBAAuthenticationRequest(org.keycloak.protocol.oidc.grants.ciba.channel.CIBAAuthenticationRequest) OAuthErrorException(org.keycloak.OAuthErrorException) ErrorResponseException(org.keycloak.services.ErrorResponseException) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) WebApplicationException(javax.ws.rs.WebApplicationException) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) NoCache(org.jboss.resteasy.annotations.cache.NoCache)

Example 5 with CibaConfig

use of org.keycloak.models.CibaConfig in project keycloak by keycloak.

the class RepresentationToModel method updateCibaSettings.

private static void updateCibaSettings(RealmRepresentation rep, RealmModel realm) {
    Map<String, String> newAttributes = rep.getAttributesOrEmpty();
    CibaConfig cibaPolicy = realm.getCibaPolicy();
    cibaPolicy.setBackchannelTokenDeliveryMode(newAttributes.get(CibaConfig.CIBA_BACKCHANNEL_TOKEN_DELIVERY_MODE));
    cibaPolicy.setExpiresIn(newAttributes.get(CibaConfig.CIBA_EXPIRES_IN));
    cibaPolicy.setPoolingInterval(newAttributes.get(CibaConfig.CIBA_INTERVAL));
    cibaPolicy.setAuthRequestedUserHint(newAttributes.get(CibaConfig.CIBA_AUTH_REQUESTED_USER_HINT));
}
Also used : CibaConfig(org.keycloak.models.CibaConfig) ArtifactBindingUtils.computeArtifactBindingIdentifierString(org.keycloak.protocol.saml.util.ArtifactBindingUtils.computeArtifactBindingIdentifierString)

Aggregations

CibaConfig (org.keycloak.models.CibaConfig)5 ClientModel (org.keycloak.models.ClientModel)3 ErrorResponseException (org.keycloak.services.ErrorResponseException)3 Consumes (javax.ws.rs.Consumes)2 POST (javax.ws.rs.POST)2 Produces (javax.ws.rs.Produces)2 WebApplicationException (javax.ws.rs.WebApplicationException)2 NoCache (org.jboss.resteasy.annotations.cache.NoCache)2 UserModel (org.keycloak.models.UserModel)2 CIBAAuthenticationRequest (org.keycloak.protocol.oidc.grants.ciba.channel.CIBAAuthenticationRequest)2 ClientPolicyException (org.keycloak.services.clientpolicy.ClientPolicyException)2 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)1 Path (javax.ws.rs.Path)1 OAuthErrorException (org.keycloak.OAuthErrorException)1 Algorithm (org.keycloak.jose.jws.Algorithm)1 OAuth2DeviceCodeModel (org.keycloak.models.OAuth2DeviceCodeModel)1 AuthenticationChannelProvider (org.keycloak.protocol.oidc.grants.ciba.channel.AuthenticationChannelProvider)1 Status (org.keycloak.protocol.oidc.grants.ciba.channel.AuthenticationChannelResponse.Status)1 BackchannelAuthenticationRequestContext (org.keycloak.protocol.oidc.grants.ciba.clientpolicy.context.BackchannelAuthenticationRequestContext)1 BackchannelAuthenticationEndpointRequest (org.keycloak.protocol.oidc.grants.ciba.endpoints.request.BackchannelAuthenticationEndpointRequest)1