Skip to content

feat(config): disable device_code grant by default #2068

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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 @@ -365,7 +365,10 @@ public void init(HttpSecurity httpSecurity) throws Exception {
List<RequestMatcher> requestMatchers = new ArrayList<>();
this.configurers.values().forEach((configurer) -> {
configurer.init(httpSecurity);
requestMatchers.add(configurer.getRequestMatcher());
RequestMatcher matcher = configurer.getRequestMatcher();
if (matcher != null) {
requestMatchers.add(matcher);
}
});
String jwkSetEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils.withMultipleIssuersPattern(authorizationServerSettings.getJwkSetEndpoint())
Expand All @@ -380,7 +383,10 @@ public void init(HttpSecurity httpSecurity) throws Exception {
preferredMatchers.add(getRequestMatcher(OAuth2TokenEndpointConfigurer.class));
preferredMatchers.add(getRequestMatcher(OAuth2TokenIntrospectionEndpointConfigurer.class));
preferredMatchers.add(getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class));
preferredMatchers.add(getRequestMatcher(OAuth2DeviceAuthorizationEndpointConfigurer.class));
RequestMatcher deviceAuthMatcher = getRequestMatcher(OAuth2DeviceAuthorizationEndpointConfigurer.class);
if (deviceAuthMatcher != null) {
preferredMatchers.add(deviceAuthMatcher);
}
RequestMatcher preferredMatcher = getRequestMatcher(
OAuth2PushedAuthorizationRequestEndpointConfigurer.class);
if (preferredMatcher != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,19 +192,23 @@ void init(HttpSecurity httpSecurity) {
? OAuth2ConfigurerUtils
.withMultipleIssuersPattern(authorizationServerSettings.getTokenRevocationEndpoint())
: authorizationServerSettings.getTokenRevocationEndpoint();
String deviceAuthorizationEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
.withMultipleIssuersPattern(authorizationServerSettings.getDeviceAuthorizationEndpoint())
: authorizationServerSettings.getDeviceAuthorizationEndpoint();
String pushedAuthorizationRequestEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
.withMultipleIssuersPattern(authorizationServerSettings.getPushedAuthorizationRequestEndpoint())
.withMultipleIssuersPattern(authorizationServerSettings.getPushedAuthorizationRequestEndpoint())
: authorizationServerSettings.getPushedAuthorizationRequestEndpoint();
this.requestMatcher = new OrRequestMatcher(new AntPathRequestMatcher(tokenEndpointUri, HttpMethod.POST.name()),
new AntPathRequestMatcher(tokenIntrospectionEndpointUri, HttpMethod.POST.name()),
new AntPathRequestMatcher(tokenRevocationEndpointUri, HttpMethod.POST.name()),
new AntPathRequestMatcher(deviceAuthorizationEndpointUri, HttpMethod.POST.name()),
new AntPathRequestMatcher(pushedAuthorizationRequestEndpointUri, HttpMethod.POST.name()));
List<RequestMatcher> requestMatchers = new ArrayList<>();
requestMatchers.add(new AntPathRequestMatcher(tokenEndpointUri, HttpMethod.POST.name()));
requestMatchers.add(new AntPathRequestMatcher(tokenIntrospectionEndpointUri, HttpMethod.POST.name()));
requestMatchers.add(new AntPathRequestMatcher(tokenRevocationEndpointUri, HttpMethod.POST.name()));
if (authorizationServerSettings.isDeviceGrantEnabled()) {
String deviceAuthorizationEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
.withMultipleIssuersPattern(authorizationServerSettings.getDeviceAuthorizationEndpoint())
: authorizationServerSettings.getDeviceAuthorizationEndpoint();
requestMatchers.add(new AntPathRequestMatcher(deviceAuthorizationEndpointUri, HttpMethod.POST.name()));
}
requestMatchers.add(new AntPathRequestMatcher(pushedAuthorizationRequestEndpointUri, HttpMethod.POST.name()));
this.requestMatcher = new OrRequestMatcher(requestMatchers);
List<AuthenticationProvider> authenticationProviders = createDefaultAuthenticationProviders(httpSecurity);
if (!this.authenticationProviders.isEmpty()) {
authenticationProviders.addAll(0, this.authenticationProviders);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,13 @@ public OAuth2DeviceAuthorizationEndpointConfigurer verificationUri(String verifi
@Override
public void init(HttpSecurity builder) {
AuthorizationServerSettings authorizationServerSettings = OAuth2ConfigurerUtils
.getAuthorizationServerSettings(builder);
.getAuthorizationServerSettings(builder);
if (!authorizationServerSettings.isDeviceGrantEnabled()) {
return;
}
String deviceAuthorizationEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
.withMultipleIssuersPattern(authorizationServerSettings.getDeviceAuthorizationEndpoint())
.withMultipleIssuersPattern(authorizationServerSettings.getDeviceAuthorizationEndpoint())
: authorizationServerSettings.getDeviceAuthorizationEndpoint();
this.requestMatcher = new AntPathRequestMatcher(deviceAuthorizationEndpointUri, HttpMethod.POST.name());

Expand All @@ -217,7 +220,11 @@ public void init(HttpSecurity builder) {
public void configure(HttpSecurity builder) {
AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);
AuthorizationServerSettings authorizationServerSettings = OAuth2ConfigurerUtils
.getAuthorizationServerSettings(builder);
.getAuthorizationServerSettings(builder);

if (!authorizationServerSettings.isDeviceGrantEnabled()) {
return;
}

String deviceAuthorizationEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,13 @@ public OAuth2DeviceVerificationEndpointConfigurer consentPage(String consentPage
@Override
public void init(HttpSecurity builder) {
AuthorizationServerSettings authorizationServerSettings = OAuth2ConfigurerUtils
.getAuthorizationServerSettings(builder);
.getAuthorizationServerSettings(builder);
if (!authorizationServerSettings.isDeviceGrantEnabled()) {
return;
}
String deviceVerificationEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
.withMultipleIssuersPattern(authorizationServerSettings.getDeviceVerificationEndpoint())
.withMultipleIssuersPattern(authorizationServerSettings.getDeviceVerificationEndpoint())
: authorizationServerSettings.getDeviceVerificationEndpoint();
this.requestMatcher = new OrRequestMatcher(
new AntPathRequestMatcher(deviceVerificationEndpointUri, HttpMethod.GET.name()),
Expand All @@ -254,7 +257,11 @@ public void init(HttpSecurity builder) {
public void configure(HttpSecurity builder) {
AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);
AuthorizationServerSettings authorizationServerSettings = OAuth2ConfigurerUtils
.getAuthorizationServerSettings(builder);
.getAuthorizationServerSettings(builder);

if (!authorizationServerSettings.isDeviceGrantEnabled()) {
return;
}

String deviceVerificationEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,21 +163,31 @@ public String getOidcLogoutEndpoint() {
return getSetting(ConfigurationSettingNames.AuthorizationServer.OIDC_LOGOUT_ENDPOINT);
}

/**
* Returns {@code true} if the OAuth 2.0 Device Authorization Grant is enabled.
* The default is {@code false}.
* @return {@code true} if the Device Authorization Grant is enabled, {@code false} otherwise
*/
public boolean isDeviceGrantEnabled() {
return getSetting(ConfigurationSettingNames.AuthorizationServer.DEVICE_GRANT_ENABLED);
}

/**
* Constructs a new {@link Builder} with the default settings.
* @return the {@link Builder}
*/
public static Builder builder() {
return new Builder().multipleIssuersAllowed(false)
.authorizationEndpoint("/oauth2/authorize")
.pushedAuthorizationRequestEndpoint("/oauth2/par")
.deviceAuthorizationEndpoint("/oauth2/device_authorization")
.deviceVerificationEndpoint("/oauth2/device_verification")
.tokenEndpoint("/oauth2/token")
.jwkSetEndpoint("/oauth2/jwks")
.tokenRevocationEndpoint("/oauth2/revoke")
.tokenIntrospectionEndpoint("/oauth2/introspect")
.oidcClientRegistrationEndpoint("/connect/register")
.authorizationEndpoint("/oauth2/authorize")
.pushedAuthorizationRequestEndpoint("/oauth2/par")
.deviceAuthorizationEndpoint("/oauth2/device_authorization")
.deviceVerificationEndpoint("/oauth2/device_verification")
.deviceGrantEnabled(false)
.tokenEndpoint("/oauth2/token")
.jwkSetEndpoint("/oauth2/jwks")
.tokenRevocationEndpoint("/oauth2/revoke")
.tokenIntrospectionEndpoint("/oauth2/introspect")
.oidcClientRegistrationEndpoint("/connect/register")
.oidcUserInfoEndpoint("/userinfo")
.oidcLogoutEndpoint("/connect/logout");
}
Expand Down Expand Up @@ -281,6 +291,16 @@ public Builder deviceVerificationEndpoint(String deviceVerificationEndpoint) {
deviceVerificationEndpoint);
}

/**
* Enables the OAuth 2.0 Device Authorization Grant.
* @param deviceGrantEnabled {@code true} to enable the Device Authorization Grant
* @return the {@link Builder} for further configuration
*/
public Builder deviceGrantEnabled(boolean deviceGrantEnabled) {
return setting(ConfigurationSettingNames.AuthorizationServer.DEVICE_GRANT_ENABLED,
deviceGrantEnabled);
}

/**
* Sets the OAuth 2.0 Token endpoint.
* @param tokenEndpoint the Token endpoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,15 @@ public static final class AuthorizationServer {
* Set the OAuth 2.0 Device Verification endpoint.
*/
public static final String DEVICE_VERIFICATION_ENDPOINT = AUTHORIZATION_SERVER_SETTINGS_NAMESPACE
.concat("device-verification-endpoint");
.concat("device-verification-endpoint");

/**
* Set to {@code true} if the OAuth 2.0 Device Authorization Grant is enabled.
* The default is {@code false}.
*/
public static final String DEVICE_GRANT_ENABLED = AUTHORIZATION_SERVER_SETTINGS_NAMESPACE
.concat("device-grant-enabled");


/**
* Set the OAuth 2.0 Token endpoint.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,17 @@ public static void destroy() {
}

@Test
public void requestWhenDeviceAuthorizationRequestNotAuthenticatedThenUnauthorized() throws Exception {
public void requestWhenDeviceAuthorizationEndpointDisabledThenNotFound() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();

this.mvc.perform(post(DEFAULT_DEVICE_AUTHORIZATION_ENDPOINT_URI))
.andExpect(status().isNotFound());
}

@Test
public void requestWhenDeviceAuthorizationRequestNotAuthenticatedThenUnauthorized() throws Exception {
this.spring.register(AuthorizationServerConfigurationWithDeviceGrant.class).autowire();

// @formatter:off
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
.authorizationGrantType(AuthorizationGrantType.DEVICE_CODE)
Expand All @@ -200,7 +208,7 @@ public void requestWhenDeviceAuthorizationRequestNotAuthenticatedThenUnauthorize

@Test
public void requestWhenRegisteredClientMissingThenUnauthorized() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
this.spring.register(AuthorizationServerConfigurationWithDeviceGrant.class).autowire();

// @formatter:off
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
Expand Down Expand Up @@ -272,7 +280,7 @@ public void requestWhenDeviceAuthorizationRequestValidThenReturnDeviceAuthorizat

@Test
public void requestWhenDeviceVerificationRequestUnauthenticatedThenUnauthorized() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
this.spring.register(AuthorizationServerConfigurationWithDeviceGrant.class).autowire();

// @formatter:off
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
Expand Down Expand Up @@ -357,7 +365,7 @@ public void requestWhenDeviceVerificationRequestValidThenDisplaysConsentPage() t

@Test
public void requestWhenDeviceAuthorizationConsentRequestUnauthenticatedThenBadRequest() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
this.spring.register(AuthorizationServerConfigurationWithDeviceGrant.class).autowire();

// @formatter:off
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
Expand Down Expand Up @@ -395,7 +403,7 @@ public void requestWhenDeviceAuthorizationConsentRequestUnauthenticatedThenBadRe

@Test
public void requestWhenDeviceAuthorizationConsentRequestValidThenRedirectsToSuccessPage() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
this.spring.register(AuthorizationServerConfigurationWithDeviceGrant.class).autowire();

// @formatter:off
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
Expand Down Expand Up @@ -445,7 +453,7 @@ public void requestWhenDeviceAuthorizationConsentRequestValidThenRedirectsToSucc

@Test
public void requestWhenAccessTokenRequestUnauthenticatedThenUnauthorized() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
this.spring.register(AuthorizationServerConfigurationWithDeviceGrant.class).autowire();

// @formatter:off
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
Expand Down Expand Up @@ -481,7 +489,7 @@ public void requestWhenAccessTokenRequestUnauthenticatedThenUnauthorized() throw

@Test
public void requestWhenAccessTokenRequestValidThenReturnAccessTokenResponse() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
this.spring.register(AuthorizationServerConfigurationWithDeviceGrant.class).autowire();

// @formatter:off
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
Expand Down Expand Up @@ -553,7 +561,7 @@ public void requestWhenAccessTokenRequestValidThenReturnAccessTokenResponse() th

@Test
public void requestWhenAccessTokenRequestWithDPoPProofThenReturnDPoPBoundAccessToken() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
this.spring.register(AuthorizationServerConfigurationWithDeviceGrant.class).autowire();

// @formatter:off
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
Expand Down Expand Up @@ -683,11 +691,24 @@ PasswordEncoder passwordEncoder() {

@EnableWebSecurity
@Import(OAuth2AuthorizationServerConfiguration.class)
static class AuthorizationServerConfigurationWithMultipleIssuersAllowed extends AuthorizationServerConfiguration {
static class AuthorizationServerConfigurationWithDeviceGrant extends AuthorizationServerConfiguration {

@Bean
AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().deviceGrantEnabled(true).build();
}

}

@EnableWebSecurity
@Import(OAuth2AuthorizationServerConfiguration.class)
static class AuthorizationServerConfigurationWithMultipleIssuersAllowed extends AuthorizationServerConfigurationWithDeviceGrant {

@Bean
AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().multipleIssuersAllowed(true).build();
return AuthorizationServerSettings.builder().multipleIssuersAllowed(true)
.deviceGrantEnabled(true)
.build();
}

}
Expand Down