Search in sources :

Example 1 with InvalidRequestObjectException

use of io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException in project gravitee-access-management by gravitee-io.

the class JWEServiceImpl method decrypt.

@Override
public Single<JWT> decrypt(String jwt, Client client, boolean encRequired) {
    try {
        // Parse a first time to check if the JWT is encrypted
        JWT parsedJwt = JWTParser.parse(jwt);
        if (parsedJwt instanceof EncryptedJWT) {
            JWEObject jweObject = JWEObject.parse(jwt);
            JWEAlgorithm algorithm = jweObject.getHeader().getAlgorithm();
            if (this.domain.useFapiBrazilProfile() && !(isKeyEncCompliantWithFapiBrazil(algorithm.getName()) && isContentEncCompliantWithFapiBrazil(jweObject.getHeader().getEncryptionMethod().getName()))) {
                return Single.error(new InvalidRequestObjectException("Request object must be encrypted using RSA-OAEP with A256GCM"));
            }
            // RSA decryption
            if (RSACryptoProvider.SUPPORTED_ALGORITHMS.contains(algorithm)) {
                return decrypt(jweObject, client, JWKFilter.RSA_KEY_ENCRYPTION(), jwk -> new RSADecrypter(JWKConverter.convert((RSAKey) jwk)));
            } else // Curve decryption (Elliptic "EC" & Edward "OKP")
            if (ECDHCryptoProvider.SUPPORTED_ALGORITHMS.contains(algorithm)) {
                return decrypt(jweObject, client, JWKFilter.CURVE_KEY_ENCRYPTION(), jwk -> {
                    if (KeyType.EC.getValue().equals(jwk.getKty())) {
                        return new ECDHDecrypter(JWKConverter.convert((ECKey) jwk));
                    }
                    return new X25519Decrypter(JWKConverter.convert((OKPKey) jwk));
                });
            } else // AES decryption ("OCT" keys)
            if (AESCryptoProvider.SUPPORTED_ALGORITHMS.contains(algorithm)) {
                return decrypt(jweObject, client, JWKFilter.OCT_KEY_ENCRYPTION(algorithm), jwk -> new AESDecrypter(JWKConverter.convert((OCTKey) jwk)));
            } else // Direct decryption ("OCT" keys)
            if (DirectCryptoProvider.SUPPORTED_ALGORITHMS.contains(algorithm)) {
                return decrypt(jweObject, client, JWKFilter.OCT_KEY_ENCRYPTION(jweObject.getHeader().getEncryptionMethod()), jwk -> new DirectDecrypter(JWKConverter.convert((OCTKey) jwk)));
            } else // Password Base decryption ("OCT" keys)
            if (PasswordBasedCryptoProvider.SUPPORTED_ALGORITHMS.contains(algorithm)) {
                return decrypt(jweObject, client, JWKFilter.OCT_KEY_ENCRYPTION(), jwk -> {
                    OctetSequenceKey octKey = JWKConverter.convert((OCTKey) jwk);
                    return new PasswordBasedDecrypter(octKey.getKeyValue().decode());
                });
            }
            return Single.error(new ServerErrorException("Unable to perform Json Web Decryption, unsupported algorithm: " + algorithm.getName()));
        } else if (encRequired) {
            return Single.error(new InvalidRequestObjectException("Request Object must be encrypted"));
        } else {
            return Single.just(parsedJwt);
        }
    } catch (Exception ex) {
        return Single.error(ex);
    }
}
Also used : JWKSet(io.gravitee.am.model.oidc.JWKSet) Client(io.gravitee.am.model.oidc.Client) JWKFilter(io.gravitee.am.gateway.handler.oidc.service.jwk.JWKFilter) Completable(io.reactivex.Completable) Maybe(io.reactivex.Maybe) LoggerFactory(org.slf4j.LoggerFactory) Autowired(org.springframework.beans.factory.annotation.Autowired) com.nimbusds.jose(com.nimbusds.jose) JWTParser(com.nimbusds.jwt.JWTParser) Single(io.reactivex.Single) Flowable(io.reactivex.Flowable) OAuth2Exception(io.gravitee.am.common.exception.oauth2.OAuth2Exception) io.gravitee.am.model.jose(io.gravitee.am.model.jose) JWT(com.nimbusds.jwt.JWT) JWKService(io.gravitee.am.gateway.handler.oidc.service.jwk.JWKService) InvalidClientMetadataException(io.gravitee.am.service.exception.InvalidClientMetadataException) OctetSequenceKey(com.nimbusds.jose.jwk.OctetSequenceKey) KeyType(com.nimbusds.jose.jwk.KeyType) JWEService(io.gravitee.am.gateway.handler.oidc.service.jwe.JWEService) Predicate(java.util.function.Predicate) Domain(io.gravitee.am.model.Domain) InvalidRequestObjectException(io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException) ServerErrorException(io.gravitee.am.common.exception.oauth2.ServerErrorException) JWKConverter(io.gravitee.am.gateway.handler.oidc.service.jwk.converter.JWKConverter) KeyUse(com.nimbusds.jose.jwk.KeyUse) Optional(java.util.Optional) EncryptedJWT(com.nimbusds.jwt.EncryptedJWT) JWAlgorithmUtils(io.gravitee.am.gateway.handler.oidc.service.utils.JWAlgorithmUtils) com.nimbusds.jose.crypto(com.nimbusds.jose.crypto) com.nimbusds.jose.crypto.impl(com.nimbusds.jose.crypto.impl) JWT(com.nimbusds.jwt.JWT) EncryptedJWT(com.nimbusds.jwt.EncryptedJWT) InvalidRequestObjectException(io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException) OAuth2Exception(io.gravitee.am.common.exception.oauth2.OAuth2Exception) InvalidClientMetadataException(io.gravitee.am.service.exception.InvalidClientMetadataException) InvalidRequestObjectException(io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException) ServerErrorException(io.gravitee.am.common.exception.oauth2.ServerErrorException) OctetSequenceKey(com.nimbusds.jose.jwk.OctetSequenceKey) ServerErrorException(io.gravitee.am.common.exception.oauth2.ServerErrorException) EncryptedJWT(com.nimbusds.jwt.EncryptedJWT)

Example 2 with InvalidRequestObjectException

use of io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException in project gravitee-access-management by gravitee-io.

the class RequestObjectServiceImpl method registerRequestObject.

@Override
public Single<RequestObjectRegistrationResponse> registerRequestObject(RequestObjectRegistrationRequest request, Client client) {
    try {
        JWT jwt = JWTParser.parse(request.getRequest());
        return checkRequestObjectAlgorithm(jwt).andThen(Single.defer(() -> validateSignature((SignedJWT) jwt, client))).flatMap(new Function<JWT, SingleSource<RequestObject>>() {

            @Override
            public SingleSource<RequestObject> apply(JWT jwt) throws Exception {
                RequestObject requestObject = new RequestObject();
                requestObject.setId(UUID.random().toString());
                requestObject.setClient(client.getId());
                requestObject.setDomain(client.getDomain());
                requestObject.setCreatedAt(new Date());
                // There is no information from the specification about a valid expiration...
                Instant expirationInst = requestObject.getCreatedAt().toInstant().plus(Duration.ofDays(1));
                requestObject.setExpireAt(Date.from(expirationInst));
                requestObject.setPayload(request.getRequest());
                return requestObjectRepository.create(requestObject);
            }
        }).flatMap((Function<RequestObject, SingleSource<RequestObjectRegistrationResponse>>) requestObject -> {
            RequestObjectRegistrationResponse response = new RequestObjectRegistrationResponse();
            response.setIss(openIDDiscoveryService.getIssuer(request.getOrigin()));
            response.setAud(client.getClientId());
            response.setRequestUri(RESOURCE_OBJECT_URN_PREFIX + requestObject.getId());
            response.setExp(requestObject.getExpireAt().getTime());
            return Single.just(response);
        });
    } catch (ParseException pe) {
        return Single.error(new InvalidRequestObjectException());
    }
}
Also used : JWKSet(io.gravitee.am.model.oidc.JWKSet) JWSService(io.gravitee.am.gateway.handler.oidc.service.jws.JWSService) Client(io.gravitee.am.model.oidc.Client) Date(java.util.Date) URISyntaxException(java.net.URISyntaxException) Autowired(org.springframework.beans.factory.annotation.Autowired) JWTParser(com.nimbusds.jwt.JWTParser) RequestObjectRegistrationRequest(io.gravitee.am.gateway.handler.oidc.service.request.RequestObjectRegistrationRequest) RequestObjectRegistrationResponse(io.gravitee.am.gateway.handler.oidc.service.request.RequestObjectRegistrationResponse) UUID(io.gravitee.common.utils.UUID) JWT(com.nimbusds.jwt.JWT) Duration(java.time.Duration) JWKService(io.gravitee.am.gateway.handler.oidc.service.jwk.JWKService) ParseException(java.text.ParseException) io.reactivex(io.reactivex) JWAlgorithmUtils.isSignAlgCompliantWithFapi(io.gravitee.am.gateway.handler.oidc.service.utils.JWAlgorithmUtils.isSignAlgCompliantWithFapi) UriBuilder(io.gravitee.am.common.web.UriBuilder) HttpResponse(io.vertx.reactivex.ext.web.client.HttpResponse) JWEService(io.gravitee.am.gateway.handler.oidc.service.jwe.JWEService) Domain(io.gravitee.am.model.Domain) InvalidRequestObjectException(io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException) Instant(java.time.Instant) SignedJWT(com.nimbusds.jwt.SignedJWT) WebClient(io.vertx.reactivex.ext.web.client.WebClient) RequestObjectRepository(io.gravitee.am.repository.oidc.api.RequestObjectRepository) RequestObjectService(io.gravitee.am.gateway.handler.oidc.service.request.RequestObjectService) Function(io.reactivex.functions.Function) RequestObject(io.gravitee.am.repository.oidc.model.RequestObject) JWK(io.gravitee.am.model.jose.JWK) OpenIDDiscoveryService(io.gravitee.am.gateway.handler.oidc.service.discovery.OpenIDDiscoveryService) Function(io.reactivex.functions.Function) JWT(com.nimbusds.jwt.JWT) SignedJWT(com.nimbusds.jwt.SignedJWT) Instant(java.time.Instant) ParseException(java.text.ParseException) InvalidRequestObjectException(io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException) Date(java.util.Date) RequestObject(io.gravitee.am.repository.oidc.model.RequestObject) RequestObjectRegistrationResponse(io.gravitee.am.gateway.handler.oidc.service.request.RequestObjectRegistrationResponse)

Example 3 with InvalidRequestObjectException

use of io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException in project gravitee-access-management by gravitee-io.

the class PushedAuthorizationRequestServiceTest method shouldNotPersist_RequestWithUnexpectedClaims.

@Test
public void shouldNotPersist_RequestWithUnexpectedClaims() throws Exception {
    final Client client = createClient();
    final String jwtString = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiMTIzNDU2Nzg5MCIsImh0dHA6Ly9vcCJdLCJjbGllbnRfaWQiOiJjbGllbnRpZCIsInJlcXVlc3QiOiJkc2Zkc2YifQ.S6EQZgosP7FlIfyiV85bjeWnEW4yGjf8PlAZiYIZkyIgiHzlFIEnisxc_P42dKcFK8azW6xVw7OiOYLoIEo2QhZqvT4YZWgAjlqZoaMzBs68zkQr10xXrMLK8k-6wsQUONy49f7cR5niauuKYMgeVc4k5qLDvc6p1iKfUZu6VVvv-nhNT3GOacgJqwviofI-ZvBGGr0O8kP13nWf5RRElNgNw06Hnza139KwqEsim7kFDzs9TCrXl-3CzYvYtF-VYTsDTLf9ArkJgsxvs1PSULu0Sq9m5_sokJuV3DiF9daj2v3Zmd0ZYRbr1OSKreseW0fxNGmQZyHaVgtEowUv8g";
    final JWT parse = JWTParser.parse(jwtString);
    final LinkedMultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
    parameters.add("request", jwtString);
    parameters.add("client_id", client.getClientId());
    final PushedAuthorizationRequest par = new PushedAuthorizationRequest();
    par.setParameters(parameters);
    par.setId("parid");
    par.setClient(client.getId());
    when(jweService.decrypt(any(), anyBoolean())).thenReturn(Single.just(parse));
    final TestObserver<PushedAuthorizationRequestResponse> observer = cut.registerParameters(par, client).test();
    observer.awaitTerminalEvent();
    observer.assertError(e -> e instanceof InvalidRequestObjectException && e.getMessage().equals("Claims request and request_uri are forbidden"));
    verify(repository, never()).create(any());
}
Also used : PushedAuthorizationRequest(io.gravitee.am.repository.oauth2.model.PushedAuthorizationRequest) LinkedMultiValueMap(io.gravitee.common.util.LinkedMultiValueMap) JWT(com.nimbusds.jwt.JWT) SignedJWT(com.nimbusds.jwt.SignedJWT) Client(io.gravitee.am.model.oidc.Client) InvalidRequestObjectException(io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException) Test(org.junit.Test)

Example 4 with InvalidRequestObjectException

use of io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException in project gravitee-access-management by gravitee-io.

the class AuthorizationRequestParseRequestObjectHandler method checkOAuthParameters.

private void checkOAuthParameters(RoutingContext context, JWT jwt) {
    // So that the request is a valid OAuth 2.0 Authorization Request, values for the response_type and client_id
    // parameters MUST be included using the OAuth 2.0 request syntax, since they are REQUIRED by OAuth 2.0. The
    // values for these parameters MUST match those in the Request Object, if present.
    String clientId = context.request().getParam(io.gravitee.am.common.oauth2.Parameters.CLIENT_ID);
    String responseType = context.request().getParam(io.gravitee.am.common.oauth2.Parameters.RESPONSE_TYPE);
    try {
        Map<String, Object> claims = jwt.getJWTClaimsSet().getClaims();
        String reqObjClientId = (String) claims.get(io.gravitee.am.common.oauth2.Parameters.CLIENT_ID);
        if (reqObjClientId != null && !reqObjClientId.equals(clientId)) {
            throw new InvalidRequestObjectException("client_id does not match request parameter");
        }
        String reqObjResponseType = (String) claims.get(io.gravitee.am.common.oauth2.Parameters.RESPONSE_TYPE);
        if (responseType != null && reqObjResponseType != null && !reqObjResponseType.equals(responseType)) {
            throw new InvalidRequestObjectException("response_type does not match request parameter");
        }
    } catch (ParseException pe) {
        throw new InvalidRequestObjectException();
    }
}
Also used : ParseException(java.text.ParseException) InvalidRequestObjectException(io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException)

Example 5 with InvalidRequestObjectException

use of io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException in project gravitee-access-management by gravitee-io.

the class AuthorizationRequestParseRequestObjectHandler method validateRequestObjectClaims.

private Single<JWT> validateRequestObjectClaims(RoutingContext context, JWT jwt) {
    if (this.domain.usePlainFapiProfile()) {
        try {
            final boolean fromRequestUri = context.get(REQUEST_OBJECT_FROM_URI);
            final JWTClaimsSet jwtClaimsSet = jwt.getJWTClaimsSet();
            // in addition FAPI requires some claims that are optional in the OIDC core spec (like exp, nbf...)
            if (jwtClaimsSet.getExpirationTime() == null || jwtClaimsSet.getExpirationTime().before(new Date())) {
                throw generateException(jwtClaimsSet.getExpirationTime() == null && fromRequestUri, "Request object must contains valid exp claim");
            }
            List<String> redirectUri = context.queryParam(io.gravitee.am.common.oauth2.Parameters.REDIRECT_URI);
            final String redirectUriClaim = jwtClaimsSet.getStringClaim(io.gravitee.am.common.oauth2.Parameters.REDIRECT_URI);
            if (redirectUriClaim == null || (redirectUriClaim != null && redirectUri != null && !redirectUri.isEmpty() && !redirectUriClaim.equals(redirectUri.get(0)))) {
                // remove redirect_uri provided as parameter and continue to let AuthorizationRequestParseParametersHandler
                // throws the right error according to the client configuration
                context.request().params().remove(io.gravitee.am.common.oauth2.Parameters.REDIRECT_URI);
                throw new InvalidRequestException("Missing or invalid redirect_uri");
            }
            final Date nbf = jwtClaimsSet.getNotBeforeTime();
            if (nbf == null || (nbf.getTime() + ONE_HOUR_IN_MILLIS) < jwtClaimsSet.getExpirationTime().getTime()) {
                throw generateException(fromRequestUri, "Request object older than 60 minutes");
            }
            List<String> state = context.queryParam(io.gravitee.am.common.oauth2.Parameters.STATE);
            final String stateClaim = jwtClaimsSet.getStringClaim(io.gravitee.am.common.oauth2.Parameters.STATE);
            if (state != null && !state.isEmpty() && (stateClaim == null || !stateClaim.equals(state.get(0)))) {
                throw generateException(fromRequestUri, "Request object must contains valid state claim");
            }
            final OpenIDProviderMetadata openIDProviderMetadata = context.get(PROVIDER_METADATA_CONTEXT_KEY);
            if (jwtClaimsSet.getAudience() == null || (openIDProviderMetadata != null && !jwtClaimsSet.getAudience().contains(openIDProviderMetadata.getIssuer()))) {
                // the aud claim in the request object shall be, or shall be an array containing, the OP’s Issuer Identifier URL;
                throw generateException(fromRequestUri, "Invalid audience claim");
            }
            List<String> scope = context.queryParam(io.gravitee.am.common.oauth2.Parameters.SCOPE);
            final String scopeClaim = jwtClaimsSet.getStringClaim(Claims.scope);
            if (scope != null && !scope.isEmpty() && (scopeClaim == null || !scopeClaim.equals(scope.get(0)))) {
                throw generateException(fromRequestUri, "Request object must contains valid scope claim");
            }
            // String scopeClaim = jwtClaimsSet.getStringClaim(Claims.scope);
            if (scopeClaim != null && scopeClaim.contains("openid") && StringUtils.isEmpty(jwtClaimsSet.getStringClaim(Parameters.NONCE))) {
                // If the client requests the openid scope, the authorization server shall require the nonce parameter defined
                throw generateException(fromRequestUri, "Scope openid expect the nonce parameter defined");
            } else if ((scopeClaim == null || !scopeClaim.contains("openid")) && StringUtils.isEmpty(jwtClaimsSet.getStringClaim(io.gravitee.am.common.oauth2.Parameters.STATE))) {
                // If the client does not request the openid scope, the authorization server shall require the state parameter defined
                throw generateException(fromRequestUri, "Absence of scope openid expect the state parameter defined");
            }
        } catch (OAuth2Exception e) {
            return Single.error(e);
        } catch (ParseException e) {
            return Single.error(new InvalidRequestObjectException());
        }
    }
    return Single.just(jwt);
}
Also used : JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) InvalidRequestException(io.gravitee.am.common.exception.oauth2.InvalidRequestException) OpenIDProviderMetadata(io.gravitee.am.gateway.handler.oidc.service.discovery.OpenIDProviderMetadata) ParseException(java.text.ParseException) InvalidRequestObjectException(io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException) OAuth2Exception(io.gravitee.am.common.exception.oauth2.OAuth2Exception)

Aggregations

InvalidRequestObjectException (io.gravitee.am.common.exception.oauth2.InvalidRequestObjectException)6 Client (io.gravitee.am.model.oidc.Client)4 JWT (com.nimbusds.jwt.JWT)3 OAuth2Exception (io.gravitee.am.common.exception.oauth2.OAuth2Exception)3 JWEService (io.gravitee.am.gateway.handler.oidc.service.jwe.JWEService)3 JWTParser (com.nimbusds.jwt.JWTParser)2 SignedJWT (com.nimbusds.jwt.SignedJWT)2 UriBuilder (io.gravitee.am.common.web.UriBuilder)2 OpenIDDiscoveryService (io.gravitee.am.gateway.handler.oidc.service.discovery.OpenIDDiscoveryService)2 JWKService (io.gravitee.am.gateway.handler.oidc.service.jwk.JWKService)2 Domain (io.gravitee.am.model.Domain)2 JWKSet (io.gravitee.am.model.oidc.JWKSet)2 ParseException (java.text.ParseException)2 Autowired (org.springframework.beans.factory.annotation.Autowired)2 com.nimbusds.jose (com.nimbusds.jose)1 com.nimbusds.jose.crypto (com.nimbusds.jose.crypto)1 com.nimbusds.jose.crypto.impl (com.nimbusds.jose.crypto.impl)1 KeyType (com.nimbusds.jose.jwk.KeyType)1 KeyUse (com.nimbusds.jose.jwk.KeyUse)1 OctetSequenceKey (com.nimbusds.jose.jwk.OctetSequenceKey)1