Browse Source

Add Kotlin DSL for OAuth Authorization Server configuration

Signed-off-by: Mehrdad <mehrdad.bozorgmehr@gmail.com>
pull/18150/head
Mehrdad 1 month ago
parent
commit
7a2612deed
  1. 33
      config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt
  2. 414
      config/src/main/kotlin/org/springframework/security/config/annotation/web/OAuth2AuthorizationServerDsl.kt
  3. 27
      config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OAuth2AuthorizationServerSecurityMarker.kt
  4. 51
      config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcClientRegistrationEndpointDsl.kt
  5. 88
      config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcDsl.kt
  6. 51
      config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcLogoutEndpointDsl.kt
  7. 42
      config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcProviderConfigurationEndpointDsl.kt
  8. 56
      config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcUserInfoEndpointDsl.kt
  9. 161
      config/src/test/kotlin/org/springframework/security/config/annotation/web/OAuth2AuthorizationServerDslTests.kt

33
config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt

@ -1059,6 +1059,39 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu @@ -1059,6 +1059,39 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
this.http.oauth2ResourceServer(oauth2ResourceServerCustomizer)
}
/**
* Configures OAuth 2.1 Authorization Server support.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* oidc {
* userInfoEndpoint { }
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param oauth2AuthorizationServerConfiguration custom configuration to configure the
* OAuth 2.1 Authorization Server support
* @see [OAuth2AuthorizationServerDsl]
*/
fun oauth2AuthorizationServer(oauth2AuthorizationServerConfiguration: OAuth2AuthorizationServerDsl.() -> Unit) {
val oauth2AuthorizationServerCustomizer = OAuth2AuthorizationServerDsl().apply(oauth2AuthorizationServerConfiguration).get()
this.http.oauth2AuthorizationServer(oauth2AuthorizationServerCustomizer)
}
/**
* Configures OIDC 1.0 logout support.
*

414
config/src/main/kotlin/org/springframework/security/config/annotation/web/OAuth2AuthorizationServerDsl.kt

@ -0,0 +1,414 @@ @@ -0,0 +1,414 @@
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.security.config.annotation.web
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.*
import org.springframework.security.config.annotation.web.oauth2.server.authorization.OidcDsl
import org.springframework.security.oauth2.core.OAuth2Token
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator
/**
* A Kotlin DSL to configure [HttpSecurity] OAuth 2.1 Authorization Server support using idiomatic Kotlin code.
*
* @author Mehrdad Bozorgmehr
* @since 7.0
* @property registeredClientRepository the repository of registered clients.
* @property authorizationService the authorization service.
* @property authorizationConsentService the authorization consent service.
* @property authorizationServerSettings the authorization server settings.
* @property tokenGenerator the token generator.
*/
@SecurityMarker
class OAuth2AuthorizationServerDsl {
var registeredClientRepository: RegisteredClientRepository? = null
var authorizationService: OAuth2AuthorizationService? = null
var authorizationConsentService: OAuth2AuthorizationConsentService? = null
var authorizationServerSettings: AuthorizationServerSettings? = null
var tokenGenerator: OAuth2TokenGenerator<out OAuth2Token>? = null
private var clientAuthenticationConfig: ((OAuth2ClientAuthenticationConfigurer) -> Unit)? = null
private var authorizationServerMetadataEndpointConfig: ((OAuth2AuthorizationServerMetadataEndpointConfigurer) -> Unit)? = null
private var authorizationEndpointConfig: ((OAuth2AuthorizationEndpointConfigurer) -> Unit)? = null
private var pushedAuthorizationRequestEndpointConfig: ((OAuth2PushedAuthorizationRequestEndpointConfigurer) -> Unit)? = null
private var tokenEndpointConfig: ((OAuth2TokenEndpointConfigurer) -> Unit)? = null
private var tokenIntrospectionEndpointConfig: ((OAuth2TokenIntrospectionEndpointConfigurer) -> Unit)? = null
private var tokenRevocationEndpointConfig: ((OAuth2TokenRevocationEndpointConfigurer) -> Unit)? = null
private var deviceAuthorizationEndpointConfig: ((OAuth2DeviceAuthorizationEndpointConfigurer) -> Unit)? = null
private var deviceVerificationEndpointConfig: ((OAuth2DeviceVerificationEndpointConfigurer) -> Unit)? = null
private var clientRegistrationEndpointConfig: ((OAuth2ClientRegistrationEndpointConfigurer) -> Unit)? = null
private var oidcConfig: ((OidcConfigurer) -> Unit)? = null
/**
* Configures OAuth 2.0 Client Authentication.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* clientAuthentication {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param clientAuthenticationConfiguration custom configurations to configure OAuth 2.0 client authentication
*/
fun clientAuthentication(clientAuthenticationConfiguration: OAuth2ClientAuthenticationConfigurer.() -> Unit) {
this.clientAuthenticationConfig = clientAuthenticationConfiguration
}
/**
* Configures the OAuth 2.0 Authorization Server Metadata Endpoint.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* authorizationServerMetadataEndpoint {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param authorizationServerMetadataEndpointConfiguration custom configurations to configure the metadata endpoint
*/
fun authorizationServerMetadataEndpoint(authorizationServerMetadataEndpointConfiguration: OAuth2AuthorizationServerMetadataEndpointConfigurer.() -> Unit) {
this.authorizationServerMetadataEndpointConfig = authorizationServerMetadataEndpointConfiguration
}
/**
* Configures the OAuth 2.0 Authorization Endpoint.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* authorizationEndpoint {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param authorizationEndpointConfiguration custom configurations to configure the authorization endpoint
*/
fun authorizationEndpoint(authorizationEndpointConfiguration: OAuth2AuthorizationEndpointConfigurer.() -> Unit) {
this.authorizationEndpointConfig = authorizationEndpointConfiguration
}
/**
* Configures the OAuth 2.0 Pushed Authorization Request Endpoint.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* pushedAuthorizationRequestEndpoint {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param pushedAuthorizationRequestEndpointConfiguration custom configurations to configure the PAR endpoint
*/
fun pushedAuthorizationRequestEndpoint(pushedAuthorizationRequestEndpointConfiguration: OAuth2PushedAuthorizationRequestEndpointConfigurer.() -> Unit) {
this.pushedAuthorizationRequestEndpointConfig = pushedAuthorizationRequestEndpointConfiguration
}
/**
* Configures the OAuth 2.0 Token Endpoint.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* tokenEndpoint {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param tokenEndpointConfiguration custom configurations to configure the token endpoint
*/
fun tokenEndpoint(tokenEndpointConfiguration: OAuth2TokenEndpointConfigurer.() -> Unit) {
this.tokenEndpointConfig = tokenEndpointConfiguration
}
/**
* Configures the OAuth 2.0 Token Introspection Endpoint.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* tokenIntrospectionEndpoint {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param tokenIntrospectionEndpointConfiguration custom configurations to configure the token introspection endpoint
*/
fun tokenIntrospectionEndpoint(tokenIntrospectionEndpointConfiguration: OAuth2TokenIntrospectionEndpointConfigurer.() -> Unit) {
this.tokenIntrospectionEndpointConfig = tokenIntrospectionEndpointConfiguration
}
/**
* Configures the OAuth 2.0 Token Revocation Endpoint.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* tokenRevocationEndpoint {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param tokenRevocationEndpointConfiguration custom configurations to configure the token revocation endpoint
*/
fun tokenRevocationEndpoint(tokenRevocationEndpointConfiguration: OAuth2TokenRevocationEndpointConfigurer.() -> Unit) {
this.tokenRevocationEndpointConfig = tokenRevocationEndpointConfiguration
}
/**
* Configures the OAuth 2.0 Device Authorization Endpoint.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* deviceAuthorizationEndpoint {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param deviceAuthorizationEndpointConfiguration custom configurations to configure the device authorization endpoint
*/
fun deviceAuthorizationEndpoint(deviceAuthorizationEndpointConfiguration: OAuth2DeviceAuthorizationEndpointConfigurer.() -> Unit) {
this.deviceAuthorizationEndpointConfig = deviceAuthorizationEndpointConfiguration
}
/**
* Configures the OAuth 2.0 Device Verification Endpoint.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* deviceVerificationEndpoint {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param deviceVerificationEndpointConfiguration custom configurations to configure the device verification endpoint
*/
fun deviceVerificationEndpoint(deviceVerificationEndpointConfiguration: OAuth2DeviceVerificationEndpointConfigurer.() -> Unit) {
this.deviceVerificationEndpointConfig = deviceVerificationEndpointConfiguration
}
/**
* Configures the OAuth 2.0 Dynamic Client Registration Endpoint.
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* clientRegistrationEndpoint {
* // custom configuration
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param clientRegistrationEndpointConfiguration custom configurations to configure the client registration endpoint
*/
fun clientRegistrationEndpoint(clientRegistrationEndpointConfiguration: OAuth2ClientRegistrationEndpointConfigurer.() -> Unit) {
this.clientRegistrationEndpointConfig = clientRegistrationEndpointConfiguration
}
/**
* Configures OpenID Connect 1.0 support (disabled by default).
*
* Example:
*
* ```
* @Configuration
* @EnableWebSecurity
* class SecurityConfig {
*
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* oauth2AuthorizationServer {
* oidc {
* userInfoEndpoint {
* userInfoMapper = myUserInfoMapper
* }
* }
* }
* }
* return http.build()
* }
* }
* ```
*
* @param oidcConfiguration custom configurations to configure OpenID Connect 1.0 support
* @see [OidcDsl]
*/
fun oidc(oidcConfiguration: OidcDsl.() -> Unit) {
this.oidcConfig = OidcDsl().apply(oidcConfiguration).get()
}
internal fun get(): (OAuth2AuthorizationServerConfigurer) -> Unit {
return { oauth2AuthorizationServer ->
registeredClientRepository?.also { oauth2AuthorizationServer.registeredClientRepository(it) }
authorizationService?.also { oauth2AuthorizationServer.authorizationService(it) }
authorizationConsentService?.also { oauth2AuthorizationServer.authorizationConsentService(it) }
authorizationServerSettings?.also { oauth2AuthorizationServer.authorizationServerSettings(it) }
tokenGenerator?.also { oauth2AuthorizationServer.tokenGenerator(it) }
clientAuthenticationConfig?.also { oauth2AuthorizationServer.clientAuthentication(it) }
authorizationServerMetadataEndpointConfig?.also { oauth2AuthorizationServer.authorizationServerMetadataEndpoint(it) }
authorizationEndpointConfig?.also { oauth2AuthorizationServer.authorizationEndpoint(it) }
pushedAuthorizationRequestEndpointConfig?.also { oauth2AuthorizationServer.pushedAuthorizationRequestEndpoint(it) }
tokenEndpointConfig?.also { oauth2AuthorizationServer.tokenEndpoint(it) }
tokenIntrospectionEndpointConfig?.also { oauth2AuthorizationServer.tokenIntrospectionEndpoint(it) }
tokenRevocationEndpointConfig?.also { oauth2AuthorizationServer.tokenRevocationEndpoint(it) }
deviceAuthorizationEndpointConfig?.also { oauth2AuthorizationServer.deviceAuthorizationEndpoint(it) }
deviceVerificationEndpointConfig?.also { oauth2AuthorizationServer.deviceVerificationEndpoint(it) }
clientRegistrationEndpointConfig?.also { oauth2AuthorizationServer.clientRegistrationEndpoint(it) }
oidcConfig?.also { oauth2AuthorizationServer.oidc(it) }
}
}
}

27
config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OAuth2AuthorizationServerSecurityMarker.kt

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.security.config.annotation.web.oauth2.server.authorization
/**
* Marker annotation indicating that the annotated class is part of the OAuth2 Authorization Server Security DSL.
*
* @author Mehrdad Bozorgmehr
* @since 7.0
*/
@DslMarker
annotation class OAuth2AuthorizationServerSecurityMarker

51
config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcClientRegistrationEndpointDsl.kt

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.security.config.annotation.web.oauth2.server.authorization
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OidcClientRegistrationEndpointConfigurer
import org.springframework.security.web.authentication.AuthenticationConverter
import org.springframework.security.web.authentication.AuthenticationFailureHandler
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import java.util.function.Consumer
/**
* A Kotlin DSL to configure the OpenID Connect Dynamic Client Registration 1.0 Endpoint using idiomatic Kotlin code.
*
* @author Mehrdad Bozorgmehr
* @since 7.0
*/
@OAuth2AuthorizationServerSecurityMarker
class OidcClientRegistrationEndpointDsl {
var clientRegistrationRequestConverter: AuthenticationConverter? = null
var clientRegistrationRequestConverters: Consumer<MutableList<AuthenticationConverter>>? = null
var authenticationProviders: Consumer<MutableList<AuthenticationProvider>>? = null
var clientRegistrationResponseHandler: AuthenticationSuccessHandler? = null
var errorResponseHandler: AuthenticationFailureHandler? = null
internal fun get(): (OidcClientRegistrationEndpointConfigurer) -> Unit {
return { clientRegistrationEndpoint ->
clientRegistrationRequestConverter?.also { clientRegistrationEndpoint.clientRegistrationRequestConverter(it) }
clientRegistrationRequestConverters?.also { clientRegistrationEndpoint.clientRegistrationRequestConverters(it) }
authenticationProviders?.also { clientRegistrationEndpoint.authenticationProviders(it) }
clientRegistrationResponseHandler?.also { clientRegistrationEndpoint.clientRegistrationResponseHandler(it) }
errorResponseHandler?.also { clientRegistrationEndpoint.errorResponseHandler(it) }
}
}
}

88
config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcDsl.kt

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.security.config.annotation.web.oauth2.server.authorization
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OidcConfigurer
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OidcProviderConfigurationEndpointConfigurer
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OidcLogoutEndpointConfigurer
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OidcClientRegistrationEndpointConfigurer
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OidcUserInfoEndpointConfigurer
/**
* A Kotlin DSL to configure OpenID Connect 1.0 support using idiomatic Kotlin code.
*
* @author Mehrdad Bozorgmehr
* @since 7.0
*/
@OAuth2AuthorizationServerSecurityMarker
class OidcDsl {
private var providerConfigurationEndpointConfig: ((OidcProviderConfigurationEndpointConfigurer) -> Unit)? = null
private var logoutEndpointConfig: ((OidcLogoutEndpointConfigurer) -> Unit)? = null
private var clientRegistrationEndpointConfig: ((OidcClientRegistrationEndpointConfigurer) -> Unit)? = null
private var userInfoEndpointConfig: ((OidcUserInfoEndpointConfigurer) -> Unit)? = null
/**
* Configures the OpenID Connect 1.0 Provider Configuration Endpoint.
*
* @param providerConfigurationEndpointConfiguration custom configuration to apply
*/
fun providerConfigurationEndpoint(providerConfigurationEndpointConfiguration: OidcProviderConfigurationEndpointDsl.() -> Unit) {
this.providerConfigurationEndpointConfig = OidcProviderConfigurationEndpointDsl()
.apply(providerConfigurationEndpointConfiguration).get()
}
/**
* Configures the OpenID Connect 1.0 RP-Initiated Logout Endpoint.
*
* @param logoutEndpointConfiguration custom configuration to apply
*/
fun logoutEndpoint(logoutEndpointConfiguration: OidcLogoutEndpointDsl.() -> Unit) {
this.logoutEndpointConfig = OidcLogoutEndpointDsl()
.apply(logoutEndpointConfiguration).get()
}
/**
* Configures the OpenID Connect Dynamic Client Registration 1.0 Endpoint.
*
* @param clientRegistrationEndpointConfiguration custom configuration to apply
*/
fun clientRegistrationEndpoint(clientRegistrationEndpointConfiguration: OidcClientRegistrationEndpointDsl.() -> Unit) {
this.clientRegistrationEndpointConfig = OidcClientRegistrationEndpointDsl()
.apply(clientRegistrationEndpointConfiguration).get()
}
/**
* Configures the OpenID Connect 1.0 UserInfo Endpoint.
*
* @param userInfoEndpointConfiguration custom configuration to apply
*/
fun userInfoEndpoint(userInfoEndpointConfiguration: OidcUserInfoEndpointDsl.() -> Unit) {
this.userInfoEndpointConfig = OidcUserInfoEndpointDsl()
.apply(userInfoEndpointConfiguration).get()
}
internal fun get(): (OidcConfigurer) -> Unit {
return { oidc ->
providerConfigurationEndpointConfig?.also { oidc.providerConfigurationEndpoint(it) }
logoutEndpointConfig?.also { oidc.logoutEndpoint(it) }
clientRegistrationEndpointConfig?.also { oidc.clientRegistrationEndpoint(it) }
userInfoEndpointConfig?.also { oidc.userInfoEndpoint(it) }
}
}
}

51
config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcLogoutEndpointDsl.kt

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.security.config.annotation.web.oauth2.server.authorization
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OidcLogoutEndpointConfigurer
import org.springframework.security.web.authentication.AuthenticationConverter
import org.springframework.security.web.authentication.AuthenticationFailureHandler
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import java.util.function.Consumer
/**
* A Kotlin DSL to configure the OpenID Connect 1.0 RP-Initiated Logout Endpoint using idiomatic Kotlin code.
*
* @author Mehrdad Bozorgmehr
* @since 7.0
*/
@OAuth2AuthorizationServerSecurityMarker
class OidcLogoutEndpointDsl {
var logoutRequestConverter: AuthenticationConverter? = null
var logoutRequestConverters: Consumer<MutableList<AuthenticationConverter>>? = null
var authenticationProviders: Consumer<MutableList<AuthenticationProvider>>? = null
var logoutResponseHandler: AuthenticationSuccessHandler? = null
var errorResponseHandler: AuthenticationFailureHandler? = null
internal fun get(): (OidcLogoutEndpointConfigurer) -> Unit {
return { logoutEndpoint ->
logoutRequestConverter?.also { logoutEndpoint.logoutRequestConverter(it) }
logoutRequestConverters?.also { logoutEndpoint.logoutRequestConverters(it) }
authenticationProviders?.also { logoutEndpoint.authenticationProviders(it) }
logoutResponseHandler?.also { logoutEndpoint.logoutResponseHandler(it) }
errorResponseHandler?.also { logoutEndpoint.errorResponseHandler(it) }
}
}
}

42
config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcProviderConfigurationEndpointDsl.kt

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.security.config.annotation.web.oauth2.server.authorization
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OidcProviderConfigurationEndpointConfigurer
import org.springframework.security.oauth2.server.authorization.oidc.OidcProviderConfiguration
import java.util.function.Consumer
/**
* A Kotlin DSL to configure the OpenID Connect 1.0 Provider Configuration Endpoint using idiomatic Kotlin code.
*
* @author Mehrdad Bozorgmehr
* @since 7.0
*/
@OAuth2AuthorizationServerSecurityMarker
class OidcProviderConfigurationEndpointDsl {
var providerConfigurationCustomizer: Consumer<OidcProviderConfiguration.Builder>? = null
internal fun get(): (OidcProviderConfigurationEndpointConfigurer) -> Unit {
return { providerConfigurationEndpoint ->
providerConfigurationCustomizer?.also {
providerConfigurationEndpoint.providerConfigurationCustomizer(it)
}
}
}
}

56
config/src/main/kotlin/org/springframework/security/config/annotation/web/oauth2/server/authorization/OidcUserInfoEndpointDsl.kt

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.security.config.annotation.web.oauth2.server.authorization
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OidcUserInfoEndpointConfigurer
import org.springframework.security.oauth2.core.oidc.OidcUserInfo
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationContext
import org.springframework.security.web.authentication.AuthenticationConverter
import org.springframework.security.web.authentication.AuthenticationFailureHandler
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import java.util.function.Consumer
import java.util.function.Function
/**
* A Kotlin DSL to configure the OpenID Connect 1.0 UserInfo Endpoint using idiomatic Kotlin code.
*
* @author Mehrdad Bozorgmehr
* @since 7.0
*/
@OAuth2AuthorizationServerSecurityMarker
class OidcUserInfoEndpointDsl {
var userInfoRequestConverter: AuthenticationConverter? = null
var userInfoRequestConverters: Consumer<MutableList<AuthenticationConverter>>? = null
var authenticationProviders: Consumer<MutableList<AuthenticationProvider>>? = null
var userInfoResponseHandler: AuthenticationSuccessHandler? = null
var errorResponseHandler: AuthenticationFailureHandler? = null
var userInfoMapper: Function<OidcUserInfoAuthenticationContext, OidcUserInfo>? = null
internal fun get(): (OidcUserInfoEndpointConfigurer) -> Unit {
return { userInfoEndpoint ->
userInfoRequestConverter?.also { userInfoEndpoint.userInfoRequestConverter(it) }
userInfoRequestConverters?.also { userInfoEndpoint.userInfoRequestConverters(it) }
authenticationProviders?.also { userInfoEndpoint.authenticationProviders(it) }
userInfoResponseHandler?.also { userInfoEndpoint.userInfoResponseHandler(it) }
errorResponseHandler?.also { userInfoEndpoint.errorResponseHandler(it) }
userInfoMapper?.also { userInfoEndpoint.userInfoMapper(it) }
}
}
}

161
config/src/test/kotlin/org/springframework/security/config/annotation/web/OAuth2AuthorizationServerDslTests.kt

@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.security.config.annotation.web
import com.nimbusds.jose.jwk.JWKSet
import com.nimbusds.jose.jwk.RSAKey
import com.nimbusds.jose.jwk.source.ImmutableJWKSet
import com.nimbusds.jose.jwk.source.JWKSource
import com.nimbusds.jose.proc.SecurityContext
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.test.SpringTestContext
import org.springframework.security.config.test.SpringTestContextExtension
import org.springframework.security.oauth2.core.AuthorizationGrantType
import org.springframework.security.oauth2.core.ClientAuthenticationMethod
import org.springframework.security.oauth2.jwt.JwtDecoder
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings
import org.springframework.security.web.SecurityFilterChain
import org.springframework.test.web.servlet.MockMvc
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.interfaces.RSAPublicKey
import java.util.UUID
/**
* Tests for [OAuth2AuthorizationServerDsl]
*
* @author Mehrdad
*/
@ExtendWith(SpringTestContextExtension::class)
class OAuth2AuthorizationServerDslTests {
@JvmField
val spring = SpringTestContext(this)
@Autowired
lateinit var mockMvc: MockMvc
@Test
fun `oauth2AuthorizationServer when custom registered client repository then configuration applies`() {
this.spring.register(AuthorizationServerConfig::class.java).autowire()
}
@Configuration
@EnableWebSecurity
open class AuthorizationServerConfig {
@Bean
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
oauth2AuthorizationServer {
registeredClientRepository = registeredClientRepository()
}
}
return http.build()
}
@Bean
open fun registeredClientRepository(): RegisteredClientRepository {
val registeredClient = RegisteredClient.withId("test-client")
.clientId("test-client")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("http://localhost:8080/authorized")
.build()
return InMemoryRegisteredClientRepository(registeredClient)
}
@Bean
open fun authorizationServerSettings(): AuthorizationServerSettings {
return AuthorizationServerSettings.builder().build()
}
}
@Test
fun `oauth2AuthorizationServer when oidc configured then oidc enabled`() {
this.spring.register(AuthorizationServerOidcConfig::class.java).autowire()
}
@Configuration
@EnableWebSecurity
open class AuthorizationServerOidcConfig {
@Bean
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
oauth2AuthorizationServer {
registeredClientRepository = registeredClientRepository()
oidc {
// Enable OIDC support
}
}
}
return http.build()
}
@Bean
open fun registeredClientRepository(): RegisteredClientRepository {
val registeredClient = RegisteredClient.withId("test-client")
.clientId("test-client")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("http://localhost:8080/authorized")
.scope("openid")
.build()
return InMemoryRegisteredClientRepository(registeredClient)
}
@Bean
open fun authorizationServerSettings(): AuthorizationServerSettings {
return AuthorizationServerSettings.builder().build()
}
@Bean
open fun jwkSource(): JWKSource<SecurityContext> {
val keyPair = generateRsaKey()
val rsaKey = RSAKey.Builder(keyPair.public as RSAPublicKey)
.privateKey(keyPair.private)
.keyID(UUID.randomUUID().toString())
.build()
val jwkSet = JWKSet(rsaKey)
return ImmutableJWKSet(jwkSet)
}
@Bean
open fun jwtDecoder(jwkSource: JWKSource<SecurityContext>): JwtDecoder {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource)
}
private fun generateRsaKey(): KeyPair {
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
keyPairGenerator.initialize(2048)
return keyPairGenerator.generateKeyPair()
}
}
}
Loading…
Cancel
Save