From 3caffa98cc93b2ab2af83d80e6d69f8246830877 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Jul 2022 16:58:30 +0000 Subject: [PATCH 1/5] Bump commons-configuration2 from 2.7 to 2.8.0 Bumps commons-configuration2 from 2.7 to 2.8.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-configuration2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0d21e40..9c65cb3 100644 --- a/pom.xml +++ b/pom.xml @@ -41,7 +41,7 @@ 3.12.0 1.9.4 1.9.3 - 2.7 + 2.8.0 2.8.0 4.9.1 2.9.0 From 380eddbcaba4f1de9592c9db0efe1dc0cd110324 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Wed, 19 Oct 2022 12:58:12 +0200 Subject: [PATCH 2/5] SPHEREON-1096: added client credentials in body support --- authentication-lib-main/pom.xml | 2 +- .../api/TokenRequestBuilder.java | 1 - .../api/config/ClientCredentialsMode.java | 43 ++++++++++++ .../objects/GenerateTokenRequestBuilder.java | 53 ++++++++++----- .../impl/objects/HttpRequestHandler.java | 2 +- .../impl/objects/RequestParameterKey.java | 3 + .../impl/objects/TokenRequestImpl.java | 61 ++++++++--------- .../granttypes/ClientCredentialBuilder.java | 37 +++++++++- .../ClientCredentialsGrantImpl.java | 67 ++++++++++++++++++- .../libs/authentication/CredentialsTest.java | 25 +++++++ authentication-lib-osgi/pom.xml | 2 +- pom.xml | 6 +- spring-boot-test/pom.xml | 2 +- 13 files changed, 244 insertions(+), 60 deletions(-) create mode 100644 authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/config/ClientCredentialsMode.java diff --git a/authentication-lib-main/pom.xml b/authentication-lib-main/pom.xml index 2c158f1..0ed0c11 100644 --- a/authentication-lib-main/pom.xml +++ b/authentication-lib-main/pom.xml @@ -21,7 +21,7 @@ com.sphereon.public authentication-lib-modules - 0.1.8-SNAPSHOT + 0.2.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/TokenRequestBuilder.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/TokenRequestBuilder.java index 418ccc7..49f24ea 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/TokenRequestBuilder.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/TokenRequestBuilder.java @@ -24,7 +24,6 @@ public interface TokenRequestBuilder { TokenRequest build(); - final class Builder { private final ApiConfiguration configuration; diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/config/ClientCredentialsMode.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/config/ClientCredentialsMode.java new file mode 100644 index 0000000..87286f1 --- /dev/null +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/config/ClientCredentialsMode.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Sphereon BV https://sphereon.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.sphereon.libs.authentication.api.config; + +import com.sphereon.commons.exceptions.EnumParseException; +import org.apache.commons.lang3.StringUtils; + +public enum ClientCredentialsMode { + BASIC_HEADER, BODY; + + + public static ClientCredentialsMode fromString(String value) { + if (StringUtils.isNotEmpty(value)) { + for (ClientCredentialsMode persistenceMode : ClientCredentialsMode.values()) { + if (reformat(persistenceMode.name()).equals(reformat(value))) { + return persistenceMode; + } + } + } + throw new EnumParseException("Could not parse " + value + " as ClientCredentialsMode"); + } + + + private static String reformat(String value) { + return value.replace("_", "") + .replace("-", "") + .toLowerCase(); + } +} diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestBuilder.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestBuilder.java index f53a7d8..0c7936a 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestBuilder.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestBuilder.java @@ -19,6 +19,7 @@ import com.sphereon.libs.authentication.api.TokenRequest; import com.sphereon.libs.authentication.api.TokenRequestBuilder; import com.sphereon.libs.authentication.api.config.ApiConfiguration; +import com.sphereon.libs.authentication.api.config.ClientCredentialsMode; import com.sphereon.libs.authentication.api.granttypes.Grant; import com.sphereon.libs.authentication.impl.config.ConfigManager; import com.sphereon.libs.authentication.impl.config.ConfigManagerProvider; @@ -38,6 +39,7 @@ class Builder implements TokenRequestBuilder { private Grant grant; private String scope; private Long validityPeriodInSeconds; + private ClientCredentialsMode clientCredentialsMode; public Builder(ApiConfiguration configuration) { @@ -45,6 +47,11 @@ public Builder(ApiConfiguration configuration) { } + public GenerateTokenRequestBuilder.Builder withClientCredentialsMode(final ClientCredentialsMode clientCredentialsMode) { + this.clientCredentialsMode = clientCredentialsMode; + return this; + } + public GenerateTokenRequestBuilder.Builder withConsumerKey(String consumerKey) { this.consumerKey = consumerKey; return this; @@ -90,6 +97,7 @@ public TokenRequest build() { configPersistence.loadConfig(configManager); GenerateTokenRequestImpl tokenRequest = new GenerateTokenRequestImpl(configuration); tokenRequest.setGrant(grant); + tokenRequest.setClientCredentialsMode(clientCredentialsMode); tokenRequest.setConsumerKey(consumerKey); tokenRequest.setConsumerSecret(consumerSecret); tokenRequest.setScope(scope); @@ -99,28 +107,37 @@ public TokenRequest build() { private void validate() { - if (this.grant == null) { - this.grant = configuration.getDefaultGrant(); - } - if (this.grant == null) { - this.grant = new ClientCredentialBuilder.ClientCredentialGrantBuilder().build(); + if (clientCredentialsMode == null) { + this.clientCredentialsMode = ClientCredentialsMode.BASIC_HEADER; // Backwards compatibility } - if (StringUtils.isEmpty(consumerKey)) { - this.consumerKey = configuration.getConsumerKey(); - } - if (StringUtils.isEmpty(consumerKey)) { - throw new IllegalArgumentException(String.format( - "The consumer key variable was not found for application %s. Please check your configuration.", - configuration.getApplication())); + if(clientCredentialsMode == ClientCredentialsMode.BASIC_HEADER) { + if (StringUtils.isEmpty(consumerKey)) { + this.consumerKey = configuration.getConsumerKey(); + } + if (StringUtils.isEmpty(consumerKey)) { + throw new IllegalArgumentException(String.format( + "The consumer key variable was not found for application %s. Please check your configuration.", + configuration.getApplication())); + } + if (StringUtils.isEmpty(consumerSecret)) { + this.consumerSecret = configuration.getConsumerSecret(); + } + if (StringUtils.isEmpty(consumerSecret)) { + throw new IllegalArgumentException(String.format( + "The consumer secret variable was not found for application %s. Please check your configuration.", + configuration.getApplication())); + } } - if (StringUtils.isEmpty(consumerSecret)) { - this.consumerSecret = configuration.getConsumerSecret(); + if (this.grant == null) { + this.grant = configuration.getDefaultGrant(); } - if (StringUtils.isEmpty(consumerSecret)) { - throw new IllegalArgumentException(String.format( - "The consumer secret variable was not found for application %s. Please check your configuration.", - configuration.getApplication())); + if (this.grant == null) { + this.grant = new ClientCredentialBuilder.ClientCredentialGrantBuilder() + .withClientCredentialsMode(clientCredentialsMode) + .withConsumerKey(consumerKey) + .withConsumerSecret(consumerSecret) + .build(); } if (StringUtils.isEmpty(scope)) { this.scope = configuration.getDefaultScope(); diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java index 36cf1a2..ef441c2 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java @@ -84,10 +84,10 @@ public Headers buildHeaders(RequestParameters requestParameters) { requestParameters.headerParameters(parameterMap); Headers.Builder headerBuilder = new Headers.Builder(); + headerBuilder.add("Content-Type", "application/x-www-form-urlencoded"); for (Map.Entry entry : parameterMap.entrySet()) { Assert.notNull(entry.getValue(), "Header parameter " + entry.getKey() + " not set."); headerBuilder.add(entry.getKey().getValue(), entry.getValue()); - } return headerBuilder.build(); } diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/RequestParameterKey.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/RequestParameterKey.java index 8d8fc8b..e121072 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/RequestParameterKey.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/RequestParameterKey.java @@ -23,6 +23,9 @@ public enum RequestParameterKey implements StringValueEnum { GRANT_TYPE("grant_type"), USER_NAME("username"), PASSWORD("password"), + + CLIENT_ID("client_id"), + CLIENT_SECRET("client_secret"), REFRESH_TOKEN("refresh_token"), WINDOWS_TOKEN("windows_token"), KERBEROS_REALM("kerberos_realm"), diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/TokenRequestImpl.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/TokenRequestImpl.java index a895714..fb17ee3 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/TokenRequestImpl.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/TokenRequestImpl.java @@ -20,12 +20,15 @@ import com.sphereon.libs.authentication.api.TokenRequest; import com.sphereon.libs.authentication.api.TokenResponse; import com.sphereon.libs.authentication.api.config.ApiConfiguration; +import com.sphereon.libs.authentication.api.config.ClientCredentialsMode; import com.sphereon.libs.authentication.impl.RequestParameters; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Request; import okhttp3.Response; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasypt.contrib.org.apache.commons.codec_1_3.binary.Base64; @@ -50,6 +53,7 @@ abstract class TokenRequestImpl implements TokenRequest, RequestParameters { private transient String consumerSecret; protected String scope; + private ClientCredentialsMode clientCredentialsMode; public TokenRequestImpl(ApiConfiguration configuration) { @@ -67,6 +71,14 @@ public void setScope(String scope) { } + public ClientCredentialsMode getClientCredentialsMode() { + return clientCredentialsMode; + } + + public void setClientCredentialsMode(final ClientCredentialsMode clientCredentialsMode) { + this.clientCredentialsMode = clientCredentialsMode; + } + public String getConsumerKey() { return consumerKey; } @@ -101,12 +113,15 @@ public void removeTokenResponseListener(TokenResponseListener listener) { @Override public void headerParameters(Map parameterMap) { - try { - String clientParameters = String.format("%s:%s", getConsumerKey(), getConsumerSecret()); - String authorizationHeader = String.format("Basic %s", new String(base64Encoder.encode(clientParameters.getBytes("UTF-8")))); - parameterMap.put(RequestParameterKey.AUTHORIZATION, authorizationHeader); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); + // This must be available for all grant types as long as credentials mode is BASIC_HEADER + if (getClientCredentialsMode() == ClientCredentialsMode.BASIC_HEADER) { + try { + String clientParameters = String.format("%s:%s", getConsumerKey(), getConsumerSecret()); + String authorizationHeader = String.format("Basic %s", new String(base64Encoder.encode(clientParameters.getBytes("UTF-8")))); + parameterMap.put(RequestParameterKey.AUTHORIZATION, authorizationHeader); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } } } @@ -162,37 +177,19 @@ public void onResponse(Call call, Response response) throws IOException { }); } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof TokenRequestImpl)) { - return false; - } + public boolean equals(final Object o) { + if (this == o) return true; - TokenRequestImpl that = (TokenRequestImpl) o; + if (!(o instanceof TokenRequestImpl)) return false; - if (configuration != null ? !configuration.equals(that.configuration) : that.configuration != null) { - return false; - } - if (getConsumerKey() != null ? !getConsumerKey().equals(that.getConsumerKey()) : that.getConsumerKey() != null) { - return false; - } - if (getConsumerSecret() != null ? !getConsumerSecret().equals(that.getConsumerSecret()) : that.getConsumerSecret() != null) { - return false; - } - return getScope() != null ? getScope().equals(that.getScope()) : that.getScope() == null; - } + final TokenRequestImpl that = (TokenRequestImpl) o; + return new EqualsBuilder().append(tokenResponseListeners, that.tokenResponseListeners).append(configuration, that.configuration).append(consumerKey, that.consumerKey).append(consumerSecret, that.consumerSecret).append(scope, that.scope).append(clientCredentialsMode, that.clientCredentialsMode).isEquals(); + } @Override public int hashCode() { - int result = configuration != null ? configuration.hashCode() : 0; - result = 31 * result + (getConsumerKey() != null ? getConsumerKey().hashCode() : 0); - result = 31 * result + (getConsumerSecret() != null ? getConsumerSecret().hashCode() : 0); - result = 31 * result + (getScope() != null ? getScope().hashCode() : 0); - return result; + return new HashCodeBuilder(17, 37).append(tokenResponseListeners).append(configuration).append(consumerKey).append(consumerSecret).append(scope).append(clientCredentialsMode).toHashCode(); } -} \ No newline at end of file +} diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialBuilder.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialBuilder.java index 814a274..465c3a2 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialBuilder.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialBuilder.java @@ -16,13 +16,21 @@ package com.sphereon.libs.authentication.impl.objects.granttypes; +import com.sphereon.commons.assertions.Assert; import com.sphereon.libs.authentication.api.GrantBuilder; +import com.sphereon.libs.authentication.api.config.ClientCredentialsMode; import com.sphereon.libs.authentication.api.granttypes.ClientCredentialGrant; public interface ClientCredentialBuilder { final class ClientCredentialGrantBuilder implements GrantBuilder { + private ClientCredentialsMode clientCredentialsMode; + private String consumerKey; + + private String consumerSecret; + + public static ClientCredentialGrantBuilder newInstance() { return new ClientCredentialGrantBuilder(); } @@ -34,7 +42,34 @@ public ClientCredentialGrant build() { public ClientCredentialGrant build(boolean validate) { - return new ClientCredentialGrantImpl(); + if (validate) { + validate(); + } + + return new ClientCredentialGrantImpl(clientCredentialsMode, consumerKey, consumerSecret); + } + + private void validate() { + Assert.notNull(clientCredentialsMode, "clientCredentialsMode is not set in ClientCredentialGrantBuilder"); + if(clientCredentialsMode == ClientCredentialsMode.BODY) { + Assert.notNull(consumerKey, "consumerKey is not set in ClientCredentialGrantBuilder"); + Assert.notNull(consumerSecret, "consumerSecret is not set in ClientCredentialGrantBuilder"); + } + } + + public ClientCredentialGrantBuilder withClientCredentialsMode(final ClientCredentialsMode clientCredentialsMode) { + this.clientCredentialsMode = clientCredentialsMode; + return this; + } + + public ClientCredentialGrantBuilder withConsumerKey(String consumerKey) { + this.consumerKey = consumerKey; + return this; + } + + public ClientCredentialGrantBuilder withConsumerSecret(String consumerSecret) { + this.consumerSecret = consumerSecret; + return this; } } } diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialsGrantImpl.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialsGrantImpl.java index 65c414b..89ed174 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialsGrantImpl.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialsGrantImpl.java @@ -16,20 +16,35 @@ package com.sphereon.libs.authentication.impl.objects.granttypes; +import com.sphereon.libs.authentication.api.config.ClientCredentialsMode; import com.sphereon.libs.authentication.api.granttypes.ClientCredentialGrant; import com.sphereon.libs.authentication.api.granttypes.GrantType; import com.sphereon.libs.authentication.impl.RequestParameters; import com.sphereon.libs.authentication.impl.config.ConfigManager; import com.sphereon.libs.authentication.impl.config.ConfigPersistence; import com.sphereon.libs.authentication.impl.objects.RequestParameterKey; +import org.apache.commons.lang3.StringUtils; import java.util.Map; +import java.util.Objects; class ClientCredentialGrantImpl implements ClientCredentialGrant, RequestParameters, ConfigPersistence { + private ClientCredentialsMode clientCredentialsMode; + private String clientId; + + private String clientSecret; + + ClientCredentialGrantImpl() { } + public ClientCredentialGrantImpl(final ClientCredentialsMode clientCredentialsMode, final String clientId, final String clientSecret) { + setClientCredentialsMode(clientCredentialsMode); + setClientId(clientId); + setClientSecret(clientSecret); + } + @Override public void headerParameters(Map parameterMap) { @@ -38,7 +53,16 @@ public void headerParameters(Map parameterMap) { @Override public void bodyParameters(Map parameterMap) { - parameterMap.put(RequestParameterKey.GRANT_TYPE, GrantTypeKey.CLIENT_CREDENTIALS.getValue()); + if(clientCredentialsMode == ClientCredentialsMode.BODY) { + parameterMap.put(RequestParameterKey.GRANT_TYPE, GrantTypeKey.CLIENT_CREDENTIALS.getValue()); + final String clientId = getClientId(); + if (StringUtils.isNotBlank(clientId)) { + parameterMap.put(RequestParameterKey.CLIENT_ID, clientId); + } + if (StringUtils.isNotBlank(clientSecret)) { + parameterMap.put(RequestParameterKey.CLIENT_SECRET, getClientSecret()); + } + } } @@ -57,4 +81,45 @@ public GrantType getGrantType() { return GrantType.CLIENT_CREDENTIAL; } + public ClientCredentialsMode getClientCredentialsMode() { + return clientCredentialsMode; + } + + public void setClientCredentialsMode(final ClientCredentialsMode clientCredentialsMode) { + this.clientCredentialsMode = clientCredentialsMode; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(final String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(final String clientSecret) { + this.clientSecret = clientSecret; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof ClientCredentialGrantImpl)) return false; + + final ClientCredentialGrantImpl that = (ClientCredentialGrantImpl) o; + + if (!Objects.equals(clientId, that.clientId)) return false; + return Objects.equals(clientSecret, that.clientSecret); + } + + @Override + public int hashCode() { + int result = clientId != null ? clientId.hashCode() : 0; + result = 31 * result + (clientSecret != null ? clientSecret.hashCode() : 0); + return result; + } } diff --git a/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java b/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java index 5f901f8..fdd71b0 100644 --- a/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java +++ b/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java @@ -20,6 +20,7 @@ import com.sphereon.libs.authentication.api.TokenRequest; import com.sphereon.libs.authentication.api.TokenResponse; import com.sphereon.libs.authentication.api.config.ApiConfiguration; +import com.sphereon.libs.authentication.api.config.ClientCredentialsMode; import com.sphereon.libs.authentication.api.granttypes.Grant; import org.junit.Assert; import org.junit.FixMethodOrder; @@ -47,6 +48,30 @@ public CredentialsTest() { public void test_10_ClientCredential() { AuthenticationApi authenticationApi = new AuthenticationApi.Builder().build(); TokenRequest tokenRequest = authenticationApi.requestToken() + .withClientCredentialsMode(ClientCredentialsMode.BASIC_HEADER) + .withConsumerKey("gJ33aNcX3Zj3iqMQhyfQc4AIpfca") + .withConsumerSecret("v1XDT6Mdh_5xcCod1fnyUMYsZXsa") + .withScope("UnitTest") + .withValidityPeriod(VALIDITY_PERIOD + SAFETY_MARGIN_SECONDS) + .build(); + TokenResponse tokenResponse = tokenRequest.execute(); + Assert.assertNotNull(tokenResponse.getAccessToken()); + this.prevToken.set(tokenResponse.getAccessToken()); + waitSeconds(2L); + Assert.assertFalse(tokenResponse.isExpired()); + tokenResponse = tokenRequest.execute(); + Assert.assertFalse(tokenResponse.isExpired()); + waitSeconds(tokenResponse.getExpiresInSeconds()); + Assert.assertTrue(tokenResponse.isExpired()); + tokenResponse = tokenRequest.execute(); + Assert.assertFalse(tokenResponse.isExpired()); + } + + @Test + public void test_12_ClientCredentialBody() { + AuthenticationApi authenticationApi = new AuthenticationApi.Builder().build(); + TokenRequest tokenRequest = authenticationApi.requestToken() + .withClientCredentialsMode(ClientCredentialsMode.BODY) .withConsumerKey("gJ33aNcX3Zj3iqMQhyfQc4AIpfca") .withConsumerSecret("v1XDT6Mdh_5xcCod1fnyUMYsZXsa") .withScope("UnitTest") diff --git a/authentication-lib-osgi/pom.xml b/authentication-lib-osgi/pom.xml index 168a21f..34dade8 100644 --- a/authentication-lib-osgi/pom.xml +++ b/authentication-lib-osgi/pom.xml @@ -21,7 +21,7 @@ com.sphereon.public authentication-lib-modules - 0.1.8-SNAPSHOT + 0.2.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 9c65cb3..4bc7201 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.0.0 com.sphereon.public - 0.1.8-SNAPSHOT + 0.2.0-SNAPSHOT authentication-lib-modules authentication-lib-main @@ -32,8 +32,8 @@ - 11 - 11 + 8 + 8 3.8.1 2.5.3 1.9.5 diff --git a/spring-boot-test/pom.xml b/spring-boot-test/pom.xml index bdabfc9..1208200 100644 --- a/spring-boot-test/pom.xml +++ b/spring-boot-test/pom.xml @@ -21,7 +21,7 @@ com.sphereon.public authentication-lib-modules - 0.1.8-SNAPSHOT + 0.2.0-SNAPSHOT ../pom.xml 4.0.0 From 79482cfd637d45b172bbbd203f54a648a4dc3b02 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Wed, 19 Oct 2022 13:21:03 +0200 Subject: [PATCH 3/5] SPHEREON-1096: added client credentials in body support --- .../impl/objects/HttpRequestHandler.java | 5 +-- .../ClientCredentialsGrantImpl.java | 2 +- .../libs/authentication/CredentialsTest.java | 32 ++++++++++--------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java index ef441c2..0010791 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java @@ -22,6 +22,7 @@ import com.sphereon.libs.authentication.api.config.ApiConfiguration; import com.sphereon.libs.authentication.impl.RequestParameters; import okhttp3.*; +import org.apache.commons.lang3.StringUtils; import java.io.IOException; import java.lang.reflect.Type; @@ -48,7 +49,7 @@ public Request newTokenRequest(String urlBase, Headers headers, FormBody request Assert.notNull(urlBase, "No urlBase was specified"); Request.Builder request = new Request.Builder() - .url(urlBase + TokenPathParameters.TOKEN) + .url(StringUtils.appendIfMissing(urlBase, "/") + TokenPathParameters.TOKEN) .headers(headers) .post(requestBody); return request.build(); @@ -57,7 +58,7 @@ public Request newTokenRequest(String urlBase, Headers headers, FormBody request public Request newRevokeRequest(String urlBase, Headers headers, FormBody requestBody) { Request.Builder request = new Request.Builder() - .url(urlBase + TokenPathParameters.REVOKE) + .url(StringUtils.appendIfMissing(urlBase, "/") + TokenPathParameters.REVOKE) .headers(headers) .post(requestBody); return request.build(); diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialsGrantImpl.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialsGrantImpl.java index 89ed174..d1dcc60 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialsGrantImpl.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/granttypes/ClientCredentialsGrantImpl.java @@ -53,8 +53,8 @@ public void headerParameters(Map parameterMap) { @Override public void bodyParameters(Map parameterMap) { + parameterMap.put(RequestParameterKey.GRANT_TYPE, GrantTypeKey.CLIENT_CREDENTIALS.getValue()); if(clientCredentialsMode == ClientCredentialsMode.BODY) { - parameterMap.put(RequestParameterKey.GRANT_TYPE, GrantTypeKey.CLIENT_CREDENTIALS.getValue()); final String clientId = getClientId(); if (StringUtils.isNotBlank(clientId)) { parameterMap.put(RequestParameterKey.CLIENT_ID, clientId); diff --git a/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java b/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java index fdd71b0..c567281 100644 --- a/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java +++ b/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java @@ -21,6 +21,8 @@ import com.sphereon.libs.authentication.api.TokenResponse; import com.sphereon.libs.authentication.api.config.ApiConfiguration; import com.sphereon.libs.authentication.api.config.ClientCredentialsMode; +import com.sphereon.libs.authentication.api.config.PersistenceMode; +import com.sphereon.libs.authentication.api.config.PersistenceType; import com.sphereon.libs.authentication.api.granttypes.Grant; import org.junit.Assert; import org.junit.FixMethodOrder; @@ -68,26 +70,26 @@ public void test_10_ClientCredential() { } @Test - public void test_12_ClientCredentialBody() { - AuthenticationApi authenticationApi = new AuthenticationApi.Builder().build(); + public void test_12_ClientCredentialBodyMicrosoft() { + ApiConfiguration configuration = new ApiConfiguration.Builder() + .withGatewayBaseUrl("https://login.microsoftonline.com/e2a42b2f-7460-4499-afc2-425315ef058a/oauth2/v2.0") + .withApplication(APPLICATION_NAME) + .withPersistenceType(PersistenceType.IN_MEMORY) + .withPersistenceMode(PersistenceMode.READ_WRITE) + .build(); + + AuthenticationApi authenticationApi = new AuthenticationApi.Builder() + .withConfiguration(configuration) + .build(); + TokenRequest tokenRequest = authenticationApi.requestToken() .withClientCredentialsMode(ClientCredentialsMode.BODY) - .withConsumerKey("gJ33aNcX3Zj3iqMQhyfQc4AIpfca") - .withConsumerSecret("v1XDT6Mdh_5xcCod1fnyUMYsZXsa") - .withScope("UnitTest") - .withValidityPeriod(VALIDITY_PERIOD + SAFETY_MARGIN_SECONDS) + .withConsumerKey("a6f86e05-b1d5-4103-95ff-fd5212bba102") + .withConsumerSecret("5to8Q~oLPbb6qohpXpQzbyR-y4DuZJI2vHcO4csj") + .withScope("https://graph.microsoft.com/.default") .build(); TokenResponse tokenResponse = tokenRequest.execute(); Assert.assertNotNull(tokenResponse.getAccessToken()); - this.prevToken.set(tokenResponse.getAccessToken()); - waitSeconds(2L); - Assert.assertFalse(tokenResponse.isExpired()); - tokenResponse = tokenRequest.execute(); - Assert.assertFalse(tokenResponse.isExpired()); - waitSeconds(tokenResponse.getExpiresInSeconds()); - Assert.assertTrue(tokenResponse.isExpired()); - tokenResponse = tokenRequest.execute(); - Assert.assertFalse(tokenResponse.isExpired()); } From 61823b2f77a1dba5cb059ebdeac3170bc7d9df77 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Wed, 19 Oct 2022 13:25:22 +0200 Subject: [PATCH 4/5] SPHEREON-1096: pom comment --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4bc7201..0985d9d 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ - 8 + 8 8 3.8.1 2.5.3 From c48e7edbfecea6895cb382fed68955eeb7f71946 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Mon, 21 Nov 2022 17:14:15 +0100 Subject: [PATCH 5/5] SPHEREON-1096: Added support for withTokenEndpointPath & withResource --- .../api/config/ApiConfiguration.java | 4 +++ .../impl/config/ApiConfigurationImpl.java | 10 ++++++ .../impl/config/ApiConfigurator.java | 5 +++ .../objects/GenerateTokenRequestBuilder.java | 9 ++++- .../objects/GenerateTokenRequestImpl.java | 35 +++---------------- .../impl/objects/HttpRequestHandler.java | 32 ++++++++++++----- .../impl/objects/RequestParameterKey.java | 1 + .../impl/objects/TokenRequestImpl.java | 8 +++++ .../libs/authentication/CredentialsTest.java | 30 ++++++++++++++-- pom.xml | 2 +- 10 files changed, 91 insertions(+), 45 deletions(-) diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/config/ApiConfiguration.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/config/ApiConfiguration.java index 3bb98ab..2dee626 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/config/ApiConfiguration.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/api/config/ApiConfiguration.java @@ -31,6 +31,10 @@ public interface ApiConfiguration extends ApiConfigurator { void setGatewayBaseUrl(String gatewayBaseUrl); + String getTokenEndpointPath(); + + void setTokenEndpointPath(String tokenEndpointPath); + PersistenceType getPersistenceType(); void setPersistenceType(PersistenceType persistenceType); diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/config/ApiConfigurationImpl.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/config/ApiConfigurationImpl.java index 02eeae4..4db7500 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/config/ApiConfigurationImpl.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/config/ApiConfigurationImpl.java @@ -38,6 +38,7 @@ class ApiConfigurationImpl implements ApiConfiguration, ConfigPersistence, Confi private PersistenceMode persistenceMode = PersistenceMode.READ_ONLY; private String gatewayBaseUrl = DEFAULT_GATEWAY_URL; + private String tokenEndpointPath; private File standalonePropertyFile; @@ -87,6 +88,15 @@ public void setGatewayBaseUrl(String gatewayBaseUrl) { this.gatewayBaseUrl = gatewayBaseUrl; } + @Override + public String getTokenEndpointPath() { + return tokenEndpointPath; + } + + @Override + public void setTokenEndpointPath(final String tokenEndpointPath) { + this.tokenEndpointPath = tokenEndpointPath; + } @Override public PersistenceType getPersistenceType() { diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/config/ApiConfigurator.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/config/ApiConfigurator.java index 9690cd7..e5ca8cd 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/config/ApiConfigurator.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/config/ApiConfigurator.java @@ -111,6 +111,11 @@ public Builder withGatewayBaseUrl(String gatewayBaseUrl) { return this; } + public Builder withTokenEndpointPath(String path) { + configuration.setTokenEndpointPath(path); + return this; + } + public ApiConfiguration build() { validate(); diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestBuilder.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestBuilder.java index 0c7936a..456aeb4 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestBuilder.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestBuilder.java @@ -38,6 +38,7 @@ class Builder implements TokenRequestBuilder { private String consumerSecret; private Grant grant; private String scope; + private String resource; private Long validityPeriodInSeconds; private ClientCredentialsMode clientCredentialsMode; @@ -75,6 +76,11 @@ public GenerateTokenRequestBuilder.Builder withScope(String scope) { return this; } + public GenerateTokenRequestBuilder.Builder withResource(String resource) { + this.resource = resource; + return this; + } + public GenerateTokenRequestBuilder.Builder withValidityPeriod(int validityPeriodInSeconds) { this.validityPeriodInSeconds = Long.valueOf(validityPeriodInSeconds); @@ -101,6 +107,7 @@ public TokenRequest build() { tokenRequest.setConsumerKey(consumerKey); tokenRequest.setConsumerSecret(consumerSecret); tokenRequest.setScope(scope); + tokenRequest.setResource(resource); tokenRequest.setValidityPeriodInSeconds(validityPeriodInSeconds); return tokenRequest; } @@ -111,7 +118,7 @@ private void validate() { this.clientCredentialsMode = ClientCredentialsMode.BASIC_HEADER; // Backwards compatibility } - if(clientCredentialsMode == ClientCredentialsMode.BASIC_HEADER) { + if (clientCredentialsMode == ClientCredentialsMode.BASIC_HEADER) { if (StringUtils.isEmpty(consumerKey)) { this.consumerKey = configuration.getConsumerKey(); } diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestImpl.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestImpl.java index 8de3528..877197c 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestImpl.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/GenerateTokenRequestImpl.java @@ -141,7 +141,7 @@ private void buildAndExecuteRequestAsync() { private Request buildRequest(HttpRequestHandler requestHandler) { FormBody requestBody = requestHandler.buildBody(this); Headers headers = requestHandler.buildHeaders(this); - return requestHandler.newTokenRequest(configuration.getGatewayBaseUrl(), headers, requestBody); + return requestHandler.newTokenRequest(configuration.getGatewayBaseUrl(), configuration.getTokenEndpointPath(), headers, requestBody); } @@ -161,37 +161,10 @@ public void bodyParameters(Map parameterMap) { if (getScope() != null) { parameterMap.put(RequestParameterKey.SCOPE, "" + getScope()); } + if (getResource() != null) { + parameterMap.put(RequestParameterKey.RESOURCE, "" + getResource()); + } RequestParameters grantParameters = (RequestParameters) getGrant(); grantParameters.bodyParameters(parameterMap); } - - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof GenerateTokenRequestImpl)) { - return false; - } - if (!super.equals(o)) { - return false; - } - - GenerateTokenRequestImpl that = (GenerateTokenRequestImpl) o; - - if (getGrant() != null ? !getGrant().equals(that.getGrant()) : that.getGrant() != null) { - return false; - } - return getValidityPeriodInSeconds() != null ? getValidityPeriodInSeconds().equals(that.getValidityPeriodInSeconds()) : that.getValidityPeriodInSeconds() == null; - } - - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (getGrant() != null ? getGrant().hashCode() : 0); - result = 31 * result + (getValidityPeriodInSeconds() != null ? getValidityPeriodInSeconds().hashCode() : 0); - return result; - } } diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java index 0010791..ad5b5f7 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/HttpRequestHandler.java @@ -45,22 +45,36 @@ public HttpRequestHandler(ApiConfiguration configuration) { } - public Request newTokenRequest(String urlBase, Headers headers, FormBody requestBody) { + public Request newTokenRequest(String urlBase, final String tokenEndpointPath, Headers headers, FormBody requestBody) { Assert.notNull(urlBase, "No urlBase was specified"); + final StringBuilder urlBuilder = new StringBuilder(urlBase); + if (!urlBase.endsWith("/")) { + urlBuilder.append('/'); + } + if (StringUtils.isNotBlank(tokenEndpointPath)) { + if (tokenEndpointPath.startsWith("/")) { + urlBuilder.append(tokenEndpointPath.substring(1)); + } else { + urlBuilder.append(tokenEndpointPath); + } + } else { + urlBuilder.append(TokenPathParameters.TOKEN.getValue()); + } + Request.Builder request = new Request.Builder() - .url(StringUtils.appendIfMissing(urlBase, "/") + TokenPathParameters.TOKEN) - .headers(headers) - .post(requestBody); + .url(urlBuilder.toString()) + .headers(headers) + .post(requestBody); return request.build(); } public Request newRevokeRequest(String urlBase, Headers headers, FormBody requestBody) { Request.Builder request = new Request.Builder() - .url(StringUtils.appendIfMissing(urlBase, "/") + TokenPathParameters.REVOKE) - .headers(headers) - .post(requestBody); + .url(StringUtils.appendIfMissing(urlBase, "/") + TokenPathParameters.REVOKE) + .headers(headers) + .post(requestBody); return request.build(); } @@ -107,8 +121,8 @@ public String getResponseBodyContent(Response response) throws IOException { Assert.notNull(responseBody, "The remote endpoint did not return a response body."); String responseBodyString = responseBody.string(); Assert.isTrue(!"application/json".equals(responseBody.contentType()), - String.format("The remote endpoint responded with content type %s while application/json is expected. Content:%n%s", - responseBody.contentType(), responseBodyString)); + String.format("The remote endpoint responded with content type %s while application/json is expected. Content:%n%s", + responseBody.contentType(), responseBodyString)); return responseBodyString; } diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/RequestParameterKey.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/RequestParameterKey.java index e121072..532bc80 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/RequestParameterKey.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/RequestParameterKey.java @@ -33,6 +33,7 @@ public enum RequestParameterKey implements StringValueEnum { ASSERTION("assertions"), VALIDITY_PERIOD("validity_period"), SCOPE("scope"), + RESOURCE("resource"), AUTHORIZATION("Authorization"), TOKEN("token"); diff --git a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/TokenRequestImpl.java b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/TokenRequestImpl.java index fb17ee3..189b6f0 100644 --- a/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/TokenRequestImpl.java +++ b/authentication-lib-main/src/main/java/com/sphereon/libs/authentication/impl/objects/TokenRequestImpl.java @@ -53,6 +53,7 @@ abstract class TokenRequestImpl implements TokenRequest, RequestParameters { private transient String consumerSecret; protected String scope; + protected String resource; private ClientCredentialsMode clientCredentialsMode; @@ -70,6 +71,13 @@ public void setScope(String scope) { this.scope = scope; } + public void setResource(final String resource) { + this.resource = resource; + } + + public String getResource() { + return resource; + } public ClientCredentialsMode getClientCredentialsMode() { return clientCredentialsMode; diff --git a/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java b/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java index c567281..0ef0004 100644 --- a/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java +++ b/authentication-lib-main/src/test/java/com/sphereon/libs/authentication/CredentialsTest.java @@ -70,7 +70,7 @@ public void test_10_ClientCredential() { } @Test - public void test_12_ClientCredentialBodyMicrosoft() { + public void test_12_ClientCredentialBodyAzure() { ApiConfiguration configuration = new ApiConfiguration.Builder() .withGatewayBaseUrl("https://login.microsoftonline.com/e2a42b2f-7460-4499-afc2-425315ef058a/oauth2/v2.0") .withApplication(APPLICATION_NAME) @@ -84,14 +84,38 @@ public void test_12_ClientCredentialBodyMicrosoft() { TokenRequest tokenRequest = authenticationApi.requestToken() .withClientCredentialsMode(ClientCredentialsMode.BODY) - .withConsumerKey("a6f86e05-b1d5-4103-95ff-fd5212bba102") - .withConsumerSecret("5to8Q~oLPbb6qohpXpQzbyR-y4DuZJI2vHcO4csj") + .withConsumerKey("6b2b3ffe-cc9a-4e5a-968a-613a847237e5") + .withConsumerSecret("URb8Q~jFhn8KKw08s5izc4cxCdhcEmRy4s0e0cLG") .withScope("https://graph.microsoft.com/.default") .build(); TokenResponse tokenResponse = tokenRequest.execute(); Assert.assertNotNull(tokenResponse.getAccessToken()); } + @Test + public void test_14_ClientCredentialBodySharepoint() { + ApiConfiguration configuration = new ApiConfiguration.Builder() + .withGatewayBaseUrl("https://accounts.accesscontrol.windows.net/e2a42b2f-7460-4499-afc2-425315ef058a") + .withTokenEndpointPath("tokens/OAuth/2") + .withApplication(APPLICATION_NAME) + .withPersistenceType(PersistenceType.IN_MEMORY) + .withPersistenceMode(PersistenceMode.READ_WRITE) + .build(); + + AuthenticationApi authenticationApi = new AuthenticationApi.Builder() + .withConfiguration(configuration) + .build(); + + TokenRequest tokenRequest = authenticationApi.requestToken() + .withClientCredentialsMode(ClientCredentialsMode.BODY) + .withConsumerKey("9a78b885-4d8c-4a3a-a409-6989d6711d8a@e2a42b2f-7460-4499-afc2-425315ef058a") + .withConsumerSecret("iuDRQ1MrLJY1Uqyf8pMjWbk3xd9kfEH4y9THe3mNgZM=") + .withResource("00000003-0000-0ff1-ce00-000000000000/sphereon.sharepoint.com@e2a42b2f-7460-4499-afc2-425315ef058a") + .build(); + TokenResponse tokenResponse = tokenRequest.execute(); + Assert.assertNotNull(tokenResponse.getAccessToken()); + } + @Test public void test_20_UserPassword() { diff --git a/pom.xml b/pom.xml index 0985d9d..1bae143 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ 1.9.3 2.8.0 2.8.0 - 4.9.1 + 4.10.0 2.9.0 6.0.0 4.13.2