Search in sources :

Example 6 with ClientModel

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

the class DeviceEndpoint method checkClient.

private ClientModel checkClient(String clientId) {
    if (clientId == null) {
        event.error(Errors.INVALID_REQUEST);
        throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST, Messages.MISSING_PARAMETER, OIDCLoginProtocol.CLIENT_ID_PARAM);
    }
    event.client(clientId);
    ClientModel client = realm.getClientByClientId(clientId);
    if (client == null) {
        event.error(Errors.CLIENT_NOT_FOUND);
        throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST, Messages.CLIENT_NOT_FOUND);
    }
    if (!client.isEnabled()) {
        event.error(Errors.CLIENT_DISABLED);
        throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST, Messages.CLIENT_DISABLED);
    }
    if (!realm.getOAuth2DeviceConfig().isOAuth2DeviceAuthorizationGrantEnabled(client)) {
        event.error(Errors.NOT_ALLOWED);
        throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST, Messages.OAUTH2_DEVICE_AUTHORIZATION_GRANT_DISABLED);
    }
    if (client.isBearerOnly()) {
        event.error(Errors.NOT_ALLOWED);
        throw new ErrorPageException(session, null, Response.Status.FORBIDDEN, Messages.BEARER_ONLY);
    }
    String protocol = client.getProtocol();
    if (protocol == null) {
        logger.warnf("Client '%s' doesn't have protocol set. Fallback to openid-connect. Please fix client configuration", clientId);
        protocol = OIDCLoginProtocol.LOGIN_PROTOCOL;
    }
    if (!protocol.equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
        event.error(Errors.INVALID_CLIENT);
        throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST, "Wrong client protocol.");
    }
    session.getContext().setClient(client);
    return client;
}
Also used : ClientModel(org.keycloak.models.ClientModel) ErrorPageException(org.keycloak.services.ErrorPageException)

Example 7 with ClientModel

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

the class DeviceEndpoint method handleDeviceRequest.

/**
 * Handles device authorization requests.
 *
 * @return the device authorization response.
 */
@Path("")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response handleDeviceRequest() {
    cors = Cors.add(request).auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
    logger.trace("Processing @POST request");
    event.event(EventType.OAUTH2_DEVICE_AUTH);
    checkSsl();
    checkRealm();
    ClientModel client = authenticateClient();
    AuthorizationEndpointRequest request = AuthorizationEndpointRequestParserProcessor.parseRequest(event, session, client, httpRequest.getDecodedFormParameters());
    if (!TokenUtil.isOIDCRequest(request.getScope())) {
        ServicesLogger.LOGGER.oidcScopeMissing();
    }
    // So back button doesn't work
    CacheControlUtil.noBackButtonCacheControlHeader();
    if (!realm.getOAuth2DeviceConfig().isOAuth2DeviceAuthorizationGrantEnabled(client)) {
        event.error(Errors.NOT_ALLOWED);
        throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Client not allowed for OAuth 2.0 Device Authorization Grant", Response.Status.BAD_REQUEST);
    }
    // https://tools.ietf.org/html/rfc7636#section-4
    AuthorizationEndpointChecker checker = new AuthorizationEndpointChecker().event(event).client(client).request(request);
    try {
        checker.checkPKCEParams();
    } catch (AuthorizationEndpointChecker.AuthorizationCheckException ex) {
        throw new ErrorResponseException(ex.getError(), ex.getErrorDescription(), Response.Status.BAD_REQUEST);
    }
    try {
        session.clientPolicy().triggerOnEvent(new DeviceAuthorizationRequestContext(request, httpRequest.getDecodedFormParameters()));
    } catch (ClientPolicyException cpe) {
        throw new ErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
    }
    int expiresIn = realm.getOAuth2DeviceConfig().getLifespan(client);
    int interval = realm.getOAuth2DeviceConfig().getPoolingInterval(client);
    OAuth2DeviceCodeModel deviceCode = OAuth2DeviceCodeModel.create(realm, client, Base64Url.encode(SecretGenerator.getInstance().randomBytes()), request.getScope(), request.getNonce(), expiresIn, interval, null, null, request.getAdditionalReqParams(), request.getCodeChallenge(), request.getCodeChallengeMethod());
    OAuth2DeviceUserCodeProvider userCodeProvider = session.getProvider(OAuth2DeviceUserCodeProvider.class);
    String secret = userCodeProvider.generate();
    OAuth2DeviceUserCodeModel userCode = new OAuth2DeviceUserCodeModel(realm, deviceCode.getDeviceCode(), secret);
    // To inform "expired_token" to the client, the lifespan of the cache provider is longer than device code
    int lifespanSeconds = expiresIn + interval + 10;
    OAuth2DeviceTokenStoreProvider store = session.getProvider(OAuth2DeviceTokenStoreProvider.class);
    store.put(deviceCode, userCode, lifespanSeconds);
    try {
        String deviceUrl = DeviceGrantType.oauth2DeviceVerificationUrl(session.getContext().getUri()).build(realm.getName()).toString();
        OAuth2DeviceAuthorizationResponse response = new OAuth2DeviceAuthorizationResponse();
        response.setDeviceCode(deviceCode.getDeviceCode());
        response.setUserCode(userCodeProvider.display(secret));
        response.setExpiresIn(expiresIn);
        response.setInterval(interval);
        response.setVerificationUri(deviceUrl);
        response.setVerificationUriComplete(deviceUrl + "?user_code=" + response.getUserCode());
        return cors.builder(Response.ok(JsonSerialization.writeValueAsBytes(response)).type(MediaType.APPLICATION_JSON_TYPE)).build();
    } catch (Exception e) {
        throw new RuntimeException("Error creating OAuth 2.0 Device Authorization Response.", e);
    }
}
Also used : DeviceAuthorizationRequestContext(org.keycloak.protocol.oidc.grants.device.clientpolicy.context.DeviceAuthorizationRequestContext) OAuth2DeviceTokenStoreProvider(org.keycloak.models.OAuth2DeviceTokenStoreProvider) AuthorizationEndpointRequest(org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest) OAuthErrorException(org.keycloak.OAuthErrorException) ErrorResponseException(org.keycloak.services.ErrorResponseException) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) ErrorPageException(org.keycloak.services.ErrorPageException) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) OAuth2DeviceUserCodeProvider(org.keycloak.models.OAuth2DeviceUserCodeProvider) ClientModel(org.keycloak.models.ClientModel) AuthorizationEndpointChecker(org.keycloak.protocol.oidc.endpoints.AuthorizationEndpointChecker) OAuth2DeviceCodeModel(org.keycloak.models.OAuth2DeviceCodeModel) OAuth2DeviceAuthorizationResponse(org.keycloak.representations.OAuth2DeviceAuthorizationResponse) ErrorResponseException(org.keycloak.services.ErrorResponseException) OAuth2DeviceUserCodeModel(org.keycloak.models.OAuth2DeviceUserCodeModel) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces)

Example 8 with ClientModel

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

the class DeviceEndpoint method authenticateClient.

private ClientModel authenticateClient() {
    // https://tools.ietf.org/html/draft-ietf-oauth-device-flow-15#section-3.1
    // The spec says "The client authentication requirements of Section 3.2.1 of [RFC6749]
    // apply to requests on this endpoint".
    AuthorizeClientUtil.ClientAuthResult clientAuth = AuthorizeClientUtil.authorizeClient(session, event, cors);
    ClientModel client = clientAuth.getClient();
    if (client == null) {
        event.error(Errors.INVALID_REQUEST);
        throw new ErrorPageException(session, null, Response.Status.BAD_REQUEST, Messages.MISSING_PARAMETER, OIDCLoginProtocol.CLIENT_ID_PARAM);
    }
    checkClient(client.getClientId());
    return client;
}
Also used : ClientModel(org.keycloak.models.ClientModel) ErrorPageException(org.keycloak.services.ErrorPageException) AuthorizeClientUtil(org.keycloak.protocol.oidc.utils.AuthorizeClientUtil)

Example 9 with ClientModel

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

the class BackchannelAuthenticationCallbackEndpoint method verifyAuthenticationRequest.

private BackchannelAuthCallbackContext verifyAuthenticationRequest(HttpHeaders headers) {
    String rawBearerToken = AppAuthManager.extractAuthorizationHeaderTokenOrReturnNull(headers);
    if (rawBearerToken == null) {
        throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Invalid token", Response.Status.UNAUTHORIZED);
    }
    AccessToken bearerToken;
    try {
        bearerToken = TokenVerifier.createWithoutSignature(session.tokens().decode(rawBearerToken, AccessToken.class)).withDefaultChecks().realmUrl(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName())).checkActive(true).audience(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName())).verify().getToken();
    } catch (Exception e) {
        event.error(Errors.INVALID_TOKEN);
        // authentication channel id format is invalid or it has already been used
        throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Invalid token", Response.Status.FORBIDDEN);
    }
    OAuth2DeviceTokenStoreProvider store = session.getProvider(OAuth2DeviceTokenStoreProvider.class);
    OAuth2DeviceCodeModel deviceCode = store.getByUserCode(realm, bearerToken.getId());
    if (deviceCode == null) {
        throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Invalid token", Response.Status.FORBIDDEN);
    }
    if (!deviceCode.isPending()) {
        cancelRequest(bearerToken.getId());
        throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Invalid token", Response.Status.FORBIDDEN);
    }
    ClientModel issuedFor = realm.getClientByClientId(bearerToken.getIssuedFor());
    if (issuedFor == null || !issuedFor.isEnabled()) {
        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Invalid token recipient", Response.Status.BAD_REQUEST);
    }
    if (!deviceCode.getClientId().equals(issuedFor.getClientId())) {
        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Token recipient mismatch", Response.Status.BAD_REQUEST);
    }
    session.getContext().setClient(issuedFor);
    event.client(issuedFor);
    return new BackchannelAuthCallbackContext(bearerToken, deviceCode);
}
Also used : OAuth2DeviceTokenStoreProvider(org.keycloak.models.OAuth2DeviceTokenStoreProvider) ClientModel(org.keycloak.models.ClientModel) OAuth2DeviceCodeModel(org.keycloak.models.OAuth2DeviceCodeModel) AccessToken(org.keycloak.representations.AccessToken) ErrorResponseException(org.keycloak.services.ErrorResponseException) OAuthErrorException(org.keycloak.OAuthErrorException) ErrorResponseException(org.keycloak.services.ErrorResponseException) IOException(java.io.IOException)

Example 10 with ClientModel

use of org.keycloak.models.ClientModel 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)

Aggregations

ClientModel (org.keycloak.models.ClientModel)344 RealmModel (org.keycloak.models.RealmModel)148 UserModel (org.keycloak.models.UserModel)88 RoleModel (org.keycloak.models.RoleModel)74 KeycloakSession (org.keycloak.models.KeycloakSession)67 Test (org.junit.Test)64 UserSessionModel (org.keycloak.models.UserSessionModel)41 ResourceServer (org.keycloak.authorization.model.ResourceServer)39 Policy (org.keycloak.authorization.model.Policy)38 HashMap (java.util.HashMap)37 AuthorizationProvider (org.keycloak.authorization.AuthorizationProvider)36 AbstractTestRealmKeycloakTest (org.keycloak.testsuite.AbstractTestRealmKeycloakTest)34 ModelTest (org.keycloak.testsuite.arquillian.annotation.ModelTest)34 List (java.util.List)32 Map (java.util.Map)32 Path (javax.ws.rs.Path)29 LinkedList (java.util.LinkedList)28 ClientScopeModel (org.keycloak.models.ClientScopeModel)28 ArrayList (java.util.ArrayList)27 AuthenticatedClientSessionModel (org.keycloak.models.AuthenticatedClientSessionModel)27