Skip to content

Commit

Permalink
Skip prooftoken check for app2app communications (#1565)
Browse files Browse the repository at this point in the history
* add ias_apis claim to the TokenClaims

Signed-off-by: liga-oz <[email protected]>

* add ias_apis check for proofToken validation

Signed-off-by: liga-oz <[email protected]>


---------

Signed-off-by: liga-oz <[email protected]>
  • Loading branch information
liga-oz authored Jun 20, 2024
1 parent 52af1da commit d658d5a
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/
public final class TokenClaims {


private TokenClaims() {
throw new IllegalStateException("Utility class");
}
Expand All @@ -25,6 +26,8 @@ private TokenClaims() {
public static final String GIVEN_NAME = "given_name";
public static final String FAMILY_NAME = "family_name";
public static final String EMAIL = "email";
public static final String IAS_APIS = "ias_apis";

/**
* IAS applications provide this attribute if the user was authenticated via an OIDC trust to an IAS tenant and if
* the user actually has a user UUID. This is true if the user physically exists in the IAS user store and IAS is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protected PublicKey getPublicKey(Token token, JwtSignatureAlgorithm algorithm) t
requestParams.put(HttpHeaders.X_APP_TID, token.getAppTid());
requestParams.put(HttpHeaders.X_CLIENT_ID, configuration.getClientId());
requestParams.put(HttpHeaders.X_AZP, token.getClaimAsString(TokenClaims.AUTHORIZATION_PARTY));
if (isProofTokenValidationEnabled) {
if (isProofTokenValidationEnabled && !token.hasClaim(TokenClaims.IAS_APIS)) {
X509Certificate cert = (X509Certificate) SecurityContext.getClientCertificate();

if (cert == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void setup() throws IOException {

tokenKeyServiceMock = Mockito.mock(OAuth2TokenKeyService.class);
when(tokenKeyServiceMock
.retrieveTokenKeys(any(), anyMap()))
.retrieveTokenKeys(any(), argThat(new ParamsHasNoClientCertHeader())))
.thenReturn(IOUtils.resourceToString("/iasJsonWebTokenKeys.json", UTF_8));

endpointsProviderMock = Mockito.mock(OAuth2ServiceEndpointsProvider.class);
Expand Down Expand Up @@ -150,7 +150,7 @@ public void validate_whenAppTidIsNull_withDisabledAppTid() {
}

@Test
public void validate_withEnabledProofTokenCheck() throws IOException {
public void validate_withEnabledProofTokenCheck_app2service() throws IOException {
String certString = IOUtils.resourceToString("/cf-forwarded-client-cert.txt", UTF_8);
Certificate cert = X509Certificate.newCertificate(certString);
SecurityContext.setClientCertificate(cert);
Expand All @@ -171,23 +171,30 @@ public void validate_withEnabledProofTokenCheck() throws IOException {
}

@Test
public void validationFails_withEnabledProofTokenCheck_noCert() {
public void validate_withEnabledProofTokenCheck_app2app() {
Token iasToken = new SapIdToken(
"eyJraWQiOiJkZWZhdWx0LWtpZC1pYXMiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjY5NzQwMzE2MDAsImF6cCI6IlQwMDAzMTAiLCJjaWQiOiJUMDAwMzEwIiwiYXVkIjoiVDAwMDMxMCIsInpvbmVfdXVpZCI6InRoZS16b25lLWlkIiwiYXBwX3RpZCI6InRoZS1hcHAtdGlkIiwidXNlcl91dWlkIjoiMTIzNDU2Nzg5MCIsInNjaW1faWQiOiJzY2ltLTEyMzQ1Njc4OTAiLCJzdWIiOiJQMTc2OTQ1IiwiaXNzIjoiaHR0cHM6Ly9hcHBsaWNhdGlvbi5teWF1dGguY29tIiwiZ2l2ZW5fbmFtZSI6ImpvaG4iLCJmYW1pbHlfbmFtZSI6ImRvZSIsImVtYWlsIjoiam9obi5kb2VAZW1haWwub3JnIiwiaWFzX2FwaXMiOiJpYXNfYXBpcyJ9.XScl2bUr12mDNmVJahYIHEr7rlfaBFoyjR4UTJvOuEKXIQIgf58hRqbDNoKNM2pRiue8FvlD4TuI1OQ9r4wQgJ86sa0YIly7YfOhX6XQoDUXCcFVU_MsYTZJo2LMmOziD5EHt9wakRhWN3FqDM7KG4j_-HOhj3k0I72gFt83BToQHcMsW26eDQ7qfeeiNFsuUWzX8U-hZzCdOsl6EGYw2VU9kedEACH7xsOmfDdfLEPHu1HmjRmywdE118z4fPXpIvSN47V4VeXU8jZptRgxz1TDLT2w_zb4IPJInacadMVLNIVcrWqplQKTiS7nUCzCk2_aSKnBjerO5ugoERS9HA");

SapIdJwtSignatureValidator cut = new SapIdJwtSignatureValidator(
mockConfiguration,
OAuth2TokenKeyServiceWithCache.getInstance()
.withTokenKeyService(tokenKeyServiceMock),
OidcConfigurationServiceWithCache.getInstance()
.withOidcConfigurationService(oidcConfigServiceMock));
cut.enableProofTokenValidationCheck();
assertTrue(cut.validate(iasToken).isErroneous());
assertTrue(cut.validate(iasToken).isValid());
}

static class ParamsHasClientCertHeader implements ArgumentMatcher<Map<String, String>> {

@Override
public boolean matches(Map<String, String> map) {
return map.get(X509Constants.FWD_CLIENT_CERT_SUB) == null && map.get(HttpHeaders.X_CLIENT_CERT) != null;
}
@Test
public void validationFails_withEnabledProofTokenCheck_noCert() {
SapIdJwtSignatureValidator cut = new SapIdJwtSignatureValidator(
mockConfiguration,
OAuth2TokenKeyServiceWithCache.getInstance()
.withTokenKeyService(tokenKeyServiceMock),
OidcConfigurationServiceWithCache.getInstance()
.withOidcConfigurationService(oidcConfigServiceMock));
cut.enableProofTokenValidationCheck();
assertTrue(cut.validate(iasToken).isErroneous());
}

@Test
Expand Down Expand Up @@ -263,4 +270,20 @@ public void validationFails_whenOAuthServerIsUnavailable() throws OAuth2ServiceE
assertThat(result.getErrorDescription(), containsString("JWKS could not be fetched"));
}

static class ParamsHasClientCertHeader implements ArgumentMatcher<Map<String, String>> {

@Override
public boolean matches(Map<String, String> map) {
return map.get(X509Constants.FWD_CLIENT_CERT_SUB) == null && map.get(HttpHeaders.X_CLIENT_CERT) != null;
}
}

static class ParamsHasNoClientCertHeader implements ArgumentMatcher<Map<String, String>> {

@Override
public boolean matches(Map<String, String> map) {
return map.get(HttpHeaders.X_CLIENT_CERT) == null;
}
}

}

0 comments on commit d658d5a

Please sign in to comment.