Search in sources :

Example 1 with AuthorizationEndpointChecker

use of org.keycloak.protocol.oidc.endpoints.AuthorizationEndpointChecker in project keycloak by keycloak.

the class ParEndpoint method request.

@Path("/")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response request() {
    ProfileHelper.requireFeature(Profile.Feature.PAR);
    cors = Cors.add(httpRequest).auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
    event.event(EventType.PUSHED_AUTHORIZATION_REQUEST);
    checkSsl();
    checkRealm();
    authorizeClient();
    if (httpRequest.getDecodedFormParameters().containsKey(REQUEST_URI_PARAM)) {
        throw throwErrorResponseException(OAuthErrorException.INVALID_REQUEST, "It is not allowed to include request_uri to PAR.", Response.Status.BAD_REQUEST);
    }
    try {
        authorizationRequest = AuthorizationEndpointRequestParserProcessor.parseRequest(event, session, client, httpRequest.getDecodedFormParameters());
    } catch (Exception e) {
        throw throwErrorResponseException(OAuthErrorException.INVALID_REQUEST_OBJECT, e.getMessage(), Response.Status.BAD_REQUEST);
    }
    AuthorizationEndpointChecker checker = new AuthorizationEndpointChecker().event(event).client(client).realm(realm).request(authorizationRequest).session(session);
    try {
        checker.checkRedirectUri();
    } catch (AuthorizationEndpointChecker.AuthorizationCheckException ex) {
        throw throwErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Invalid parameter: redirect_uri", Response.Status.BAD_REQUEST);
    }
    try {
        checker.checkResponseType();
    } catch (AuthorizationEndpointChecker.AuthorizationCheckException ex) {
        if (ex.getError().equals(OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE)) {
            throw throwErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Unsupported response type", Response.Status.BAD_REQUEST);
        } else {
            ex.throwAsCorsErrorResponseException(cors);
        }
    }
    try {
        checker.checkValidScope();
    } catch (AuthorizationEndpointChecker.AuthorizationCheckException ex) {
        // PAR throws this as "invalid_request" error
        throw throwErrorResponseException(OAuthErrorException.INVALID_REQUEST, ex.getErrorDescription(), Response.Status.BAD_REQUEST);
    }
    try {
        checker.checkInvalidRequestMessage();
        checker.checkOIDCRequest();
        checker.checkOIDCParams();
        checker.checkPKCEParams();
    } catch (AuthorizationEndpointChecker.AuthorizationCheckException ex) {
        ex.throwAsCorsErrorResponseException(cors);
    }
    try {
        session.clientPolicy().triggerOnEvent(new PushedAuthorizationRequestContext(authorizationRequest, httpRequest.getDecodedFormParameters()));
    } catch (ClientPolicyException cpe) {
        throw throwErrorResponseException(cpe.getError(), cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
    }
    Map<String, String> params = new HashMap<>();
    UUID key = UUID.randomUUID();
    String requestUri = REQUEST_URI_PREFIX + key.toString();
    int expiresIn = realm.getParPolicy().getRequestUriLifespan();
    httpRequest.getDecodedFormParameters().forEach((k, v) -> {
        // PAR store only accepts Map so that MultivaluedMap needs to be converted to Map.
        String singleValue = String.valueOf(v).replace("[", "").replace("]", "");
        params.put(k, singleValue);
    });
    params.put(PAR_CREATED_TIME, String.valueOf(System.currentTimeMillis()));
    PushedAuthzRequestStoreProvider parStore = session.getProvider(PushedAuthzRequestStoreProvider.class);
    parStore.put(key, expiresIn, params);
    ParResponse parResponse = new ParResponse(requestUri, expiresIn);
    session.getProvider(SecurityHeadersProvider.class).options().allowEmptyContentType();
    return cors.builder(Response.status(Response.Status.CREATED).entity(parResponse).type(MediaType.APPLICATION_JSON_TYPE)).build();
}
Also used : PushedAuthzRequestStoreProvider(org.keycloak.models.PushedAuthzRequestStoreProvider) ParResponse(org.keycloak.protocol.oidc.par.ParResponse) AuthorizationEndpointChecker(org.keycloak.protocol.oidc.endpoints.AuthorizationEndpointChecker) HashMap(java.util.HashMap) PushedAuthorizationRequestContext(org.keycloak.protocol.oidc.par.clientpolicy.context.PushedAuthorizationRequestContext) UUID(java.util.UUID) OAuthErrorException(org.keycloak.OAuthErrorException) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces)

Example 2 with AuthorizationEndpointChecker

use of org.keycloak.protocol.oidc.endpoints.AuthorizationEndpointChecker 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)

Aggregations

Consumes (javax.ws.rs.Consumes)2 POST (javax.ws.rs.POST)2 Path (javax.ws.rs.Path)2 Produces (javax.ws.rs.Produces)2 OAuthErrorException (org.keycloak.OAuthErrorException)2 AuthorizationEndpointChecker (org.keycloak.protocol.oidc.endpoints.AuthorizationEndpointChecker)2 ClientPolicyException (org.keycloak.services.clientpolicy.ClientPolicyException)2 HashMap (java.util.HashMap)1 UUID (java.util.UUID)1 ClientModel (org.keycloak.models.ClientModel)1 OAuth2DeviceCodeModel (org.keycloak.models.OAuth2DeviceCodeModel)1 OAuth2DeviceTokenStoreProvider (org.keycloak.models.OAuth2DeviceTokenStoreProvider)1 OAuth2DeviceUserCodeModel (org.keycloak.models.OAuth2DeviceUserCodeModel)1 OAuth2DeviceUserCodeProvider (org.keycloak.models.OAuth2DeviceUserCodeProvider)1 PushedAuthzRequestStoreProvider (org.keycloak.models.PushedAuthzRequestStoreProvider)1 AuthorizationEndpointRequest (org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest)1 DeviceAuthorizationRequestContext (org.keycloak.protocol.oidc.grants.device.clientpolicy.context.DeviceAuthorizationRequestContext)1 ParResponse (org.keycloak.protocol.oidc.par.ParResponse)1 PushedAuthorizationRequestContext (org.keycloak.protocol.oidc.par.clientpolicy.context.PushedAuthorizationRequestContext)1 OAuth2DeviceAuthorizationResponse (org.keycloak.representations.OAuth2DeviceAuthorizationResponse)1