mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-30 16:52:13 +00:00
Add Message Security Preparation Steps
Issue gh-11337
This commit is contained in:
parent
5721b0351e
commit
31a1486b88
@ -212,6 +212,273 @@ companion object {
|
|||||||
`@EnableMethodSecurity` and `<method-security>` activate stricter enforcement of Spring Security's non-repeatable or otherwise incompatible annotations.
|
`@EnableMethodSecurity` and `<method-security>` activate stricter enforcement of Spring Security's non-repeatable or otherwise incompatible annotations.
|
||||||
If after moving to either you see ``AnnotationConfigurationException``s in your logs, follow the instructions in the exception message to clean up your application's method security annotation usage.
|
If after moving to either you see ``AnnotationConfigurationException``s in your logs, follow the instructions in the exception message to clean up your application's method security annotation usage.
|
||||||
|
|
||||||
|
=== Use `AuthorizationManager` for Message Security
|
||||||
|
|
||||||
|
xref:servlet/integrations/websocket.adoc[Message Security] has been xref:servlet/integrations/websocket.adoc#websocket-configuration[improved] through {security-api-url}org/springframework/security/authorization/AuthorizationManager.html[the `AuthorizationManager` API] and direct use of Spring AOP.
|
||||||
|
|
||||||
|
==== Ensure all messages have defined authorization rules
|
||||||
|
|
||||||
|
The now-deprecated {security-api-url}org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.html[message security support] permits all messages by default.
|
||||||
|
xref:servlet/integrations/websocket.adoc[The new support] has the stronger default of denying all messages.
|
||||||
|
|
||||||
|
To prepare for this, ensure that authorization rules exist are declared for every request.
|
||||||
|
|
||||||
|
For example, an application configuration like:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Override
|
||||||
|
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||||
|
messages
|
||||||
|
.simpDestMatchers("/user/queue/errors").permitAll()
|
||||||
|
.simpDestMatchers("/admin/**").hasRole("ADMIN");
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
override fun configureInbound(messages: MessageSecurityMetadataSourceRegistry) {
|
||||||
|
messages
|
||||||
|
.simpDestMatchers("/user/queue/errors").permitAll()
|
||||||
|
.simpDestMatchers("/admin/**").hasRole("ADMIN")
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Xml
|
||||||
|
[source,xml,role="secondary"]
|
||||||
|
----
|
||||||
|
<websocket-message-broker>
|
||||||
|
<intercept-message pattern="/user/queue/errors" access="permitAll"/>
|
||||||
|
<intercept-message pattern="/admin/**" access="hasRole('ADMIN')"/>
|
||||||
|
</websocket-message-broker>
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
should change to:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Override
|
||||||
|
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||||
|
messages
|
||||||
|
.simpTypeMatchers(CONNECT, DISCONNECT, UNSUBSCRIBE).permitAll()
|
||||||
|
.simpDestMatchers("/user/queue/errors").permitAll()
|
||||||
|
.simpDestMatchers("/admin/**").hasRole("ADMIN")
|
||||||
|
.anyMessage().denyAll();
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
override fun configureInbound(messages: MessageSecurityMetadataSourceRegistry) {
|
||||||
|
messages
|
||||||
|
.simpTypeMatchers(CONNECT, DISCONNECT, UNSUBSCRIBE).permitAll()
|
||||||
|
.simpDestMatchers("/user/queue/errors").permitAll()
|
||||||
|
.simpDestMatchers("/admin/**").hasRole("ADMIN")
|
||||||
|
.anyMessage().denyAll()
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Xml
|
||||||
|
[source,xml,role="secondary"]
|
||||||
|
----
|
||||||
|
<websocket-message-broker>
|
||||||
|
<intercept-message type="CONNECT" access="permitAll"/>
|
||||||
|
<intercept-message type="DISCONNECT" access="permitAll"/>
|
||||||
|
<intercept-message type="UNSUBSCRIBE" access="permitAll"/>
|
||||||
|
<intercept-message pattern="/user/queue/errors" access="permitAll"/>
|
||||||
|
<intercept-message pattern="/admin/**" access="hasRole('ADMIN')"/>
|
||||||
|
<intercept-message pattern="/**" access="denyAll"/>
|
||||||
|
</websocket-message-broker>
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
==== Add `@EnableWebSocketSecurity`
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
====
|
||||||
|
If you want to have CSRF disabled and you are using Java configuration, the migration steps are slightly different.
|
||||||
|
Instead of using `@EnableWebSocketSecurity`, you will override the appropriate methods in `WebSocketMessageBrokerConfigurer` yourself.
|
||||||
|
Please see xref:servlet/integrations/websocket.adoc#websocket-sameorigin-disable[the reference manual] for details about this step.
|
||||||
|
====
|
||||||
|
|
||||||
|
If you are using Java Configuration, add {security-api-url}org/springframework/security/config/annotation/web/socket/EnableWebSocketSecurity.html[`@EnableWebSocketSecurity`] to your application.
|
||||||
|
|
||||||
|
For example, you can add it to your websocket security configuration class, like so:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@EnableWebSocketSecurity
|
||||||
|
@Configuration
|
||||||
|
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@EnableWebSocketSecurity
|
||||||
|
@Configuration
|
||||||
|
class WebSocketSecurityConfig: AbstractSecurityWebSocketMessageBrokerConfigurer() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
This will make a prototype instance of `MessageMatcherDelegatingAuthorizationManager.Builder` available to encourage configuration by composition instead of extension.
|
||||||
|
|
||||||
|
==== Use an `AuthorizationManager<Message<?>>` instance
|
||||||
|
|
||||||
|
To start using `AuthorizationManager`, you can set the `use-authorization-manager` attribute in XML or you can publish an `AuthorizationManager<Message<?>>` `@Bean` in Java.
|
||||||
|
|
||||||
|
For example, the following application configuration:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Override
|
||||||
|
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||||
|
messages
|
||||||
|
.simpTypeMatchers(CONNECT, DISCONNECT, UNSUBSCRIBE).permitAll()
|
||||||
|
.simpDestMatchers("/user/queue/errors").permitAll()
|
||||||
|
.simpDestMatchers("/admin/**").hasRole("ADMIN")
|
||||||
|
.anyMessage().denyAll();
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
override fun configureInbound(messages: MessageSecurityMetadataSourceRegistry) {
|
||||||
|
messages
|
||||||
|
.simpTypeMatchers(CONNECT, DISCONNECT, UNSUBSCRIBE).permitAll()
|
||||||
|
.simpDestMatchers("/user/queue/errors").permitAll()
|
||||||
|
.simpDestMatchers("/admin/**").hasRole("ADMIN")
|
||||||
|
.anyMessage().denyAll()
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Xml
|
||||||
|
[source,xml,role="secondary"]
|
||||||
|
----
|
||||||
|
<websocket-message-broker>
|
||||||
|
<intercept-message type="CONNECT" access="permitAll"/>
|
||||||
|
<intercept-message type="DISCONNECT" access="permitAll"/>
|
||||||
|
<intercept-message type="UNSUBSCRIBE" access="permitAll"/>
|
||||||
|
<intercept-message pattern="/user/queue/errors" access="permitAll"/>
|
||||||
|
<intercept-message pattern="/admin/**" access="hasRole('ADMIN')"/>
|
||||||
|
<intercept-message pattern="/**" access="denyAll"/>
|
||||||
|
</websocket-message-broker>
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
changes to:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
AuthorizationManager<Message<?>> messageSecurity(MessageMatcherDelegatingAuthorizationManager.Builder messages) {
|
||||||
|
messages
|
||||||
|
.simpTypeMatchers(CONNECT, DISCONNECT, UNSUBSCRIBE).permitAll()
|
||||||
|
.simpDestMatchers("/user/queue/errors").permitAll()
|
||||||
|
.simpDestMatchers("/admin/**").hasRole("ADMIN")
|
||||||
|
.anyMessage().denyAll();
|
||||||
|
return messages.build();
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun messageSecurity(val messages: MessageMatcherDelegatingAuthorizationManager.Builder): AuthorizationManager<Message<?>> {
|
||||||
|
messages
|
||||||
|
.simpTypeMatchers(CONNECT, DISCONNECT, UNSUBSCRIBE).permitAll()
|
||||||
|
.simpDestMatchers("/user/queue/errors").permitAll()
|
||||||
|
.simpDestMatchers("/admin/**").hasRole("ADMIN")
|
||||||
|
.anyMessage().denyAll()
|
||||||
|
return messages.build()
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Xml
|
||||||
|
[source,xml,role="secondary"]
|
||||||
|
----
|
||||||
|
<websocket-message-broker use-authorization-manager="true">
|
||||||
|
<intercept-message type="CONNECT" access="permitAll"/>
|
||||||
|
<intercept-message type="DISCONNECT" access="permitAll"/>
|
||||||
|
<intercept-message type="UNSUBSCRIBE" access="permitAll"/>
|
||||||
|
<intercept-message pattern="/user/queue/errors" access="permitAll"/>
|
||||||
|
<intercept-message pattern="/admin/**" access="hasRole('ADMIN')"/>
|
||||||
|
<intercept-message pattern="/**" access="denyAll"/>
|
||||||
|
</websocket-message-broker>
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
==== Stop Implementing `AbstractSecurityWebSocketMessageBrokerConfigurer`
|
||||||
|
|
||||||
|
If you are using Java configuration, you can now simply extend `WebSocketMessageBrokerConfigurer`.
|
||||||
|
|
||||||
|
For example, if your class that extends `AbstractSecurityWebSocketMessageBrokerConfigurer` is called `WebSocketSecurityConfig`, then:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@EnableWebSocketSecurity
|
||||||
|
@Configuration
|
||||||
|
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@EnableWebSocketSecurity
|
||||||
|
@Configuration
|
||||||
|
class WebSocketSecurityConfig: AbstractSecurityWebSocketMessageBrokerConfigurer() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
changes to:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@EnableWebSocketSecurity
|
||||||
|
@Configuration
|
||||||
|
public class WebSocketSecurityConfig implements WebSocketMessageBrokerConfigurer {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@EnableWebSocketSecurity
|
||||||
|
@Configuration
|
||||||
|
class WebSocketSecurityConfig: WebSocketMessageBrokerConfigurer {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
== Reactive
|
== Reactive
|
||||||
|
|
||||||
=== Use `AuthorizationManager` for Method Security
|
=== Use `AuthorizationManager` for Method Security
|
||||||
|
Loading…
x
Reference in New Issue
Block a user