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);
}
}
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());
}
}
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());
}
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();
}
}
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);
}
Aggregations