Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand Down Expand Up @@ -755,14 +756,26 @@ public static final class ClientSettings implements Serializable {
@Serial
private static final long serialVersionUID = 7495627155437124692L;

private boolean requireProofKey;

private ClientSettings() {
private final Map<String, Object> settings;

private ClientSettings(Map<String, Object> settings) {
this.settings = Collections.unmodifiableMap(new LinkedHashMap<>(settings));
}

private static final String REQUIRE_PROOF_KEY = "settings.client.require-proof-key";

public boolean isRequireProofKey() {
return this.requireProofKey;
return Boolean.TRUE.equals(getSetting(REQUIRE_PROOF_KEY));
}

@SuppressWarnings("unchecked")
public <T> @Nullable T getSetting(String name) {
Assert.hasText(name, "name cannot be empty");
return (T) this.settings.get(name);
}

public Map<String, Object> getSettings() {
return this.settings;
}

@Override
Expand All @@ -773,17 +786,17 @@ public boolean equals(@Nullable Object o) {
if (!(o instanceof ClientSettings that)) {
return false;
}
return this.requireProofKey == that.requireProofKey;
return Objects.equals(this.settings, that.settings);
}

@Override
public int hashCode() {
return Objects.hashCode(this.requireProofKey);
return Objects.hashCode(this.settings);
}

@Override
public String toString() {
return "ClientSettings{" + "requireProofKey=" + this.requireProofKey + '}';
return "ClientSettings{" + "settings=" + this.settings + '}';
}

public static Builder builder() {
Expand All @@ -792,11 +805,12 @@ public static Builder builder() {

public static final class Builder {

private boolean requireProofKey = true;
private final Map<String, Object> settings = new LinkedHashMap<>();

private Builder() {
this.settings.put(REQUIRE_PROOF_KEY, true);
}

/**
* Set to {@code true} if the client is required to provide a proof key
* challenge and verifier when performing the Authorization Code Grant flow.
Expand All @@ -805,14 +819,35 @@ private Builder() {
* @return the {@link Builder} for further configuration
*/
public Builder requireProofKey(boolean requireProofKey) {
this.requireProofKey = requireProofKey;
return setting(REQUIRE_PROOF_KEY, requireProofKey);
}

/**
* Sets a configuration setting.
* @param name the name of the setting
* @param value the value of the setting
* @return the {@link Builder} for further configuration
*/
public Builder setting(String name, Object value) {
Assert.hasText(name, "name cannot be empty");
Assert.notNull(value, "value cannot be null");
this.settings.put(name, value);
return this;
}

/**
* Sets the configuration settings.
* @param settings the configuration settings
* @return the {@link Builder} for further configuration
*/
public Builder settings(Consumer<Map<String, Object>> settingsConsumer) {
Assert.notNull(settingsConsumer, "settingsConsumer cannot be null");
settingsConsumer.accept(this.settings);
return this;
}

public ClientSettings build() {
ClientSettings clientSettings = new ClientSettings();
clientSettings.requireProofKey = this.requireProofKey;
return clientSettings;
return new ClientSettings(this.settings);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -751,4 +751,79 @@ private static <T> T getStaticValue(Field field, Class<T> clazz) {
}
}

@Test
void buildWhenScopesHaveInvalidCharactersThenThrowException() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All 3x tests are not related to the changes made to ClientSettings. Please remove and add applicable tests.

assertThatIllegalArgumentException().isThrownBy(() ->
// @formatter:off
ClientRegistration.withRegistrationId("test")
.clientId("client")
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
.authorizationUri("https://provider.com/auth")
.tokenUri("https://provider.com/token")
.scope("read", "invalid scope ^") // space is 0x20, which is outside the valid range
.build()
// @formatter:on
);
}

@Test
void buildWhenClientCredentialsMissingTokenUriThenThrowException() {
assertThatIllegalArgumentException().isThrownBy(() ->
// @formatter:off
ClientRegistration.withRegistrationId("test")
.clientId("client")
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
// Missing tokenUri
.build()
// @formatter:on
);
}

@Test
void buildWhenValidThenSettingsAreCorrect() {
// @formatter:off
ClientRegistration registration = ClientRegistration.withRegistrationId("google")
.clientId("my-client")
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.tokenUri("https://google.com/token")
.build();
// @formatter:on
assertThat(registration.getRegistrationId()).isEqualTo("google");
assertThat(registration.getClientId()).isEqualTo("my-client");
// ClientSettings assertions
assertThat(registration.getClientSettings()).isNotNull();
assertThat(registration.getClientSettings().isRequireProofKey()).isTrue();
assertThat(registration.getClientSettings().getSettings()).containsKey("settings.client.require-proof-key");
}

@Test
void clientSettingsWhenCustomSettingThenGetSettingReturnsValue() {
ClientRegistration.ClientSettings clientSettings = ClientRegistration.ClientSettings.builder()
.setting("custom.key", "customValue")
.build();
assertThat(clientSettings.<String>getSetting("custom.key")).isEqualTo("customValue");
}

@Test
void clientSettingsWhenSettingsConsumerThenSettingsApplied() {
ClientRegistration.ClientSettings clientSettings = ClientRegistration.ClientSettings.builder()
.settings(s -> s.put("custom.key", "value"))
.build();
assertThat(clientSettings.<String>getSetting("custom.key")).isEqualTo("value");
}

@Test
void clientSettingsGetSettingWhenNameEmptyThenThrowException() {
ClientRegistration.ClientSettings clientSettings = ClientRegistration.ClientSettings.builder().build();
assertThatIllegalArgumentException()
.isThrownBy(() -> clientSettings.getSetting(""))
.withMessageContaining("name cannot be empty");
}

@Test
void clientSettingsSettingsConsumerWhenNullThenThrowException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> ClientRegistration.ClientSettings.builder().settings(null));
}
}