From 93898044815b23cdd32a51fda17648337db9265b Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 20 Nov 2023 14:24:16 +0100 Subject: [PATCH 01/12] Adapt to optimized IAS server API --- .../validators/JwtIssuerValidator.java | 72 +++----- .../SapIdJwtSignatureValidator.java | 2 +- .../validators/JwtIssuerValidatorTest.java | 173 +++++++++++------- .../SapIdJwtSignatureValidatorTest.java | 2 +- .../DefaultOidcConfigurationService.java | 2 +- 5 files changed, 140 insertions(+), 111 deletions(-) diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java index 9696da438..7050a15b4 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java @@ -6,16 +6,18 @@ package com.sap.cloud.security.token.validation.validators; import com.sap.cloud.security.config.OAuth2ServiceConfiguration; -import com.sap.cloud.security.config.Service; +import com.sap.cloud.security.json.JsonParsingException; import com.sap.cloud.security.token.Token; import com.sap.cloud.security.token.validation.ValidationResult; import com.sap.cloud.security.token.validation.Validator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.URI; -import java.net.URISyntaxException; +import java.net.MalformedURLException; +import java.net.URL; import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; import static com.sap.cloud.security.token.validation.ValidationResults.createInvalid; import static com.sap.cloud.security.token.validation.ValidationResults.createValid; @@ -36,6 +38,7 @@ * These checks are a prerequisite for using the `JwtSignatureValidator`. */ class JwtIssuerValidator implements Validator { + protected static final String HTTPS_SCHEME = "https://"; private final List domains; protected final Logger logger = LoggerFactory.getLogger(getClass()); @@ -54,55 +57,34 @@ class JwtIssuerValidator implements Validator { @Override public ValidationResult validate(Token token) { - String issuer = token.getIssuer(); - if (token.getService().equals(Service.IAS) && !issuer.startsWith("http")) { - issuer = "https://" + issuer; - } - ValidationResult validationResult = validateUrl(issuer); - if (validationResult.isErroneous()) { - return validationResult; + String issuer; + + try { + issuer = token.getIssuer(); + } catch(JsonParsingException e) { + return createInvalid("Issuer validation can not be performed because token issuer claim was not a String value."); } - return matchesTokenIssuerUrl(issuer); - } - private ValidationResult matchesTokenIssuerUrl(String issuer) { - URI issuerUri = URI.create(issuer); - if (issuerUri.getQuery() == null && issuerUri.getFragment() == null && issuerUri.getHost() != null) { - for (String d : domains) { - if (issuerUri.getHost().endsWith(d)) { - return createValid(); - } - } + if (issuer == null || issuer.isBlank()) { + return createInvalid("Issuer validation can not be performed because token does not contain an issuer claim."); } - return createInvalid( - "Issuer is not trusted because issuer '{}' doesn't match any of these domains '{}' of the identity provider.", - issuer, domains); - } - private ValidationResult validateUrl(String issuer) { - URI issuerUri; + String issuerUrl = issuer.startsWith(HTTPS_SCHEME) ? issuer : HTTPS_SCHEME + issuer; try { - if (issuer == null || issuer.trim().isEmpty()) { - return createInvalid( - "Issuer validation can not be performed because Jwt token does not contain an issuer claim."); - } - if (!issuer.startsWith("http")) { - return createInvalid( - "Issuer is not trusted because issuer '{}' does not provide a valid URI (missing http scheme). Please contact your Identity Provider Administrator.", - issuer); - } - issuerUri = new URI(issuer); - if (issuerUri.getQuery() == null && issuerUri.getFragment() == null && issuerUri.getHost() != null) { + new URL(issuerUrl); + } catch (MalformedURLException e) { + return createInvalid("Issuer validation can not be performed because token issuer is not a valid URL suitable for https."); + } + + String issuerDomain = issuerUrl.substring(HTTPS_SCHEME.length()); + for(String d : domains) { + // a string that ends with . and contains 1-63 letters, digits or '-' before that for the subdomain + String validSubdomainPattern = String.format("^[a-zA-Z0-9-]{1,63}\\.%s$", Pattern.quote(d)); + if(Objects.equals(d, issuerDomain) || issuerDomain.matches(validSubdomainPattern)) { return createValid(); } - } catch (URISyntaxException e) { - logger.error( - "Error: issuer claim '{}' does not provide a valid URI: {}. Please contact your Identity Provider Administrator.", - issuer, e.getMessage(), e); } - return createInvalid( - "Issuer is not trusted because issuer does not provide a valid URI. Please contact your Identity Provider Administrator.", - issuer); - } + return createInvalid("Issuer {} was not a trusted domain or a subdomain of the trusted domains {}.", issuer, domains); + } } diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/SapIdJwtSignatureValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/SapIdJwtSignatureValidator.java index 6e25ec7f5..86193f732 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/SapIdJwtSignatureValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/SapIdJwtSignatureValidator.java @@ -68,7 +68,7 @@ private URI getJwksUri(Token token) throws OAuth2ServiceException { } if (isTenantIdCheckEnabled && !domain.equals("" + configuration.getUrl()) && token.getAppTid() == null) { - throw new IllegalArgumentException("OIDC token must provide a valid " + TokenClaims.SAP_GLOBAL_APP_TID + " header when issuer has a different domain than the url from the service credentials."); + throw new IllegalArgumentException("OIDC token must provide the " + TokenClaims.SAP_GLOBAL_APP_TID + " claim for tenant validation when issuer is not the same as the url from the service credentials."); } diff --git a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidatorTest.java b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidatorTest.java index 25e32befe..59c1fbb0e 100644 --- a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidatorTest.java +++ b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidatorTest.java @@ -8,7 +8,6 @@ import com.sap.cloud.security.config.Service; import com.sap.cloud.security.token.SapIdToken; import com.sap.cloud.security.token.Token; -import com.sap.cloud.security.token.TokenClaims; import com.sap.cloud.security.token.validation.ValidationResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -20,11 +19,9 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.when; @@ -32,12 +29,13 @@ class JwtIssuerValidatorTest { private JwtIssuerValidator cut; private Token token; - private final String[] domains = new String[] { "customer.ondemand.com", "accounts400.ondemand.com" }; + private final String[] trustedDomains = new String[] { "customer.ondemand.com", "accounts400.ondemand.com" }; @BeforeEach void setup() { - cut = new JwtIssuerValidator(Arrays.asList(domains)); + cut = new JwtIssuerValidator(Arrays.asList(trustedDomains)); token = Mockito.mock(SapIdToken.class); + when(token.getService()).thenReturn(Service.IAS); } @Test @@ -49,84 +47,133 @@ void constructor_throwsOnNullValues() { .hasMessageContainingAll("JwtIssuerValidator", "domain(s)"); } - @Test - void validationFails_whenIssuerDomainDoesNotMatchIdentityProviderDomains() { - configureMock("https://otherdomain.test.ondemand.com", null); - assertThat(cut.validate(token).isValid(), is(false)); - } - @ParameterizedTest - @NullAndEmptySource - @ValueSource(strings = { " " }) - void validationIgnoresEmptyIssuer_whenIasIssuerIsGiven(String issuer) { - cut = new JwtIssuerValidator(Collections.singletonList("accounts400.ondemand.com")); - configureMock(issuer, "https://test.accounts400.ondemand.com"); + @CsvSource({ + "accounts400.ondemand.com", + "https://accounts400.ondemand.com", + "tenant.accounts400.ondemand.com", + "https://tenant.accounts400.ondemand.com", + "tenant-0815WithNumbers.accounts400.ondemand.com", + "https://tenant-0815WithNumbers.accounts400.ondemand.com" + }) + void validationSucceeds_forValidIssuers(String issuer) { + when(token.getIssuer()).thenReturn(issuer); ValidationResult validationResult = cut.validate(token); assertThat(validationResult.isValid(), is(true)); - } - - @Test - void validationSucceeds_whenIasIssuerIsEmptyOrNull() { - cut = new JwtIssuerValidator(Collections.singletonList("accounts400.ondemand.com")); - configureMock("https://test.accounts400.ondemand.com", null); - - ValidationResult validationResult = cut.validate(token); assertThat(validationResult.isErroneous(), is(false)); } @Test - void validationFails_withoutMatchingIasIssuer() { - configureMock("https://otherDomain.accounts400.ondemand.com", "https://iasDomain.accounts.ondemand.com"); + void validationFails_whenSubdomainHasMoreThan63Characters() { + for(String d : trustedDomains) { + when(token.getIssuer()).thenReturn("https://a." + d); + assertThat(cut.validate(token).isValid(), is(true)); - ValidationResult validationResult = cut.validate(token); - assertThat(validationResult.isErroneous(), is(true)); - assertThat(validationResult.getErrorDescription(), startsWith( - "Issuer is not trusted because issuer 'https://iasDomain.accounts.ondemand.com' doesn't match any of these domains '[customer.ondemand.com, accounts400.ondemand.com]' of the identity provider.")); + when(token.getIssuer()).thenReturn("https://" + "a".repeat(63) + "." + d); + assertThat(cut.validate(token).isValid(), is(true)); + + when(token.getIssuer()).thenReturn("https://" + "a".repeat(64) + "." + d); + assertThat(cut.validate(token).isValid(), is(false)); + } } - @Test - void validationIgnoresInvalidIssuer_whenIasIssuerIsGiven() { - cut = new JwtIssuerValidator(Arrays.asList(domains)); - configureMock("invalid_url", "https://otherDomain.accounts400.ondemand.com"); + @ParameterizedTest + @CsvSource({ + "https://accou\tnts400.ondemand.com", + "https://accou\nnts400.ondemand.com", + "https://accounts400.onde\tmand.com", + "https://accounts400.onde\nmand.com", + "https://tena\tnt.accounts400.ondemand.com", + "https://tena\nnt.accounts400.ondemand.com", + "https://tenant.accounts400.onde\tmand.com", + "https://tenant.accounts400.onde\nmand.com" + }) + void validationFails_whenIssuerContainsInvisibleCharacters(String issuer) { + when(token.getIssuer()).thenReturn(issuer); + assertThat(cut.validate(token).isValid(), is(false)); + assertThat(cut.validate(token).isErroneous(), is(true)); + } - ValidationResult validationResult = cut.validate(token); - assertThat(validationResult.isErroneous(), is(false)); + @ParameterizedTest + @CsvSource({ + "https://accounts400%2eondemand.com", + "https://accounts400.ondemand.com%2eattackerdomain.com", + "https://tenant%2eaccounts400.ondemand.com", + "https://attackerdomain.com%2eaccounts400.ondemand.com", + "tenant%2d0815WithNumbers.accounts400.ondemand.com", + }) + void validationFails_whenIssuerContainsEncodedCharacters(String issuer) { + when(token.getIssuer()).thenReturn(issuer); + assertThat(cut.validate(token).isValid(), is(false)); + assertThat(cut.validate(token).isErroneous(), is(true)); } @ParameterizedTest - @CsvSource({ "https://subdomain.accounts400.ondemand.com#anyFragment_keys", - "https://subdomain.accounts400.ondemand.com?a=b", - "\0://myauth.com", - "https://otherDomain.org?accounts400.ondemand.com", }) - void validationFails_iasIssuerUrl(String iasIssuer) { - cut = new JwtIssuerValidator(Arrays.asList(domains)); - configureMock("https://otherDomain.accounts400.ondemand.com", iasIssuer); + @NullAndEmptySource + @ValueSource(strings = { " " }) + void validationFails_whenIssuerIsEmpty(String issuer) { + when(token.getIssuer()).thenReturn(issuer); + assertThat(cut.validate(token).isValid(), is(false)); + assertThat(cut.validate(token).isErroneous(), is(true)); + } - ValidationResult validationResult = cut.validate(token); - assertThat(validationResult.isErroneous(), is(true)); - assertThat(validationResult.getErrorDescription(), startsWith("Issuer is not trusted because issuer ")); + @Test + void validationFails_whenIssuerIsNotAValidURL() { + when(token.getIssuer()).thenReturn("https://"); + assertThat(cut.validate(token).isValid(), is(false)); + assertThat(cut.validate(token).isErroneous(), is(true)); + + when(token.getIssuer()).thenReturn("http://"); + assertThat(cut.validate(token).isValid(), is(false)); + assertThat(cut.validate(token).isErroneous(), is(true)); + + when(token.getIssuer()).thenReturn("http://" + trustedDomains[0]); + assertThat(cut.validate(token).isValid(), is(false)); + assertThat(cut.validate(token).isErroneous(), is(true)); } @ParameterizedTest - @CsvSource({ "https://otherDomain.accounts400.ondemand.com,", - "https://paas.accounts400.ondemand.com,", - "https://nestle.com,paas.accounts400.ondemand.com,", - "subdomain.accounts400.ondemand.com,", - "https://nestle.com,https://paas.accounts400.ondemand.com," }) - void validationSucceeds(String issuer, String iasIssuer) { - cut = new JwtIssuerValidator(Arrays.asList(domains)); - configureMock(issuer, iasIssuer); - - ValidationResult validationResult = cut.validate(token); - assertThat(validationResult.isValid(), is(true)); + @CsvSource({ + "https://accounts400.ondemand.coma", + "https://accounts400.ondemand.com0", + "https://accounts400.ondemand.com/", + "https://accounts400.ondemand.com/path", + "https://accounts400.ondemand.com%2f", + "https://accounts400.ondemand.com%2fpath", + "https://accounts400.ondemand.com&", + "https://accounts400.ondemand.com%26", + "https://accounts400.ondemand.com?", + "https://accounts400.ondemand.com?foo", + "https://accounts400.ondemand.com?foo=bar", + "https://accounts400.ondemand.com%3f", + "https://accounts400.ondemand.com%3ffoo", + "https://accounts400.ondemand.com%3ffoo=bar", + "https://accounts400.ondemand.com#", + "https://accounts400.ondemand.com#foo", + "https://accounts400.ondemand.com%23", + "https://accounts400.ondemand.com%23foo", + "https://user@accounts400.ondemand.com", + "https://user%40accounts400.ondemand.com", + }) + void validationFails_whenIssuerContainsMoreThanDomain(String issuer) { + when(token.getIssuer()).thenReturn(issuer); + assertThat(cut.validate(token).isValid(), is(false)); + assertThat(cut.validate(token).isErroneous(), is(true)); } - private void configureMock(String issuer, String iasIssuer) { - when(token.getService()).thenReturn(Service.IAS); - when(token.getIssuer()).thenCallRealMethod(); - when(token.getClaimAsString(TokenClaims.ISSUER)).thenReturn(issuer); - when(token.getClaimAsString(TokenClaims.IAS_ISSUER)).thenReturn(iasIssuer); - when(token.hasClaim("ias_iss")).thenReturn(iasIssuer != null); + @ParameterizedTest + @CsvSource({ + "https://attackerdomain.com", + "https://tenant.attackerdomain.com", + "https://myaccounts400.ondemand.com", + "https://accounts400.ondemand.com.attackerDomain.com", + "https://accounts400.ondemand.com%2eattackerDomain.com", + "https://accounts400.ondemand.com%2dattackerDomain.com", + }) + void validationFails_whenIssuerIsNotASubdomainOfTrustedDomains(String issuer) { + when(token.getIssuer()).thenReturn(issuer); + assertThat(cut.validate(token).isValid(), is(false)); + assertThat(cut.validate(token).isErroneous(), is(true)); } } diff --git a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/SapIdJwtSignatureValidatorTest.java b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/SapIdJwtSignatureValidatorTest.java index 4232ce892..5d59f4556 100644 --- a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/SapIdJwtSignatureValidatorTest.java +++ b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/SapIdJwtSignatureValidatorTest.java @@ -118,7 +118,7 @@ public void validationFails_WhenAppTidIsNull() { ValidationResult validationResult = cut.validate(iasPaasToken); assertTrue(validationResult.isErroneous()); assertThat(validationResult.getErrorDescription(), - containsString("OIDC token must provide a valid app_tid header when issuer has a different domain than the url from the service credentials.")); + containsString("Token signature can not be validated because: OIDC token must provide the app_tid claim for tenant validation when issuer is not the same as the url from the service credentials.")); } @Test diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOidcConfigurationService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOidcConfigurationService.java index 551225709..0cacdcbbf 100644 --- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOidcConfigurationService.java +++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOidcConfigurationService.java @@ -40,7 +40,7 @@ public DefaultOidcConfigurationService(CloseableHttpClient httpClient) { public static URI getDiscoveryEndpointUri(@Nonnull String issuerUri) { // to support existing IAS applications - URI uri = URI.create(issuerUri.startsWith("http") ? issuerUri : "https://" + issuerUri); + URI uri = URI.create(issuerUri.startsWith("https://") ? issuerUri : "https://" + issuerUri); return UriUtil.expandPath(uri, DISCOVERY_ENDPOINT_DEFAULT); } From 4270fc4036beb1138ab1f70020626fb8bc8212b2 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Fri, 24 Nov 2023 10:04:36 +0100 Subject: [PATCH 02/12] Bump version to 3.3.0 Adjust CHANGELOG --- CHANGELOG.md | 6 ++++++ README.md | 2 +- bom/pom.xml | 2 +- env/pom.xml | 2 +- java-api/README.md | 2 +- java-api/pom.xml | 2 +- java-security-it/pom.xml | 2 +- java-security-test/README.md | 2 +- java-security-test/pom.xml | 2 +- java-security/README.md | 2 +- java-security/pom.xml | 2 +- pom.xml | 2 +- samples/java-security-usage-ias/pom.xml | 4 ++-- samples/java-security-usage/pom.xml | 4 ++-- samples/java-tokenclient-usage/pom.xml | 4 ++-- samples/sap-java-buildpack-api-usage/pom.xml | 2 +- samples/spring-security-basic-auth/pom.xml | 6 +++--- samples/spring-security-hybrid-usage/pom.xml | 4 ++-- samples/spring-security-xsuaa-usage/pom.xml | 4 ++-- samples/spring-webflux-security-xsuaa-usage/pom.xml | 4 ++-- spring-security-compatibility/pom.xml | 2 +- spring-security-starter/pom.xml | 2 +- spring-security/Migration_SpringXsuaaProjects.md | 2 +- spring-security/README.md | 2 +- spring-security/pom.xml | 4 ++-- spring-xsuaa-it/pom.xml | 4 ++-- spring-xsuaa-starter/pom.xml | 2 +- spring-xsuaa-test/README.md | 2 +- spring-xsuaa-test/pom.xml | 2 +- spring-xsuaa/README.md | 4 ++-- spring-xsuaa/pom.xml | 2 +- token-client/README.md | 6 +++--- token-client/pom.xml | 2 +- 33 files changed, 51 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51398b7a0..71d1b03e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +## 3.3.0 +- [java-security] + - [XSUAA/IAS] Adapt optimized server API +- [spring-xsuaa] + - Adapt optimized server API + ## 3.2.1 Hot fix for the CVE-2023-5072 diff --git a/README.md b/README.md index 37ec1a52e..83b66761a 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ The SAP Cloud Security Services Integration is published to maven central: https com.sap.cloud.security java-bom - 3.2.1 + 3.3.0 import pom diff --git a/bom/pom.xml b/bom/pom.xml index 6a240efdf..d7421ecb8 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -8,7 +8,7 @@ com.sap.cloud.security java-bom - 3.2.1 + 3.3.0 pom java-bom diff --git a/env/pom.xml b/env/pom.xml index 8b9d2e7d7..7b27337d8 100644 --- a/env/pom.xml +++ b/env/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 3.2.1 + 3.3.0 com.sap.cloud.security diff --git a/java-api/README.md b/java-api/README.md index 6301f8ba6..20f531b62 100644 --- a/java-api/README.md +++ b/java-api/README.md @@ -5,6 +5,6 @@ com.sap.cloud.security java-api - 3.2.1 + 3.3.0 ``` diff --git a/java-api/pom.xml b/java-api/pom.xml index c2140df7f..765d3e363 100644 --- a/java-api/pom.xml +++ b/java-api/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 3.2.1 + 3.3.0 com.sap.cloud.security diff --git a/java-security-it/pom.xml b/java-security-it/pom.xml index 23c9c56ba..2c6a1fbc7 100644 --- a/java-security-it/pom.xml +++ b/java-security-it/pom.xml @@ -9,7 +9,7 @@ parent com.sap.cloud.security.xsuaa - 3.2.1 + 3.3.0 java-security-it diff --git a/java-security-test/README.md b/java-security-test/README.md index ff6bfe3e9..964cfc37e 100644 --- a/java-security-test/README.md +++ b/java-security-test/README.md @@ -40,7 +40,7 @@ It is pre-configured with a security filter that only accepts valid tokens. Furt com.sap.cloud.security java-security-test - 3.2.1 + 3.3.0 test ``` diff --git a/java-security-test/pom.xml b/java-security-test/pom.xml index dd16ea3b1..b2801f2e6 100644 --- a/java-security-test/pom.xml +++ b/java-security-test/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 3.2.1 + 3.3.0 com.sap.cloud.security diff --git a/java-security/README.md b/java-security/README.md index a8557c018..3ffc7b862 100644 --- a/java-security/README.md +++ b/java-security/README.md @@ -67,7 +67,7 @@ To be able to validate tokens it performs the following tasks: com.sap.cloud.security java-security - 3.2.1 + 3.3.0 org.apache.httpcomponents.client5 diff --git a/java-security/pom.xml b/java-security/pom.xml index 7a034d058..ce67d85ac 100644 --- a/java-security/pom.xml +++ b/java-security/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 3.2.1 + 3.3.0 com.sap.cloud.security diff --git a/pom.xml b/pom.xml index d19103000..32f65e64d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.sap.cloud.security.xsuaa parent - 3.2.1 + 3.3.0 pom parent diff --git a/samples/java-security-usage-ias/pom.xml b/samples/java-security-usage-ias/pom.xml index 63dc2bd08..b34dac2a7 100755 --- a/samples/java-security-usage-ias/pom.xml +++ b/samples/java-security-usage-ias/pom.xml @@ -6,13 +6,13 @@ 4.0.0 com.sap.cloud.security.xssec.samples java-security-usage-ias - 3.2.1 + 3.3.0 war 17 17 - 3.2.1 + 3.3.0 2.0.5 4.5.14 6.0.0 diff --git a/samples/java-security-usage/pom.xml b/samples/java-security-usage/pom.xml index 9f9f7590d..74ec220ba 100755 --- a/samples/java-security-usage/pom.xml +++ b/samples/java-security-usage/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.sap.cloud.security.xssec.samples java-security-usage - 3.2.1 + 3.3.0 war org.apache.logging.log4j @@ -53,7 +53,7 @@ These (spring) dependencies need to be provided: com.sap.cloud.security.xsuaa xsuaa-spring-boot-starter - 3.2.1 + 3.3.0 ``` diff --git a/spring-xsuaa/pom.xml b/spring-xsuaa/pom.xml index 04085de0e..71fe8699e 100644 --- a/spring-xsuaa/pom.xml +++ b/spring-xsuaa/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 3.2.1 + 3.3.0 spring-xsuaa diff --git a/token-client/README.md b/token-client/README.md index ea3bed9d7..44fe90372 100644 --- a/token-client/README.md +++ b/token-client/README.md @@ -49,7 +49,7 @@ In context of a Spring Boot application you can leverage autoconfiguration provi com.sap.cloud.security resourceserver-security-spring-boot-starter - 3.2.1 + 3.3.0 ``` In context of Spring Applications you will need the following dependencies: @@ -57,7 +57,7 @@ In context of Spring Applications you will need the following dependencies: com.sap.cloud.security.xsuaa token-client - 3.2.1 + 3.3.0 org.apache.httpcomponents @@ -124,7 +124,7 @@ See the [OAuth2ServiceConfiguration](#oauth2serviceconfiguration) section and [H com.sap.cloud.security.xsuaa token-client - 3.2.1 + 3.3.0 org.apache.httpcomponents diff --git a/token-client/pom.xml b/token-client/pom.xml index 3b8a80e89..e682fa473 100644 --- a/token-client/pom.xml +++ b/token-client/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 3.2.1 + 3.3.0 token-client From 1242a97dbd89e5a270e844c45790c72e467ec4ab Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Fri, 24 Nov 2023 13:24:08 +0100 Subject: [PATCH 03/12] fix expected error message in unit test --- .../cloud/security/test/integration/XsuaaIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/XsuaaIntegrationTest.java b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/XsuaaIntegrationTest.java index 10c64ae87..932bb1475 100644 --- a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/XsuaaIntegrationTest.java +++ b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/XsuaaIntegrationTest.java @@ -83,7 +83,7 @@ public void xsuaaTokenValidationFails_withIasCombiningValidator() { ValidationResult result = tokenValidator.validate(token); assertThat(result.isValid()).isFalse(); assertThat(result.getErrorDescription()).startsWith( - "Issuer is not trusted because issuer 'http://auth.com' doesn't match any of these domains '[myauth.com]' of the identity provider"); + "Issuer http://auth.com was not a trusted domain or a subdomain of the trusted domains [myauth.com]."); } @Test From eab8c30732e3eb146b09e37616098005ee9a2f95 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Fri, 24 Nov 2023 13:50:44 +0100 Subject: [PATCH 04/12] Fixes for java-security-test --- .../com/sap/cloud/security/test/SecurityTest.java | 3 ++- .../cloud/security/test/SecurityTestRuleTest.java | 12 +++++++----- .../client/DefaultOidcConfigurationService.java | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java index bfa9efda6..84503752e 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java @@ -39,6 +39,7 @@ import javax.annotation.Nullable; import java.io.IOException; import java.net.URI; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.security.interfaces.RSAPublicKey; @@ -284,7 +285,7 @@ public void setup() throws Exception { .willReturn(aResponse().withBody(createDefaultOidcConfigurationResponse()) .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.value()))); jwksUrl = endpointsProvider.getJwksUri().toString(); - issuerUrl = wireMockServer.baseUrl(); + issuerUrl = new URL(wireMockServer.baseUrl()).getHost(); } /** diff --git a/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java b/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java index a05ddd14a..46abf77b9 100644 --- a/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java +++ b/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java @@ -28,7 +28,9 @@ import org.mockito.Mockito; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URI; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; @@ -114,20 +116,20 @@ public void getPreconfiguredJwtGenerator_tokenHasExpirationDate() { } @Test - public void getPreconfiguredJwtGenerator_tokenHasCorrectIssuer() { + public void getPreconfiguredJwtGenerator_tokenHasCorrectIssuer() throws MalformedURLException { Token token = cut.getPreconfiguredJwtGenerator().createToken(); - assertThat(token.getClaimAsString(TokenClaims.ISSUER)).isEqualTo(cut.base.wireMockServer.baseUrl()); + assertThat(token.getClaimAsString(TokenClaims.ISSUER)).isEqualTo(new URL(cut.base.wireMockServer.baseUrl()).getHost()); } @Test - public void getConfigurationBuilderFromFile_configurationHasCorrectUrl() { + public void getConfigurationBuilderFromFile_configurationHasCorrectUrl() throws MalformedURLException { OAuth2ServiceConfiguration configuration = cut .getOAuth2ServiceConfigurationBuilderFromFile("/vcapServices/vcapSimple.json") .build(); assertThat(configuration.getUrl()).isNotNull(); - assertThat(configuration.getUrl().toString()).isEqualTo(cut.base.wireMockServer.baseUrl()); + assertThat(configuration.getUrl().toString()).isEqualTo(new URL(cut.base.wireMockServer.baseUrl()).getHost()); } @Test @@ -137,7 +139,7 @@ public void getJwtGeneratorFromFile_setsTestingDefaults() throws IOException { String baseUrl = cut.base.wireMockServer.baseUrl(); URI jwksUrl = new XsuaaDefaultEndpoints(baseUrl, null).getJwksUri(); assertThat(token.getHeaderParameterAsString(TokenHeader.JWKS_URL)).isEqualTo(jwksUrl.toString()); - assertThat(token.getClaimAsString(TokenClaims.ISSUER)).isEqualTo(baseUrl); + assertThat(token.getClaimAsString(TokenClaims.ISSUER)).isEqualTo(new URL(baseUrl).getHost()); } @Test diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOidcConfigurationService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOidcConfigurationService.java index 0cacdcbbf..f0519929e 100644 --- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOidcConfigurationService.java +++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOidcConfigurationService.java @@ -40,7 +40,7 @@ public DefaultOidcConfigurationService(CloseableHttpClient httpClient) { public static URI getDiscoveryEndpointUri(@Nonnull String issuerUri) { // to support existing IAS applications - URI uri = URI.create(issuerUri.startsWith("https://") ? issuerUri : "https://" + issuerUri); + URI uri = URI.create(issuerUri.startsWith("http://localhost") || issuerUri.startsWith("https://") ? issuerUri : "https://" + issuerUri); return UriUtil.expandPath(uri, DISCOVERY_ENDPOINT_DEFAULT); } From ef04f8d4d29fef073a310d25f77d0d619909361c Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Fri, 24 Nov 2023 16:47:41 +0100 Subject: [PATCH 05/12] Fixes for java-security-test --- .../src/main/java/com/sap/cloud/security/test/SecurityTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java index 7740fb239..e7f3a7434 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java @@ -289,7 +289,7 @@ public void setup() throws Exception { .willReturn(aResponse().withBody(createDefaultOidcConfigurationResponse()) .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.value()))); jwksUrl = endpointsProvider.getJwksUri().toString(); - issuerUrl = new URL(wireMockServer.baseUrl()).getHost(); + issuerUrl = wireMockServer.baseUrl(); } /** From 19713634e4e518a186c188be468ca1349580e8fc Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Fri, 24 Nov 2023 16:48:01 +0100 Subject: [PATCH 06/12] Fixes for java-security-test --- .../security/test/performance/SpringSecurityPerformanceIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-security-it/src/test/java/com/sap/cloud/security/test/performance/SpringSecurityPerformanceIT.java b/java-security-it/src/test/java/com/sap/cloud/security/test/performance/SpringSecurityPerformanceIT.java index d0e1e48e9..e448a8f49 100644 --- a/java-security-it/src/test/java/com/sap/cloud/security/test/performance/SpringSecurityPerformanceIT.java +++ b/java-security-it/src/test/java/com/sap/cloud/security/test/performance/SpringSecurityPerformanceIT.java @@ -80,7 +80,7 @@ private OAuth2ServiceConfigurationBuilder createXsuaaConfigurationBuilder() { private OAuth2ServiceConfigurationBuilder createIasConfigurationBuilder() { return OAuth2ServiceConfigurationBuilder.forService(IAS) - .withDomains(SecurityTest.DEFAULT_DOMAIN) + .withDomains(securityIasTest.getWireMockServer().baseUrl()) .withClientId(SecurityTest.DEFAULT_CLIENT_ID); } } From 1970582f5ceb0142ca6fb83334cbfc7d3fb89a47 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Fri, 24 Nov 2023 17:04:35 +0100 Subject: [PATCH 07/12] Fixes for java-security-test --- .../cloud/security/test/SecurityTestRuleTest.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java b/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java index 46abf77b9..b891399a1 100644 --- a/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java +++ b/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java @@ -28,9 +28,7 @@ import org.mockito.Mockito; import java.io.IOException; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; @@ -116,30 +114,30 @@ public void getPreconfiguredJwtGenerator_tokenHasExpirationDate() { } @Test - public void getPreconfiguredJwtGenerator_tokenHasCorrectIssuer() throws MalformedURLException { + public void getPreconfiguredJwtGenerator_tokenHasCorrectIssuer() { Token token = cut.getPreconfiguredJwtGenerator().createToken(); - assertThat(token.getClaimAsString(TokenClaims.ISSUER)).isEqualTo(new URL(cut.base.wireMockServer.baseUrl()).getHost()); + assertThat(token.getClaimAsString(TokenClaims.ISSUER)).isEqualTo(cut.base.wireMockServer.baseUrl()); } @Test - public void getConfigurationBuilderFromFile_configurationHasCorrectUrl() throws MalformedURLException { + public void getConfigurationBuilderFromFile_configurationHasCorrectUrl() { OAuth2ServiceConfiguration configuration = cut .getOAuth2ServiceConfigurationBuilderFromFile("/vcapServices/vcapSimple.json") .build(); assertThat(configuration.getUrl()).isNotNull(); - assertThat(configuration.getUrl().toString()).isEqualTo(new URL(cut.base.wireMockServer.baseUrl()).getHost()); + assertThat(configuration.getUrl().toString()).isEqualTo(cut.base.wireMockServer.baseUrl()); } @Test - public void getJwtGeneratorFromFile_setsTestingDefaults() throws IOException { + public void getJwtGeneratorFromFile_setsTestingDefaults() { Token token = cut.getJwtGeneratorFromFile("/token.json").createToken(); String baseUrl = cut.base.wireMockServer.baseUrl(); URI jwksUrl = new XsuaaDefaultEndpoints(baseUrl, null).getJwksUri(); assertThat(token.getHeaderParameterAsString(TokenHeader.JWKS_URL)).isEqualTo(jwksUrl.toString()); - assertThat(token.getClaimAsString(TokenClaims.ISSUER)).isEqualTo(new URL(baseUrl).getHost()); + assertThat(token.getClaimAsString(TokenClaims.ISSUER)).isEqualTo(baseUrl); } @Test From 2b20e7a7aa98e82f83bdaa73cc015225b0fb88f3 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 27 Nov 2023 11:26:01 +0100 Subject: [PATCH 08/12] Fixes for java-security-test --- .../main/java/com/sap/cloud/security/test/SecurityTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java index e7f3a7434..ec42b72f2 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java @@ -38,8 +38,6 @@ import javax.annotation.Nullable; import java.io.IOException; -import java.net.URI; -import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.security.interfaces.RSAPublicKey; @@ -191,7 +189,7 @@ public OAuth2ServiceConfigurationBuilder getOAuth2ServiceConfigurationBuilderFro .mapToOAuth2ServiceConfigurationBuilder(serviceBindings.get(0)); if (builder != null) { // adjust domain and URL of the config to fit the mocked service instance - builder = builder.withDomains(URI.create(issuerUrl).getHost()).withUrl(issuerUrl); + builder = builder.withDomains(issuerUrl).withUrl(issuerUrl); } return builder; From 23e46b77693c18e827f2915a4195874892a54f4d Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 27 Nov 2023 11:52:41 +0100 Subject: [PATCH 09/12] add Breaking Change to CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71d1b03e8..2373d97c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. ## 3.3.0 +**Breaking Change [java-security-test]**: To validate mocked XSUAA tokens issued by java-security-test module, the UAA_DOMAIN property of the service configuration must now include the port of the Wiremock server.\ +Likewise for validating IAS tokens, the trusted *domains* array of the service configuration also needs to include the Wiremock URL including the port.\ +The full wiremock URL is available via SecurityTestContext#getWireMockServer#baseUrl. + +*Note*: If you are building your configuration via SecurityTestContext#getOAuth2ServiceConfigurationBuilderFromFile, this will already be preconfigured correctly, but you must not overwrite these properties with only "localhost". + - [java-security] - [XSUAA/IAS] Adapt optimized server API - [spring-xsuaa] From 6831b07c0b966bbbf65ae63ebe35deb884d56492 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 27 Nov 2023 11:54:00 +0100 Subject: [PATCH 10/12] Set UAA_DOMAIN to wiremockServer.baseUrl() in SecurityTest --- .../java/com/sap/cloud/security/test/SecurityTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java index ec42b72f2..145de37ee 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java @@ -11,6 +11,7 @@ import com.sap.cloud.security.config.OAuth2ServiceConfigurationBuilder; import com.sap.cloud.security.config.Service; import com.sap.cloud.security.config.ServiceBindingMapper; +import com.sap.cloud.security.config.ServiceConstants; import com.sap.cloud.security.json.JsonParsingException; import com.sap.cloud.security.test.api.ApplicationServerConfiguration; import com.sap.cloud.security.test.api.SecurityTestContext; @@ -185,11 +186,15 @@ public OAuth2ServiceConfigurationBuilder getOAuth2ServiceConfigurationBuilderFro LOGGER.warn("More than one OAuth2 service binding found in resource. Using configuration of first one!"); } - OAuth2ServiceConfigurationBuilder builder = ServiceBindingMapper - .mapToOAuth2ServiceConfigurationBuilder(serviceBindings.get(0)); + ServiceBinding binding = serviceBindings.get(0); + OAuth2ServiceConfigurationBuilder builder = ServiceBindingMapper.mapToOAuth2ServiceConfigurationBuilder(binding); if (builder != null) { // adjust domain and URL of the config to fit the mocked service instance builder = builder.withDomains(issuerUrl).withUrl(issuerUrl); + + if(Objects.equals(Service.from(binding.getServiceName().get()), XSUAA)) { + builder.withProperty(ServiceConstants.XSUAA.UAA_DOMAIN, wireMockServer.baseUrl()); + } } return builder; From 5163f175edec67d80755792f45cf14fac7a9da8f Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 27 Nov 2023 11:54:26 +0100 Subject: [PATCH 11/12] Remove no longer needed explicit UAA_DOMAIN configuration from test --- .../security/test/integration/ssrf/JavaSSRFAttackTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/JavaSSRFAttackTest.java b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/JavaSSRFAttackTest.java index fce6a15a5..8519e3786 100644 --- a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/JavaSSRFAttackTest.java +++ b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/JavaSSRFAttackTest.java @@ -7,7 +7,6 @@ import com.sap.cloud.security.config.OAuth2ServiceConfigurationBuilder; import com.sap.cloud.security.config.Service; -import com.sap.cloud.security.config.ServiceConstants; import com.sap.cloud.security.test.RSAKeys; import com.sap.cloud.security.test.extension.SecurityTestExtension; import com.sap.cloud.security.token.Token; @@ -65,9 +64,8 @@ class JavaSSRFAttackTest { void maliciousPartOfJwksIsNotUsedToObtainToken(String jwksUrl, boolean isValid) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { OAuth2ServiceConfigurationBuilder configuration = - extension.getContext() - .getOAuth2ServiceConfigurationBuilderFromFile("/xsuaa/vcap_services-single.json") - .withProperty(ServiceConstants.XSUAA.UAA_DOMAIN, extension.getContext().getWireMockServer().baseUrl()); + extension.getContext().getOAuth2ServiceConfigurationBuilderFromFile("/xsuaa/vcap_services-single.json"); + Token token; if (isValid) { token = extension.getContext().getJwtGeneratorFromFile("/xsuaa/token.json") From b79576d059fb3914f2a96e75cca7362790086734 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 27 Nov 2023 12:54:01 +0100 Subject: [PATCH 12/12] adapt JwtIssuerValidator to support issuer validation for http://localhost: issuers for test scenarios --- .../validation/validators/JwtIssuerValidator.java | 4 ++-- .../validators/JwtIssuerValidatorTest.java | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java index 7050a15b4..5f8a859c9 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java @@ -69,14 +69,14 @@ public ValidationResult validate(Token token) { return createInvalid("Issuer validation can not be performed because token does not contain an issuer claim."); } - String issuerUrl = issuer.startsWith(HTTPS_SCHEME) ? issuer : HTTPS_SCHEME + issuer; + String issuerUrl = issuer.startsWith(HTTPS_SCHEME) || issuer.startsWith("http://localhost") ? issuer : HTTPS_SCHEME + issuer; try { new URL(issuerUrl); } catch (MalformedURLException e) { return createInvalid("Issuer validation can not be performed because token issuer is not a valid URL suitable for https."); } - String issuerDomain = issuerUrl.substring(HTTPS_SCHEME.length()); + String issuerDomain = issuerUrl.substring(issuerUrl.indexOf("://") + 3); // issuerUrl was validated above to begin either with http:// or https:// for(String d : domains) { // a string that ends with . and contains 1-63 letters, digits or '-' before that for the subdomain String validSubdomainPattern = String.format("^[a-zA-Z0-9-]{1,63}\\.%s$", Pattern.quote(d)); diff --git a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidatorTest.java b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidatorTest.java index 59c1fbb0e..500069f10 100644 --- a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidatorTest.java +++ b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidatorTest.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.hamcrest.CoreMatchers.is; @@ -64,6 +65,20 @@ void validationSucceeds_forValidIssuers(String issuer) { assertThat(validationResult.isErroneous(), is(false)); } + /** + * Test ensures that issuer validation also succeeds for servers running on http://localhost:, e.g. when using java-security-test module. + */ + @Test + void supportsHttpLocalhostIssuers() { + String localDomain = "localhost:5555"; + JwtIssuerValidator cut = new JwtIssuerValidator(List.of(localDomain)); + when(token.getIssuer()).thenReturn("http://" + localDomain); + + ValidationResult validationResult = cut.validate(token); + assertThat(validationResult.isValid(), is(true)); + assertThat(validationResult.isErroneous(), is(false)); + } + @Test void validationFails_whenSubdomainHasMoreThan63Characters() { for(String d : trustedDomains) {