diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClient.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClient.java index 232b81b8..bfc612e5 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClient.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -250,10 +250,10 @@ public class RegisteredClient implements Serializable { private String clientSecret; private Instant clientSecretExpiresAt; private String clientName; - private Set clientAuthenticationMethods = new HashSet<>(); - private Set authorizationGrantTypes = new HashSet<>(); - private Set redirectUris = new HashSet<>(); - private Set scopes = new HashSet<>(); + private final Set clientAuthenticationMethods = new HashSet<>(); + private final Set authorizationGrantTypes = new HashSet<>(); + private final Set redirectUris = new HashSet<>(); + private final Set scopes = new HashSet<>(); private ClientSettings clientSettings; private TokenSettings tokenSettings; @@ -483,11 +483,31 @@ public class RegisteredClient implements Serializable { if (CollectionUtils.isEmpty(this.clientAuthenticationMethods)) { this.clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC); } + if (this.clientSettings == null) { + ClientSettings.Builder builder = ClientSettings.builder(); + if (isPublicClientType()) { + // @formatter:off + builder + .requireProofKey(true) + .requireAuthorizationConsent(true); + // @formatter:on + } + this.clientSettings = builder.build(); + } + if (this.tokenSettings == null) { + this.tokenSettings = TokenSettings.builder().build(); + } validateScopes(); validateRedirectUris(); return create(); } + private boolean isPublicClientType() { + return this.authorizationGrantTypes.contains(AuthorizationGrantType.AUTHORIZATION_CODE) && + this.clientAuthenticationMethods.size() == 1 && + this.clientAuthenticationMethods.contains(ClientAuthenticationMethod.NONE); + } + private RegisteredClient create() { RegisteredClient registeredClient = new RegisteredClient(); @@ -505,10 +525,8 @@ public class RegisteredClient implements Serializable { new HashSet<>(this.redirectUris)); registeredClient.scopes = Collections.unmodifiableSet( new HashSet<>(this.scopes)); - registeredClient.clientSettings = this.clientSettings != null ? - this.clientSettings : ClientSettings.builder().build(); - registeredClient.tokenSettings = this.tokenSettings != null ? - this.tokenSettings : TokenSettings.builder().build(); + registeredClient.clientSettings = this.clientSettings; + registeredClient.tokenSettings = this.tokenSettings; return registeredClient; } diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClientTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClientTests.java index 4df7d72f..e775748d 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClientTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -382,4 +382,32 @@ public class RegisteredClientTests { assertThat(registration.getRedirectUris()).doesNotContain(newRedirectUri); assertThat(updated.getRedirectUris()).containsExactly(newRedirectUri); } + + @Test + public void buildWhenPublicClientTypeThenDefaultSettings() { + Instant clientIdIssuedAt = Instant.now(); + RegisteredClient registration = RegisteredClient.withId(ID) + .clientId(CLIENT_ID) + .clientIdIssuedAt(clientIdIssuedAt) + .clientName("client-name") + .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + .clientAuthenticationMethod(ClientAuthenticationMethod.NONE) + .redirectUris(redirectUris -> redirectUris.addAll(REDIRECT_URIS)) + .scopes(scopes -> scopes.addAll(SCOPES)) + .build(); + + assertThat(registration.getId()).isEqualTo(ID); + assertThat(registration.getClientId()).isEqualTo(CLIENT_ID); + assertThat(registration.getClientIdIssuedAt()).isEqualTo(clientIdIssuedAt); + assertThat(registration.getClientName()).isEqualTo("client-name"); + assertThat(registration.getAuthorizationGrantTypes()) + .isEqualTo(Collections.singleton(AuthorizationGrantType.AUTHORIZATION_CODE)); + assertThat(registration.getClientAuthenticationMethods()) + .isEqualTo(Collections.singleton(ClientAuthenticationMethod.NONE)); + assertThat(registration.getRedirectUris()).isEqualTo(REDIRECT_URIS); + assertThat(registration.getScopes()).isEqualTo(SCOPES); + assertThat(registration.getClientSettings().isRequireProofKey()).isTrue(); + assertThat(registration.getClientSettings().isRequireAuthorizationConsent()).isTrue(); + } + }