params)
throws OAuth2ServiceException, InvalidKeySpecException, NoSuchAlgorithmException {
assertNotNull(keyAlgorithm, "keyAlgorithm must not be null.");
assertHasText(keyId, "keyId must not be null.");
@@ -146,9 +150,9 @@ public PublicKey getPublicKey(JwtSignatureAlgorithm keyAlgorithm, String keyId,
CacheKey cacheKey = new CacheKey(keyUri, params);
JsonWebKeySet jwks = getCache().getIfPresent(cacheKey.toString());
- if(jwks == null) {
- jwks = retrieveTokenKeysAndUpdateCache(cacheKey);
- }
+ if (jwks == null) {
+ jwks = retrieveTokenKeysAndUpdateCache(cacheKey);
+ }
if (jwks.getAll().isEmpty()) {
LOGGER.error("Retrieved no token keys from {} for the given header parameters.", keyUri);
@@ -165,14 +169,14 @@ public PublicKey getPublicKey(JwtSignatureAlgorithm keyAlgorithm, String keyId,
throw new IllegalArgumentException("Key with kid " + keyId + " not found in JWKS.");
}
- private JsonWebKeySet retrieveTokenKeysAndUpdateCache(CacheKey cacheKey) throws OAuth2ServiceException {
- String jwksJson = getTokenKeyService().retrieveTokenKeys(cacheKey.keyUri(), cacheKey.params());
+ private JsonWebKeySet retrieveTokenKeysAndUpdateCache(CacheKey cacheKey) throws OAuth2ServiceException {
+ String jwksJson = getTokenKeyService().retrieveTokenKeys(cacheKey.keyUri(), cacheKey.params());
- JsonWebKeySet keySet = JsonWebKeySetFactory.createFromJson(jwksJson);
- getCache().put(cacheKey.toString(), keySet);
+ JsonWebKeySet keySet = JsonWebKeySetFactory.createFromJson(jwksJson);
+ getCache().put(cacheKey.toString(), keySet);
- return keySet;
- }
+ return keySet;
+ }
private TokenKeyCacheConfiguration getCheckedConfiguration(CacheConfiguration cacheConfiguration) {
Assertions.assertNotNull(cacheConfiguration, "CacheConfiguration must not be null!");
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 86193f7322..74453b5d85 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
@@ -23,79 +23,86 @@
* Jwt Signature validator for OIDC tokens issued by Identity service
*/
class SapIdJwtSignatureValidator extends JwtSignatureValidator {
- private boolean isTenantIdCheckEnabled = true;
-
- SapIdJwtSignatureValidator(OAuth2ServiceConfiguration configuration, OAuth2TokenKeyServiceWithCache tokenKeyService, OidcConfigurationServiceWithCache oidcConfigurationService) {
- super(configuration, tokenKeyService, oidcConfigurationService);
- }
-
- /**
- * Disables the tenant id check. In case JWT issuer (`iss` claim) differs from `url` attribute of
- * {@link OAuth2ServiceConfiguration}, claim {@link TokenClaims#SAP_GLOBAL_APP_TID} needs to be
- * present in token to ensure that the tenant belongs to this issuer.
- *
- * Use with caution as it relaxes the validation rules! It is not recommended to
- * disable this check for standard Identity service setup.
- */
- protected void disableTenantIdCheck() {
- this.isTenantIdCheckEnabled = false;
- }
-
- @Override
- protected PublicKey getPublicKey(Token token, JwtSignatureAlgorithm algorithm) throws OAuth2ServiceException {
- String keyId = DEFAULT_KEY_ID;
- if (token.hasHeaderParameter(KID_PARAMETER_NAME)) {
- keyId = token.getHeaderParameterAsString(KID_PARAMETER_NAME);
- }
-
- URI jkuUri = getJwksUri(token);
- Map params = new HashMap<>(3, 1);
- params.put(HttpHeaders.X_APP_TID, token.getAppTid());
- params.put(HttpHeaders.X_CLIENT_ID, configuration.getClientId());
- params.put(HttpHeaders.X_AZP, token.getClaimAsString(TokenClaims.AUTHORIZATION_PARTY));
-
- try {
- return tokenKeyService.getPublicKey(algorithm, keyId, jkuUri, params);
- } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- private URI getJwksUri(Token token) throws OAuth2ServiceException {
- String domain = token.getIssuer();
- if (domain == null) {
- throw new IllegalArgumentException("Token does not contain mandatory " + TokenClaims.ISSUER + " header.");
- }
-
- if (isTenantIdCheckEnabled && !domain.equals("" + configuration.getUrl()) && token.getAppTid() == null) {
- 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.");
- }
-
-
- return this.getOidcJwksUri(domain);
- }
-
- /**
- * Fetches the JWKS URI from the OIDC .well-known endpoint under the given domain that must have already been validated to be trustworthy in advance, e.g. with an additional {@link JwtIssuerValidator}.
- *
- * @param domain a trustworthy domain that supplies an OIDC .well-known endpoint
- * @return the URI to the JWKS of the OIDC service under the given domain
- * @throws OAuth2ServiceException if server call fails
- */
- @Nonnull
- private URI getOidcJwksUri(String domain) throws OAuth2ServiceException {
- URI discoveryUri = DefaultOidcConfigurationService.getDiscoveryEndpointUri(domain);
-
- OAuth2ServiceEndpointsProvider endpointsProvider = oidcConfigurationService.getOrRetrieveEndpoints(discoveryUri);
- if (endpointsProvider == null) {
- throw new OAuth2ServiceException("OIDC .well-known configuration could not be retrieved.");
- }
-
- URI jkuUri = endpointsProvider.getJwksUri();
- if (jkuUri == null) {
- throw new IllegalArgumentException("OIDC .well-known response did not contain JWKS URI.");
- }
-
- return jkuUri;
- }
+ private boolean isTenantIdCheckEnabled = true;
+
+ SapIdJwtSignatureValidator(OAuth2ServiceConfiguration configuration, OAuth2TokenKeyServiceWithCache tokenKeyService,
+ OidcConfigurationServiceWithCache oidcConfigurationService) {
+ super(configuration, tokenKeyService, oidcConfigurationService);
+ }
+
+ /**
+ * Disables the tenant id check. In case JWT issuer (`iss` claim) differs from
+ * `url` attribute of {@link OAuth2ServiceConfiguration}, claim
+ * {@link TokenClaims#SAP_GLOBAL_APP_TID} needs to be present in token to ensure
+ * that the tenant belongs to this issuer.
+ *
+ * Use with caution as it relaxes the validation rules! It is not recommended to
+ * disable this check for standard Identity service setup.
+ */
+ protected void disableTenantIdCheck() {
+ this.isTenantIdCheckEnabled = false;
+ }
+
+ @Override
+ protected PublicKey getPublicKey(Token token, JwtSignatureAlgorithm algorithm) throws OAuth2ServiceException {
+ String keyId = DEFAULT_KEY_ID;
+ if (token.hasHeaderParameter(KID_PARAMETER_NAME)) {
+ keyId = token.getHeaderParameterAsString(KID_PARAMETER_NAME);
+ }
+
+ URI jkuUri = getJwksUri(token);
+ Map params = new HashMap<>(3, 1);
+ params.put(HttpHeaders.X_APP_TID, token.getAppTid());
+ params.put(HttpHeaders.X_CLIENT_ID, configuration.getClientId());
+ params.put(HttpHeaders.X_AZP, token.getClaimAsString(TokenClaims.AUTHORIZATION_PARTY));
+
+ try {
+ return tokenKeyService.getPublicKey(algorithm, keyId, jkuUri, params);
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private URI getJwksUri(Token token) throws OAuth2ServiceException {
+ String domain = token.getIssuer();
+ if (domain == null) {
+ throw new IllegalArgumentException("Token does not contain mandatory " + TokenClaims.ISSUER + " header.");
+ }
+
+ if (isTenantIdCheckEnabled && !domain.equals("" + configuration.getUrl()) && token.getAppTid() == null) {
+ 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.");
+ }
+
+ return this.getOidcJwksUri(domain);
+ }
+
+ /**
+ * Fetches the JWKS URI from the OIDC .well-known endpoint under the given
+ * domain that must have already been validated to be trustworthy in advance,
+ * e.g. with an additional {@link JwtIssuerValidator}.
+ *
+ * @param domain
+ * a trustworthy domain that supplies an OIDC .well-known endpoint
+ * @return the URI to the JWKS of the OIDC service under the given domain
+ * @throws OAuth2ServiceException
+ * if server call fails
+ */
+ @Nonnull
+ private URI getOidcJwksUri(String domain) throws OAuth2ServiceException {
+ URI discoveryUri = DefaultOidcConfigurationService.getDiscoveryEndpointUri(domain);
+
+ OAuth2ServiceEndpointsProvider endpointsProvider = oidcConfigurationService
+ .getOrRetrieveEndpoints(discoveryUri);
+ if (endpointsProvider == null) {
+ throw new OAuth2ServiceException("OIDC .well-known configuration could not be retrieved.");
+ }
+
+ URI jkuUri = endpointsProvider.getJwksUri();
+ if (jkuUri == null) {
+ throw new IllegalArgumentException("OIDC .well-known response did not contain JWKS URI.");
+ }
+
+ return jkuUri;
+ }
}
diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java
index 0c27020fa7..483c2f6f93 100644
--- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java
+++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java
@@ -23,82 +23,94 @@
* Jwt Signature validator for Access tokens issued by Xsuaa service
*/
class XsuaaJwtSignatureValidator extends JwtSignatureValidator {
- public static final Logger LOGGER = LoggerFactory.getLogger(XsuaaJwtSignatureValidator.class);
-
- /*
- * The following list of factories brings backward-compatibility for test credentials in consumer applications written before 2.17.0 that are used to validate java-security-test tokens.
- * This is necessary to construct the correct JKU when 'localhost' without port is defined as uaadomain in the service credentials.
- * Implementations of this interface absolutely MUST NOT be supplied outside test scope and MUST NOT be used for any other purpose to preserve application security.
- */
- List jkuFactories = new ArrayList<>() {
- {
- try {
- ServiceLoader.load(XsuaaJkuFactory.class).forEach(this::add);
- LOGGER.debug("loaded XsuaaJkuFactory service providers: {}", this);
- } catch (Exception | ServiceConfigurationError e) {
- LOGGER.warn("Unexpected failure while loading XsuaaJkuFactory service providers: {}", e.getMessage());
- }
- }
- };
-
- XsuaaJwtSignatureValidator(OAuth2ServiceConfiguration configuration, OAuth2TokenKeyServiceWithCache tokenKeyService, OidcConfigurationServiceWithCache oidcConfigurationService) {
- super(configuration, tokenKeyService, oidcConfigurationService);
- }
-
- @Override
- protected PublicKey getPublicKey(Token token, JwtSignatureAlgorithm algorithm) throws OAuth2ServiceException, InvalidKeySpecException, NoSuchAlgorithmException {
- PublicKey key = null;
-
- try {
- key = fetchPublicKey(token, algorithm);
- } catch (OAuth2ServiceException | InvalidKeySpecException | NoSuchAlgorithmException | IllegalArgumentException e) {
- if (!configuration.hasProperty(ServiceConstants.XSUAA.VERIFICATION_KEY)) {
- throw e;
- }
- }
-
- if (key == null && configuration.hasProperty(ServiceConstants.XSUAA.VERIFICATION_KEY)) {
- String fallbackKey = configuration.getProperty(ServiceConstants.XSUAA.VERIFICATION_KEY);
- try {
- key = JsonWebKeyImpl.createPublicKeyFromPemEncodedPublicKey(JwtSignatureAlgorithm.RS256, fallbackKey);
- } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
- throw new IllegalArgumentException("Fallback validation key supplied via " + ServiceConstants.XSUAA.VERIFICATION_KEY + " property in service credentials could not be used: {}", ex);
- }
- }
-
- return key;
- }
-
-
- private PublicKey fetchPublicKey(Token token, JwtSignatureAlgorithm algorithm) throws OAuth2ServiceException, InvalidKeySpecException, NoSuchAlgorithmException {
- String keyId = configuration.isLegacyMode() ? KEY_ID_VALUE_LEGACY : token.getHeaderParameterAsString(KID_PARAMETER_NAME);
- if (keyId == null) {
- throw new IllegalArgumentException("Token does not contain the mandatory " + KID_PARAMETER_NAME + " header.");
- }
-
- String zidQueryParam = composeZidQueryParameter(token);
-
- String jwksUri;
- if (jkuFactories.isEmpty()) {
- jwksUri = configuration.isLegacyMode()
- ? configuration.getUrl() + "/token_keys"
- : configuration.getProperty(UAA_DOMAIN) + "/token_keys" + zidQueryParam;
- } else {
- LOGGER.info("Loaded custom JKU factory");
- jwksUri = jkuFactories.get(0).create(token.getTokenValue());
- }
-
- URI uri = URI.create(jwksUri);
- uri = uri.isAbsolute() ? uri : URI.create("https://" + jwksUri);
- Map params = Collections.singletonMap(HttpHeaders.X_ZID, token.getAppTid());
- return tokenKeyService.getPublicKey(algorithm, keyId, uri, params);
- }
-
- private String composeZidQueryParameter(Token token) {
- String zid = token.getAppTid();
- if (zid != null && !zid.isBlank()){
- return "?zid=" + zid;
- }
- return "";
- }
+ public static final Logger LOGGER = LoggerFactory.getLogger(XsuaaJwtSignatureValidator.class);
+
+ /*
+ * The following list of factories brings backward-compatibility for test
+ * credentials in consumer applications written before 2.17.0 that are used to
+ * validate java-security-test tokens. This is necessary to construct the
+ * correct JKU when 'localhost' without port is defined as uaadomain in the
+ * service credentials. Implementations of this interface absolutely MUST NOT be
+ * supplied outside test scope and MUST NOT be used for any other purpose to
+ * preserve application security.
+ */
+ List jkuFactories = new ArrayList<>() {
+ {
+ try {
+ ServiceLoader.load(XsuaaJkuFactory.class).forEach(this::add);
+ LOGGER.debug("loaded XsuaaJkuFactory service providers: {}", this);
+ } catch (Exception | ServiceConfigurationError e) {
+ LOGGER.warn("Unexpected failure while loading XsuaaJkuFactory service providers: {}", e.getMessage());
+ }
+ }
+ };
+
+ XsuaaJwtSignatureValidator(OAuth2ServiceConfiguration configuration, OAuth2TokenKeyServiceWithCache tokenKeyService,
+ OidcConfigurationServiceWithCache oidcConfigurationService) {
+ super(configuration, tokenKeyService, oidcConfigurationService);
+ }
+
+ @Override
+ protected PublicKey getPublicKey(Token token, JwtSignatureAlgorithm algorithm)
+ throws OAuth2ServiceException, InvalidKeySpecException, NoSuchAlgorithmException {
+ PublicKey key = null;
+
+ try {
+ key = fetchPublicKey(token, algorithm);
+ } catch (OAuth2ServiceException | InvalidKeySpecException | NoSuchAlgorithmException
+ | IllegalArgumentException e) {
+ if (!configuration.hasProperty(ServiceConstants.XSUAA.VERIFICATION_KEY)) {
+ throw e;
+ }
+ }
+
+ if (key == null && configuration.hasProperty(ServiceConstants.XSUAA.VERIFICATION_KEY)) {
+ String fallbackKey = configuration.getProperty(ServiceConstants.XSUAA.VERIFICATION_KEY);
+ try {
+ key = JsonWebKeyImpl.createPublicKeyFromPemEncodedPublicKey(JwtSignatureAlgorithm.RS256, fallbackKey);
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
+ throw new IllegalArgumentException(
+ "Fallback validation key supplied via " + ServiceConstants.XSUAA.VERIFICATION_KEY
+ + " property in service credentials could not be used: {}",
+ ex);
+ }
+ }
+
+ return key;
+ }
+
+ private PublicKey fetchPublicKey(Token token, JwtSignatureAlgorithm algorithm)
+ throws OAuth2ServiceException, InvalidKeySpecException, NoSuchAlgorithmException {
+ String keyId = configuration.isLegacyMode() ? KEY_ID_VALUE_LEGACY
+ : token.getHeaderParameterAsString(KID_PARAMETER_NAME);
+ if (keyId == null) {
+ throw new IllegalArgumentException(
+ "Token does not contain the mandatory " + KID_PARAMETER_NAME + " header.");
+ }
+
+ String zidQueryParam = composeZidQueryParameter(token);
+
+ String jwksUri;
+ if (jkuFactories.isEmpty()) {
+ jwksUri = configuration.isLegacyMode()
+ ? configuration.getUrl() + "/token_keys"
+ : configuration.getProperty(UAA_DOMAIN) + "/token_keys" + zidQueryParam;
+ } else {
+ LOGGER.info("Loaded custom JKU factory");
+ jwksUri = jkuFactories.get(0).create(token.getTokenValue());
+ }
+
+ URI uri = URI.create(jwksUri);
+ uri = uri.isAbsolute() ? uri : URI.create("https://" + jwksUri);
+ Map params = Collections.singletonMap(HttpHeaders.X_ZID, token.getAppTid());
+ return tokenKeyService.getPublicKey(algorithm, keyId, uri, params);
+ }
+
+ private String composeZidQueryParameter(Token token) {
+ String zid = token.getAppTid();
+ if (zid != null && !zid.isBlank()) {
+ return "?zid=" + zid;
+ }
+ return "";
+ }
}
diff --git a/java-security/src/test/java/com/sap/cloud/security/servlet/HybridTokenFactoryTest.java b/java-security/src/test/java/com/sap/cloud/security/servlet/HybridTokenFactoryTest.java
new file mode 100644
index 0000000000..1da1174474
--- /dev/null
+++ b/java-security/src/test/java/com/sap/cloud/security/servlet/HybridTokenFactoryTest.java
@@ -0,0 +1,50 @@
+package com.sap.cloud.security.servlet;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import com.sap.cloud.security.token.XsuaaToken;
+import org.apache.commons.io.IOUtils;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class HybridTokenFactoryTest {
+
+ private ListAppender logWatcher;
+ private HybridTokenFactory cut;
+
+ @BeforeEach
+ public void setup() {
+ cut = new HybridTokenFactory();
+ cut.xsAppId = null;
+ cut.xsScopeConverter = null;
+ logWatcher = new ListAppender<>();
+ logWatcher.start();
+ ((Logger) LoggerFactory.getLogger(HybridTokenFactory.class)).addAppender(logWatcher);
+ }
+
+ @AfterEach
+ void teardown() {
+ ((Logger) LoggerFactory.getLogger(HybridTokenFactory.class)).detachAndStopAllAppenders();
+ }
+
+ @Test
+ void oneWarningMessageIncaseSecurityConfigIsMissing() throws IOException {
+ String jwt = IOUtils.resourceToString("/xsuaaJwtBearerTokenRSA256.txt", UTF_8);
+ XsuaaToken token = (XsuaaToken) cut.create(jwt);
+ cut.create(jwt);
+
+ assertThat(token.getIssuer()).isEqualTo("http://auth.com");
+ assertThrows(IllegalArgumentException.class, () -> token.hasLocalScope("abc"));
+ assertThat(logWatcher.list).isNotNull().hasSize(1);
+ assertThat(logWatcher.list.get(0).getMessage()).contains("There is no xsuaa service configuration");
+ }
+}
\ No newline at end of file
diff --git a/java-security/src/test/java/com/sap/cloud/security/token/XsuaaTokenTest.java b/java-security/src/test/java/com/sap/cloud/security/token/XsuaaTokenTest.java
index 8832a5481b..2a17b0dc94 100644
--- a/java-security/src/test/java/com/sap/cloud/security/token/XsuaaTokenTest.java
+++ b/java-security/src/test/java/com/sap/cloud/security/token/XsuaaTokenTest.java
@@ -34,7 +34,8 @@ public XsuaaTokenTest() throws IOException {
@Test
public void constructor_raiseIllegalArgumentExceptions() {
- assertThatThrownBy(() -> new XsuaaToken("")).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("jwtToken must not be null / empty");
+ assertThatThrownBy(() -> new XsuaaToken("")).isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("jwtToken must not be null / empty");
assertThatThrownBy(() -> new XsuaaToken("abc")).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("JWT token does not consist of 'header'.'payload'.'signature'.");
diff --git a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/IdTokenSignatureValidatorTest.java b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/IdTokenSignatureValidatorTest.java
index 392dc11451..bb4658a9a0 100644
--- a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/IdTokenSignatureValidatorTest.java
+++ b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/IdTokenSignatureValidatorTest.java
@@ -73,7 +73,7 @@ public void setup() throws IOException {
tokenKeyServiceMock = Mockito.mock(OAuth2TokenKeyService.class);
when(tokenKeyServiceMock.retrieveTokenKeys(JKU_URI, PARAMS))
- .thenReturn(IOUtils.resourceToString("/iasJsonWebTokenKeys.json", UTF_8));
+ .thenReturn(IOUtils.resourceToString("/iasJsonWebTokenKeys.json", UTF_8));
cut = new SapIdJwtSignatureValidator(
mockConfiguration,
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 500069f108..405ab5b0c8 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
@@ -66,7 +66,8 @@ void validationSucceeds_forValidIssuers(String issuer) {
}
/**
- * Test ensures that issuer validation also succeeds for servers running on http://localhost:, e.g. when using java-security-test module.
+ * Test ensures that issuer validation also succeeds for servers running on
+ * http://localhost:, e.g. when using java-security-test module.
*/
@Test
void supportsHttpLocalhostIssuers() {
@@ -81,7 +82,7 @@ void supportsHttpLocalhostIssuers() {
@Test
void validationFails_whenSubdomainHasMoreThan63Characters() {
- for(String d : trustedDomains) {
+ for (String d : trustedDomains) {
when(token.getIssuer()).thenReturn("https://a." + d);
assertThat(cut.validate(token).isValid(), is(true));
diff --git a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/OAuth2TokenKeyServiceWithCacheTest.java b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/OAuth2TokenKeyServiceWithCacheTest.java
index 2894bed269..f0caae1840 100644
--- a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/OAuth2TokenKeyServiceWithCacheTest.java
+++ b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/OAuth2TokenKeyServiceWithCacheTest.java
@@ -41,9 +41,9 @@ public class OAuth2TokenKeyServiceWithCacheTest {
private static final String CLIENT_ID = "client_id";
private static final String AZP = "azp";
private static final Map PARAMS = Map.of(
- HttpHeaders.X_APP_TID, APP_TID,
- HttpHeaders.X_CLIENT_ID, CLIENT_ID,
- HttpHeaders.X_AZP, AZP);
+ HttpHeaders.X_APP_TID, APP_TID,
+ HttpHeaders.X_CLIENT_ID, CLIENT_ID,
+ HttpHeaders.X_AZP, AZP);
@Before
public void setup() throws IOException {
@@ -89,9 +89,11 @@ public void changeCacheConfiguration_tooLongDuration_leftUnchanged() {
}
@Test
- public void retrieveTokenKeysUsesCorrectParams() throws OAuth2ServiceException, InvalidKeySpecException, NoSuchAlgorithmException {
+ public void retrieveTokenKeysUsesCorrectParams()
+ throws OAuth2ServiceException, InvalidKeySpecException, NoSuchAlgorithmException {
PublicKey key1 = cut.getPublicKey(JwtSignatureAlgorithm.RS256, "key-id-0", TOKEN_KEYS_URI, PARAMS);
- Map otherParams = Map.of(HttpHeaders.X_APP_TID, "otherAppTid", HttpHeaders.X_CLIENT_ID, "otherClientId");
+ Map otherParams = Map.of(HttpHeaders.X_APP_TID, "otherAppTid", HttpHeaders.X_CLIENT_ID,
+ "otherClientId");
PublicKey key2 = cut.getPublicKey(JwtSignatureAlgorithm.RS256, "key-id-0", TOKEN_KEYS_URI, otherParams);
assertThat(String.valueOf(key1.getAlgorithm())).isEqualTo("RSA");
@@ -139,7 +141,8 @@ public void retrieveTokenKeys_afterCacheWasCleared()
}
@Test
- public void getCachedTokenKeys_noAppTid_noAzp() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
+ public void getCachedTokenKeys_noAppTid_noAzp()
+ throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
Map params = Map.of(HttpHeaders.X_CLIENT_ID, CLIENT_ID);
when(tokenKeyServiceMock.retrieveTokenKeys(eq(TOKEN_KEYS_URI), eq(params)))
.thenReturn(IOUtils.resourceToString("/jsonWebTokenKeys.json", StandardCharsets.UTF_8));
@@ -189,14 +192,17 @@ public void retrieveTokenKeysForNewKeyId()
public void retrieveTokenKeysDoesNotCacheOnServerException()
throws OAuth2ServiceException, InvalidKeySpecException, NoSuchAlgorithmException {
Map invalidParams = Map.of(HttpHeaders.X_APP_TID, "invalidAppTid");
- when(tokenKeyServiceMock.retrieveTokenKeys(any(), eq(invalidParams))).thenThrow(new OAuth2ServiceException("Invalid parameters provided"));
+ when(tokenKeyServiceMock.retrieveTokenKeys(any(), eq(invalidParams)))
+ .thenThrow(new OAuth2ServiceException("Invalid parameters provided"));
cut.getPublicKey(JwtSignatureAlgorithm.RS256, "key-id-0", TOKEN_KEYS_URI, PARAMS);
- assertThatThrownBy(() -> cut.getPublicKey(JwtSignatureAlgorithm.RS256, "key-id-0", TOKEN_KEYS_URI, invalidParams)).
- isInstanceOf(OAuth2ServiceException.class).hasMessageStartingWith("Invalid");
+ assertThatThrownBy(
+ () -> cut.getPublicKey(JwtSignatureAlgorithm.RS256, "key-id-0", TOKEN_KEYS_URI, invalidParams))
+ .isInstanceOf(OAuth2ServiceException.class).hasMessageStartingWith("Invalid");
- assertThatThrownBy(() -> cut.getPublicKey(JwtSignatureAlgorithm.RS256, "key-id-0", TOKEN_KEYS_URI, invalidParams))
- .isInstanceOf(OAuth2ServiceException.class).hasMessageStartingWith("Invalid");
+ assertThatThrownBy(
+ () -> cut.getPublicKey(JwtSignatureAlgorithm.RS256, "key-id-0", TOKEN_KEYS_URI, invalidParams))
+ .isInstanceOf(OAuth2ServiceException.class).hasMessageStartingWith("Invalid");
verify(tokenKeyServiceMock, times(1)).retrieveTokenKeys(any(), eq(PARAMS));
verify(tokenKeyServiceMock, times(2)).retrieveTokenKeys(any(), eq(invalidParams));
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 5d59f45566..5f335a8a16 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
@@ -59,7 +59,7 @@ public void setup() throws IOException {
tokenKeyServiceMock = Mockito.mock(OAuth2TokenKeyService.class);
when(tokenKeyServiceMock
.retrieveTokenKeys(any(), anyMap()))
- .thenReturn(IOUtils.resourceToString("/iasJsonWebTokenKeys.json", UTF_8));
+ .thenReturn(IOUtils.resourceToString("/iasJsonWebTokenKeys.json", UTF_8));
endpointsProviderMock = Mockito.mock(OAuth2ServiceEndpointsProvider.class);
when(endpointsProviderMock.getJwksUri()).thenReturn(DUMMY_JKU_URI);
@@ -76,28 +76,30 @@ public void setup() throws IOException {
@Test
public void validate_throwsWhenTokenIsNull() {
- Token tokenSpy = Mockito.spy(iasToken);
- doReturn(null).when(tokenSpy).getTokenValue();
+ Token tokenSpy = Mockito.spy(iasToken);
+ doReturn(null).when(tokenSpy).getTokenValue();
ValidationResult validationResult = cut.validate(tokenSpy);
assertTrue(validationResult.isErroneous());
- assertThat(validationResult.getErrorDescription(), containsString("JWT token validation failed because token content was null."));
+ assertThat(validationResult.getErrorDescription(),
+ containsString("JWT token validation failed because token content was null."));
}
@Test
public void validate_throwsWhenAlgorithmIsNull() {
- Token tokenSpy = Mockito.spy(iasToken);
- doReturn(null).when(tokenSpy).getHeaderParameterAsString(JsonWebKeyConstants.ALG_PARAMETER_NAME);
+ Token tokenSpy = Mockito.spy(iasToken);
+ doReturn(null).when(tokenSpy).getHeaderParameterAsString(JsonWebKeyConstants.ALG_PARAMETER_NAME);
ValidationResult validationResult = cut.validate(tokenSpy);
assertTrue(validationResult.isErroneous());
- assertThat(validationResult.getErrorDescription(), containsString("JWT token validation with signature algorithm 'null' is not supported"));
+ assertThat(validationResult.getErrorDescription(),
+ containsString("JWT token validation with signature algorithm 'null' is not supported"));
}
@Test
public void validate_throwsWhenKeyIdIsNull() {
- Token tokenSpy = Mockito.spy(iasToken);
- doReturn(null).when(tokenSpy).getHeaderParameterAsString(JsonWebKeyConstants.KID_PARAMETER_NAME);
+ Token tokenSpy = Mockito.spy(iasToken);
+ doReturn(null).when(tokenSpy).getHeaderParameterAsString(JsonWebKeyConstants.KID_PARAMETER_NAME);
ValidationResult validationResult = cut.validate(tokenSpy);
assertTrue(validationResult.isErroneous());
@@ -118,7 +120,8 @@ public void validationFails_WhenAppTidIsNull() {
ValidationResult validationResult = cut.validate(iasPaasToken);
assertTrue(validationResult.isErroneous());
assertThat(validationResult.getErrorDescription(),
- 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."));
+ 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
@@ -162,35 +165,39 @@ public void validationFails_whenJwtProvidesNoSignature() {
String tokenWithNoSignature = new StringBuilder(tokenHeaderPayloadSignature[0])
.append(".")
.append(tokenHeaderPayloadSignature[1]).toString();
- Token tokenSpy = Mockito.spy(iasToken);
- doReturn(tokenWithNoSignature).when(tokenSpy).getTokenValue();
+ Token tokenSpy = Mockito.spy(iasToken);
+ doReturn(tokenWithNoSignature).when(tokenSpy).getTokenValue();
ValidationResult result = cut.validate(tokenSpy);
assertThat(result.isErroneous(), is(true));
- assertThat(result.getErrorDescription(), containsString("Jwt token does not consist of three sections: 'header'.'payload'.'signature'."));
+ assertThat(result.getErrorDescription(),
+ containsString("Jwt token does not consist of three sections: 'header'.'payload'.'signature'."));
}
@Test
public void validationFails_whenTokenAlgorithmIsNotSupported() {
- Token tokenSpy = Mockito.spy(iasToken);
+ Token tokenSpy = Mockito.spy(iasToken);
String unsupportedAlgorithm = "UnsupportedAlgorithm";
- doReturn(unsupportedAlgorithm).when(tokenSpy).getHeaderParameterAsString(JsonWebKeyConstants.ALG_PARAMETER_NAME);
+ doReturn(unsupportedAlgorithm).when(tokenSpy)
+ .getHeaderParameterAsString(JsonWebKeyConstants.ALG_PARAMETER_NAME);
- ValidationResult validationResult = cut.validate(tokenSpy);
+ ValidationResult validationResult = cut.validate(tokenSpy);
assertThat(validationResult.isErroneous(), is(true));
- assertThat(validationResult.getErrorDescription(), startsWith("JWT token validation with signature algorithm '" + unsupportedAlgorithm + "' is not supported."));
+ assertThat(validationResult.getErrorDescription(), startsWith(
+ "JWT token validation with signature algorithm '" + unsupportedAlgorithm + "' is not supported."));
}
@Test
public void validationFails_whenTokenAlgorithmIsNone() {
- Token tokenSpy = Mockito.spy(iasToken);
- doReturn("NONE").when(tokenSpy).getHeaderParameterAsString(JsonWebKeyConstants.ALG_PARAMETER_NAME);
+ Token tokenSpy = Mockito.spy(iasToken);
+ doReturn("NONE").when(tokenSpy).getHeaderParameterAsString(JsonWebKeyConstants.ALG_PARAMETER_NAME);
- ValidationResult validationResult = cut.validate(tokenSpy);
+ ValidationResult validationResult = cut.validate(tokenSpy);
- assertThat(validationResult.isErroneous(), is(true));
- assertThat(validationResult.getErrorDescription(), startsWith("JWT token validation with signature algorithm 'NONE' is not supported."));
+ assertThat(validationResult.isErroneous(), is(true));
+ assertThat(validationResult.getErrorDescription(),
+ startsWith("JWT token validation with signature algorithm 'NONE' is not supported."));
}
@Test
diff --git a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsaJwtSignatureValidatorTest.java b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsaJwtSignatureValidatorTest.java
index 19926bffcd..52bf16e101 100644
--- a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsaJwtSignatureValidatorTest.java
+++ b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsaJwtSignatureValidatorTest.java
@@ -52,7 +52,7 @@ public void setup() throws IOException {
tokenKeyServiceMock = Mockito.mock(OAuth2TokenKeyService.class);
when(tokenKeyServiceMock
.retrieveTokenKeys(eq(JKU_URI), anyMap()))
- .thenReturn(IOUtils.resourceToString("/jsonWebTokenKeys.json", UTF_8));
+ .thenReturn(IOUtils.resourceToString("/jsonWebTokenKeys.json", UTF_8));
cut = new XsuaaJwtSignatureValidator(
mockConfiguration,
diff --git a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidatorTest.java b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidatorTest.java
index 8eeb54832e..b50d1d4f9a 100644
--- a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidatorTest.java
+++ b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidatorTest.java
@@ -59,9 +59,10 @@ public void setup() throws IOException {
tokenKeyServiceMock = Mockito.mock(OAuth2TokenKeyService.class);
when(tokenKeyServiceMock
- .retrieveTokenKeys(URI.create("https://authentication.stagingaws.hanavlab.ondemand.com/token_keys?zid=uaa"),
+ .retrieveTokenKeys(
+ URI.create("https://authentication.stagingaws.hanavlab.ondemand.com/token_keys?zid=uaa"),
Map.of(HttpHeaders.X_ZID, "uaa")))
- .thenReturn(IOUtils.resourceToString("/jsonWebTokenKeys.json", UTF_8));
+ .thenReturn(IOUtils.resourceToString("/jsonWebTokenKeys.json", UTF_8));
cut = new XsuaaJwtSignatureValidator(
mockConfiguration,
diff --git a/pom.xml b/pom.xml
index 15b477f6bf..89233a1c0b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
com.sap.cloud.security.xsuaa
parent
- 3.3.2
+ 3.3.4
pom
parent
@@ -57,33 +57,33 @@
17
3.2.1
- 3.2.1
- 6.1.2
+ 3.2.2
+ 6.1.3
6.2.1
2.5.2.RELEASE
1.1.1.RELEASE
- 12.0.5
- 3.6.1
+ 12.0.5
+ 3.6.2
2.22.1
- 2.0.10
+ 2.0.11
20231013
- 0.10.1
- 5.3
+ 0.10.2
+ 5.3.1
4.5.14
3.1.5
2.15.1
6.0.0
4.13.2
5.9.2
- 3.2.3
+ 3.2.5
1.3
- 5.8.0
- 3.24.2
+ 5.9.0
+ 3.25.2
3.3.1
- 3.6.1
+ 3.6.2
1.3.2
4.8.3
- 4.8.2.0
+ 4.8.3.0
false
${skipTests}
@@ -105,12 +105,6 @@
-
-
- org.springframework
- spring-expression
- ${spring.core.version}
-
com.sap.cloud.security
@@ -119,20 +113,6 @@
pom
import
-
- org.eclipse.jetty
- jetty-bom
- ${org.eclipse.jetty.bom.version}
- pom
- import
-
-
- org.eclipse.jetty.ee9
- jetty-ee9-bom
- ${org.eclipse.jetty.bom.version}
- pom
- import
-
@@ -340,7 +320,7 @@
org.apache.maven.plugins
maven-pmd-plugin
- 3.21.0
+ 3.21.2
${skipTests}
@@ -405,7 +385,7 @@
org.owasp
dependency-check-maven
- 9.0.7
+ 9.0.9
diff --git a/samples/java-security-usage-ias/pom.xml b/samples/java-security-usage-ias/pom.xml
index 05c539a48f..37df71b8aa 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.3.2
+ 3.3.4
war
17
17
- 3.3.2
+ 3.3.4
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 4d4a3371a2..7d9f644d80 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.3.2
+ 3.3.4
war
dependency-check-maven
- 9.0.2
+ 9.0.6
diff --git a/samples/spring-security-xsuaa-usage/pom.xml b/samples/spring-security-xsuaa-usage/pom.xml
index 588f2f9a74..a8ab8e4230 100644
--- a/samples/spring-security-xsuaa-usage/pom.xml
+++ b/samples/spring-security-xsuaa-usage/pom.xml
@@ -16,7 +16,7 @@
com.sap.cloud.security.samples
spring-security-xsuaa-usage
- 3.3.2
+ 3.3.4
spring-security-xsuaa-usage
@@ -29,7 +29,7 @@
UTF-8
UTF-8
17
- 3.3.2
+ 3.3.4
5.2.1
@@ -98,7 +98,7 @@
org.owasp
dependency-check-maven
- 9.0.2
+ 9.0.6
diff --git a/samples/spring-webflux-security-xsuaa-usage/pom.xml b/samples/spring-webflux-security-xsuaa-usage/pom.xml
index b640c5bef1..451c99a1f8 100644
--- a/samples/spring-webflux-security-xsuaa-usage/pom.xml
+++ b/samples/spring-webflux-security-xsuaa-usage/pom.xml
@@ -81,7 +81,7 @@
org.owasp
dependency-check-maven
- 9.0.2
+ 9.0.6
diff --git a/spring-security-compatibility/pom.xml b/spring-security-compatibility/pom.xml
index d704e46586..c77e4cd900 100644
--- a/spring-security-compatibility/pom.xml
+++ b/spring-security-compatibility/pom.xml
@@ -9,7 +9,7 @@
com.sap.cloud.security.xsuaa
parent
- 3.3.2
+ 3.3.4
com.sap.cloud.security.xsuaa
diff --git a/spring-security-compatibility/src/test/java/com/sap/cloud/security/comp/XsuaaTokenCompTest.java b/spring-security-compatibility/src/test/java/com/sap/cloud/security/comp/XsuaaTokenCompTest.java
index 39b5fe218f..061971c69c 100644
--- a/spring-security-compatibility/src/test/java/com/sap/cloud/security/comp/XsuaaTokenCompTest.java
+++ b/spring-security-compatibility/src/test/java/com/sap/cloud/security/comp/XsuaaTokenCompTest.java
@@ -1,6 +1,6 @@
/**
- * SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Cloud Security Client Java contributors
- *
+ * SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Cloud Security Client Java contributors*
+ *
* SPDX-License-Identifier: Apache-2.0
*/
package com.sap.cloud.security.comp;
@@ -227,7 +227,7 @@ void getSubdomainFails() {
@Test
void getAppToken() {
token = XsuaaTokenComp.createInstance(jwtGenerator.createToken());
- assertThat(token.getAppToken(), startsWith("eyJqa3UiOiJodHRwOi8vbG9jYWx"));
+ assertThat(token.getAppToken(), startsWith("eyJraWQiOiJkZWZhdWx0LWtpZCIs"));
}
@Test
diff --git a/spring-security-starter/pom.xml b/spring-security-starter/pom.xml
index 1d84c1cfd0..22ab6bbaeb 100644
--- a/spring-security-starter/pom.xml
+++ b/spring-security-starter/pom.xml
@@ -16,7 +16,7 @@
com.sap.cloud.security.xsuaa
parent
- 3.3.2
+ 3.3.4
com.sap.cloud.security
diff --git a/spring-security/Migration_SpringXsuaaProjects.md b/spring-security/Migration_SpringXsuaaProjects.md
index 790979a479..9b0d7daa7b 100644
--- a/spring-security/Migration_SpringXsuaaProjects.md
+++ b/spring-security/Migration_SpringXsuaaProjects.md
@@ -157,7 +157,7 @@ It is provided in an extra module. This maven dependency needs to be provided ad
com.sap.cloud.security.xsuaa
spring-security-compatibility
- 3.3.2
+ 3.3.4
```
diff --git a/spring-security/README.md b/spring-security/README.md
index 0478777a69..4412f3e3b9 100644
--- a/spring-security/README.md
+++ b/spring-security/README.md
@@ -66,7 +66,7 @@ These (spring) dependencies need to be provided:
com.sap.cloud.security
resourceserver-security-spring-boot-starter
- 3.3.2
+ 3.3.4
```
@@ -78,12 +78,12 @@ Depending on the service bindings in the environment, a different implementation
In addition, a bean of type [XsuaaTokenFlows](../token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlows.java) is provided that can be used to fetch XSUAA tokens.
#### Autoconfiguration classes
-| Autoconfiguration class | Description |
-|--------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [HybridAuthorizationAutoConfiguration](./src/main/java/com/sap/cloud/security/spring/autoconfig/HybridAuthorizationAutoConfiguration.java) | Creates a converter ([XsuaaTokenAuthorizationConverter](./src/main/java/com/sap/cloud/security/spring/token/authentication/XsuaaTokenAuthorizationConverter.java)) that removes the XSUAA application identifier from the scope names, allowing local scope checks to be performed using [Spring's common built-in expression](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-common-built-in) `hasAuthority |
-| [HybridIdentityServicesAutoConfiguration](./src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java) | Configures a `JwtDecoder` which is able to decode and validate tokens from Xsuaa and/or Identity service
Furthermore it registers `IdentityServiceConfiguration` and optionally `XsuaaServiceConfiguration`, that allow overriding the identity service configurations found in the service bindings (via `identity.*` and `xsuaa.*` properties). |
-| [XsuaaTokenFlowAutoConfiguration](./src/main/java/com/sap/cloud/security/spring/autoconfig/XsuaaTokenFlowAutoConfiguration.java) | Configures an `XsuaaTokenFlows` bean to fetch the XSUAA tokens. Starting with `2.10.0` version it supports X.509 based authentication |
-| [SecurityContextAutoConfiguration](./src/main/java/com/sap/cloud/security/spring/autoconfig/SecurityContextAutoConfiguration.java) | Configures [`JavaSecurityContextHolderStrategy`](./src/main/java/com/sap/cloud/security/spring/token/authentication/JavaSecurityContextHolderStrategy.java) to be used as `SecurityContextHolderStrategy` to keep the `com.sap.cloud.security.token.SecurityContext` in sync |
+| Autoconfiguration class | Description |
+|--------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [HybridAuthorizationAutoConfiguration](./src/main/java/com/sap/cloud/security/spring/autoconfig/HybridAuthorizationAutoConfiguration.java) | Creates a converter ([XsuaaTokenAuthorizationConverter](./src/main/java/com/sap/cloud/security/spring/token/authentication/XsuaaTokenAuthorizationConverter.java)) that removes the XSUAA application identifier from the scope names, allowing local scope checks to be performed using [Spring's common built-in expression](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-common-built-in) `hasAuthority`. Supports only single Xsuaa binding |
+| [HybridIdentityServicesAutoConfiguration](./src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java) | Configures a `JwtDecoder` which is able to decode and validate tokens from Xsuaa and/or Identity service
Furthermore it registers `IdentityServiceConfiguration` and optionally `XsuaaServiceConfiguration`, that allow overriding the identity service configurations found in the service bindings (via `identity.*` and `xsuaa.*` properties). |
+| [XsuaaTokenFlowAutoConfiguration](./src/main/java/com/sap/cloud/security/spring/autoconfig/XsuaaTokenFlowAutoConfiguration.java) | Configures an `XsuaaTokenFlows` bean to fetch the XSUAA tokens. Starting with `2.10.0` version it supports X.509 based authentication |
+| [SecurityContextAutoConfiguration](./src/main/java/com/sap/cloud/security/spring/autoconfig/SecurityContextAutoConfiguration.java) | Configures [`JavaSecurityContextHolderStrategy`](./src/main/java/com/sap/cloud/security/spring/token/authentication/JavaSecurityContextHolderStrategy.java) to be used as `SecurityContextHolderStrategy` to keep the `com.sap.cloud.security.token.SecurityContext` in sync |
#### Autoconfiguration properties
| Autoconfiguration property | Default value | Description |
@@ -93,6 +93,19 @@ In addition, a bean of type [XsuaaTokenFlows](../token-client/src/main/java/com/
You can gradually replace auto-configurations as explained [here](https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html).
+#### Multiple Xsuaa configurations
+:warning: In case of multiple Xsuaa configurations, the [XsuaaTokenAuthorizationConverter](./src/main/java/com/sap/cloud/security/spring/token/authentication/XsuaaTokenAuthorizationConverter.java) bean is not autoconfigured.
+The bean needs to be created manually based on the service configuration you want the converter to be initialized with.
+
+For example, to create a converter that removes the application identifier of the *first* XSUAA configuration from the scope names, you could create the following bean:
+
+```java
+@Bean
+public Converter xsuaaAuthConverter(XsuaaServiceConfigurations xsuaaConfigs) {
+ return new XsuaaTokenAuthorizationConverter(xsuaaConfigs.getConfigurations().get(0).getProperty(APP_ID));
+}
+```
+You may want to filter the list accessible via `XsuaaServiceConfigurations#getConfigurations` based on the configuration properties to find a specific configuration from the list.
### Security Configuration
This is an example how to configure your application as Spring Security OAuth 2.0 Resource Server for authentication of HTTP requests:
@@ -314,14 +327,7 @@ sap.security.services:
```
#### Multiple XSUAA bindings
-If you need to manually configure the application for more than one XSUAA service instances (e.g. one of plan `application` and another one of plan `broker`), you can provide them as follows:
-````yaml
- sap.security.services:
- xsuaa[0]:
- ... # credentials of XSUAA of plan 'application'
- xsuaa[1]:
- clientid: # clientid of XSUAA of plan 'broker'
-````
+If you need to manually configure the application for more than one XSUAA service instances (e.g. one of plan `application` and another one of plan `broker`), you need to provide them as `VCAP_SERVICES` environment variable (see second point of [Local Testing](#local-testing) section).
### Local testing
To run or debug your secured application locally you need to provide the mandatory Xsuaa or Identity service configuration attributes prior to launching the application.
@@ -425,8 +431,10 @@ Make sure that you have defined the following mandatory attribute in the service
:bulb: Example of minimal application configuration [application.yml](../samples/spring-security-hybrid-usage/src/test/resources/application.yml) for local setup.
+❗Limitation❗ Multiple Xsuaa services cannot be defined as application properties in Spring application.yml or application.properties files as Spring does not recognize arrays in the property files. The service Configurations have to be defined as environment variable e.g. `VCAP_SERVICES={"xsuaa": [...]} `
+
## Samples
- [Hybrid Usage](../samples/spring-security-hybrid-usage)
Demonstrates how to leverage ``spring-security`` library to secure a Spring Boot web application with tokens issued by SAP Identity service or XSUAA. Furthermore, it documents how to implement Spring WebMvcTests using `java-security-test` library.
- [Basic Auth Usage](../samples/spring-security-basic-auth)
-Legacy example that demonstrates how to leverage ``spring-security`` library to secure a Spring Boot web application with username/password provided via Basic Auth header. Furthermore, it documents how to implement Spring WebMvcTests using `java-security-test` library.
\ No newline at end of file
+Legacy example that demonstrates how to leverage ``spring-security`` library to secure a Spring Boot web application with username/password provided via Basic Auth header. Furthermore, it documents how to implement Spring WebMvcTests using `java-security-test` library.
diff --git a/spring-security/pom.xml b/spring-security/pom.xml
index cff8f537e2..0dda8020c1 100644
--- a/spring-security/pom.xml
+++ b/spring-security/pom.xml
@@ -9,13 +9,13 @@
com.sap.cloud.security.xsuaa
parent
- 3.3.2
+ 3.3.4
com.sap.cloud.security
spring-security
jar
- 3.3.2
+ 3.3.4
diff --git a/spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java b/spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java
index 215e3fc541..a1ee27ad77 100644
--- a/spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java
+++ b/spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java
@@ -5,8 +5,8 @@
*/
package com.sap.cloud.security.spring.autoconfig;
-import com.sap.cloud.security.spring.config.IdentityServiceConfiguration;
import com.sap.cloud.security.config.ServiceConstants;
+import com.sap.cloud.security.spring.config.IdentityServiceConfiguration;
import com.sap.cloud.security.spring.config.XsuaaServiceConfiguration;
import com.sap.cloud.security.spring.config.XsuaaServiceConfigurations;
import com.sap.cloud.security.spring.token.authentication.JwtDecoderBuilder;
@@ -83,11 +83,16 @@ public JwtDecoder hybridJwtDecoder(XsuaaServiceConfiguration xsuaaConfig,
public JwtDecoder hybridJwtDecoderMultiXsuaaServices(IdentityServiceConfiguration identityConfig) {
LOGGER.debug("auto-configures HybridJwtDecoder when bound to multiple xsuaa service instances.");
- /* Use only primary XSUAA config and up to 1 more config of type BROKER to stay backward-compatible now that XsuaaServiceConfigurations contains all XSUAA
- configurations instead of only two. */
+ /*
+ * Use only primary XSUAA config and up to 1 more config of type BROKER to stay
+ * backward-compatible now that XsuaaServiceConfigurations contains all XSUAA
+ * configurations instead of only two.
+ */
List allXsuaaConfigs = xsuaaConfigs.getConfigurations();
- List usedXsuaaConfigs = allXsuaaConfigs.subList(0, Math.min(2, allXsuaaConfigs.size()));
- if (usedXsuaaConfigs.size() == 2 && !ServiceConstants.Plan.BROKER.toString().equals(usedXsuaaConfigs.get(1).getProperty(ServiceConstants.SERVICE_PLAN))) {
+ List usedXsuaaConfigs = allXsuaaConfigs.subList(0,
+ Math.min(2, allXsuaaConfigs.size()));
+ if (usedXsuaaConfigs.size() == 2 && !ServiceConstants.Plan.BROKER.toString()
+ .equals(usedXsuaaConfigs.get(1).getProperty(ServiceConstants.SERVICE_PLAN))) {
usedXsuaaConfigs = usedXsuaaConfigs.subList(0, 1);
}
diff --git a/spring-security/src/main/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactory.java b/spring-security/src/main/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactory.java
index adbb8053f3..fd3685a275 100644
--- a/spring-security/src/main/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactory.java
+++ b/spring-security/src/main/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactory.java
@@ -59,7 +59,7 @@ public class IdentityServicesPropertySourceFactory implements PropertySourceFact
.asList("clientid", "clientsecret", "domains", "url", "name", "plan"));
private Properties properties;
-
+
@Override
@SuppressWarnings("squid:S2259") // false positive
public PropertySource> createPropertySource(String name, EncodedResource resource) throws IOException {
@@ -68,18 +68,19 @@ public PropertySource> createPropertySource(String name, EncodedResource resou
&& resource.getResource().getFilename() != null && !resource.getResource().getFilename().isEmpty()) {
environment = Environments.readFromInput(resource.getResource().getInputStream());
}
-
+
this.properties = new Properties();
-
+
mapXsuaaProperties(environment);
mapIasProperties(environment);
logger.debug("Parsed {} properties from identity services. {}", this.properties.size(),
this.properties.stringPropertyNames());
-
+
return new PropertiesPropertySource(name == null ? PROPERTIES_KEY : name, this.properties);
}
- private void mapXsuaaAttributesSingleInstance(final OAuth2ServiceConfiguration oAuth2ServiceConfiguration, final String prefix) {
+ private void mapXsuaaAttributesSingleInstance(final OAuth2ServiceConfiguration oAuth2ServiceConfiguration,
+ final String prefix) {
for (String key : XSUAA_ATTRIBUTES) {
if (oAuth2ServiceConfiguration.hasProperty(key)) {
this.properties.put(prefix + key, oAuth2ServiceConfiguration.getProperty(key));
@@ -92,27 +93,30 @@ private void mapXsuaaProperties(@Nonnull Environment environment) {
if (numberOfXsuaaConfigurations == 0) {
return;
}
-
+
/*
- * Case "single XSUAA service configuration":
- * Then we do not use an array for describing the properties.
+ * Case "single XSUAA service configuration": Then we do not use an array for
+ * describing the properties.
*/
final OAuth2ServiceConfiguration xsuaaConfiguration = environment.getXsuaaConfiguration();
if (numberOfXsuaaConfigurations == 1) {
mapXsuaaAttributesSingleInstance(xsuaaConfiguration, XSUAA_PREFIX);
return;
}
-
+
/*
- * Case "multiple XSUAA service configurations":
- * For historic reasons, the first two items in the array have a special meaning:
- * - Item 0 is exclusively used for environment.getXsuaaConfiguration() ("an arbitrary Xsuaa configuration" of plan "application").
- * - Item 1 is optionally used for environment.getXsuaaConfigurationForTokenExchange() ("an arbitrary Xsuaa configuration" of plan "broker").
+ * Case "multiple XSUAA service configurations": For historic reasons, the first
+ * two items in the array have a special meaning: - Item 0 is exclusively used
+ * for environment.getXsuaaConfiguration() ("an arbitrary Xsuaa configuration"
+ * of plan "application"). - Item 1 is optionally used for
+ * environment.getXsuaaConfigurationForTokenExchange()
+ * ("an arbitrary Xsuaa configuration" of plan "broker").
*/
mapXsuaaAttributesSingleInstance(xsuaaConfiguration, PROPERTIES_KEY + ".xsuaa[0].");
-
+
int position = 1;
- final OAuth2ServiceConfiguration xsuaaConfigurationForTokenExchange = environment.getXsuaaConfigurationForTokenExchange();
+ final OAuth2ServiceConfiguration xsuaaConfigurationForTokenExchange = environment
+ .getXsuaaConfigurationForTokenExchange();
if (xsuaaConfigurationForTokenExchange != null) {
mapXsuaaAttributesSingleInstance(xsuaaConfigurationForTokenExchange, PROPERTIES_KEY + ".xsuaa[1].");
position = 2;
@@ -122,13 +126,15 @@ private void mapXsuaaProperties(@Nonnull Environment environment) {
* For all other items coming thereafter, there is no order defined anymore.
* However, we must not duplicate the instances...
*/
- final List remainingXsuaaConfigurations = environment.getServiceConfigurationsAsList().get(Service.XSUAA)
+ final List remainingXsuaaConfigurations = environment
+ .getServiceConfigurationsAsList().get(Service.XSUAA)
.stream()
.filter(e -> e != xsuaaConfiguration && e != xsuaaConfigurationForTokenExchange)
.toList();
- /* Usage of ".forEach" would have been preferred here,
- * but Closures in JDK8 do not permit accessing non-final "position".
+ /*
+ * Usage of ".forEach" would have been preferred here, but Closures in JDK8 do
+ * not permit accessing non-final "position".
*/
for (OAuth2ServiceConfiguration config : remainingXsuaaConfigurations) {
final String prefix = String.format(PROPERTIES_KEY + ".xsuaa[%d].", position++);
diff --git a/spring-security/src/main/java/com/sap/cloud/security/spring/token/SpringSecurityContext.java b/spring-security/src/main/java/com/sap/cloud/security/spring/token/SpringSecurityContext.java
index 0b460309b9..ca384d3c06 100644
--- a/spring-security/src/main/java/com/sap/cloud/security/spring/token/SpringSecurityContext.java
+++ b/spring-security/src/main/java/com/sap/cloud/security/spring/token/SpringSecurityContext.java
@@ -56,7 +56,8 @@ public static Token getToken() {
return (Token) principal;
}
throw new AccessDeniedException(
- "Access forbidden: SecurityContextHolder does not contain a principal of type 'Token'. Found instead a principal of type " + principal.getClass());
+ "Access forbidden: SecurityContextHolder does not contain a principal of type 'Token'. Found instead a principal of type "
+ + principal.getClass());
}
/**
diff --git a/spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/AuthenticationToken.java b/spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/AuthenticationToken.java
index 1928bf35a0..9eea873d51 100644
--- a/spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/AuthenticationToken.java
+++ b/spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/AuthenticationToken.java
@@ -10,6 +10,7 @@
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.util.Assert;
+import java.lang.reflect.Field;
import java.io.Serial;
import java.util.Collection;
@@ -60,17 +61,35 @@ public String getName() {
@Override
public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj != null && this.getClass() != obj.getClass()) {
+ AuthenticationToken that = (AuthenticationToken) obj;
+ return compareObjects(this.token,that.token) && this.getAuthorities().equals(that.getAuthorities());
+ }
+
+ public static boolean compareObjects(Object obj1, Object obj2) {
+ if (obj2 == null) {
return false;
}
- if (obj == null) {
+ if (!obj1.getClass().equals(obj2.getClass())) {
return false;
}
- AuthenticationToken that = (AuthenticationToken) obj;
- return this.token.equals(that.token) && this.getAuthorities().equals(that.getAuthorities());
+ Field[] fields = obj1.getClass().getDeclaredFields();
+ for (Field field : fields) {
+ field.setAccessible(true);
+ try {
+ Object value1 = field.get(obj1);
+ Object value2 = field.get(obj2);
+ if (value1 == null || value2 == null) {
+ if (value1 != value2) {
+ return false;
+ }
+ } else if (!value1.equals(value2)) {
+ return false;
+ }
+ } catch (IllegalAccessException e) {
+ // handle exception
+ }
+ }
+ return true;
}
@Override
diff --git a/spring-security/src/test/java/com/sap/cloud/security/spring/config/ConfigurationAssertions.java b/spring-security/src/test/java/com/sap/cloud/security/spring/config/ConfigurationAssertions.java
index b6ae430d9f..b930a4ae91 100644
--- a/spring-security/src/test/java/com/sap/cloud/security/spring/config/ConfigurationAssertions.java
+++ b/spring-security/src/test/java/com/sap/cloud/security/spring/config/ConfigurationAssertions.java
@@ -6,12 +6,15 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ConfigurationAssertions {
- static void assertXsuaaConfigsAreEqual(XsuaaServiceConfiguration xsuaaConfig, OAuth2ServiceConfiguration oauthConfig) {
- assertEquals(oauthConfig.getClientId(), xsuaaConfig.getClientId());
- assertEquals(oauthConfig.getClientSecret(), xsuaaConfig.getClientSecret());
- assertEquals(oauthConfig.getProperty(ServiceConstants.XSUAA.UAA_DOMAIN), xsuaaConfig.getProperty(ServiceConstants.XSUAA.UAA_DOMAIN));
- assertEquals(oauthConfig.getProperty(ServiceConstants.XSUAA.APP_ID), xsuaaConfig.getProperty(ServiceConstants.XSUAA.APP_ID));
- assertEquals(oauthConfig.getProperty(ServiceConstants.NAME), xsuaaConfig.getName());
- assertEquals(oauthConfig.getProperty(ServiceConstants.SERVICE_PLAN), xsuaaConfig.getPlan());
- }
+ static void assertXsuaaConfigsAreEqual(XsuaaServiceConfiguration xsuaaConfig,
+ OAuth2ServiceConfiguration oauthConfig) {
+ assertEquals(oauthConfig.getClientId(), xsuaaConfig.getClientId());
+ assertEquals(oauthConfig.getClientSecret(), xsuaaConfig.getClientSecret());
+ assertEquals(oauthConfig.getProperty(ServiceConstants.XSUAA.UAA_DOMAIN),
+ xsuaaConfig.getProperty(ServiceConstants.XSUAA.UAA_DOMAIN));
+ assertEquals(oauthConfig.getProperty(ServiceConstants.XSUAA.APP_ID),
+ xsuaaConfig.getProperty(ServiceConstants.XSUAA.APP_ID));
+ assertEquals(oauthConfig.getProperty(ServiceConstants.NAME), xsuaaConfig.getName());
+ assertEquals(oauthConfig.getProperty(ServiceConstants.SERVICE_PLAN), xsuaaConfig.getPlan());
+ }
}
diff --git a/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryBrokerNoHoleTest.java b/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryBrokerNoHoleTest.java
index 651eb294c6..9bd364b9cc 100644
--- a/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryBrokerNoHoleTest.java
+++ b/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryBrokerNoHoleTest.java
@@ -19,12 +19,15 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
- * Tests that the {@link IdentityServicesPropertySourceFactory} puts 2 XSUAA service instances with plan 'application' into the Spring properties without creating a hole at index 1.
- * For backward-compatibility, the order of the service instance must be as follows:
- * Index 0: Configuration accessible via Environment#getXsuaaConfiguration (Application)
- * Index 1: Configuration accessible via Environment#getXsuaaConfigurationForTokenExchange (Broker) if exists, otherwise next XSUAA configuration
- * Index 2+: Remaining XSUAA configurations
- * In addition, tests that the IAS service instance from the environment is correctly added as well.
+ * Tests that the {@link IdentityServicesPropertySourceFactory} puts 2 XSUAA
+ * service instances with plan 'application' into the Spring properties without
+ * creating a hole at index 1. For backward-compatibility, the order of the
+ * service instance must be as follows: Index 0: Configuration accessible via
+ * Environment#getXsuaaConfiguration (Application) Index 1: Configuration
+ * accessible via Environment#getXsuaaConfigurationForTokenExchange (Broker) if
+ * exists, otherwise next XSUAA configuration Index 2+: Remaining XSUAA
+ * configurations In addition, tests that the IAS service instance from the
+ * environment is correctly added as well.
*/
@SpringBootTest(classes = { BrokerHoleTestConfigurationFromFile.class })
class IdentityServicesPropertySourceFactoryBrokerNoHoleTest {
@@ -41,7 +44,7 @@ void testInjectedPropertyValues() {
assertEquals("xsuaadomain", configuration.xsuaaDomain0);
assertEquals("xsappname2", configuration.xsuaaAppName0);
assertEquals("xsuaaInstance0", configuration.xsuaaName0);
- assertEquals("application", configuration.xsuaaPlan0.toLowerCase());
+ assertEquals("application", configuration.xsuaaPlan0);
assertEquals("", configuration.unknown0);
/* Index 1 */
@@ -49,12 +52,12 @@ void testInjectedPropertyValues() {
assertEquals("client-secret", configuration.xsuaaClientSecret1);
assertEquals("xsappname", configuration.xsuaaAppName1);
assertEquals("xsuaaInstance1", configuration.xsuaaName1);
- assertEquals("application", configuration.xsuaaPlan1.toLowerCase());
+ assertEquals("application", configuration.xsuaaPlan1);
/* Index 2 */
assertEquals("none", configuration.xsuaaClientId2);
assertEquals("none", configuration.xsuaaClientSecret2);
-
+
/* IAS */
assertEquals("client-id-ias", configuration.identityClientId);
assertEquals("client-secret-ias", configuration.identityClientSecret);
@@ -72,7 +75,7 @@ void testInjectedPropertyValues() {
class BrokerHoleTestConfigurationFromFile {
/* Index 0 */
-
+
@Value("${sap.security.services.xsuaa[0].url:}")
public String xsuaaUrl0;
@@ -97,9 +100,8 @@ class BrokerHoleTestConfigurationFromFile {
@Value("${sap.security.services.xsuaa[0].unknown:}")
public String unknown0;
-
/* Index 1 */
-
+
@Value("${sap.security.services.xsuaa[1].clientid:none}")
public String xsuaaClientId1;
@@ -114,19 +116,17 @@ class BrokerHoleTestConfigurationFromFile {
@Value("${sap.security.services.xsuaa[1].plan:}")
public String xsuaaPlan1;
-
+
/* Index 2 */
-
+
@Value("${sap.security.services.xsuaa[2].clientid:none}")
public String xsuaaClientId2;
@Value("${sap.security.services.xsuaa[2].clientsecret:none}")
public String xsuaaClientSecret2;
-
-
/* IAS */
-
+
@Value("${sap.security.services.identity.clientid:}")
public String identityClientId;
diff --git a/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryFourXsuaaOneIasTest.java b/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryFourXsuaaOneIasTest.java
index cf13509d4a..f5e9debf8d 100644
--- a/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryFourXsuaaOneIasTest.java
+++ b/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryFourXsuaaOneIasTest.java
@@ -5,7 +5,6 @@
*/
package com.sap.cloud.security.spring.config;
-import com.sap.cloud.security.config.ServiceConstants;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -19,13 +18,15 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
- * Tests that the {@link IdentityServicesPropertySourceFactory} puts 2 XSUAA service instances with plan 'application' and 2 with plan 'broker' into the Spring properties
- * in the correct order.
- * For backward-compatibility, the order of the service instance must be as follows:
- * Index 0: Configuration accessible via Environment#getXsuaaConfiguration (Application)
- * Index 1: Configuration accessible via Environment#getXsuaaConfigurationForTokenExchange (Broker) if exists, otherwise next XSUAA configuration
- * Index 2+: Remaining XSUAA configurations
- * In addition, tests that the IAS service instance from the environment is correctly added as well.
+ * Tests that the {@link IdentityServicesPropertySourceFactory} puts 2 XSUAA
+ * service instances with plan 'application' and 2 with plan 'broker' into the
+ * Spring properties in the correct order. For backward-compatibility, the order
+ * of the service instance must be as follows: Index 0: Configuration accessible
+ * via Environment#getXsuaaConfiguration (Application) Index 1: Configuration
+ * accessible via Environment#getXsuaaConfigurationForTokenExchange (Broker) if
+ * exists, otherwise next XSUAA configuration Index 2+: Remaining XSUAA
+ * configurations In addition, tests that the IAS service instance from the
+ * environment is correctly added as well.
*/
@SpringBootTest(classes = { FourXsuaaOneIasTestConfigurationFromFile.class })
class IdentityServicesPropertySourceFactoryFourXsuaaOneIasTest {
@@ -42,28 +43,28 @@ void testInjectedPropertyValues() {
assertEquals("xsuaadomain", configuration.xsuaaDomain0);
assertEquals("xsappname2", configuration.xsuaaAppName0);
assertEquals("xsuaaInstance2", configuration.xsuaaName0);
- assertEquals("application", configuration.xsuaaPlan0.toLowerCase());
+ assertEquals("application", configuration.xsuaaPlan0);
assertEquals("", configuration.unknown0);
/* Index 1 */
assertEquals("client-id-broker", configuration.xsuaaClientId1);
assertEquals("client-secret-broker", configuration.xsuaaClientSecret1);
assertEquals("xsuaaInstance0", configuration.xsuaaName1);
- assertEquals("broker", configuration.xsuaaPlan1.toLowerCase());
+ assertEquals("broker", configuration.xsuaaPlan1);
/* Index 2 */
assertEquals("client-id-broker2", configuration.xsuaaClientId2);
assertEquals("client-secret-broker2", configuration.xsuaaClientSecret2);
assertEquals("xsuaaInstance1", configuration.xsuaaName2);
- assertEquals("broker", configuration.xsuaaPlan2.toLowerCase());
+ assertEquals("broker", configuration.xsuaaPlan2);
/* Index 3 */
assertEquals("client-id", configuration.xsuaaClientId3);
assertEquals("client-secret", configuration.xsuaaClientSecret3);
assertEquals("xsappname", configuration.xsuaaAppName3);
assertEquals("xsuaaInstance3", configuration.xsuaaName3);
- assertEquals("application", configuration.xsuaaPlan3.toLowerCase());
-
+ assertEquals("application", configuration.xsuaaPlan3);
+
/* IAS */
assertEquals("client-id-ias", configuration.identityClientId);
assertEquals("client-secret-ias", configuration.identityClientSecret);
@@ -71,7 +72,7 @@ void testInjectedPropertyValues() {
assertTrue(configuration.identityDomains.contains("iasdomain.com"));
assertEquals(2, configuration.identityDomains.size());
assertEquals("identityInstance0", configuration.identityName0);
- assertEquals(ServiceConstants.Plan.BROKER, ServiceConstants.Plan.from(configuration.identityPlan));
+ assertEquals("broker", configuration.identityPlan);
}
}
@@ -81,7 +82,7 @@ void testInjectedPropertyValues() {
class FourXsuaaOneIasTestConfigurationFromFile {
/* Index 0 */
-
+
@Value("${sap.security.services.xsuaa[0].url:}")
public String xsuaaUrl0;
@@ -105,9 +106,9 @@ class FourXsuaaOneIasTestConfigurationFromFile {
@Value("${sap.security.services.xsuaa[0].unknown:}")
public String unknown0;
-
+
/* Index 1 */
-
+
@Value("${sap.security.services.xsuaa[1].clientid:}")
public String xsuaaClientId1;
@@ -120,9 +121,8 @@ class FourXsuaaOneIasTestConfigurationFromFile {
@Value("${sap.security.services.xsuaa[1].plan:}")
public String xsuaaPlan1;
-
/* Index 2 */
-
+
@Value("${sap.security.services.xsuaa[2].clientid:}")
public String xsuaaClientId2;
@@ -136,7 +136,7 @@ class FourXsuaaOneIasTestConfigurationFromFile {
public String xsuaaPlan2;
/* Index 3 */
-
+
@Value("${sap.security.services.xsuaa[3].clientid:}")
public String xsuaaClientId3;
@@ -151,9 +151,9 @@ class FourXsuaaOneIasTestConfigurationFromFile {
@Value("${sap.security.services.xsuaa[3].plan:}")
public String xsuaaPlan3;
-
+
/* IAS */
-
+
@Value("${sap.security.services.identity.clientid:}")
public String identityClientId;
diff --git a/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryTest.java b/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryTest.java
index 1c18f70ba5..f29a7cc682 100644
--- a/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryTest.java
+++ b/spring-security/src/test/java/com/sap/cloud/security/spring/config/IdentityServicesPropertySourceFactoryTest.java
@@ -30,7 +30,7 @@ void testInjectedPropertyValues() {
assertEquals("xsuaadomain", configuration.xsuaaDomain);
assertEquals("xsappname", configuration.xsuaaAppName);
assertEquals("xsuaaInstance0", configuration.xsuaaName);
- assertEquals("application", configuration.xsuaaPlan.toLowerCase());
+ assertEquals("application", configuration.xsuaaPlan);
assertEquals("", configuration.unknown);
@@ -38,7 +38,7 @@ void testInjectedPropertyValues() {
assertEquals("client-secret-ias", configuration.identityClientSecret);
assertEquals("iasdomain", configuration.identityDomains.get(0));
assertEquals("identityInstance0", configuration.identityName);
- assertEquals("broker", configuration.identityPlan.toLowerCase());
+ assertEquals("broker", configuration.identityPlan);
}
}
diff --git a/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationLoadingIntegrationTest.java b/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationLoadingIntegrationTest.java
index a87289762d..0a8cd4d8c9 100644
--- a/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationLoadingIntegrationTest.java
+++ b/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationLoadingIntegrationTest.java
@@ -21,8 +21,11 @@
import static java.nio.charset.StandardCharsets.UTF_8;
/**
- * Tests the integration between XsuaaServiceConfiguration and IdentityServicesPropertySourceFactory.
- * The XSUAA configuration properties of the XsuaaServiceConfiguration are asserted to be equal to those of the configuration used to populate the Spring properties via IdentityServicesPropertySourceFactory.
+ * Tests the integration between XsuaaServiceConfiguration and
+ * IdentityServicesPropertySourceFactory. The XSUAA configuration properties of
+ * the XsuaaServiceConfiguration are asserted to be equal to those of the
+ * configuration used to populate the Spring properties via
+ * IdentityServicesPropertySourceFactory.
*/
@SpringBootTest(classes = { SingleXsuaaConfigurationFromFile.class })
class XsuaaServiceConfigurationLoadingIntegrationTest {
@@ -46,6 +49,8 @@ void configuresXsuaaServiceConfiguration() {
}
@Configuration
-@PropertySource(factory = IdentityServicesPropertySourceFactory.class, value = { "classpath:singleXsuaaAndIasBinding.json" })
+@PropertySource(factory = IdentityServicesPropertySourceFactory.class, value = {
+ "classpath:singleXsuaaAndIasBinding.json" })
@EnableConfigurationProperties(XsuaaServiceConfiguration.class)
-class SingleXsuaaConfigurationFromFile {}
+class SingleXsuaaConfigurationFromFile {
+}
diff --git a/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationsLoadingIntegrationTest.java b/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationsLoadingIntegrationTest.java
index 05450a014b..6dbd709557 100644
--- a/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationsLoadingIntegrationTest.java
+++ b/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationsLoadingIntegrationTest.java
@@ -25,9 +25,13 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
- * Tests the integration between XsuaaServiceConfigurations and IdentityServicesPropertySourceFactory.
- * The XSUAA configuration properties of the XsuaaServiceConfigurations are asserted to be equal to those of the configuration used to populate the Spring properties via IdentityServicesPropertySourceFactory.
- * In addition, to assert backward compatibility, the test makes assertions about indices 0 and 1 in the configuration list of XsuaaServiceConfigurations.
+ * Tests the integration between XsuaaServiceConfigurations and
+ * IdentityServicesPropertySourceFactory. The XSUAA configuration properties of
+ * the XsuaaServiceConfigurations are asserted to be equal to those of the
+ * configuration used to populate the Spring properties via
+ * IdentityServicesPropertySourceFactory. In addition, to assert backward
+ * compatibility, the test makes assertions about indices 0 and 1 in the
+ * configuration list of XsuaaServiceConfigurations.
*/
@SpringBootTest(classes = { MultipleXsuaaConfigurationsFromFile.class })
class XsuaaServiceConfigurationsLoadingIntegrationTest {
@@ -59,6 +63,8 @@ void configuresXsuaaServiceConfigurations() {
}
@Configuration
-@PropertySource(factory = IdentityServicesPropertySourceFactory.class, value = { "classpath:fourXsuaaBindingsAndOneIasBinding.json" })
+@PropertySource(factory = IdentityServicesPropertySourceFactory.class, value = {
+ "classpath:fourXsuaaBindingsAndOneIasBinding.json" })
@EnableConfigurationProperties(XsuaaServiceConfigurations.class)
-class MultipleXsuaaConfigurationsFromFile {}
\ No newline at end of file
+class MultipleXsuaaConfigurationsFromFile {
+}
\ No newline at end of file
diff --git a/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationsTest.java b/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationsTest.java
index 4bcdb2c786..b50945b4bd 100644
--- a/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationsTest.java
+++ b/spring-security/src/test/java/com/sap/cloud/security/spring/config/XsuaaServiceConfigurationsTest.java
@@ -31,12 +31,14 @@ void configuresXsuaaServiceConfigurations() {
"sap.security.services.xsuaa[1].name:xsuaaInstance1",
"sap.security.services.xsuaa[1].plan:broker")
.run(context -> {
- XsuaaServiceConfiguration config0 = context.getBean(XsuaaServiceConfigurations.class).getConfigurations().get(0);
+ XsuaaServiceConfiguration config0 = context.getBean(XsuaaServiceConfigurations.class)
+ .getConfigurations().get(0);
assertEquals("cid0", config0.getClientId());
assertEquals("xsuaaInstance0", config0.getName());
assertEquals("broker", config0.getPlan());
- XsuaaServiceConfiguration config1 = context.getBean(XsuaaServiceConfigurations.class).getConfigurations().get(1);
+ XsuaaServiceConfiguration config1 = context.getBean(XsuaaServiceConfigurations.class)
+ .getConfigurations().get(1);
assertEquals("cid1", config1.getClientId());
assertEquals("xsuaaInstance1", config1.getName());
assertEquals("broker", config1.getPlan());
diff --git a/spring-xsuaa-it/pom.xml b/spring-xsuaa-it/pom.xml
index 89e325943b..fb91421e0d 100644
--- a/spring-xsuaa-it/pom.xml
+++ b/spring-xsuaa-it/pom.xml
@@ -14,12 +14,12 @@
spring-xsuaa-it
spring-xsuaa-it
- 3.3.2
+ 3.3.4
4.10.0
17
- 3.3.2
+ 3.3.4
diff --git a/spring-xsuaa-mock/README.md b/spring-xsuaa-mock/README.md
new file mode 100644
index 0000000000..d2b3d1f1e8
--- /dev/null
+++ b/spring-xsuaa-mock/README.md
@@ -0,0 +1,81 @@
+# XSUAA Security Xsuaa Mock Library
+
+## Deprecation Note
+**This is in maintaince mode, don't use it for new projects!**
+Instead, make use of [`java-security-test`](/java-security-test) testing library, which uses WireMock, supports JUnit 4 and JUnit 5 and can be enhanced easily. Have a look at the [spring-security-xsuaa-usage](/samples/spring-security-xsuaa-usage) as usage reference.
+
+## Description
+This library enhances the spring-xsuaa project. This includes a `XsuaaMockWebServer` web server for the Xsuaa service that can provide *token_keys* for an offline JWT token validation. This is required only when there is no Xsuaa service (OAuth resource-server) in place, which is only the case in context of unit tests, as well as when running your Spring boot application locally.
+
+The default implementation offers already valid *token_keys* for JWT tokens, that are generated by the [`JwtGenerator`](/spring-xsuaa-test/src/main/java/com/sap/cloud/security/xsuaa/test/JwtGenerator.java) (`spring-xsuaa-test` library).
+
+## Requirements
+- Java 8
+- maven 3.3.9 or later
+- Spring Boot 2.1 and later
+
+## Configuration
+
+### Maven Dependency
+```xml
+
+ com.sap.cloud.security.xsuaa
+ spring-xsuaa-mock
+ 2.13.7
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
+```
+
+### Setup Mock Web Server
+Add the following class, which makes sure, that the Xsuaa mock web server is only started in case a dedicated profile e.g. `uaamock` is active. Make sure that this profile (`uaamock`) is never active in production!
+
+```java
+import com.sap.cloud.security.xsuaa.mock.XsuaaMockWebServer;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.env.EnvironmentPostProcessor;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.Profiles;
+
+public class XsuaaMockPostProcessor implements EnvironmentPostProcessor {
+
+ private static final XsuaaMockWebServer mockAuthorizationServer = new XsuaaMockWebServer();
+
+ @Override
+ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
+ if (environment.acceptsProfiles(Profiles.of("uaamock"))) {
+ environment.getPropertySources().addFirst(mockAuthorizationServer);
+ }
+ }
+}
+```
+
+Then you have to register this class to `META-INF/spring.factories`:
+
+```
+org.springframework.boot.env.EnvironmentPostProcessor=<>.XsuaaMockPostProcessor
+```
+
+### XSUAA Service Configuration
+
+From version `1.5.0` on the [`MockXsuaaServiceConfiguration`](src/main/java/com/sap/cloud/security/xsuaa/mock/MockXsuaaServiceConfiguration.java) is auto-configured [here](src/main/java/com/sap/cloud/security/xsuaa/mock/autoconfiguration/XsuaaMockAutoConfiguration.java). This class overwrites Xsuaa url and uaadomain to point to the Xsuaa Mock Web Server. This is relevant for validating the `jku` URI that is provided as part of the JSON Web Signature (JWS). The `jku` of the Jwt token issued by the `JwtGenerator` references the public key URI of the `XsuaaMockWebServer` used for generating the signature.
+
+### Extendability
+Note: it is possible to extend the dispatcher and pass this to the `XsuaaMockWebServer` constructor. An example `XsuaaMockPostProcessor` implementation can be found [here](src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockPostProcessor.java).
+
+### Multitenancy
+From version `1.3.0` and higher you can configure the `JwtGenerator` with a dedicated **subdomain** of a subaccount, e.g. `testdomain` and the header with a **keyId**:
+```java
+String yourSubdomain = "testdomain";
+String yourClientId = "sb-xsapp!20";
+String jwtTokenHeaderKeyId = "legacy-token-key-" + yourSubdomain;
+
+String jwtToken = new JwtGenerator(yourClientId, yourSubdomain).setJwtHeaderKeyId(jwtTokenHeaderKeyId).getToken().getTokenValue();
+```
+
+Then your Mock Web Server is called for example with `http://localhost:33195/testdomain/token_keys` and can be configured in such a way, that it provides different token keys for different domains. The domain `testdomain` is already handled by the default [`XsuaaRequestDispatcher`](src/main/java/com/sap/cloud/security/xsuaa/mock/XsuaaRequestDispatcher.java) implementation.
+
+## Samples
+- [cloud-application-security-sample](https://github.com/SAP-samples/cloud-application-security-sample)
diff --git a/spring-xsuaa-mock/pom.xml b/spring-xsuaa-mock/pom.xml
new file mode 100644
index 0000000000..f33456a72f
--- /dev/null
+++ b/spring-xsuaa-mock/pom.xml
@@ -0,0 +1,118 @@
+
+
+
+
+ 4.0.0
+
+
+ com.sap.cloud.security.xsuaa
+ parent
+ 2.13.7
+
+
+ spring-xsuaa-mock
+ spring-xsuaa-mock
+ DEPRECATED in favor of com.sap.cloud.security:java-security-test
+ jar
+
+ 4.9.3
+
+
+
+
+ com.sap.cloud.security.xsuaa
+ spring-xsuaa
+
+
+ org.springframework.security
+ spring-security-oauth2-resource-server
+ provided
+
+
+ org.springframework.security
+ spring-security-oauth2-jose
+ provided
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+ provided
+
+
+ com.squareup.okhttp3
+ mockwebserver
+ ${mockwebserver.version}
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+
+
+
+
+ commons-io
+ commons-io
+ compile
+
+
+ org.hamcrest
+ hamcrest-all
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ ${maven.source.plugin.version}
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-pmd-plugin
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+
+
+
+
+
diff --git a/spring-xsuaa-starter/pom.xml b/spring-xsuaa-starter/pom.xml
index 6778272ac6..275de41653 100644
--- a/spring-xsuaa-starter/pom.xml
+++ b/spring-xsuaa-starter/pom.xml
@@ -16,7 +16,7 @@
com.sap.cloud.security.xsuaa
parent
- 3.3.2
+ 3.3.4
xsuaa-spring-boot-starter
@@ -31,20 +31,6 @@
-
-
- ch.qos.logback
- logback-core
- 1.4.14
- provided
-
-
-
- ch.qos.logback
- logback-classic
- 1.4.14
- provided
-
org.springframework.boot
spring-boot-starter
diff --git a/spring-xsuaa-test/README.md b/spring-xsuaa-test/README.md
index f27734040b..e3f99ec469 100644
--- a/spring-xsuaa-test/README.md
+++ b/spring-xsuaa-test/README.md
@@ -31,7 +31,7 @@ This includes for example a `JwtGenerator` that generates JSON Web Tokens (JWT)
com.sap.cloud.security.xsuaa
spring-xsuaa-test
- 3.3.2
+ 3.3.4
test
diff --git a/spring-xsuaa-test/pom.xml b/spring-xsuaa-test/pom.xml
index 70b6ed041d..1e68e1489e 100644
--- a/spring-xsuaa-test/pom.xml
+++ b/spring-xsuaa-test/pom.xml
@@ -9,7 +9,7 @@
com.sap.cloud.security.xsuaa
parent
- 3.3.2
+ 3.3.4
spring-xsuaa-test
diff --git a/spring-xsuaa/Migration_JavaContainerSecurityProjects.md b/spring-xsuaa/Migration_JavaContainerSecurityProjects.md
index d530fc4535..c033b4086c 100644
--- a/spring-xsuaa/Migration_JavaContainerSecurityProjects.md
+++ b/spring-xsuaa/Migration_JavaContainerSecurityProjects.md
@@ -117,7 +117,8 @@ In case of multiple bindings you need to adapt your **Spring Security Configurat
```java
@PropertySource(factory = XsuaaServicePropertySourceFactory.class, value = {""})
```
-2. Instead, provide your own implementation of `XsuaaSecurityConfiguration` interface to access the **primary Xsuaa service configuration** of your application (chose the service instance of plan `application` here), which are exposed in the `VCAP_SERVICES` system environment variable (in Cloud Foundry). As of version `2.6.2` you can implement it like that:
+2. Instead, provide your own implementation of `XsuaaSecurityConfiguration` interface to access the **primary Xsuaa service configuration** of your application (chose the service instance of plan `application` here), which are exposed in the `VCAP_SERVICES` system environment variable (in Cloud Foundry).
+Starting with version `2.6.2` you can implement it like that:
```java
import com.sap.cloud.security.xsuaa.XsuaaCredentials;
@@ -137,7 +138,7 @@ In case of multiple bindings you need to adapt your **Spring Security Configurat
}
```
-3. You need to overwrite `JwtDecoder` bean so that the `AudienceValidator` checks the JWT audience not only against the client id of the primary Xsuaa service instance, but also of the binding of plan `broker`. As of version `2.6.2` you can implement it like that:
+3. You need to overwrite `JwtDecoder` bean so that the `AudienceValidator` checks the JWT audience not only against the client id of the primary Xsuaa service instance, but also of the binding of plan `broker`. Starting with version `2.6.2` you can implement it like that:
```java
@Bean
@ConfigurationProperties("vcap.services.<>.credentials")
diff --git a/spring-xsuaa/README.md b/spring-xsuaa/README.md
index a55f25a7f3..c48dfc6496 100644
--- a/spring-xsuaa/README.md
+++ b/spring-xsuaa/README.md
@@ -39,7 +39,7 @@ These (spring) dependencies need to be provided:
com.sap.cloud.security.xsuaa
spring-xsuaa
- 3.3.2
+ 3.3.4
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.3.2
+ 3.3.4
```
diff --git a/spring-xsuaa/pom.xml b/spring-xsuaa/pom.xml
index c8b377b13f..5d06323750 100644
--- a/spring-xsuaa/pom.xml
+++ b/spring-xsuaa/pom.xml
@@ -9,7 +9,7 @@
com.sap.cloud.security.xsuaa
parent
- 3.3.2
+ 3.3.4
spring-xsuaa
@@ -164,7 +164,7 @@
uk.org.webcompere
system-stubs-jupiter
- 2.1.5
+ 2.1.6
test
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/IasToken.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/IasToken.java
index c8bf030c9e..0429b29744 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/IasToken.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/IasToken.java
@@ -102,6 +102,7 @@ public String getZoneId() {
@Override
public String getAppTid() {
- return decodedToken.hasClaim(SAP_GLOBAL_APP_TID) ? decodedToken.getClaimAsString(SAP_GLOBAL_APP_TID) : decodedToken.getClaimAsString(SAP_GLOBAL_ZONE_ID);
+ return decodedToken.hasClaim(SAP_GLOBAL_APP_TID) ? decodedToken.getClaimAsString(SAP_GLOBAL_APP_TID)
+ : decodedToken.getClaimAsString(SAP_GLOBAL_ZONE_ID);
}
}
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContext.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContext.java
index ca0187c790..d60f700665 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContext.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContext.java
@@ -41,7 +41,8 @@ public static Token getToken() {
return (Token) principal;
}
throw new AccessDeniedException(
- "Access forbidden: SecurityContextHolder does not contain a principal of type 'Token'. Found instead a principal of type " + principal.getClass());
+ "Access forbidden: SecurityContextHolder does not contain a principal of type 'Token'. Found instead a principal of type "
+ + principal.getClass());
}
/**
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java
index df79eb550d..7854f41049 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java
@@ -146,9 +146,9 @@ private static String getZid(JWT jwt) {
TokenClaims.CLAIM_ZONE_ID);
} catch (ParseException e) {
- zid =null;
+ zid = null;
}
- if (zid != null && zid.isBlank()){
+ if (zid != null && zid.isBlank()) {
zid = null;
}
return zid;
@@ -194,8 +194,9 @@ private void canVerifyWithKey(String kid, String uaadomain) {
private String composeJku(String uaaDomain, String zid) {
String zidQueryParam = zid != null ? "?zid=" + zid : "";
- // uaaDomain in configuration is always without a schema, but for testing purpose http schema can be used
- if (uaaDomain.startsWith("http://")){
+ // uaaDomain in configuration is always without a schema, but for testing
+ // purpose http schema can be used
+ if (uaaDomain.startsWith("http://")) {
return uaaDomain + "/token_keys" + zidQueryParam;
}
return "https://" + uaaDomain + "/token_keys" + zidQueryParam;
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java
index 6e546e40ad..65e19e542a 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java
@@ -9,20 +9,20 @@
public class XsuaaLocalhostJkuFactory implements XsuaaJkuFactory {
- @Override
- public String create(String token) {
- String tokenJku;
- try {
- JWT jwt = JWTParser.parse(token);
- tokenJku = (String) jwt.getHeader().toJSONObject().get(TokenHeader.JWKS_URL);
- } catch (ParseException e) {
- throw new RuntimeException(e);
- }
+ @Override
+ public String create(String token) {
+ String tokenJku;
+ try {
+ JWT jwt = JWTParser.parse(token);
+ tokenJku = (String) jwt.getHeader().toJSONObject().get(TokenHeader.JWKS_URL);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
- if (tokenJku == null || tokenJku.contains("localhost") || tokenJku.contains("127.0.0.1")) {
- return tokenJku;
- }
+ if (tokenJku == null || tokenJku.contains("localhost") || tokenJku.contains("127.0.0.1")) {
+ return tokenJku;
+ }
- throw new IllegalArgumentException("JKU is not trusted because it does not target localhost.");
- }
+ throw new IllegalArgumentException("JKU is not trusted because it does not target localhost.");
+ }
}
\ No newline at end of file
diff --git a/token-client/README.md b/token-client/README.md
index acbfdcc00e..a8dd6e6425 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.3.2
+ 3.3.4
```
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.3.2
+ 3.3.4
org.apache.httpcomponents
@@ -124,7 +124,7 @@ See the [OAuth2ServiceConfiguration](#oauth2serviceconfiguration) section and [H
com.sap.cloud.security.xsuaa
token-client
- 3.3.2
+ 3.3.4
org.apache.httpcomponents
diff --git a/token-client/pom.xml b/token-client/pom.xml
index 466c64daa4..d24caf93ea 100644
--- a/token-client/pom.xml
+++ b/token-client/pom.xml
@@ -9,7 +9,7 @@
com.sap.cloud.security.xsuaa
parent
- 3.3.2
+ 3.3.4
token-client
@@ -111,12 +111,6 @@
1.4.14
test
-
- io.github.hakky54
- logcaptor
- 2.9.2
- test
-
org.wiremock
wiremock-standalone
diff --git a/token-client/src/main/java/com/sap/cloud/security/client/DefaultHttpClientFactory.java b/token-client/src/main/java/com/sap/cloud/security/client/DefaultHttpClientFactory.java
index 980d1e4cbe..7337928b9b 100644
--- a/token-client/src/main/java/com/sap/cloud/security/client/DefaultHttpClientFactory.java
+++ b/token-client/src/main/java/com/sap/cloud/security/client/DefaultHttpClientFactory.java
@@ -16,15 +16,10 @@
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.GeneralSecurityException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -41,7 +36,6 @@
* implementation of {@link HttpClientFactory}.
*/
public class DefaultHttpClientFactory implements HttpClientFactory {
- private static final Logger LOGGER = LoggerFactory.getLogger(DefaultHttpClientFactory.class);
private static final int DEFAULT_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(5);
private static final int DEFAULT_SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(30);
@@ -49,8 +43,6 @@ public class DefaultHttpClientFactory implements HttpClientFactory {
private static final int MAX_CONNECTIONS = 200;
private final ConcurrentHashMap sslConnectionPool = new ConcurrentHashMap<>();
private final org.apache.http.client.config.RequestConfig requestConfig;
- // reuse ssl connections
- final Set httpClientsCreated = Collections.synchronizedSet(new HashSet<>());
public DefaultHttpClientFactory() {
requestConfig = org.apache.http.client.config.RequestConfig.custom()
@@ -64,15 +56,11 @@ public DefaultHttpClientFactory() {
@Override
public CloseableHttpClient createClient(ClientIdentity clientIdentity) throws HttpClientException {
String clientId = clientIdentity != null ? clientIdentity.getId() : null;
- if (httpClientsCreated.contains(clientId)) {
- LOGGER.warn("Application has already created HttpClient for clientId = {}, please check.", clientId);
- }
- httpClientsCreated.add(clientId);
HttpClientBuilder httpClientBuilder = HttpClients.custom().setDefaultRequestConfig(requestConfig);
if (clientId != null && clientIdentity.isCertificateBased()) {
- SslConnection connectionPool = sslConnectionPool.computeIfAbsent(clientId,
- s -> new SslConnection(clientIdentity));
+ SslConnection connectionPool = sslConnectionPool.compute(clientId,
+ (s, c) -> new SslConnection(clientIdentity));
return httpClientBuilder
.setConnectionManager(connectionPool.poolingConnectionManager)
.setSSLContext(connectionPool.context)
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOAuth2TokenKeyService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOAuth2TokenKeyService.java
index a658752782..8389adc94c 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOAuth2TokenKeyService.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultOAuth2TokenKeyService.java
@@ -41,11 +41,12 @@ public DefaultOAuth2TokenKeyService(@Nonnull CloseableHttpClient httpClient) {
}
@Override
- public String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, Map params) throws OAuth2ServiceException {
+ public String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, Map params)
+ throws OAuth2ServiceException {
Assertions.assertNotNull(tokenKeysEndpointUri, "Token key endpoint must not be null!");
HttpUriRequest request = new HttpGet(tokenKeysEndpointUri);
- for(Map.Entry p : params.entrySet()) {
+ for (Map.Entry p : params.entrySet()) {
request.addHeader(p.getKey(), p.getValue());
}
request.addHeader(HttpHeaders.USER_AGENT, HttpClientUtil.getUserAgent());
@@ -58,10 +59,12 @@ public String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, Map headers) {
@@ -70,6 +70,7 @@ public Integer getHttpStatusCode() {
/**
* Returns the HTTP headers of the failed OAuth2 service request
+ *
* @return list of HTTP headers
*/
public List getHeaders() {
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenKeyService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenKeyService.java
index 8f3e100516..43d45bbdaf 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenKeyService.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenKeyService.java
@@ -26,37 +26,37 @@ public interface OAuth2TokenKeyService {
* @param tokenKeysEndpointUri
* the token endpoint URI (jku).
* @param tenantId
- * the unique identifier of the tenant. Obligatory parameter in context of
- * multi-tenant IAS applications to make sure that the tenant id
- * belongs to the IAS tenant.
- * @return list of JSON Web Token (JWT) keys as
- * JSON string.
+ * the unique identifier of the tenant. Obligatory parameter in
+ * context of multi-tenant IAS applications to make sure that the
+ * tenant id belongs to the IAS tenant.
+ * @return list of JSON Web Token (JWT) keys as JSON string.
* @throws OAuth2ServiceException
* in case of an error during the http request.
*/
- default String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, @Nullable String tenantId) throws OAuth2ServiceException {
+ default String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, @Nullable String tenantId)
+ throws OAuth2ServiceException {
return retrieveTokenKeys(tokenKeysEndpointUri, Collections.singletonMap(HttpHeaders.X_APP_TID, tenantId));
}
/**
- * @deprecated Use {@link OAuth2TokenKeyService#retrieveTokenKeys(URI, Map)} instead
- * Requests token web key set from IAS OAuth Server.
+ * @deprecated Use {@link OAuth2TokenKeyService#retrieveTokenKeys(URI, Map)}
+ * instead Requests token web key set from IAS OAuth Server.
*
* @param tokenKeysEndpointUri
* the token endpoint URI (jku).
* @param tenantId
- * the unique identifier of the tenant. Obligatory parameter in context of
- * multi-tenant IAS applications to make sure that the tenant id
- * belongs to the IAS tenant.
+ * the unique identifier of the tenant. Obligatory parameter in
+ * context of multi-tenant IAS applications to make sure that the
+ * tenant id belongs to the IAS tenant.
* @param clientId
- * clientId from the service binding
- * @return list of JSON Web Token (JWT) keys as
- * JSON string.
+ * clientId from the service binding
+ * @return list of JSON Web Token (JWT) keys as JSON string.
* @throws OAuth2ServiceException
* in case of an error during the http request.
*/
@Deprecated
- default String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, @Nullable String tenantId, @Nullable String clientId) throws OAuth2ServiceException {
+ default String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, @Nullable String tenantId,
+ @Nullable String clientId) throws OAuth2ServiceException {
Map params = new HashMap<>(2, 1);
params.put(HttpHeaders.X_APP_TID, tenantId);
params.put(HttpHeaders.X_CLIENT_ID, clientId);
@@ -67,10 +67,15 @@ default String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, @Nullable St
/**
* Retrieves the JWKS (JSON Web Key Set) from the OAuth2 Server.
*
- * @param tokenKeysEndpointUri the JWKS endpoint URI.
- * @param params additional header parameters that are sent along with the request. Use constants from {@link HttpHeaders} for the header keys.
+ * @param tokenKeysEndpointUri
+ * the JWKS endpoint URI.
+ * @param params
+ * additional header parameters that are sent along with the request.
+ * Use constants from {@link HttpHeaders} for the header keys.
* @return a JWKS in JSON format.
- * @throws OAuth2ServiceException in case of an error during the http request.
+ * @throws OAuth2ServiceException
+ * in case of an error during the http request.
*/
- String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, Map params) throws OAuth2ServiceException;
+ String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, Map params)
+ throws OAuth2ServiceException;
}
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java
index b7cea77371..013fbdef80 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java
@@ -13,9 +13,12 @@
import java.util.Map;
/**
- * Retrieves OAuth2 Access Tokens as documented on
- * Cloud Foundry UAA.
- * Note that the XSUAA API might differ slightly from these specs which is why not all parameters from the Cloud Foundry UAA documentation are configurable via this library.
+ * Retrieves OAuth2 Access Tokens as documented on Cloud
+ * Foundry UAA.
+ * Note that the XSUAA API might differ slightly from these specs which is why
+ * not all parameters from the Cloud Foundry UAA documentation are configurable
+ * via this library.
*/
public interface OAuth2TokenService {
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/SpringOAuth2TokenKeyService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/SpringOAuth2TokenKeyService.java
index bd08cba1ad..2bff1b6151 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/SpringOAuth2TokenKeyService.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/SpringOAuth2TokenKeyService.java
@@ -40,7 +40,7 @@ public String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, Map p : params.entrySet()) {
+ for (Map.Entry p : params.entrySet()) {
headers.set(p.getKey(), p.getValue());
}
@@ -52,12 +52,12 @@ public String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, Map h.getKey() + ": " + String.join(",", h.getValue()))
- .collect(Collectors.joining(", ")) + "]")
+ "Error retrieving token keys. Request headers [" + headers.entrySet().stream()
+ .map(h -> h.getKey() + ": " + String.join(",", h.getValue()))
+ .collect(Collectors.joining(", ")) + "]")
.withUri(tokenKeysEndpointUri)
.withHeaders(response.getHeaders().size() != 0 ? response.getHeaders().entrySet().stream().map(
- h -> h.getKey() + ": " + String.join(",", h.getValue()))
+ h -> h.getKey() + ": " + String.join(",", h.getValue()))
.toArray(String[]::new) : null)
.withStatusCode(response.getStatusCode().value())
.withResponseBody(response.getBody())
@@ -65,11 +65,11 @@ public String retrieveTokenKeys(@Nonnull URI tokenKeysEndpointUri, Map h.getKey() + ": " + String.join(",", h.getValue())))
.withUri(tokenKeysEndpointUri)
.withHeaders(ex.getResponseHeaders() != null ? ex.getResponseHeaders().entrySet().stream().map(
- h -> h.getKey() + ": " + String.join(",", h.getValue()))
+ h -> h.getKey() + ": " + String.join(",", h.getValue()))
.toArray(String[]::new) : null)
.withStatusCode(ex.getStatusCode().value())
.withResponseBody(ex.getResponseBodyAsString())
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java
index dbee575890..7079ea0f90 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java
@@ -72,12 +72,14 @@ protected OAuth2TokenResponse requestAccessToken(URI tokenEndpointUri, HttpHeade
String warningMsg = String.format(
"Error retrieving JWT token. Received status code %s. Call to XSUAA was not successful: %s",
ex.getStatusCode(), ex.getResponseBodyAsString());
- throw new OAuth2ServiceException(warningMsg, ex.getStatusCode().value(), getHeaders(ex.getResponseHeaders()));
+ throw new OAuth2ServiceException(warningMsg, ex.getStatusCode().value(),
+ getHeaders(ex.getResponseHeaders()));
} catch (HttpServerErrorException ex) {
String warningMsg = String.format("Server error while obtaining access token from XSUAA (%s): %s",
ex.getStatusCode(), ex.getResponseBodyAsString());
LOGGER.error(warningMsg, ex);
- throw new OAuth2ServiceException(warningMsg, ex.getStatusCode().value(), getHeaders(ex.getResponseHeaders()));
+ throw new OAuth2ServiceException(warningMsg, ex.getStatusCode().value(),
+ getHeaders(ex.getResponseHeaders()));
} catch (ResourceAccessException ex) {
String warningMsg = String.format(
"RestClient isn't configured properly - Error while obtaining access token from XSUAA (%s): %s",
@@ -98,7 +100,7 @@ protected OAuth2TokenResponse requestAccessToken(URI tokenEndpointUri, HttpHeade
}
private static List getHeaders(org.springframework.http.HttpHeaders ex) {
- if (ex != null){
+ if (ex != null) {
return ex.toSingleValueMap().entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).toList();
}
return Collections.emptyList();
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/http/HttpHeaders.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/http/HttpHeaders.java
index da5b70c93a..2bb01e6455 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/http/HttpHeaders.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/http/HttpHeaders.java
@@ -20,15 +20,14 @@ public class HttpHeaders {
/**
* @deprecated use {@link #X_APP_TID} instead
*
- * will be removed with next major release 4.0.0
+ * will be removed with next major release 4.0.0
*/
- @Deprecated(forRemoval = true )
+ @Deprecated(forRemoval = true)
public static final String X_ZONE_UUID = "x-zone_uuid";
public static final String X_APP_TID = "x-app_tid";
public static final String X_CLIENT_ID = "x-client_id";
public static final String X_AZP = "x-azp";
-
private final Set headers;
public HttpHeaders(HttpHeader... headers) {
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/JwtBearerTokenFlow.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/JwtBearerTokenFlow.java
index ce63075e93..2760f3d689 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/JwtBearerTokenFlow.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/JwtBearerTokenFlow.java
@@ -8,10 +8,7 @@
import java.util.*;
import static com.sap.cloud.security.xsuaa.Assertions.assertNotNull;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.AUTHORITIES;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.SCOPE;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.TOKEN_FORMAT;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.TOKEN_TYPE_OPAQUE;
+import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.*;
import static com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlowsUtils.buildAdditionalAuthoritiesJson;
/**
@@ -145,7 +142,8 @@ public JwtBearerTokenFlow disableCache(boolean disableCache) {
/**
* Can be used to change the format of the returned token.
*
- * @param opaque enables opaque token format when set to {@code true}.
+ * @param opaque
+ * enables opaque token format when set to {@code true}.
* @return this builder.
*/
public JwtBearerTokenFlow setOpaqueTokenFormat(boolean opaque) {
diff --git a/token-client/src/test/java/com/sap/cloud/security/client/DefaultHttpClientFactoryTest.java b/token-client/src/test/java/com/sap/cloud/security/client/DefaultHttpClientFactoryTest.java
index 14a8e19bcc..0ea0741b73 100644
--- a/token-client/src/test/java/com/sap/cloud/security/client/DefaultHttpClientFactoryTest.java
+++ b/token-client/src/test/java/com/sap/cloud/security/client/DefaultHttpClientFactoryTest.java
@@ -8,15 +8,12 @@
import com.github.tomakehurst.wiremock.WireMockServer;
import com.sap.cloud.security.config.ClientCredentials;
import com.sap.cloud.security.config.ClientIdentity;
-import nl.altindag.log.LogCaptor;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
-import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -25,9 +22,7 @@
import java.nio.charset.StandardCharsets;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
-import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.mockito.Mockito.when;
class DefaultHttpClientFactoryTest {
@@ -37,7 +32,6 @@ class DefaultHttpClientFactoryTest {
private static final ClientIdentity config = Mockito.mock(ClientIdentity.class);
private static final ClientIdentity config2 = Mockito.mock(ClientIdentity.class);
private final DefaultHttpClientFactory cut = new DefaultHttpClientFactory();
- private static LogCaptor logCaptor;
@BeforeAll
static void setup() throws IOException {
@@ -50,47 +44,6 @@ static void setup() throws IOException {
when(config2.getKey()).thenReturn(readFromFile("/privateRSAKey.txt"));
when(config2.getCertificate()).thenReturn(readFromFile("/certificates.txt"));
when(config2.isCertificateBased()).thenCallRealMethod();
-
- logCaptor = LogCaptor.forClass(DefaultHttpClientFactory.class);
- }
-
- @AfterEach
- void tearDown() {
- logCaptor.clearLogs();
- }
-
- @Test
- void createHttpClient_sameClientId() {
- HttpClient client1 = cut.createClient(config);
- HttpClient client2 = cut.createClient(config);
-
- assertNotSame(client1, client2);
-
- assertEquals(1, cut.httpClientsCreated.size());
- }
-
- @Test
- void createHttpClient_differentClientId() {
- HttpClient client1 = cut.createClient(config);
- HttpClient client2 = cut.createClient(config2);
-
- assertNotSame(client1, client2);
-
- assertEquals(2, cut.httpClientsCreated.size());
- }
-
- @Test
- void assertWarnWhenCalledMoreThanOnce() {
- cut.createClient(config);
- cut.createClient(config2);
- assertThat(logCaptor.getWarnLogs()).isEmpty();
-
- cut.createClient(config);
- assertThat(logCaptor.getWarnLogs()).hasSize(1);
- assertThat(logCaptor.getWarnLogs().get(0))
- .startsWith("Application has already created HttpClient for clientId = theClientId, please check.");
-
- logCaptor.clearLogs();
}
private static String readFromFile(String file) throws IOException {
diff --git a/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/OAuth2ServiceExceptionTest.java b/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/OAuth2ServiceExceptionTest.java
index 5530d6193b..a4ff00cd8e 100644
--- a/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/OAuth2ServiceExceptionTest.java
+++ b/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/OAuth2ServiceExceptionTest.java
@@ -8,28 +8,29 @@
import static org.junit.jupiter.api.Assertions.*;
class OAuth2ServiceExceptionTest {
- public static final String SERVICE_EXCEPTION = "Service Exception";
- private static List headers;
- private static OAuth2ServiceException builtWithHeaders;
- private static OAuth2ServiceException createdWithHeaders;
+ public static final String SERVICE_EXCEPTION = "Service Exception";
+ private static List headers;
+ private static OAuth2ServiceException builtWithHeaders;
+ private static OAuth2ServiceException createdWithHeaders;
- @BeforeAll
- static void setup() {
- headers = List.of("header1=value1", "header2=value2");
- builtWithHeaders = OAuth2ServiceException.builder(SERVICE_EXCEPTION).withHeaders(headers.toArray(String[]::new)).withStatusCode(400).build();
- createdWithHeaders = new OAuth2ServiceException(SERVICE_EXCEPTION, 400, headers);
- }
+ @BeforeAll
+ static void setup() {
+ headers = List.of("header1=value1", "header2=value2");
+ builtWithHeaders = OAuth2ServiceException.builder(SERVICE_EXCEPTION).withHeaders(headers.toArray(String[]::new))
+ .withStatusCode(400).build();
+ createdWithHeaders = new OAuth2ServiceException(SERVICE_EXCEPTION, 400, headers);
+ }
- @Test
- void testWithHeaders() {
- assertIterableEquals(headers, builtWithHeaders.getHeaders());
- assertTrue(builtWithHeaders.getMessage().contains(SERVICE_EXCEPTION));
- assertTrue(builtWithHeaders.getMessage().contains("[header1=value1, header2=value2]"));
- assertEquals(400, builtWithHeaders.getHttpStatusCode());
+ @Test
+ void testWithHeaders() {
+ assertIterableEquals(headers, builtWithHeaders.getHeaders());
+ assertTrue(builtWithHeaders.getMessage().contains(SERVICE_EXCEPTION));
+ assertTrue(builtWithHeaders.getMessage().contains("[header1=value1, header2=value2]"));
+ assertEquals(400, builtWithHeaders.getHttpStatusCode());
- assertIterableEquals(headers, createdWithHeaders.getHeaders());
- assertTrue(createdWithHeaders.getMessage().contains(SERVICE_EXCEPTION));
- assertFalse(createdWithHeaders.getMessage().contains("[header1=value1, header2=value2]"));
- assertEquals(400, createdWithHeaders.getHttpStatusCode());
- }
+ assertIterableEquals(headers, createdWithHeaders.getHeaders());
+ assertTrue(createdWithHeaders.getMessage().contains(SERVICE_EXCEPTION));
+ assertFalse(createdWithHeaders.getMessage().contains("[header1=value1, header2=value2]"));
+ assertEquals(400, createdWithHeaders.getHttpStatusCode());
+ }
}
\ No newline at end of file
diff --git a/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/SpringOAuth2TokenKeyServiceTest.java b/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/SpringOAuth2TokenKeyServiceTest.java
index 987b34c24b..c69ef0e1be 100644
--- a/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/SpringOAuth2TokenKeyServiceTest.java
+++ b/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/SpringOAuth2TokenKeyServiceTest.java
@@ -120,6 +120,7 @@ private ArgumentMatcher httpEntityContainsMandatoryHeaders() {
boolean correctAppTid = httpGet.getHeaders().get(HttpHeaders.X_APP_TID).get(0).equals(APP_TID);
boolean correctAzp = httpGet.getHeaders().get(HttpHeaders.X_AZP).get(0).equals(AZP);
return correctAppTid && correctClientId && correctAzp;
- }; }
+ };
+ }
}
\ No newline at end of file
diff --git a/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/JwtBearerTokenFlowTest.java b/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/JwtBearerTokenFlowTest.java
index d68cc12e2d..f5226bc2b5 100644
--- a/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/JwtBearerTokenFlowTest.java
+++ b/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/JwtBearerTokenFlowTest.java
@@ -138,7 +138,6 @@ public void execute_withOpaqueTokenFormat() throws TokenFlowException, OAuth2Ser
optionalParametersCaptor.capture(), anyBoolean());
assertThat(optionalParametersCaptor.getValue()).doesNotContainEntry(TOKEN_FORMAT, OPAQUE);
-
cut.setOpaqueTokenFormat(true).execute();
verify(tokenService, times(2))
.retrieveAccessTokenViaJwtBearerTokenGrant(any(), any(), any(), any(),