Search in sources :

Example 1 with AccessTokenReWriteException

use of com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException in project openbanking-aspsp by OpenBankingToolkit.

the class JwtOverridingService method rewriteIdTokenFragmentInLocationHeader.

/**
 * Rewrite the id_token fragment of a ResponseEntity such that it is replaced with a new id_token containing the
 * same body, but that is signed by the ASPSP's signing key and contains the correct kid in the jwt header.
 * @param responseEntity
 * @return a new @ResponseEntity
 * @throws AccessTokenReWriteException if there is no id_token in the Location header fragment that can be replaced,
 * or if the id_token in that fragment can't be parsed.
 */
public ResponseEntity rewriteIdTokenFragmentInLocationHeader(ResponseEntity responseEntity) throws AccessTokenReWriteException {
    if (responseEntity == null) {
        log.debug("getFragmentIdTokenInLocationHeader(): responseEntity is null");
        throw new AccessTokenReWriteException("Failed to find id_token to re-write: responseEntity is null");
    }
    log.trace("rewriteIdTokenFragmentInLocationHeader() responseEntity is '{}'", responseEntity);
    if (responseEntity.getStatusCode() != HttpStatus.FOUND) {
        log.debug("getFragmentIdTokenInLocationHeader(): responseEntity does not have a FOUND http Status; '{}'", responseEntity);
        throw new AccessTokenReWriteException("Failed to find id_token to re-write: responseEntity does not have " + "a FOUND http status");
    }
    if (responseEntity.getHeaders().getLocation() == null) {
        log.debug("getFragmentIdTokenInLocationHeader(): responseEntity has no location header: '{}'", responseEntity);
        throw new AccessTokenReWriteException("Failed to find id_token to re-write: responseEntity has no " + "location header");
    } else {
        log.debug("getFragmentIdTokenInLocationHeader(): Location is: {}", responseEntity.getHeaders().getLocation());
    }
    String uriFragment = responseEntity.getHeaders().getLocation().getFragment();
    if (uriFragment == null || uriFragment.isEmpty() || uriFragment.isBlank()) {
        log.debug("getFragmentIdTokenInLocationHeader(): Location has no fragment");
        throw new AccessTokenReWriteException("Failed to find id_token to re-write: responseEntity's Location has" + " no fragment");
    }
    ResponseEntity rewrittenResponseEntity = null;
    try {
        String locationString = responseEntity.getHeaders().getLocation().toString();
        if (locationString.contains(ID_TOKEN_PARAM + EQUALS_CHAR)) {
            Matcher matcher = ID_TOKEN_PATTERN.matcher(locationString);
            while (matcher.find()) {
                String oldIdToken = matcher.group(1);
                String newIdToken = rewriteJWS(oldIdToken);
                String newLocationHeaderValue = locationString.replaceAll(oldIdToken, newIdToken);
                if (!newLocationHeaderValue.isEmpty() && !newLocationHeaderValue.isBlank()) {
                    HttpHeaders writableHttpHeaders = HttpHeaders.writableHttpHeaders(responseEntity.getHeaders());
                    writableHttpHeaders.set(HttpHeaders.LOCATION, newLocationHeaderValue);
                    rewrittenResponseEntity = new ResponseEntity(responseEntity.getBody(), writableHttpHeaders, HttpStatus.FOUND);
                } else {
                    log.debug("rewriteIdTokenFragmentInLocationHeader() No new location header value.");
                    throw new AccessTokenReWriteException("Failed to rewrite id_token: new Location header value is " + "null or empty");
                }
            }
        } else if (locationString.contains(ERROR_PARAM + EQUALS_CHAR)) {
            // reject by user
            throw new AccessTokenReWriteException("Rejected by user");
        }
    } catch (ParseException e) {
        log.error("rewriteIdTokenFragmentInLocationHeader() Could not parse the JWT", e);
        throw new AccessTokenReWriteException("Failed to parse the responseEntity's Location fragment id_token", e);
    }
    return rewrittenResponseEntity;
}
Also used : HttpHeaders(org.springframework.http.HttpHeaders) ResponseEntity(org.springframework.http.ResponseEntity) Matcher(java.util.regex.Matcher) AccessTokenReWriteException(com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException) ParseException(java.text.ParseException)

Example 2 with AccessTokenReWriteException

use of com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException in project openbanking-aspsp by OpenBankingToolkit.

the class JwtOverridingService method rewriteAccessTokenResponseIdToken.

/**
 * rewriteAccessTokenResponseIdToken - creates a new id_token, signed with the correct ID and containing the
 * correct kid in the header. This is required as currently AM uses a different algorithm to create the kid than
 * the OB Directory does, so when signing with the OB Signing Key or an OBSeal then the key ID in the AM
 * generated id_token doesn't match the kid in the OB Directory jwks_uri and hence the id_token can't be
 * validated. To fix that we resign it using the crypto API which produces a verifyable token.
 *
 * @param responseEntity the response entity that contains the id_token. Note, the id_token will only exist if
 *                       the request to get the access token contained the openid scope, which is not mandatory.
 *                       If the response entity does not contain an id_token then there is nothing to be
 *                       re-written and the responseEntity will be returned.
 * @return Either the responseEntity passed to the method (if it contained no id_token to be re-written), or a
 * new responseEntity containing a new id_token that is verifiable.
 * @throws AccessTokenReWriteException
 */
public ResponseEntity rewriteAccessTokenResponseIdToken(ResponseEntity responseEntity) throws AccessTokenReWriteException {
    if (responseEntity == null) {
        throw new AccessTokenReWriteException("rewriteAccessTokenResponseIdToken() responseEntity is null");
    }
    if (responseEntity.getStatusCode() != HttpStatus.OK) {
        log.debug("rewriteAccessTokenResponseIdToken() responseEntity does not have success status");
        throw new AccessTokenReWriteException("Failed to rewrite access token response's id_token: responseEntity" + " status code was " + responseEntity.getStatusCode() + ". Expected 200 (OK)");
    }
    AccessTokenResponse accessTokenResponse = (AccessTokenResponse) responseEntity.getBody();
    if (accessTokenResponse == null) {
        log.debug("rewriteAccessTokenResponseIdToken() Expected body in responseEntity '{}'", responseEntity);
        throw new AccessTokenReWriteException("Failed to rewrite access token response's id_token; responseEntity" + " has no body");
    }
    String id_token = accessTokenResponse.getId_token();
    if (id_token == null) {
        log.debug("rewriteAccessTokenResponseIdToken() responseEntity body contains no id_token; '{}'", accessTokenResponse);
        return responseEntity;
    } else {
        try {
            String rewrittenJWS = rewriteJWS(id_token);
            if (rewrittenJWS == null || rewrittenJWS.isEmpty() || rewrittenJWS.isBlank()) {
                log.debug("rewriteAccessTokenResponseIdToken() rewrittenJWS is null or empty.");
                throw new AccessTokenReWriteException("Failed to rewrite access token response's id_token; " + "re-written JWS is null or empty");
            }
            accessTokenResponse.setId_token(rewrittenJWS);
        } catch (ParseException e) {
            log.debug("rewriteAccessTokenResponseIdToken() Failed to parse id_token: '{}'", id_token, e);
            throw new AccessTokenReWriteException("Failed to rewrite access token response's id_token; Could not " + "parse id_token", e);
        }
        ResponseEntity rewrittenResponseEntity = ResponseEntity.status(HttpStatus.OK).body(accessTokenResponse);
        log.trace("rewriteAccessTokenResponseIdToken() re-written responseEntity is '{}'", responseEntity);
        return rewrittenResponseEntity;
    }
}
Also used : ResponseEntity(org.springframework.http.ResponseEntity) AccessTokenReWriteException(com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException) ParseException(java.text.ParseException) AccessTokenResponse(com.forgerock.openbanking.model.oidc.AccessTokenResponse)

Example 3 with AccessTokenReWriteException

use of com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException in project openbanking-aspsp by OpenBankingToolkit.

the class JwtOverridingServiceTest method shouldFailWhenBodyHasInvalidIdToken_rewriteAccessTokenResponseIdToken.

@Test
public void shouldFailWhenBodyHasInvalidIdToken_rewriteAccessTokenResponseIdToken() {
    // Given
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.add("Location", "https://location");
    AccessTokenResponse accessTokenResponse = new AccessTokenResponse();
    accessTokenResponse.setId_token("InvalidToken");
    ResponseEntity responseEntity = new ResponseEntity(accessTokenResponse, httpHeaders, HttpStatus.OK);
    // Then
    AccessTokenReWriteException accessTokenReWriteException = catchThrowableOfType(() -> this.jwtOverridingService.rewriteAccessTokenResponseIdToken(responseEntity), AccessTokenReWriteException.class);
    // When
    assertThat(accessTokenReWriteException.getMessage()).contains("Could not parse id_token");
}
Also used : HttpHeaders(org.springframework.http.HttpHeaders) ResponseEntity(org.springframework.http.ResponseEntity) AccessTokenReWriteException(com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException) AccessTokenResponse(com.forgerock.openbanking.model.oidc.AccessTokenResponse) Test(org.junit.Test)

Example 4 with AccessTokenReWriteException

use of com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException in project openbanking-aspsp by OpenBankingToolkit.

the class JwtOverridingServiceTest method shouldFailWhenNoBody_rewriteAccessTokenResponseIdToken.

@Test
public void shouldFailWhenNoBody_rewriteAccessTokenResponseIdToken() {
    // Given
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.add("Location", "https://location");
    ResponseEntity responseEntity = new ResponseEntity(HttpStatus.OK);
    // Then
    AccessTokenReWriteException accessTokenReWriteException = catchThrowableOfType(() -> this.jwtOverridingService.rewriteAccessTokenResponseIdToken(responseEntity), AccessTokenReWriteException.class);
    // When
    assertThat(accessTokenReWriteException.getMessage()).contains("responseEntity has no body");
}
Also used : HttpHeaders(org.springframework.http.HttpHeaders) ResponseEntity(org.springframework.http.ResponseEntity) AccessTokenReWriteException(com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException) Test(org.junit.Test)

Example 5 with AccessTokenReWriteException

use of com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException in project openbanking-aspsp by OpenBankingToolkit.

the class JwtOverridingServiceTest method shouldFailWhenStatusNotFound_rewriteIdTokenFragmentInLocationHeader.

@Test
public void shouldFailWhenStatusNotFound_rewriteIdTokenFragmentInLocationHeader() {
    // Given
    amOpenBankingConfiguration.issuerId = "acme bank Ltd";
    ResponseEntity responseEntity = new ResponseEntity(HttpStatus.OK);
    // When
    AccessTokenReWriteException accessTokenReWriteException = catchThrowableOfType(() -> this.jwtOverridingService.rewriteIdTokenFragmentInLocationHeader(responseEntity), AccessTokenReWriteException.class);
    // Then
    assertThat(accessTokenReWriteException.getMessage()).contains("does not have a FOUND http status");
}
Also used : ResponseEntity(org.springframework.http.ResponseEntity) AccessTokenReWriteException(com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException) Test(org.junit.Test)

Aggregations

AccessTokenReWriteException (com.forgerock.openbanking.common.error.exception.AccessTokenReWriteException)9 ResponseEntity (org.springframework.http.ResponseEntity)8 HttpHeaders (org.springframework.http.HttpHeaders)5 ParseException (java.text.ParseException)4 Test (org.junit.Test)4 AccessTokenResponse (com.forgerock.openbanking.model.oidc.AccessTokenResponse)3 AMGateway (com.forgerock.openbanking.am.gateway.AMGateway)2 OBErrorException (com.forgerock.openbanking.exceptions.OBErrorException)2 OBErrorResponseException (com.forgerock.openbanking.exceptions.OBErrorResponseException)2 SignedJWT (com.nimbusds.jwt.SignedJWT)2 PairClientIDAuthMethod (com.forgerock.openbanking.aspsp.as.service.PairClientIDAuthMethod)1 RedirectionAction (com.forgerock.openbanking.common.model.rcs.RedirectionAction)1 ConsentDecision (com.forgerock.openbanking.common.model.rcs.consentdecision.ConsentDecision)1 GrantType (com.forgerock.openbanking.constants.OIDCConstants.GrantType)1 Tpp (com.forgerock.openbanking.model.Tpp)1 Claims (com.forgerock.openbanking.model.claim.Claims)1 JOSEException (com.nimbusds.jose.JOSEException)1 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1 Matcher (java.util.regex.Matcher)1