Merge branch '5.8.x' into 6.0.x
Closes gh-13406
This commit is contained in:
@@ -30,8 +30,10 @@ In Spring Security 5.8, this support has been refreshed to use the `Authorizatio
|
||||
To configure authorization using Java Configuration, simply include the `@EnableWebSocketSecurity` annotation and publish an `AuthorizationManager<Message<?>>` bean or in XML use the `use-authorization-manager` attribute.
|
||||
One way to do this is by using the `AuthorizationManagerMessageMatcherRegistry` to specify endpoint patterns like so:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -48,7 +50,8 @@ public class WebSocketSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -61,29 +64,26 @@ open class WebSocketSecurityConfig { // <1> <2>
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
<1> Any inbound CONNECT message requires a valid CSRF token to enforce the <<websocket-sameorigin,Same Origin Policy>>.
|
||||
<2> The `SecurityContextHolder` is populated with the user within the `simpUser` header attribute for any inbound request.
|
||||
<3> Our messages require the proper authorization. Specifically, any inbound message that starts with `/user/` will requires `ROLE_USER`. You can find additional details on authorization in <<websocket-authorization>>
|
||||
====
|
||||
|
||||
Spring Security also provides xref:servlet/appendix/namespace/websocket.adoc#nsa-websocket-security[XML Namespace] support for securing WebSockets.
|
||||
A comparable XML based configuration looks like the following:
|
||||
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
<websocket-message-broker use-authorization-manager="true"> <!--1--> <!--2-->
|
||||
<intercept-message pattern="/user/**" access="authenticated"/> <!--3-->
|
||||
</websocket-message-broker>
|
||||
----
|
||||
====
|
||||
|
||||
This will ensure that:
|
||||
|
||||
<1> Any inbound CONNECT message requires a valid CSRF token to enforce <<websocket-sameorigin,Same Origin Policy>>
|
||||
<2> The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request.
|
||||
<3> Our messages require the proper authorization. Specifically, any inbound message that starts with "/user/" will require ROLE_USER. Additional details on authorization can be found in <<websocket-authorization>>
|
||||
====
|
||||
|
||||
|
||||
=== Custom Authorization
|
||||
@@ -91,8 +91,10 @@ This will ensure that:
|
||||
When using `AuthorizationManager`, customization is quite simple.
|
||||
For example, you can publish an `AuthorizationManager` that requires that all messages have a role of "USER" using `AuthorityAuthorizationManager`, as seen below:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -106,7 +108,8 @@ public class WebSocketSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -119,19 +122,22 @@ open class WebSocketSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<bean id="authorizationManager" class="org.example.MyAuthorizationManager"/>
|
||||
|
||||
<websocket-message-broker authorization-manager-ref="myAuthorizationManager"/>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
There are several ways to further match messages, as can be seen in a more advanced example below:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -152,7 +158,8 @@ public class WebSocketSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -171,7 +178,8 @@ open class WebSocketSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
<websocket-message-broker use-authorization-manager="true">
|
||||
@@ -194,7 +202,7 @@ open class WebSocketSecurityConfig {
|
||||
<intercept-message pattern="/**" access="denyAll" /> <!--6-->
|
||||
</websocket-message-broker>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
This will ensure that:
|
||||
|
||||
@@ -296,19 +304,19 @@ Instead, we must include the token in the Stomp headers.
|
||||
Applications can xref:servlet/exploits/csrf.adoc#servlet-csrf-include[obtain a CSRF token] by accessing the request attribute named `_csrf`.
|
||||
For example, the following allows accessing the `CsrfToken` in a JSP:
|
||||
|
||||
====
|
||||
[source,javascript]
|
||||
----
|
||||
var headerName = "${_csrf.headerName}";
|
||||
var token = "${_csrf.token}";
|
||||
----
|
||||
====
|
||||
|
||||
If you use static HTML, you can expose the `CsrfToken` on a REST endpoint.
|
||||
For example, the following would expose the `CsrfToken` on the `/csrf` URL:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@RestController
|
||||
@@ -321,7 +329,8 @@ public class CsrfController {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@RestController
|
||||
@@ -332,13 +341,12 @@ class CsrfController {
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
The JavaScript can make a REST call to the endpoint and use the response to populate the `headerName` and the token.
|
||||
|
||||
We can now include the token in our Stomp client:
|
||||
|
||||
====
|
||||
[source,javascript]
|
||||
----
|
||||
...
|
||||
@@ -349,7 +357,6 @@ stompClient.connect(headers, function(frame) {
|
||||
|
||||
})
|
||||
----
|
||||
====
|
||||
|
||||
[[websocket-sameorigin-disable]]
|
||||
=== Disable CSRF within WebSockets
|
||||
@@ -357,8 +364,10 @@ NOTE: At this point, CSRF is not configurable when using `@EnableWebSocketSecuri
|
||||
|
||||
To disable CSRF, instead of using `@EnableWebSocketSecurity`, you can use XML support or add the Spring Security components yourself, like so:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -380,7 +389,8 @@ public class WebSocketSecurityConfig implements WebSocketMessageBrokerConfigurer
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -401,20 +411,23 @@ open class WebSocketSecurityConfig : WebSocketMessageBrokerConfigurer {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<websocket-message-broker use-authorization-manager="true" same-origin-disabled="true">
|
||||
<intercept-message pattern="/**" access="authenticated"/>
|
||||
</websocket-message-broker>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
On the other hand, if you are using the <<legacy-websocket-configuration,legacy `AbstractSecurityWebSocketMessageBrokerConfigurer`>> and you want to allow other domains to access your site, you can disable Spring Security's protection.
|
||||
For example, in Java Configuration you can use the following:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -429,7 +442,8 @@ public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBro
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -442,7 +456,7 @@ open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfi
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
[[websocket-expression-handler]]
|
||||
=== Custom Expression Handler
|
||||
@@ -494,7 +508,6 @@ To allow SockJS frame-based transports to work, we need to configure Spring Secu
|
||||
You can customize `X-Frame-Options` with the xref:servlet/appendix/namespace/http.adoc#nsa-frame-options[frame-options] element.
|
||||
For example, the following instructs Spring Security to use `X-Frame-Options: SAMEORIGIN`, which allows iframes within the same domain:
|
||||
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
<http>
|
||||
@@ -506,12 +519,13 @@ For example, the following instructs Spring Security to use `X-Frame-Options: SA
|
||||
</headers>
|
||||
</http>
|
||||
----
|
||||
====
|
||||
|
||||
Similarly, you can customize frame options to use the same origin within Java Configuration by using the following:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -532,7 +546,8 @@ public class WebSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -552,7 +567,7 @@ open class WebSecurityConfig {
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
[[websocket-sockjs-csrf]]
|
||||
=== SockJS & Relaxing CSRF
|
||||
@@ -571,8 +586,10 @@ We can easily achieve this by providing a CSRF `RequestMatcher`.
|
||||
Our Java configuration makes this easy.
|
||||
For example, if our stomp endpoint is `/chat`, we can disable CSRF protection only for URLs that start with `/chat/` by using the following configuration:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -600,7 +617,8 @@ public class WebSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -625,11 +643,10 @@ open class WebSecurityConfig {
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
If we use XML-based configuration, we can use thexref:servlet/appendix/namespace/http.adoc#nsa-csrf-request-matcher-ref[csrf@request-matcher-ref].
|
||||
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
<http ...>
|
||||
@@ -661,8 +678,10 @@ If we use XML-based configuration, we can use thexref:servlet/appendix/namespace
|
||||
Before Spring Security 5.8, the way to configure messaging authorization using Java Configuration, was to extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`.
|
||||
For example:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -676,7 +695,8 @@ public class WebSocketSecurityConfig
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Configuration
|
||||
@@ -686,7 +706,7 @@ open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfi
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
This will ensure that:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user