From 603eb1e64764ea149f7d9d978e1b82c1fe6f7825 Mon Sep 17 00:00:00 2001 From: Eleftheria Stein Date: Tue, 3 Mar 2020 22:24:14 -0500 Subject: [PATCH] Add OAuth2 Kotlin samples to docs Issue: gh-5558 --- .../servlet/oauth2/oauth2-client.adoc | 77 ++++- .../servlet/oauth2/oauth2-login.adoc | 308 +++++++++++++++++- .../servlet/oauth2/oauth2-resourceserver.adoc | 259 ++++++++++++++- 3 files changed, 622 insertions(+), 22 deletions(-) diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc index 8e362f15de..0c358cee0c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc @@ -19,7 +19,10 @@ In addition, `HttpSecurity.oauth2Client().authorizationCodeGrant()` enables the The following code shows the complete configuration options provided by the `HttpSecurity.oauth2Client()` DSL: -[source,java] +.OAuth2 Client Configuration Options +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter { @@ -41,6 +44,30 @@ public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2ClientSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Client { + clientRegistrationRepository = clientRegistrationRepository() + authorizedClientRepository = authorizedClientRepository() + authorizedClientService = authorizedClientService() + authorizationCodeGrant { + authorizationRequestRepository = authorizationRequestRepository() + authorizationRequestResolver = authorizationRequestResolver() + accessTokenResponseClient = accessTokenResponseClient() + } + } + } + } +} +---- +==== + The `OAuth2AuthorizedClientManager` is responsible for managing the authorization (or re-authorization) of an OAuth 2.0 Client, in collaboration with one or more `OAuth2AuthorizedClientProvider`(s). The following code shows an example of how to register an `OAuth2AuthorizedClientManager` `@Bean` and associate it with an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials` and `password` authorization grant types: @@ -583,7 +610,10 @@ The default implementation of `AuthorizationRequestRepository` is `HttpSessionOA If you have a custom implementation of `AuthorizationRequestRepository`, you may configure it as shown in the following example: -[source,java] +.AuthorizationRequestRepository Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter { @@ -601,6 +631,25 @@ public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2ClientSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Client { + authorizationCodeGrant { + authorizationRequestRepository = authorizationRequestRepository() + } + } + } + } +} +---- +==== + ===== Requesting an Access Token @@ -645,7 +694,10 @@ It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error Whether you customize `DefaultAuthorizationCodeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: -[source,java] +.Access Token Response Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter { @@ -663,6 +715,25 @@ public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2ClientSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Client { + authorizationCodeGrant { + accessTokenResponseClient = accessTokenResponseClient() + } + } + } + } +} +---- +==== + [[oauth2Client-refresh-token-grant]] ==== Refresh Token diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc index 0ec3069eea..dd4d115e94 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc @@ -283,7 +283,10 @@ public class OAuth2LoginConfig { The following example shows how to provide a `WebSecurityConfigurerAdapter` with `@EnableWebSecurity` and enable OAuth 2.0 login through `httpSecurity.oauth2Login()`: -[source,java] +.OAuth2 Login Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @@ -299,13 +302,34 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + oauth2Login { } + } + } +} +---- +==== + [[oauth2login-completely-override-autoconfiguration]] ==== Completely Override the Auto-configuration The following example shows how to completely override the auto-configuration by registering a `ClientRegistrationRepository` `@Bean` and providing a `WebSecurityConfigurerAdapter`. -[source,java,attrs="-attributes"] +.Overriding the auto-configuration +==== +.Java +[source,java,role="primary",attrs="-attributes"] ---- @Configuration public class OAuth2LoginConfig { @@ -347,6 +371,50 @@ public class OAuth2LoginConfig { } ---- +.Kotlin +[source,kotlin,role="secondary",attrs="-attributes"] +---- +@Configuration +class OAuth2LoginConfig { + + @EnableWebSecurity + class OAuth2LoginSecurityConfig: WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + oauth2Login { } + } + } + } + + @Bean + fun clientRegistrationRepository(): ClientRegistrationRepository { + return InMemoryClientRegistrationRepository(googleClientRegistration()) + } + + private fun googleClientRegistration(): ClientRegistration { + return ClientRegistration.withRegistrationId("google") + .clientId("google-client-id") + .clientSecret("google-client-secret") + .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC) + .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + .redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}") + .scope("openid", "profile", "email", "address", "phone") + .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth") + .tokenUri("https://www.googleapis.com/oauth2/v4/token") + .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo") + .userNameAttributeName(IdTokenClaimNames.SUB) + .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs") + .clientName("Google") + .build() + } +} +---- +==== + [[oauth2login-javaconfig-wo-boot]] === Java Configuration without Spring Boot 2.x @@ -407,7 +475,10 @@ For example, `oauth2Login().authorizationEndpoint()` allows configuring the _Aut The following code shows an example: -[source,java] +.Advanced OAuth2 Login Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @@ -433,6 +504,34 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Login { + authorizationEndpoint { + ... + } + redirectionEndpoint { + ... + } + tokenEndpoint { + ... + } + userInfoEndpoint { + ... + } + } + } + } +} +---- +==== + The main goal of the `oauth2Login()` DSL was to closely align with the naming, as defined in the specifications. The OAuth 2.0 Authorization Framework defines the https://tools.ietf.org/html/rfc6749#section-3[Protocol Endpoints] as follows: @@ -454,7 +553,10 @@ These claims are normally represented by a JSON object that contains a collectio The following code shows the complete configuration options available for the `oauth2Login()` DSL: -[source,java] +.OAuth2 Login Configuration Options +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @@ -489,6 +591,43 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Login { + clientRegistrationRepository = clientRegistrationRepository() + authorizedClientRepository = authorizedClientRepository() + authorizedClientService = authorizedClientService() + loginPage = "/login" + authorizationEndpoint { + baseUri = authorizationRequestBaseUri() + authorizationRequestRepository = authorizationRequestRepository() + authorizationRequestResolver = authorizationRequestResolver() + } + redirectionEndpoint { + baseUri = authorizationResponseBaseUri() + } + tokenEndpoint { + accessTokenResponseClient = accessTokenResponseClient() + } + userInfoEndpoint { + userAuthoritiesMapper = userAuthoritiesMapper() + userService = oauth2UserService() + oidcUserService = oidcUserService() + customUserType(GitHubOAuth2User::class.java, "github") + } + } + } + } +} +---- +==== + The following sections go into more detail on each of the configuration options available: * <> @@ -521,7 +660,10 @@ To override the default login page, configure `oauth2Login().loginPage()` and (o The following listing shows an example: -[source,java] +.OAuth2 Login Page Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @@ -541,6 +683,26 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Login { + loginPage = "/login/oauth2" + authorizationEndpoint { + baseUri = "/login/oauth2/authorization" + } + } + } + } +} +---- +==== + [IMPORTANT] You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. @@ -571,7 +733,10 @@ The default Authorization Response `baseUri` (redirection endpoint) is `*/login/ If you would like to customize the Authorization Response `baseUri`, configure it as shown in the following example: -[source,java] +.Redirection Endpoint Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @@ -589,6 +754,25 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Login { + redirectionEndpoint { + baseUri = "/login/oauth2/callback/*" + } + } + } + } +} +---- +==== + [IMPORTANT] ==== You also need to ensure the `ClientRegistration.redirectUriTemplate` matches the custom Authorization Response `baseUri`. @@ -636,7 +820,10 @@ There are a couple of options to choose from when mapping user authorities: Provide an implementation of `GrantedAuthoritiesMapper` and configure it as shown in the following example: -[source,java] +.Granted Authorities Mapper Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @@ -683,9 +870,50 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Login { + userInfoEndpoint { + userAuthoritiesMapper = userAuthoritiesMapper() + } + } + } + } + + private fun userAuthoritiesMapper(): GrantedAuthoritiesMapper = GrantedAuthoritiesMapper { authorities: Collection -> + val mappedAuthorities = emptySet() + + authorities.forEach { authority -> + if (authority is OidcUserAuthority) { + val idToken = authority.idToken + val userInfo = authority.userInfo + // Map the claims found in idToken and/or userInfo + // to one or more GrantedAuthority's and add it to mappedAuthorities + } else if (authority is OAuth2UserAuthority) { + val userAttributes = authority.attributes + // Map the attributes found in userAttributes + // to one or more GrantedAuthority's and add it to mappedAuthorities + } + } + + mappedAuthorities + } +} +---- +==== + Alternatively, you may register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the configuration, as shown in the following example: -[source,java] +.Granted Authorities Mapper Bean Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @@ -703,6 +931,25 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Login { } + } + } + + @Bean + fun userAuthoritiesMapper(): GrantedAuthoritiesMapper { + ... + } +} +---- +==== [[oauth2login-advanced-map-authorities-oauth2userservice]] ====== Delegation-based strategy with OAuth2UserService @@ -713,7 +960,10 @@ The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the assoc The following example shows how to implement and configure a delegation-based strategy using an OpenID Connect 1.0 UserService: -[source,java] +.OAuth2UserService Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @@ -752,6 +1002,46 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + oauth2Login { + userInfoEndpoint { + oidcUserService = oidcUserService() + } + } + } + } + + @Bean + fun oidcUserService(): OAuth2UserService { + val delegate = OidcUserService() + + return OAuth2UserService { userRequest -> + // Delegate to the default implementation for loading a user + var oidcUser = delegate.loadUser(userRequest) + + val accessToken = userRequest.accessToken + val mappedAuthorities = HashSet() + + // TODO + // 1) Fetch the authority information from the protected resource using accessToken + // 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities + // 3) Create a copy of oidcUser but use the mappedAuthorities instead + oidcUser = DefaultOidcUser(mappedAuthorities, oidcUser.idToken, oidcUser.userInfo) + + oidcUser + } + } +} +---- +==== + [[oauth2login-advanced-custom-user]] ===== Configuring a Custom OAuth2User diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc index 200705f4cc..33a15ad21f 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc @@ -124,7 +124,10 @@ There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. The first is a `WebSecurityConfigurerAdapter` that configures the app as a resource server. When including `spring-security-oauth2-jose`, this `WebSecurityConfigurerAdapter` looks like: -[source,java] +.Default JWT Configuration +==== +.Java +[source,java,role="primary"] ---- protected void configure(HttpSecurity http) { http @@ -135,11 +138,30 @@ protected void configure(HttpSecurity http) { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + jwt { } + } + } +} +---- +==== + If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. Replacing this is as simple as exposing the bean within the application: -[source,java] +.Custom JWT Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter { @@ -158,6 +180,28 @@ public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize("/messages/**", hasAuthority("SCOPE_message:read")) + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + jwt { + jwtAuthenticationConverter = myConverter() + } + } + } + } +} +---- +==== + The above requires the scope of `message:read` for any URL that starts with `/messages/`. Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. @@ -184,7 +228,10 @@ And its configuration can be overridden using `jwkSetUri()` or replaced using `d An authorization server's JWK Set Uri can be configured <> or it can be supplied in the DSL: -[source,java] +.JWK Set Uri Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter { @@ -202,6 +249,27 @@ public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + jwt { + jwkSetUri = "https://idp.example.com/.well-known/jwks.json" + } + } + } + } +} +---- +==== + Using `jwkSetUri()` takes precedence over any configuration property. [[oauth2resourceserver-jwt-decoder-dsl]] @@ -209,7 +277,10 @@ Using `jwkSetUri()` takes precedence over any configuration property. More powerful than `jwkSetUri()` is `decoder()`, which will completely replace any Boot auto configuration of `JwtDecoder`: -[source,java] +.JWT Decoder Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class DirectlyConfiguredJwtDecoder extends WebSecurityConfigurerAdapter { @@ -227,6 +298,27 @@ public class DirectlyConfiguredJwtDecoder extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class DirectlyConfiguredJwtDecoder : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + jwt { + jwtDecoder = myCustomDecoder() + } + } + } + } +} +---- +==== + This is handy when deeper configuration, like <>, <>, or <>, is necessary. [[oauth2resourceserver-jwt-decoder-bean]] @@ -411,7 +503,10 @@ When this is the case, Resource Server will attempt to coerce these scopes into This means that to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: -[source,java] +.Authorization Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter { @@ -427,6 +522,27 @@ public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize("/contacts/**", hasAuthority("SCOPE_contacts")) + authorize("/messages/**", hasAuthority("SCOPE_messages")) + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + jwt { } + } + } + } +} +---- +==== + Or similarly with method security: [source,java] @@ -444,7 +560,10 @@ Or, at other times, the resource server may need to adapt the attribute or a com To this end, the DSL exposes `jwtAuthenticationConverter()`: -[source,java] +.Authorities Extractor Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter { @@ -472,6 +591,33 @@ Converter grantedAuthoritiesExtractor() { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + jwt { + jwtAuthenticationConverter = grantedAuthoritiesExtractor() + } + } + } + } + + private fun grantedAuthoritiesExtractor(): JwtAuthenticationConverter { + val jwtAuthenticationConverter = JwtAuthenticationConverter() + jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(GrantedAuthoritiesExtractor()) + return jwtAuthenticationConverter + } +} +---- +==== + which is responsible for converting a `Jwt` into an `Authentication`. As part of its configuration, we can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities. @@ -812,7 +958,10 @@ There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. The first is a `WebSecurityConfigurerAdapter` that configures the app as a resource server. When use Opaque Token, this `WebSecurityConfigurerAdapter` looks like: -[source,java] +.Default Opaque Token Configuration +==== +.Java +[source,java,role="primary"] ---- protected void configure(HttpSecurity http) { http @@ -823,11 +972,30 @@ protected void configure(HttpSecurity http) { } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + opaqueToken { } + } + } +} +---- +==== + If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. Replacing this is as simple as exposing the bean within the application: -[source,java] +.Custom Opaque Token Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter { @@ -846,6 +1014,28 @@ public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize("/messages/**", hasAuthority("SCOPE_message:read")) + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + opaqueToken { + introspector = myIntrospector() + } + } + } + } +} +---- +==== + The above requires the scope of `message:read` for any URL that starts with `/messages/`. Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. @@ -869,7 +1059,10 @@ And its configuration can be overridden using `introspectionUri()` and `introspe An authorization server's Introspection Uri can be configured <> or it can be supplied in the DSL: -[source,java] +.Introspection URI Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class DirectlyConfiguredIntrospectionUri extends WebSecurityConfigurerAdapter { @@ -888,6 +1081,28 @@ public class DirectlyConfiguredIntrospectionUri extends WebSecurityConfigurerAda } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class DirectlyConfiguredIntrospectionUri : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + opaqueToken { + introspectionUri = "https://idp.example.com/introspect" + introspectionClientCredentials("client", "secret") + } + } + } + } +} +---- +==== + Using `introspectionUri()` takes precedence over any configuration property. [[oauth2resourceserver-opaque-introspector-dsl]] @@ -895,7 +1110,10 @@ Using `introspectionUri()` takes precedence over any configuration property. More powerful than `introspectionUri()` is `introspector()`, which will completely replace any Boot auto configuration of `OpaqueTokenIntrospector`: -[source,java] +.Introspector Configuration +==== +.Java +[source,java,role="primary"] ---- @EnableWebSecurity public class DirectlyConfiguredIntrospector extends WebSecurityConfigurerAdapter { @@ -913,6 +1131,27 @@ public class DirectlyConfiguredIntrospector extends WebSecurityConfigurerAdapter } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@EnableWebSecurity +class DirectlyConfiguredIntrospector : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + oauth2ResourceServer { + opaqueToken { + introspector = myCustomIntrospector() + } + } + } + } +} +---- +==== + This is handy when deeper configuration, like <>, <>, or <>, is necessary. [[oauth2resourceserver-opaque-introspector-bean]]