From b2efa5aad192f0fb9bf7160b7c05e6499303a820 Mon Sep 17 00:00:00 2001 From: Javier Rojas Blum Date: Thu, 4 Nov 2021 00:01:50 -0400 Subject: [PATCH] fix: jarm alignment for fapi brazil conformance --- ...sponseTypeCodeSignedEncryptedHttpTest.java | 336 +++++++++++++++++- .../ws/rs/AuthorizeRestWebServiceImpl.java | 6 +- .../rs/AuthorizeRestWebServiceValidator.java | 5 + .../authorize/JwtAuthorizationRequest.java | 7 +- 4 files changed, 345 insertions(+), 9 deletions(-) diff --git a/client/src/test/java/io/jans/as/client/ws/rs/jarm/AuthorizationResponseModeJwtResponseTypeCodeSignedEncryptedHttpTest.java b/client/src/test/java/io/jans/as/client/ws/rs/jarm/AuthorizationResponseModeJwtResponseTypeCodeSignedEncryptedHttpTest.java index 8e5596cfc20..76c22885048 100644 --- a/client/src/test/java/io/jans/as/client/ws/rs/jarm/AuthorizationResponseModeJwtResponseTypeCodeSignedEncryptedHttpTest.java +++ b/client/src/test/java/io/jans/as/client/ws/rs/jarm/AuthorizationResponseModeJwtResponseTypeCodeSignedEncryptedHttpTest.java @@ -35,7 +35,7 @@ /** * @author Javier Rojas Blum - * @version October 21, 2021 + * @version November 3, 2021 */ public class AuthorizationResponseModeJwtResponseTypeCodeSignedEncryptedHttpTest extends BaseTest { @@ -57,11 +57,11 @@ public void authorizationRequestObjectPS256RSA_OAEPA256GCM( String clientId = registerResponse.getClientId(); // 2. Request authorization - List scopes = Arrays.asList("openid", "profile", "address", "email"); + List scope = Arrays.asList("openid", "profile", "address", "email"); String state = UUID.randomUUID().toString(); String nonce = UUID.randomUUID().toString(); - AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scopes, redirectUri, null); + AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scope, redirectUri, null); authorizationRequest.setResponseMode(ResponseMode.JWT); authorizationRequest.setState(state); @@ -124,16 +124,19 @@ public void authorizationRequestObjectPS256RSA_OAEPA256GCMFail1( List responseTypes = Arrays.asList(ResponseType.CODE); // 1. Dynamic Client Registration +// RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, +// SignatureAlgorithm.PS256, KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM); RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, - SignatureAlgorithm.PS256, KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM); + SignatureAlgorithm.PS256, null, null); String clientId = registerResponse.getClientId(); // 2. Request authorization - List scopes = Arrays.asList("openid", "profile", "address", "email"); + List scope = Arrays.asList("openid", "profile", "address", "email"); String state = UUID.randomUUID().toString(); + String nonce = UUID.randomUUID().toString(); - AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scopes, redirectUri, null); + AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scope, redirectUri, nonce); authorizationRequest.setResponseMode(ResponseMode.JWT); authorizationRequest.setState(state); @@ -148,6 +151,8 @@ public void authorizationRequestObjectPS256RSA_OAEPA256GCMFail1( jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.PICTURE, ClaimValue.createEssential(false))); jwsAuthorizationRequest.addIdTokenClaim(new Claim(JwtClaimName.AUTHENTICATION_TIME, ClaimValue.createNull())); jwsAuthorizationRequest.getIdTokenMember().setMaxAge(86400); + jwsAuthorizationRequest.setScopes(scope); + jwsAuthorizationRequest.setRedirectUri(redirectUri); jwsAuthorizationRequest.setNonce(null); // FAPI: nonce param is required jwsAuthorizationRequest.setNbf((int) Instant.now().getEpochSecond()); // FAPI: require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim jwsAuthorizationRequest.setExp(jwsAuthorizationRequest.getNbf() + 3600); // FAPI: require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim @@ -173,7 +178,166 @@ public void authorizationRequestObjectPS256RSA_OAEPA256GCMFail1( AuthorizationResponse authorizationResponse = authorizationRequest(authorizationRequest, ResponseMode.QUERY_JWT, userId, userSecret); assertNotNull(authorizationResponse.getResponse()); - Jwe response = Jwe.parse(authorizationResponse.getResponse(), privateKey, null); + //Jwe response = Jwe.parse(authorizationResponse.getResponse(), privateKey, null); + Jwt response = Jwt.parse(authorizationResponse.getResponse()); + + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.ISS)); + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.AUD)); + assertNotNull(response.getClaims().getClaimAsInteger(AuthorizeResponseParam.EXP)); + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.STATE)); + assertNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.CODE)); + assertNotNull(response.getClaims().getClaimAsString("error")); + assertNotNull(response.getClaims().getClaimAsString("error_description")); + + privateKey = null; // Clear private key to do not affect to other tests + } + + @Parameters({"userId", "userSecret", "redirectUri", "redirectUris", "clientJwksUri", "RSA_OAEP_keyId", + "PS256_keyId", "dnName", "keyStoreFile", "keyStoreSecret", "sectorIdentifierUri"}) + //@Test // Enable FAPI to run this test! + public void authorizationRequestObjectPS256RSA_OAEPA256GCMFail2( + final String userId, final String userSecret, final String redirectUri, final String redirectUris, + final String clientJwksUri, final String encryptionKeyId, final String signingKeyId, final String dnName, final String keyStoreFile, + final String keyStoreSecret, final String sectorIdentifierUri) throws Exception { + showTitle("authorizationRequestObjectPS256RSA_OAEPA256GCMFail2"); + + List responseTypes = Arrays.asList(ResponseType.CODE); + + // 1. Dynamic Client Registration +// RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, +// SignatureAlgorithm.PS256, KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM); + RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, + SignatureAlgorithm.PS256, null, null); + + String clientId = registerResponse.getClientId(); + + // 2. Request authorization + List scope = Arrays.asList("openid", "profile", "address", "email"); + String state = UUID.randomUUID().toString(); + String nonce = UUID.randomUUID().toString(); + + AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scope, redirectUri, null); + authorizationRequest.setResponseMode(ResponseMode.JWT); + authorizationRequest.setState(state); + + AuthCryptoProvider cryptoProvider1 = new AuthCryptoProvider(keyStoreFile, keyStoreSecret, dnName); + + JwtAuthorizationRequest jwsAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest, SignatureAlgorithm.PS256, cryptoProvider1); + jwsAuthorizationRequest.setKeyId(signingKeyId); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.NAME, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.NICKNAME, ClaimValue.createEssential(false))); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.EMAIL, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.EMAIL_VERIFIED, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.PICTURE, ClaimValue.createEssential(false))); + jwsAuthorizationRequest.addIdTokenClaim(new Claim(JwtClaimName.AUTHENTICATION_TIME, ClaimValue.createNull())); + jwsAuthorizationRequest.getIdTokenMember().setMaxAge(86400); + jwsAuthorizationRequest.setRedirectUri(redirectUri); + jwsAuthorizationRequest.setNonce(nonce); // FAPI: nonce param is required + jwsAuthorizationRequest.setNbf((int) Instant.now().getEpochSecond()); // FAPI: require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim + jwsAuthorizationRequest.setExp(null); // FAPI: exp param is required + Jwt authJws = Jwt.parse(jwsAuthorizationRequest.getEncodedJwt()); + + JwkClient jwkClient = new JwkClient(jwksUri); + JwkResponse jwkResponse = jwkClient.exec(); + String serverKeyId = jwkResponse.getKeyId(Algorithm.RSA_OAEP); + assertNotNull(serverKeyId); + + JSONObject jwks = JwtUtil.getJSONWebKeys(jwksUri); + AuthCryptoProvider cryptoProvider2 = new AuthCryptoProvider(keyStoreFile, keyStoreSecret, dnName); + privateKey = cryptoProvider2.getPrivateKey(encryptionKeyId); + + JwtAuthorizationRequest jweAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest, + KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM, cryptoProvider2); + jweAuthorizationRequest.setKeyId(serverKeyId); + jweAuthorizationRequest.setNestedPayload(authJws); + String authJwe = jweAuthorizationRequest.getEncodedJwt(jwks); + + authorizationRequest.setRequest(authJwe); + + AuthorizationResponse authorizationResponse = authorizationRequest(authorizationRequest, ResponseMode.QUERY_JWT, userId, userSecret); + assertNotNull(authorizationResponse.getResponse()); + + //Jwe response = Jwe.parse(authorizationResponse.getResponse(), privateKey, null); + Jwt response = Jwt.parse(authorizationResponse.getResponse()); + + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.ISS)); + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.AUD)); + assertNotNull(response.getClaims().getClaimAsInteger(AuthorizeResponseParam.EXP)); + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.STATE)); + assertNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.CODE)); + assertNotNull(response.getClaims().getClaimAsString("error")); + assertNotNull(response.getClaims().getClaimAsString("error_description")); + + privateKey = null; // Clear private key to do not affect to other tests + } + + @Parameters({"userId", "userSecret", "redirectUri", "redirectUris", "clientJwksUri", "RSA_OAEP_keyId", + "PS256_keyId", "dnName", "keyStoreFile", "keyStoreSecret", "sectorIdentifierUri"}) + //@Test // Enable FAPI to run this test! + public void authorizationRequestObjectPS256RSA_OAEPA256GCMFail3( + final String userId, final String userSecret, final String redirectUri, final String redirectUris, + final String clientJwksUri, final String encryptionKeyId, final String signingKeyId, final String dnName, final String keyStoreFile, + final String keyStoreSecret, final String sectorIdentifierUri) throws Exception { + showTitle("authorizationRequestObjectPS256RSA_OAEPA256GCMFail3"); + + List responseTypes = Arrays.asList(ResponseType.CODE); + + // 1. Dynamic Client Registration +// RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, +// SignatureAlgorithm.PS256, KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM); + RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, + SignatureAlgorithm.PS256, null, null); + + String clientId = registerResponse.getClientId(); + + // 2. Request authorization + List scope = Arrays.asList("openid", "profile", "address", "email"); + String state = UUID.randomUUID().toString(); + String nonce = UUID.randomUUID().toString(); + + AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scope, redirectUri, null); + authorizationRequest.setResponseMode(ResponseMode.JWT); + authorizationRequest.setState(state); + + AuthCryptoProvider cryptoProvider1 = new AuthCryptoProvider(keyStoreFile, keyStoreSecret, dnName); + + JwtAuthorizationRequest jwsAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest, SignatureAlgorithm.PS256, cryptoProvider1); + jwsAuthorizationRequest.setKeyId(signingKeyId); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.NAME, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.NICKNAME, ClaimValue.createEssential(false))); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.EMAIL, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.EMAIL_VERIFIED, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.PICTURE, ClaimValue.createEssential(false))); + jwsAuthorizationRequest.addIdTokenClaim(new Claim(JwtClaimName.AUTHENTICATION_TIME, ClaimValue.createNull())); + jwsAuthorizationRequest.getIdTokenMember().setMaxAge(86400); + jwsAuthorizationRequest.setRedirectUri(redirectUri); + jwsAuthorizationRequest.setNonce(nonce); // FAPI: nonce param is required + jwsAuthorizationRequest.setNbf(null); // FAPI: nbf param is required + jwsAuthorizationRequest.setExp((int) Instant.now().getEpochSecond() + 3600); // FAPI: require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim + Jwt authJws = Jwt.parse(jwsAuthorizationRequest.getEncodedJwt()); + + JwkClient jwkClient = new JwkClient(jwksUri); + JwkResponse jwkResponse = jwkClient.exec(); + String serverKeyId = jwkResponse.getKeyId(Algorithm.RSA_OAEP); + assertNotNull(serverKeyId); + + JSONObject jwks = JwtUtil.getJSONWebKeys(jwksUri); + AuthCryptoProvider cryptoProvider2 = new AuthCryptoProvider(keyStoreFile, keyStoreSecret, dnName); + privateKey = cryptoProvider2.getPrivateKey(encryptionKeyId); + + JwtAuthorizationRequest jweAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest, + KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM, cryptoProvider2); + jweAuthorizationRequest.setKeyId(serverKeyId); + jweAuthorizationRequest.setNestedPayload(authJws); + String authJwe = jweAuthorizationRequest.getEncodedJwt(jwks); + + authorizationRequest.setRequest(authJwe); + + AuthorizationResponse authorizationResponse = authorizationRequest(authorizationRequest, ResponseMode.QUERY_JWT, userId, userSecret); + assertNotNull(authorizationResponse.getResponse()); + + //Jwe response = Jwe.parse(authorizationResponse.getResponse(), privateKey, null); + Jwt response = Jwt.parse(authorizationResponse.getResponse()); assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.ISS)); assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.AUD)); @@ -183,6 +347,164 @@ public void authorizationRequestObjectPS256RSA_OAEPA256GCMFail1( assertNotNull(response.getClaims().getClaimAsString("error")); assertNotNull(response.getClaims().getClaimAsString("error_description")); + privateKey = null; // Clear private key to do not affect to other tests + } + + @Parameters({"userId", "userSecret", "redirectUri", "redirectUris", "clientJwksUri", "RSA_OAEP_keyId", + "PS256_keyId", "dnName", "keyStoreFile", "keyStoreSecret", "sectorIdentifierUri"}) + //@Test // Enable FAPI to run this test! + public void authorizationRequestObjectPS256RSA_OAEPA256GCMFail4( + final String userId, final String userSecret, final String redirectUri, final String redirectUris, + final String clientJwksUri, final String encryptionKeyId, final String signingKeyId, final String dnName, final String keyStoreFile, + final String keyStoreSecret, final String sectorIdentifierUri) throws Exception { + showTitle("authorizationRequestObjectPS256RSA_OAEPA256GCMFail4"); + + List responseTypes = Arrays.asList(ResponseType.CODE); + + // 1. Dynamic Client Registration +// RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, +// SignatureAlgorithm.PS256, KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM); + RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, + SignatureAlgorithm.PS256, null, null); + + String clientId = registerResponse.getClientId(); + + // 2. Request authorization + List scope = Arrays.asList("openid", "profile", "address", "email"); + String state = UUID.randomUUID().toString(); + String nonce = UUID.randomUUID().toString(); + + AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scope, redirectUri, null); + authorizationRequest.setResponseMode(ResponseMode.JWT); + authorizationRequest.setState(state); + + AuthCryptoProvider cryptoProvider1 = new AuthCryptoProvider(keyStoreFile, keyStoreSecret, dnName); + + JwtAuthorizationRequest jwsAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest, SignatureAlgorithm.PS256, cryptoProvider1); + jwsAuthorizationRequest.setKeyId(signingKeyId); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.NAME, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.NICKNAME, ClaimValue.createEssential(false))); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.EMAIL, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.EMAIL_VERIFIED, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.PICTURE, ClaimValue.createEssential(false))); + jwsAuthorizationRequest.addIdTokenClaim(new Claim(JwtClaimName.AUTHENTICATION_TIME, ClaimValue.createNull())); + jwsAuthorizationRequest.getIdTokenMember().setMaxAge(86400); + jwsAuthorizationRequest.setRedirectUri(redirectUri); + jwsAuthorizationRequest.setNonce(nonce); // FAPI: nonce param is required + jwsAuthorizationRequest.setScopes(null); // FAPI: scope param is required + jwsAuthorizationRequest.setNbf((int) Instant.now().getEpochSecond()); // FAPI: require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim + jwsAuthorizationRequest.setExp(jwsAuthorizationRequest.getNbf() + 3600); // FAPI: require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim + Jwt authJws = Jwt.parse(jwsAuthorizationRequest.getEncodedJwt()); + + JwkClient jwkClient = new JwkClient(jwksUri); + JwkResponse jwkResponse = jwkClient.exec(); + String serverKeyId = jwkResponse.getKeyId(Algorithm.RSA_OAEP); + assertNotNull(serverKeyId); + + JSONObject jwks = JwtUtil.getJSONWebKeys(jwksUri); + AuthCryptoProvider cryptoProvider2 = new AuthCryptoProvider(keyStoreFile, keyStoreSecret, dnName); + privateKey = cryptoProvider2.getPrivateKey(encryptionKeyId); + + JwtAuthorizationRequest jweAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest, + KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM, cryptoProvider2); + jweAuthorizationRequest.setKeyId(serverKeyId); + jweAuthorizationRequest.setNestedPayload(authJws); + String authJwe = jweAuthorizationRequest.getEncodedJwt(jwks); + + authorizationRequest.setRequest(authJwe); + + AuthorizationResponse authorizationResponse = authorizationRequest(authorizationRequest, ResponseMode.QUERY_JWT, userId, userSecret); + assertNotNull(authorizationResponse.getResponse()); + + //Jwe response = Jwe.parse(authorizationResponse.getResponse(), privateKey, null); + Jwt response = Jwt.parse(authorizationResponse.getResponse()); + + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.ISS)); + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.AUD)); + assertNotNull(response.getClaims().getClaimAsInteger(AuthorizeResponseParam.EXP)); + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.STATE)); + assertNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.CODE)); + assertNotNull(response.getClaims().getClaimAsString("error")); + assertNotNull(response.getClaims().getClaimAsString("error_description")); + + privateKey = null; // Clear private key to do not affect to other tests + } + + @Parameters({"userId", "userSecret", "redirectUri", "redirectUris", "clientJwksUri", "RSA_OAEP_keyId", + "PS256_keyId", "dnName", "keyStoreFile", "keyStoreSecret", "sectorIdentifierUri"}) + //@Test // Enable FAPI to run this test! + public void authorizationRequestObjectPS256RSA_OAEPA256GCMFail5( + final String userId, final String userSecret, final String redirectUri, final String redirectUris, + final String clientJwksUri, final String encryptionKeyId, final String signingKeyId, final String dnName, final String keyStoreFile, + final String keyStoreSecret, final String sectorIdentifierUri) throws Exception { + showTitle("authorizationRequestObjectPS256RSA_OAEPA256GCMFail5"); + + List responseTypes = Arrays.asList(ResponseType.CODE); + + // 1. Dynamic Client Registration +// RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, +// SignatureAlgorithm.PS256, KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM); + RegisterResponse registerResponse = registerClient(redirectUris, responseTypes, sectorIdentifierUri, clientJwksUri, + SignatureAlgorithm.PS256, null, null); + + String clientId = registerResponse.getClientId(); + + // 2. Request authorization + List scope = Arrays.asList("openid", "profile", "address", "email"); + String state = UUID.randomUUID().toString(); + String nonce = UUID.randomUUID().toString(); + + AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scope, redirectUri, null); + authorizationRequest.setResponseMode(ResponseMode.JWT); + authorizationRequest.setState(state); + + AuthCryptoProvider cryptoProvider1 = new AuthCryptoProvider(keyStoreFile, keyStoreSecret, dnName); + + JwtAuthorizationRequest jwsAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest, SignatureAlgorithm.PS256, cryptoProvider1); + jwsAuthorizationRequest.setKeyId(signingKeyId); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.NAME, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.NICKNAME, ClaimValue.createEssential(false))); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.EMAIL, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.EMAIL_VERIFIED, ClaimValue.createNull())); + jwsAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.PICTURE, ClaimValue.createEssential(false))); + jwsAuthorizationRequest.addIdTokenClaim(new Claim(JwtClaimName.AUTHENTICATION_TIME, ClaimValue.createNull())); + jwsAuthorizationRequest.getIdTokenMember().setMaxAge(86400); + jwsAuthorizationRequest.setRedirectUri(null); + jwsAuthorizationRequest.setNonce(nonce); // FAPI: nonce param is required + jwsAuthorizationRequest.setNbf((int) Instant.now().getEpochSecond()); // FAPI: require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim + jwsAuthorizationRequest.setExp(jwsAuthorizationRequest.getNbf() + 3600); // FAPI: require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim + Jwt authJws = Jwt.parse(jwsAuthorizationRequest.getEncodedJwt()); + + JwkClient jwkClient = new JwkClient(jwksUri); + JwkResponse jwkResponse = jwkClient.exec(); + String serverKeyId = jwkResponse.getKeyId(Algorithm.RSA_OAEP); + assertNotNull(serverKeyId); + + JSONObject jwks = JwtUtil.getJSONWebKeys(jwksUri); + AuthCryptoProvider cryptoProvider2 = new AuthCryptoProvider(keyStoreFile, keyStoreSecret, dnName); + privateKey = cryptoProvider2.getPrivateKey(encryptionKeyId); + + JwtAuthorizationRequest jweAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest, + KeyEncryptionAlgorithm.RSA_OAEP, BlockEncryptionAlgorithm.A256GCM, cryptoProvider2); + jweAuthorizationRequest.setKeyId(serverKeyId); + jweAuthorizationRequest.setNestedPayload(authJws); + String authJwe = jweAuthorizationRequest.getEncodedJwt(jwks); + + authorizationRequest.setRequest(authJwe); + + AuthorizationResponse authorizationResponse = authorizationRequest(authorizationRequest, ResponseMode.QUERY_JWT, userId, userSecret); + assertNotNull(authorizationResponse.getResponse()); + + //Jwe response = Jwe.parse(authorizationResponse.getResponse(), privateKey, null); + Jwt response = Jwt.parse(authorizationResponse.getResponse()); + + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.ISS)); + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.AUD)); + assertNotNull(response.getClaims().getClaimAsInteger(AuthorizeResponseParam.EXP)); + assertNotNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.STATE)); + assertNull(response.getClaims().getClaimAsString(AuthorizeResponseParam.CODE)); + assertNotNull(response.getClaims().getClaimAsString("error")); + assertNotNull(response.getClaims().getClaimAsString("error_description")); privateKey = null; // Clear private key to do not affect to other tests } diff --git a/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java b/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java index 6069cb4d798..2c02b5ccd9f 100644 --- a/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java +++ b/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java @@ -89,7 +89,7 @@ * Implementation for request authorization through REST web services. * * @author Javier Rojas Blum - * @version October 21, 2021 + * @version November 3, 2021 */ @Path("/") public class AuthorizeRestWebServiceImpl implements AuthorizeRestWebService { @@ -384,6 +384,10 @@ private Response requestAuthorization( redirectUriResponse.setState(""); } + if (jwtRequest.getRedirectUri() != null) { + redirectUriResponse.getRedirectUri().setBaseRedirectUri(jwtRequest.getRedirectUri()); + } + authorizeRestWebServiceValidator.validateRequestObject(jwtRequest, redirectUriResponse); // MUST be equal diff --git a/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidator.java b/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidator.java index 54e84a39a36..537f281729a 100644 --- a/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidator.java +++ b/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidator.java @@ -47,6 +47,7 @@ /** * @author Yuriy Zabrovarnyy + * @version November 3, 2021 */ @Named @Stateless @@ -285,6 +286,10 @@ public String validateRedirectUri(@NotNull Client client, @Nullable String redir public String validateRedirectUri(@NotNull Client client, @Nullable String redirectUri, @Nullable String state, @Nullable String deviceAuthzUserCode, @Nullable HttpServletRequest httpRequest, @NotNull AuthorizeErrorResponseType error) { + if (appConfiguration.isFapi()) { + return redirectUri; // FAPI validator will check it in the request object. + } + if (StringUtils.isNotBlank(deviceAuthzUserCode)) { DeviceAuthorizationCacheControl deviceAuthorizationCacheControl = deviceAuthorizationService .getDeviceAuthzByUserCode(deviceAuthzUserCode); diff --git a/server/src/main/java/io/jans/as/server/model/authorize/JwtAuthorizationRequest.java b/server/src/main/java/io/jans/as/server/model/authorize/JwtAuthorizationRequest.java index bafb7cce96f..e3bc22d66c5 100644 --- a/server/src/main/java/io/jans/as/server/model/authorize/JwtAuthorizationRequest.java +++ b/server/src/main/java/io/jans/as/server/model/authorize/JwtAuthorizationRequest.java @@ -55,7 +55,7 @@ /** * @author Javier Rojas Blum - * @version September 9, 2021 + * @version November 3, 2021 */ public class JwtAuthorizationRequest { @@ -545,6 +545,11 @@ private void validateFapi() throws InvalidJwtException { throw new InvalidJwtException("nbf claim is more then 60 in the past"); } + if (exp == null) { + log.error("The exp claim is not set"); + throw new InvalidJwtException("exp claim is not set"); + } + final long nowSecondsExp = System.currentTimeMillis() / 1000; final long expDiff = exp - nowSecondsExp; if (expDiff > SIXTY_MINUTES_AS_SECONDS) { //https://github.com/JanssenProject/jans-auth-server/issues/165