Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
2560b54f
Commit
2560b54f
authored
Jun 10, 2019
by
Madhura Bhave
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add configuration support for Opaque Token authentication
Closes gh-15872
parent
8d44e318
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
541 additions
and
65 deletions
+541
-65
OAuth2ResourceServerProperties.java
...urity/oauth2/resource/OAuth2ResourceServerProperties.java
+71
-0
ReactiveOAuth2ResourceServerAutoConfiguration.java
...active/ReactiveOAuth2ResourceServerAutoConfiguration.java
+19
-3
ReactiveOAuth2ResourceServerJwkConfiguration.java
...eactive/ReactiveOAuth2ResourceServerJwkConfiguration.java
+49
-27
ReactiveOAuth2ResourceServerOpaqueTokenConfiguration.java
...ReactiveOAuth2ResourceServerOpaqueTokenConfiguration.java
+67
-0
OAuth2ResourceServerAutoConfiguration.java
...source/servlet/OAuth2ResourceServerAutoConfiguration.java
+20
-3
OAuth2ResourceServerJwtConfiguration.java
...esource/servlet/OAuth2ResourceServerJwtConfiguration.java
+52
-28
OAuth2ResourceServerOpaqueTokenConfiguration.java
...servlet/OAuth2ResourceServerOpaqueTokenConfiguration.java
+71
-0
ReactiveOAuth2ResourceServerAutoConfigurationTests.java
...e/ReactiveOAuth2ResourceServerAutoConfigurationTests.java
+102
-2
OAuth2ResourceServerAutoConfigurationTests.java
...e/servlet/OAuth2ResourceServerAutoConfigurationTests.java
+75
-0
spring-boot-features.adoc
...ing-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+15
-2
No files found.
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java
View file @
2560b54f
...
@@ -19,6 +19,8 @@ import java.io.IOException;
...
@@ -19,6 +19,8 @@ import java.io.IOException;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.charset.StandardCharsets
;
import
javax.annotation.PostConstruct
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException
;
import
org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException
;
import
org.springframework.core.io.Resource
;
import
org.springframework.core.io.Resource
;
...
@@ -41,6 +43,32 @@ public class OAuth2ResourceServerProperties {
...
@@ -41,6 +43,32 @@ public class OAuth2ResourceServerProperties {
return
this
.
jwt
;
return
this
.
jwt
;
}
}
private
final
OpaqueToken
opaqueToken
=
new
OpaqueToken
();
public
OpaqueToken
getOpaqueToken
()
{
return
this
.
opaqueToken
;
}
@PostConstruct
public
void
validate
()
{
if
(
this
.
getOpaqueToken
().
getIntrospectionUri
()
!=
null
)
{
if
(
this
.
getJwt
().
getJwkSetUri
()
!=
null
)
{
handleError
(
"jwt.jwk-set-uri"
);
}
if
(
this
.
getJwt
().
getIssuerUri
()
!=
null
)
{
handleError
(
"jwt.issuer-uri"
);
}
if
(
this
.
getJwt
().
getPublicKeyLocation
()
!=
null
)
{
handleError
(
"jwt.public-key-location"
);
}
}
}
private
void
handleError
(
String
property
)
{
throw
new
IllegalStateException
(
"Only one of "
+
property
+
" and opaque-token.introspection-uri should be configured."
);
}
public
static
class
Jwt
{
public
static
class
Jwt
{
/**
/**
...
@@ -109,4 +137,47 @@ public class OAuth2ResourceServerProperties {
...
@@ -109,4 +137,47 @@ public class OAuth2ResourceServerProperties {
}
}
public
static
class
OpaqueToken
{
/**
* Client id used to authenticate with the token introspection endpoint.
*/
private
String
clientId
;
/**
* Client secret used to authenticate with the token introspection endpoint.
*/
private
String
clientSecret
;
/**
* OAuth 2.0 endpoint through which token introspection is accomplished.
*/
private
String
introspectionUri
;
public
String
getClientId
()
{
return
this
.
clientId
;
}
public
void
setClientId
(
String
clientId
)
{
this
.
clientId
=
clientId
;
}
public
String
getClientSecret
()
{
return
this
.
clientSecret
;
}
public
void
setClientSecret
(
String
clientSecret
)
{
this
.
clientSecret
=
clientSecret
;
}
public
String
getIntrospectionUri
()
{
return
this
.
introspectionUri
;
}
public
void
setIntrospectionUri
(
String
introspectionUri
)
{
this
.
introspectionUri
=
introspectionUri
;
}
}
}
}
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfiguration.java
View file @
2560b54f
...
@@ -27,6 +27,8 @@ import org.springframework.context.annotation.Import;
...
@@ -27,6 +27,8 @@ import org.springframework.context.annotation.Import;
import
org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
;
import
org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
;
import
org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
;
import
org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
;
import
org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.authentication.OAuth2IntrospectionAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.introspection.ReactiveOAuth2TokenIntrospectionClient
;
/**
/**
* {@link EnableAutoConfiguration Auto-configuration} for Reactive OAuth2 resource server
* {@link EnableAutoConfiguration Auto-configuration} for Reactive OAuth2 resource server
...
@@ -38,10 +40,24 @@ import org.springframework.security.oauth2.server.resource.BearerTokenAuthentica
...
@@ -38,10 +40,24 @@ import org.springframework.security.oauth2.server.resource.BearerTokenAuthentica
@Configuration
(
proxyBeanMethods
=
false
)
@Configuration
(
proxyBeanMethods
=
false
)
@AutoConfigureBefore
(
ReactiveSecurityAutoConfiguration
.
class
)
@AutoConfigureBefore
(
ReactiveSecurityAutoConfiguration
.
class
)
@EnableConfigurationProperties
(
OAuth2ResourceServerProperties
.
class
)
@EnableConfigurationProperties
(
OAuth2ResourceServerProperties
.
class
)
@ConditionalOnClass
({
EnableWebFluxSecurity
.
class
,
BearerTokenAuthenticationToken
.
class
,
ReactiveJwtDecoder
.
class
})
@ConditionalOnClass
({
EnableWebFluxSecurity
.
class
})
@ConditionalOnWebApplication
(
type
=
ConditionalOnWebApplication
.
Type
.
REACTIVE
)
@ConditionalOnWebApplication
(
type
=
ConditionalOnWebApplication
.
Type
.
REACTIVE
)
@Import
({
ReactiveOAuth2ResourceServerJwkConfiguration
.
class
,
ReactiveOAuth2ResourceServerWebSecurityConfiguration
.
class
})
public
class
ReactiveOAuth2ResourceServerAutoConfiguration
{
public
class
ReactiveOAuth2ResourceServerAutoConfiguration
{
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnClass
({
BearerTokenAuthenticationToken
.
class
,
ReactiveJwtDecoder
.
class
})
@Import
({
ReactiveOAuth2ResourceServerJwkConfiguration
.
JwtConfiguration
.
class
,
ReactiveOAuth2ResourceServerJwkConfiguration
.
WebSecurityConfiguration
.
class
})
static
class
JwtConfiguration
{
}
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnClass
({
OAuth2IntrospectionAuthenticationToken
.
class
,
ReactiveOAuth2TokenIntrospectionClient
.
class
})
@Import
({
ReactiveOAuth2ResourceServerOpaqueTokenConfiguration
.
OpaqueTokenIntrospectionClientConfiguration
.
class
,
ReactiveOAuth2ResourceServerOpaqueTokenConfiguration
.
WebSecurityConfiguration
.
class
})
static
class
OpaqueTokenConfiguration
{
}
}
}
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java
View file @
2560b54f
...
@@ -20,6 +20,7 @@ import java.security.interfaces.RSAPublicKey;
...
@@ -20,6 +20,7 @@ import java.security.interfaces.RSAPublicKey;
import
java.security.spec.X509EncodedKeySpec
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.util.Base64
;
import
java.util.Base64
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition
;
import
org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition
;
...
@@ -28,13 +29,16 @@ import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2Res
...
@@ -28,13 +29,16 @@ import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2Res
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Conditional
;
import
org.springframework.context.annotation.Conditional
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.security.config.web.server.ServerHttpSecurity
;
import
org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder
;
import
org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder
;
import
org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
;
import
org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
;
import
org.springframework.security.oauth2.jwt.ReactiveJwtDecoders
;
import
org.springframework.security.oauth2.jwt.ReactiveJwtDecoders
;
import
org.springframework.security.web.server.SecurityWebFilterChain
;
/**
/**
* Configures a {@link ReactiveJwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI
* Configures a {@link ReactiveJwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI
* or Public Key configuration is available.
* or Public Key configuration is available. Also configures a
* {@link SecurityWebFilterChain} if a {@link ReactiveJwtDecoder} bean is found.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
* @author Artsiom Yudovin
* @author Artsiom Yudovin
...
@@ -42,38 +46,56 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders;
...
@@ -42,38 +46,56 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders;
@Configuration
(
proxyBeanMethods
=
false
)
@Configuration
(
proxyBeanMethods
=
false
)
class
ReactiveOAuth2ResourceServerJwkConfiguration
{
class
ReactiveOAuth2ResourceServerJwkConfiguration
{
private
final
OAuth2ResourceServerProperties
.
Jwt
properties
;
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnMissingBean
(
ReactiveJwtDecoder
.
class
)
static
class
JwtConfiguration
{
ReactiveOAuth2ResourceServerJwkConfiguration
(
OAuth2ResourceServerProperties
properties
)
{
private
final
OAuth2ResourceServerProperties
.
Jwt
properties
;
this
.
properties
=
properties
.
getJwt
();
}
@Bean
JwtConfiguration
(
OAuth2ResourceServerProperties
properties
)
{
@ConditionalOnProperty
(
name
=
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri"
)
this
.
properties
=
properties
.
getJwt
();
@ConditionalOnMissingBean
}
public
ReactiveJwtDecoder
jwtDecoder
()
{
return
new
NimbusReactiveJwtDecoder
(
this
.
properties
.
getJwkSetUri
());
}
@Bean
@Bean
@Conditional
(
KeyValueCondition
.
class
)
@ConditionalOnProperty
(
name
=
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri"
)
@ConditionalOnMissingBean
public
ReactiveJwtDecoder
jwtDecoder
()
{
public
NimbusReactiveJwtDecoder
jwtDecoderByPublicKeyValue
()
throws
Exception
{
return
new
NimbusReactiveJwtDecoder
(
this
.
properties
.
getJwkSetUri
());
RSAPublicKey
publicKey
=
(
RSAPublicKey
)
KeyFactory
.
getInstance
(
"RSA"
)
}
.
generatePublic
(
new
X509EncodedKeySpec
(
getKeySpec
(
this
.
properties
.
readPublicKey
())));
return
NimbusReactiveJwtDecoder
.
withPublicKey
(
publicKey
).
build
();
@Bean
}
@Conditional
(
KeyValueCondition
.
class
)
public
NimbusReactiveJwtDecoder
jwtDecoderByPublicKeyValue
()
throws
Exception
{
RSAPublicKey
publicKey
=
(
RSAPublicKey
)
KeyFactory
.
getInstance
(
"RSA"
)
.
generatePublic
(
new
X509EncodedKeySpec
(
getKeySpec
(
this
.
properties
.
readPublicKey
())));
return
NimbusReactiveJwtDecoder
.
withPublicKey
(
publicKey
).
build
();
}
private
byte
[]
getKeySpec
(
String
keyValue
)
{
keyValue
=
keyValue
.
replace
(
"-----BEGIN PUBLIC KEY-----"
,
""
).
replace
(
"-----END PUBLIC KEY-----"
,
""
);
return
Base64
.
getMimeDecoder
().
decode
(
keyValue
);
}
@Bean
@Conditional
(
IssuerUriCondition
.
class
)
public
ReactiveJwtDecoder
jwtDecoderByIssuerUri
()
{
return
ReactiveJwtDecoders
.
fromOidcIssuerLocation
(
this
.
properties
.
getIssuerUri
());
}
private
byte
[]
getKeySpec
(
String
keyValue
)
{
keyValue
=
keyValue
.
replace
(
"-----BEGIN PUBLIC KEY-----"
,
""
).
replace
(
"-----END PUBLIC KEY-----"
,
""
);
return
Base64
.
getMimeDecoder
().
decode
(
keyValue
);
}
}
@Bean
@Configuration
(
proxyBeanMethods
=
false
)
@Conditional
(
IssuerUriCondition
.
class
)
@ConditionalOnMissingBean
(
SecurityWebFilterChain
.
class
)
@ConditionalOnMissingBean
static
class
WebSecurityConfiguration
{
public
ReactiveJwtDecoder
jwtDecoderByIssuerUri
()
{
return
ReactiveJwtDecoders
.
fromOidcIssuerLocation
(
this
.
properties
.
getIssuerUri
());
@Bean
@ConditionalOnBean
(
ReactiveJwtDecoder
.
class
)
public
SecurityWebFilterChain
springSecurityFilterChain
(
ServerHttpSecurity
http
,
ReactiveJwtDecoder
jwtDecoder
)
{
http
.
authorizeExchange
().
anyExchange
().
authenticated
().
and
().
oauth2ResourceServer
().
jwt
()
.
jwtDecoder
(
jwtDecoder
);
return
http
.
build
();
}
}
}
}
}
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServer
WebSecurity
Configuration.java
→
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServer
OpaqueToken
Configuration.java
View file @
2560b54f
...
@@ -13,32 +13,55 @@
...
@@ -13,32 +13,55 @@
* See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and
* limitations under the License.
* limitations under the License.
*/
*/
package
org
.
springframework
.
boot
.
autoconfigure
.
security
.
oauth2
.
resource
.
reactive
;
package
org
.
springframework
.
boot
.
autoconfigure
.
security
.
oauth2
.
resource
.
reactive
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.security.config.web.server.ServerHttpSecurity
;
import
org.springframework.security.config.web.server.ServerHttpSecurity
;
import
org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
;
import
org.springframework.security.oauth2.server.resource.introspection.NimbusReactiveOAuth2TokenIntrospectionClient
;
import
org.springframework.security.oauth2.server.resource.introspection.ReactiveOAuth2TokenIntrospectionClient
;
import
org.springframework.security.web.server.SecurityWebFilterChain
;
import
org.springframework.security.web.server.SecurityWebFilterChain
;
/**
/**
* Configures a {@link SecurityWebFilterChain} for Reactive OAuth2 resource server support
* Configures a {@link ReactiveOAuth2TokenIntrospectionClient} when a token introspection
* if a {@link ReactiveJwtDecoder} bean is present.
* endpoint is available. Also configures a {@link SecurityWebFilterChain} if a
* {@link ReactiveOAuth2TokenIntrospectionClient} bean is found.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
*/
*/
@Configuration
(
proxyBeanMethods
=
false
)
class
ReactiveOAuth2ResourceServerOpaqueTokenConfiguration
{
@ConditionalOnBean
(
ReactiveJwtDecoder
.
class
)
class
ReactiveOAuth2ResourceServerWebSecurityConfiguration
{
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnMissingBean
(
ReactiveOAuth2TokenIntrospectionClient
.
class
)
@Bean
static
class
OpaqueTokenIntrospectionClientConfiguration
{
@ConditionalOnMissingBean
public
SecurityWebFilterChain
springSecurityFilterChain
(
ServerHttpSecurity
http
,
ReactiveJwtDecoder
jwtDecoder
)
{
@Bean
http
.
authorizeExchange
().
anyExchange
().
authenticated
().
and
().
oauth2ResourceServer
().
jwt
()
@ConditionalOnProperty
(
name
=
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri"
)
.
jwtDecoder
(
jwtDecoder
);
public
NimbusReactiveOAuth2TokenIntrospectionClient
oAuth2TokenIntrospectionClient
(
return
http
.
build
();
OAuth2ResourceServerProperties
properties
)
{
OAuth2ResourceServerProperties
.
OpaqueToken
opaqueToken
=
properties
.
getOpaqueToken
();
return
new
NimbusReactiveOAuth2TokenIntrospectionClient
(
opaqueToken
.
getIntrospectionUri
(),
opaqueToken
.
getClientId
(),
opaqueToken
.
getClientSecret
());
}
}
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnMissingBean
(
SecurityWebFilterChain
.
class
)
static
class
WebSecurityConfiguration
{
@Bean
@ConditionalOnBean
(
ReactiveOAuth2TokenIntrospectionClient
.
class
)
public
SecurityWebFilterChain
springSecurityFilterChain
(
ServerHttpSecurity
http
)
{
http
.
authorizeExchange
().
anyExchange
().
authenticated
().
and
().
oauth2ResourceServer
().
opaqueToken
();
return
http
.
build
();
}
}
}
}
}
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java
View file @
2560b54f
...
@@ -26,9 +26,11 @@ import org.springframework.context.annotation.Configuration;
...
@@ -26,9 +26,11 @@ import org.springframework.context.annotation.Configuration;
import
org.springframework.context.annotation.Import
;
import
org.springframework.context.annotation.Import
;
import
org.springframework.security.oauth2.jwt.JwtDecoder
;
import
org.springframework.security.oauth2.jwt.JwtDecoder
;
import
org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.authentication.OAuth2IntrospectionAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.introspection.OAuth2TokenIntrospectionClient
;
/**
/**
* {@link EnableAutoConfiguration Auto-configuration} for OAuth resource server support.
* {@link EnableAutoConfiguration Auto-configuration} for OAuth
2
resource server support.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
* @since 2.1.0
* @since 2.1.0
...
@@ -36,9 +38,24 @@ import org.springframework.security.oauth2.server.resource.authentication.JwtAut
...
@@ -36,9 +38,24 @@ import org.springframework.security.oauth2.server.resource.authentication.JwtAut
@Configuration
(
proxyBeanMethods
=
false
)
@Configuration
(
proxyBeanMethods
=
false
)
@AutoConfigureBefore
(
SecurityAutoConfiguration
.
class
)
@AutoConfigureBefore
(
SecurityAutoConfiguration
.
class
)
@EnableConfigurationProperties
(
OAuth2ResourceServerProperties
.
class
)
@EnableConfigurationProperties
(
OAuth2ResourceServerProperties
.
class
)
@ConditionalOnClass
({
JwtAuthenticationToken
.
class
,
JwtDecoder
.
class
})
@ConditionalOnWebApplication
(
type
=
ConditionalOnWebApplication
.
Type
.
SERVLET
)
@ConditionalOnWebApplication
(
type
=
ConditionalOnWebApplication
.
Type
.
SERVLET
)
@Import
({
OAuth2ResourceServerJwtConfiguration
.
class
,
OAuth2ResourceServerWebSecurityConfiguration
.
class
})
public
class
OAuth2ResourceServerAutoConfiguration
{
public
class
OAuth2ResourceServerAutoConfiguration
{
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnClass
({
JwtAuthenticationToken
.
class
,
JwtDecoder
.
class
})
@Import
({
OAuth2ResourceServerJwtConfiguration
.
JwtDecoderConfiguration
.
class
,
OAuth2ResourceServerJwtConfiguration
.
OAuth2WebSecurityConfigurerAdapter
.
class
})
static
class
JwtConfiguration
{
}
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnClass
({
OAuth2IntrospectionAuthenticationToken
.
class
,
OAuth2TokenIntrospectionClient
.
class
})
@Import
({
OAuth2ResourceServerOpaqueTokenConfiguration
.
OpaqueTokenIntrospectionClientConfiguration
.
class
,
OAuth2ResourceServerOpaqueTokenConfiguration
.
OAuth2WebSecurityConfigurerAdapter
.
class
})
static
class
OpaqueTokenConfiguration
{
}
}
}
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java
View file @
2560b54f
...
@@ -20,6 +20,7 @@ import java.security.interfaces.RSAPublicKey;
...
@@ -20,6 +20,7 @@ import java.security.interfaces.RSAPublicKey;
import
java.security.spec.X509EncodedKeySpec
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.util.Base64
;
import
java.util.Base64
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition
;
import
org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition
;
...
@@ -28,6 +29,8 @@ import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2Res
...
@@ -28,6 +29,8 @@ import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2Res
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Conditional
;
import
org.springframework.context.annotation.Conditional
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
;
import
org.springframework.security.oauth2.jose.jws.SignatureAlgorithm
;
import
org.springframework.security.oauth2.jose.jws.SignatureAlgorithm
;
import
org.springframework.security.oauth2.jwt.JwtDecoder
;
import
org.springframework.security.oauth2.jwt.JwtDecoder
;
import
org.springframework.security.oauth2.jwt.JwtDecoders
;
import
org.springframework.security.oauth2.jwt.JwtDecoders
;
...
@@ -35,7 +38,8 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
...
@@ -35,7 +38,8 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
/**
/**
* Configures a {@link JwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI or Public
* Configures a {@link JwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI or Public
* Key configuration is available.
* Key configuration is available. Also configures a {@link WebSecurityConfigurerAdapter}
* if a {@link JwtDecoder} bean is found.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
* @author Artsiom Yudovin
* @author Artsiom Yudovin
...
@@ -43,39 +47,59 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
...
@@ -43,39 +47,59 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
@Configuration
(
proxyBeanMethods
=
false
)
@Configuration
(
proxyBeanMethods
=
false
)
class
OAuth2ResourceServerJwtConfiguration
{
class
OAuth2ResourceServerJwtConfiguration
{
private
final
OAuth2ResourceServerProperties
.
Jwt
properties
;
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnMissingBean
(
JwtDecoder
.
class
)
static
class
JwtDecoderConfiguration
{
OAuth2ResourceServerJwtConfiguration
(
OAuth2ResourceServerProperties
properties
)
{
private
final
OAuth2ResourceServerProperties
.
Jwt
properties
;
this
.
properties
=
properties
.
getJwt
();
}
@Bean
JwtDecoderConfiguration
(
OAuth2ResourceServerProperties
properties
)
{
@ConditionalOnProperty
(
name
=
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri"
)
this
.
properties
=
properties
.
getJwt
();
@ConditionalOnMissingBean
}
public
JwtDecoder
jwtDecoderByJwkKeySetUri
()
{
return
NimbusJwtDecoder
.
withJwkSetUri
(
this
.
properties
.
getJwkSetUri
())
.
jwsAlgorithm
(
SignatureAlgorithm
.
from
(
this
.
properties
.
getJwsAlgorithm
())).
build
();
}
@Bean
@Bean
@Conditional
(
KeyValueCondition
.
class
)
@ConditionalOnProperty
(
name
=
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri"
)
@ConditionalOnMissingBean
public
JwtDecoder
jwtDecoderByJwkKeySetUri
()
{
public
JwtDecoder
jwtDecoderByPublicKeyValue
()
throws
Exception
{
return
NimbusJwtDecoder
.
withJwkSetUri
(
this
.
properties
.
getJwkSetUri
())
RSAPublicKey
publicKey
=
(
RSAPublicKey
)
KeyFactory
.
getInstance
(
"RSA"
)
.
jwsAlgorithm
(
SignatureAlgorithm
.
from
(
this
.
properties
.
getJwsAlgorithm
())).
build
();
.
generatePublic
(
new
X509EncodedKeySpec
(
getKeySpec
(
this
.
properties
.
readPublicKey
())));
}
return
NimbusJwtDecoder
.
withPublicKey
(
publicKey
).
build
();
}
@Bean
@Conditional
(
KeyValueCondition
.
class
)
public
JwtDecoder
jwtDecoderByPublicKeyValue
()
throws
Exception
{
RSAPublicKey
publicKey
=
(
RSAPublicKey
)
KeyFactory
.
getInstance
(
"RSA"
)
.
generatePublic
(
new
X509EncodedKeySpec
(
getKeySpec
(
this
.
properties
.
readPublicKey
())));
return
NimbusJwtDecoder
.
withPublicKey
(
publicKey
).
build
();
}
private
byte
[]
getKeySpec
(
String
keyValue
)
{
keyValue
=
keyValue
.
replace
(
"-----BEGIN PUBLIC KEY-----"
,
""
).
replace
(
"-----END PUBLIC KEY-----"
,
""
);
return
Base64
.
getMimeDecoder
().
decode
(
keyValue
);
}
@Bean
@Conditional
(
IssuerUriCondition
.
class
)
public
JwtDecoder
jwtDecoderByIssuerUri
()
{
return
JwtDecoders
.
fromOidcIssuerLocation
(
this
.
properties
.
getIssuerUri
());
}
private
byte
[]
getKeySpec
(
String
keyValue
)
{
keyValue
=
keyValue
.
replace
(
"-----BEGIN PUBLIC KEY-----"
,
""
).
replace
(
"-----END PUBLIC KEY-----"
,
""
);
return
Base64
.
getMimeDecoder
().
decode
(
keyValue
);
}
}
@Bean
@Configuration
(
proxyBeanMethods
=
false
)
@Conditional
(
IssuerUriCondition
.
class
)
@ConditionalOnMissingBean
(
WebSecurityConfigurerAdapter
.
class
)
@ConditionalOnMissingBean
static
class
OAuth2WebSecurityConfigurerAdapter
{
public
JwtDecoder
jwtDecoderByIssuerUri
()
{
return
JwtDecoders
.
fromOidcIssuerLocation
(
this
.
properties
.
getIssuerUri
());
@Bean
@ConditionalOnBean
(
JwtDecoder
.
class
)
public
WebSecurityConfigurerAdapter
jwtDecoderWebSecurityConfigurerAdapter
()
{
return
new
WebSecurityConfigurerAdapter
()
{
@Override
protected
void
configure
(
HttpSecurity
http
)
throws
Exception
{
http
.
authorizeRequests
().
anyRequest
().
authenticated
().
and
().
oauth2ResourceServer
().
jwt
();
}
};
}
}
}
}
}
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServer
WebSecurity
Configuration.java
→
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServer
OpaqueToken
Configuration.java
View file @
2560b54f
...
@@ -17,27 +17,53 @@ package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
...
@@ -17,27 +17,53 @@ package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
;
import
org.springframework.security.oauth2.jwt.JwtDecoder
;
import
org.springframework.security.oauth2.server.resource.introspection.NimbusOAuth2TokenIntrospectionClient
;
import
org.springframework.security.oauth2.server.resource.introspection.OAuth2TokenIntrospectionClient
;
/**
/**
* {@link WebSecurityConfigurerAdapter} for OAuth2 resource server support.
* Configures a {@link OAuth2TokenIntrospectionClient} when a token introspection endpoint
* is available. Also configures a {@link WebSecurityConfigurerAdapter} if a
* {@link OAuth2TokenIntrospectionClient} bean is found.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
*/
*/
@Configuration
(
proxyBeanMethods
=
false
)
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnMissingBean
(
WebSecurityConfigurerAdapter
.
class
)
class
OAuth2ResourceServerOpaqueTokenConfiguration
{
class
OAuth2ResourceServerWebSecurityConfiguration
{
@Configuration
(
proxyBeanMethods
=
false
)
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOn
Bean
(
JwtDecoder
.
class
)
@ConditionalOn
MissingBean
(
OAuth2TokenIntrospectionClient
.
class
)
static
class
O
Auth2WebSecurityConfigurerAdapter
extends
WebSecurityConfigurerAdapter
{
static
class
O
paqueTokenIntrospectionClientConfiguration
{
@Override
@Bean
protected
void
configure
(
HttpSecurity
http
)
throws
Exception
{
@ConditionalOnProperty
(
name
=
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri"
)
http
.
authorizeRequests
().
anyRequest
().
authenticated
().
and
().
oauth2ResourceServer
().
jwt
();
public
NimbusOAuth2TokenIntrospectionClient
oAuth2TokenIntrospectionClient
(
OAuth2ResourceServerProperties
properties
)
{
OAuth2ResourceServerProperties
.
OpaqueToken
opaqueToken
=
properties
.
getOpaqueToken
();
return
new
NimbusOAuth2TokenIntrospectionClient
(
opaqueToken
.
getIntrospectionUri
(),
opaqueToken
.
getClientId
(),
opaqueToken
.
getClientSecret
());
}
}
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnMissingBean
(
WebSecurityConfigurerAdapter
.
class
)
static
class
OAuth2WebSecurityConfigurerAdapter
{
@Bean
@ConditionalOnBean
(
OAuth2TokenIntrospectionClient
.
class
)
public
WebSecurityConfigurerAdapter
opaqueTokenWebSecurityConfigurerAdapter
()
{
return
new
WebSecurityConfigurerAdapter
()
{
@Override
protected
void
configure
(
HttpSecurity
http
)
throws
Exception
{
http
.
authorizeRequests
().
anyRequest
().
authenticated
().
and
().
oauth2ResourceServer
().
opaqueToken
();
}
};
}
}
}
}
...
...
spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java
View file @
2560b54f
...
@@ -46,6 +46,10 @@ import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
...
@@ -46,6 +46,10 @@ import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import
org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
;
import
org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
;
import
org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager
;
import
org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager
;
import
org.springframework.security.oauth2.server.resource.authentication.OAuth2IntrospectionAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.authentication.OAuth2IntrospectionReactiveAuthenticationManager
;
import
org.springframework.security.oauth2.server.resource.introspection.OAuth2TokenIntrospectionClient
;
import
org.springframework.security.oauth2.server.resource.introspection.ReactiveOAuth2TokenIntrospectionClient
;
import
org.springframework.security.web.server.MatcherSecurityWebFilterChain
;
import
org.springframework.security.web.server.MatcherSecurityWebFilterChain
;
import
org.springframework.security.web.server.SecurityWebFilterChain
;
import
org.springframework.security.web.server.SecurityWebFilterChain
;
import
org.springframework.security.web.server.authentication.AuthenticationWebFilter
;
import
org.springframework.security.web.server.authentication.AuthenticationWebFilter
;
...
@@ -204,6 +208,81 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
...
@@ -204,6 +208,81 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
});
});
}
}
@Test
void
autoConfigurationWhenIntrospectionUriAvailableShouldConfigureIntrospectionClient
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.opaque-token.client-id=my-client-id"
,
"spring.security.oauth2.resourceserver.opaque-token.client-secret=my-client-secret"
)
.
run
((
context
)
->
{
assertThat
(
context
).
hasSingleBean
(
ReactiveOAuth2TokenIntrospectionClient
.
class
);
assertFilterConfiguredWithOpaqueTokenAuthenticationManager
(
context
);
});
}
@Test
void
oAuth2TokenIntrospectionClientIsConditionalOnMissingBean
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
)
.
withUserConfiguration
(
OAuth2TokenIntrospectionClientConfig
.
class
)
.
run
((
this
::
assertFilterConfiguredWithOpaqueTokenAuthenticationManager
));
}
@Test
void
autoConfigurationForOpaqueTokenWhenSecurityWebFilterChainConfigPresentShouldNotAddOne
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.opaque-token.client-id=my-client-id"
,
"spring.security.oauth2.resourceserver.opaque-token.client-secret=my-client-secret"
)
.
withUserConfiguration
(
SecurityWebFilterChainConfig
.
class
).
run
((
context
)
->
{
assertThat
(
context
).
hasSingleBean
(
SecurityWebFilterChain
.
class
);
assertThat
(
context
).
hasBean
(
"testSpringSecurityFilterChain"
);
});
}
@Test
void
autoConfigurationWhenIntrospectionUriAvailableShouldBeConditionalOnClass
()
{
this
.
contextRunner
.
withClassLoader
(
new
FilteredClassLoader
(
OAuth2IntrospectionAuthenticationToken
.
class
))
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.opaque-token.client-id=my-client-id"
,
"spring.security.oauth2.resourceserver.opaque-token.client-secret=my-client-secret"
)
.
run
((
context
)
->
assertThat
(
context
).
doesNotHaveBean
(
OAuth2TokenIntrospectionClient
.
class
));
}
@Test
void
autoConfigurationWhenBothJwkSetUriAndTokenIntrospectionUriSetShouldFail
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com"
)
.
run
((
context
)
->
assertThat
(
context
).
hasFailed
().
getFailure
().
hasMessageContaining
(
"Only one of jwt.jwk-set-uri and opaque-token.introspection-uri should be configured."
));
}
@Test
void
autoConfigurationWhenBothJwtIssuerUriAndTokenIntrospectionUriSetShouldFail
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.jwt.issuer-uri=https://jwk-oidc-issuer-location.com"
)
.
run
((
context
)
->
assertThat
(
context
).
hasFailed
().
getFailure
().
hasMessageContaining
(
"Only one of jwt.issuer-uri and opaque-token.introspection-uri should be configured."
));
}
@Test
void
autoConfigurationWhenBothJwtKeyLocationAndTokenIntrospectionUriSetShouldFail
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location"
)
.
run
((
context
)
->
assertThat
(
context
).
hasFailed
().
getFailure
().
hasMessageContaining
(
"Only one of jwt.public-key-location and opaque-token.introspection-uri should be configured."
));
}
private
void
assertFilterConfiguredWithJwtAuthenticationManager
(
AssertableReactiveWebApplicationContext
context
)
{
private
void
assertFilterConfiguredWithJwtAuthenticationManager
(
AssertableReactiveWebApplicationContext
context
)
{
MatcherSecurityWebFilterChain
filterChain
=
(
MatcherSecurityWebFilterChain
)
context
MatcherSecurityWebFilterChain
filterChain
=
(
MatcherSecurityWebFilterChain
)
context
.
getBean
(
BeanIds
.
SPRING_SECURITY_FILTER_CHAIN
);
.
getBean
(
BeanIds
.
SPRING_SECURITY_FILTER_CHAIN
);
...
@@ -213,7 +292,18 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
...
@@ -213,7 +292,18 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
ReactiveAuthenticationManager
authenticationManager
=
(
ReactiveAuthenticationManager
)
ReflectionTestUtils
ReactiveAuthenticationManager
authenticationManager
=
(
ReactiveAuthenticationManager
)
ReflectionTestUtils
.
getField
(
webFilter
,
"authenticationManager"
);
.
getField
(
webFilter
,
"authenticationManager"
);
assertThat
(
authenticationManager
).
isInstanceOf
(
JwtReactiveAuthenticationManager
.
class
);
assertThat
(
authenticationManager
).
isInstanceOf
(
JwtReactiveAuthenticationManager
.
class
);
}
private
void
assertFilterConfiguredWithOpaqueTokenAuthenticationManager
(
AssertableReactiveWebApplicationContext
context
)
{
MatcherSecurityWebFilterChain
filterChain
=
(
MatcherSecurityWebFilterChain
)
context
.
getBean
(
BeanIds
.
SPRING_SECURITY_FILTER_CHAIN
);
Stream
<
WebFilter
>
filters
=
filterChain
.
getWebFilters
().
toStream
();
AuthenticationWebFilter
webFilter
=
(
AuthenticationWebFilter
)
filters
.
filter
((
f
)
->
f
instanceof
AuthenticationWebFilter
).
findFirst
().
orElse
(
null
);
ReactiveAuthenticationManager
authenticationManager
=
(
ReactiveAuthenticationManager
)
ReflectionTestUtils
.
getField
(
webFilter
,
"authenticationManager"
);
assertThat
(
authenticationManager
).
isInstanceOf
(
OAuth2IntrospectionReactiveAuthenticationManager
.
class
);
}
}
private
String
cleanIssuerPath
(
String
issuer
)
{
private
String
cleanIssuerPath
(
String
issuer
)
{
...
@@ -269,13 +359,23 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
...
@@ -269,13 +359,23 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
}
}
@Configuration
(
proxyBeanMethods
=
false
)
static
class
OAuth2TokenIntrospectionClientConfig
{
@Bean
public
ReactiveOAuth2TokenIntrospectionClient
decoder
()
{
return
mock
(
ReactiveOAuth2TokenIntrospectionClient
.
class
);
}
}
@Configuration
(
proxyBeanMethods
=
false
)
@Configuration
(
proxyBeanMethods
=
false
)
static
class
SecurityWebFilterChainConfig
{
static
class
SecurityWebFilterChainConfig
{
@Bean
@Bean
SecurityWebFilterChain
testSpringSecurityFilterChain
(
ServerHttpSecurity
http
,
ReactiveJwtDecoder
decoder
)
{
SecurityWebFilterChain
testSpringSecurityFilterChain
(
ServerHttpSecurity
http
)
{
http
.
authorizeExchange
().
pathMatchers
(
"/message/**"
).
hasRole
(
"ADMIN"
).
anyExchange
().
authenticated
().
and
()
http
.
authorizeExchange
().
pathMatchers
(
"/message/**"
).
hasRole
(
"ADMIN"
).
anyExchange
().
authenticated
().
and
()
.
oauth2ResourceServer
().
jwt
().
jwtDecoder
(
decoder
);
.
httpBasic
(
);
return
http
.
build
();
return
http
.
build
();
}
}
...
...
spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java
View file @
2560b54f
...
@@ -43,6 +43,8 @@ import org.springframework.security.config.BeanIds;
...
@@ -43,6 +43,8 @@ import org.springframework.security.config.BeanIds;
import
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
;
import
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
;
import
org.springframework.security.oauth2.jwt.JwtDecoder
;
import
org.springframework.security.oauth2.jwt.JwtDecoder
;
import
org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.authentication.OAuth2IntrospectionAuthenticationToken
;
import
org.springframework.security.oauth2.server.resource.introspection.OAuth2TokenIntrospectionClient
;
import
org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter
;
import
org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter
;
import
org.springframework.security.web.FilterChainProxy
;
import
org.springframework.security.web.FilterChainProxy
;
import
org.springframework.security.web.SecurityFilterChain
;
import
org.springframework.security.web.SecurityFilterChain
;
...
@@ -221,6 +223,68 @@ class OAuth2ResourceServerAutoConfigurationTests {
...
@@ -221,6 +223,68 @@ class OAuth2ResourceServerAutoConfigurationTests {
.
run
((
context
)
->
assertThat
(
getBearerTokenFilter
(
context
)).
isNull
());
.
run
((
context
)
->
assertThat
(
getBearerTokenFilter
(
context
)).
isNull
());
}
}
@Test
void
autoConfigurationWhenIntrospectionUriAvailableShouldConfigureIntrospectionClient
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.opaque-token.client-id=my-client-id"
,
"spring.security.oauth2.resourceserver.opaque-token.client-secret=my-client-secret"
)
.
run
((
context
)
->
{
assertThat
(
context
).
hasSingleBean
(
OAuth2TokenIntrospectionClient
.
class
);
assertThat
(
getBearerTokenFilter
(
context
)).
isNotNull
();
});
}
@Test
void
oAuth2TokenIntrospectionClientIsConditionalOnMissingBean
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
)
.
withUserConfiguration
(
OAuth2TokenIntrospectionClientConfig
.
class
)
.
run
((
context
)
->
assertThat
(
getBearerTokenFilter
(
context
)).
isNotNull
());
}
@Test
void
autoConfigurationWhenIntrospectionUriAvailableShouldBeConditionalOnClass
()
{
this
.
contextRunner
.
withClassLoader
(
new
FilteredClassLoader
(
OAuth2IntrospectionAuthenticationToken
.
class
))
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.opaque-token.client-id=my-client-id"
,
"spring.security.oauth2.resourceserver.opaque-token.client-secret=my-client-secret"
)
.
run
((
context
)
->
assertThat
(
context
).
doesNotHaveBean
(
OAuth2TokenIntrospectionClient
.
class
));
}
@Test
void
autoConfigurationWhenBothJwkSetUriAndTokenIntrospectionUriSetShouldFail
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com"
)
.
run
((
context
)
->
assertThat
(
context
).
hasFailed
().
getFailure
().
hasMessageContaining
(
"Only one of jwt.jwk-set-uri and opaque-token.introspection-uri should be configured."
));
}
@Test
void
autoConfigurationWhenBothJwtIssuerUriAndTokenIntrospectionUriSetShouldFail
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.jwt.issuer-uri=https://jwk-oidc-issuer-location.com"
)
.
run
((
context
)
->
assertThat
(
context
).
hasFailed
().
getFailure
().
hasMessageContaining
(
"Only one of jwt.issuer-uri and opaque-token.introspection-uri should be configured."
));
}
@Test
void
autoConfigurationWhenBothJwtKeyLocationAndTokenIntrospectionUriSetShouldFail
()
{
this
.
contextRunner
.
withPropertyValues
(
"spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://check-token.com"
,
"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location"
)
.
run
((
context
)
->
assertThat
(
context
).
hasFailed
().
getFailure
().
hasMessageContaining
(
"Only one of jwt.public-key-location and opaque-token.introspection-uri should be configured."
));
}
private
Filter
getBearerTokenFilter
(
AssertableWebApplicationContext
context
)
{
private
Filter
getBearerTokenFilter
(
AssertableWebApplicationContext
context
)
{
FilterChainProxy
filterChain
=
(
FilterChainProxy
)
context
.
getBean
(
BeanIds
.
SPRING_SECURITY_FILTER_CHAIN
);
FilterChainProxy
filterChain
=
(
FilterChainProxy
)
context
.
getBean
(
BeanIds
.
SPRING_SECURITY_FILTER_CHAIN
);
List
<
SecurityFilterChain
>
filterChains
=
filterChain
.
getFilterChains
();
List
<
SecurityFilterChain
>
filterChains
=
filterChain
.
getFilterChains
();
...
@@ -278,4 +342,15 @@ class OAuth2ResourceServerAutoConfigurationTests {
...
@@ -278,4 +342,15 @@ class OAuth2ResourceServerAutoConfigurationTests {
}
}
@Configuration
(
proxyBeanMethods
=
false
)
@EnableWebSecurity
static
class
OAuth2TokenIntrospectionClientConfig
{
@Bean
public
OAuth2TokenIntrospectionClient
decoder
()
{
return
mock
(
OAuth2TokenIntrospectionClient
.
class
);
}
}
}
}
spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
View file @
2560b54f
...
@@ -3801,8 +3801,8 @@ In other words, the two configurations in the following example use the Google p
...
@@ -3801,8 +3801,8 @@ In other words, the two configurations in the following example use the Google p
[[boot-features-security-oauth2-server]]
[[boot-features-security-oauth2-server]]
==== Resource Server
==== Resource Server
If you have `spring-security-oauth2-resource-server` on your classpath, Spring Boot can
If you have `spring-security-oauth2-resource-server` on your classpath, Spring Boot can
set up an OAuth2 Resource Server
as long as a JWK Set URI or OIDC Issuer URI is specified,
set up an OAuth2 Resource Server
. For JWT configuration, a JWK Set URI or OIDC Issuer URI
as shown in the following examples:
needs to be specified,
as shown in the following examples:
[source,properties,indent=0]
[source,properties,indent=0]
----
----
...
@@ -3825,7 +3825,20 @@ The same properties are applicable for both servlet and reactive applications.
...
@@ -3825,7 +3825,20 @@ The same properties are applicable for both servlet and reactive applications.
Alternatively, you can define your own `JwtDecoder` bean for servlet applications
Alternatively, you can define your own `JwtDecoder` bean for servlet applications
or a `ReactiveJwtDecoder` for reactive applications.
or a `ReactiveJwtDecoder` for reactive applications.
In cases where opaque tokens are used instead of JWTs, you can configure the following properties
to validate tokens via introspection:
[source,properties,indent=0]
----
spring.security.oauth2.resourceserver.opaque-token.introspection-uri=https://example.com/check-token
spring.security.oauth2.resourceserver.opaque-token.client-id=my-client-id
spring.security.oauth2.resourceserver.opaque-token.client-secret-my-client-secret
----
Again, the same properties are applicable for both servlet and reactive applications.
Alternatively, you can define your own `OAuth2TokenIntrospectionClient` bean for servlet applications
or a `ReactiveOAuth2TokenIntrospectionClient` for reactive applications.
==== Authorization Server
==== Authorization Server
Currently, Spring Security does not provide support for implementing an OAuth 2.0
Currently, Spring Security does not provide support for implementing an OAuth 2.0
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment