SEC-2853: Rename WebSocket XML Namespace elements
This commit is contained in:
parent
706e7fd7a2
commit
fea03536d6
|
@ -55,6 +55,6 @@ public abstract class Elements {
|
||||||
public static final String HEADERS = "headers";
|
public static final String HEADERS = "headers";
|
||||||
public static final String CSRF = "csrf";
|
public static final String CSRF = "csrf";
|
||||||
|
|
||||||
public static final String MESSAGES = "messages";
|
public static final String WEBSOCKET_MESSAGE_BROKER = "websocket-message-broker";
|
||||||
public static final String INTERCEPT_MESSAGE = "message-interceptor";
|
public static final String INTERCEPT_MESSAGE = "intercept-message";
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,10 @@ import org.springframework.security.config.http.HttpSecurityBeanDefinitionParser
|
||||||
import org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser;
|
import org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser;
|
||||||
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
|
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
|
||||||
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
||||||
import org.springframework.security.config.message.MessageSecurityBeanDefinitionParser;
|
|
||||||
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
|
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
|
||||||
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
|
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
|
||||||
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
|
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
|
||||||
|
import org.springframework.security.config.websocket.WebSocketMessageBrokerSecurityBeanDefinitionParser;
|
||||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
@ -179,7 +179,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {
|
if(ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {
|
||||||
parsers.put(Elements.MESSAGES, new MessageSecurityBeanDefinitionParser());
|
parsers.put(Elements.WEBSOCKET_MESSAGE_BROKER, new WebSocketMessageBrokerSecurityBeanDefinitionParser());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* 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.security.config.message;
|
package org.springframework.security.config.websocket;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
@ -42,13 +42,13 @@ import org.w3c.dom.Element;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses Spring Security's message namespace support. A simple example is:
|
* Parses Spring Security's websocket namespace support. A simple example is:
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* <messages>
|
* <websocket-message-broker>
|
||||||
* <message-interceptor pattern='/permitAll' access='permitAll' />
|
* <intercept-message pattern='/permitAll' access='permitAll' />
|
||||||
* <message-interceptor pattern='/denyAll' access='denyAll' />
|
* <intercept-message pattern='/denyAll' access='denyAll' />
|
||||||
* </messages>
|
* </websocket-message-broker>
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -63,10 +63,10 @@ import java.util.List;
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* <messages id="channelSecurityInterceptor">
|
* <websocket-message-broker id="channelSecurityInterceptor">
|
||||||
* <message-interceptor pattern='/permitAll' access='permitAll' />
|
* <intercept-message pattern='/permitAll' access='permitAll' />
|
||||||
* <message-interceptor pattern='/denyAll' access='denyAll' />
|
* <intercept-message pattern='/denyAll' access='denyAll' />
|
||||||
* </messages>
|
* </websocket-message-broker>
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -78,8 +78,8 @@ import java.util.List;
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public final class MessageSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
private static final Log logger = LogFactory.getLog(MessageSecurityBeanDefinitionParser.class);
|
private static final Log logger = LogFactory.getLog(WebSocketMessageBrokerSecurityBeanDefinitionParser.class);
|
||||||
|
|
||||||
private static final String ID_ATTR = "id";
|
private static final String ID_ATTR = "id";
|
||||||
|
|
|
@ -272,22 +272,22 @@ protect-pointcut.attlist &=
|
||||||
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
|
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
|
||||||
attribute access {xsd:token}
|
attribute access {xsd:token}
|
||||||
|
|
||||||
messages =
|
websocket-message-broker =
|
||||||
## Allows securing a Message Broker. There are two modes. If no id is specified: ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel. If the id is specified, creates a ChannelSecurityInterceptor that can be manually registered with the clientInboundChannel.
|
## Allows securing a Message Broker. There are two modes. If no id is specified: ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel. If the id is specified, creates a ChannelSecurityInterceptor that can be manually registered with the clientInboundChannel.
|
||||||
element messages { messages.attrlist, (message-interceptor*) }
|
element websocket-message-broker { websocket-message-broker.attrlist, (intercept-message*) }
|
||||||
|
|
||||||
messages.attrlist &=
|
websocket-message-broker.attrlist &=
|
||||||
## A bean identifier, used for referring to the bean elsewhere in the context. If specified, explicit configuration within clientInboundChannel is required. If not specified, ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel.
|
## A bean identifier, used for referring to the bean elsewhere in the context. If specified, explicit configuration within clientInboundChannel is required. If not specified, ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel.
|
||||||
attribute id {xsd:token}?
|
attribute id {xsd:token}?
|
||||||
|
|
||||||
message-interceptor =
|
intercept-message =
|
||||||
## Creates an authorization rule for a message.
|
## Creates an authorization rule for a websocket message.
|
||||||
element message-interceptor {message-interceptor.attrlist}
|
element intercept-message {intercept-message.attrlist}
|
||||||
|
|
||||||
message-interceptor.attrlist &=
|
intercept-message.attrlist &=
|
||||||
## The destination ant pattern which will be mapped to the access attribute. For example, /** matches any message with a destination, /admin/** matches any message that has a destination that starts with admin.
|
## The destination ant pattern which will be mapped to the access attribute. For example, /** matches any message with a destination, /admin/** matches any message that has a destination that starts with admin.
|
||||||
attribute pattern {xsd:token}?
|
attribute pattern {xsd:token}?
|
||||||
message-interceptor.attrlist &=
|
intercept-message.attrlist &=
|
||||||
## The access configuration attributes that apply for the configured message. For example, permitAll grants access to anyone, hasRole('ROLE_ADMIN') requires the user have the role 'ROLE_ADMIN'.
|
## The access configuration attributes that apply for the configured message. For example, permitAll grants access to anyone, hasRole('ROLE_ADMIN') requires the user have the role 'ROLE_ADMIN'.
|
||||||
attribute access {xsd:token}?
|
attribute access {xsd:token}?
|
||||||
|
|
||||||
|
|
|
@ -839,7 +839,7 @@
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
</xs:attribute>
|
</xs:attribute>
|
||||||
</xs:attributeGroup>
|
</xs:attributeGroup>
|
||||||
<xs:element name="messages">
|
<xs:element name="websocket-message-broker">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Allows securing a Message Broker. There are two modes. If no id is specified: ensures that
|
<xs:documentation>Allows securing a Message Broker. There are two modes. If no id is specified: ensures that
|
||||||
any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver
|
any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver
|
||||||
|
@ -852,12 +852,12 @@
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:message-interceptor"/>
|
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:intercept-message"/>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
<xs:attributeGroup ref="security:messages.attrlist"/>
|
<xs:attributeGroup ref="security:websocket-message-broker.attrlist"/>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:attributeGroup name="messages.attrlist">
|
<xs:attributeGroup name="websocket-message-broker.attrlist">
|
||||||
<xs:attribute name="id" type="xs:token">
|
<xs:attribute name="id" type="xs:token">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context. If specified,
|
<xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context. If specified,
|
||||||
|
@ -871,16 +871,16 @@
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
</xs:attribute>
|
</xs:attribute>
|
||||||
</xs:attributeGroup>
|
</xs:attributeGroup>
|
||||||
<xs:element name="message-interceptor">
|
<xs:element name="intercept-message">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Creates an authorization rule for a message.
|
<xs:documentation>Creates an authorization rule for a websocket message.
|
||||||
</xs:documentation>
|
</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:attributeGroup ref="security:message-interceptor.attrlist"/>
|
<xs:attributeGroup ref="security:intercept-message.attrlist"/>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:attributeGroup name="message-interceptor.attrlist">
|
<xs:attributeGroup name="intercept-message.attrlist">
|
||||||
<xs:attribute name="pattern" type="xs:token">
|
<xs:attribute name="pattern" type="xs:token">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>The destination ant pattern which will be mapped to the access attribute. For example, /**
|
<xs:documentation>The destination ant pattern which will be mapped to the access attribute. For example, /**
|
||||||
|
|
|
@ -29,7 +29,7 @@ import spock.lang.*
|
||||||
*/
|
*/
|
||||||
class XsdDocumentedTests extends Specification {
|
class XsdDocumentedTests extends Specification {
|
||||||
|
|
||||||
def ignoredIds = ['nsa-any-user-service','nsa-any-user-service-parents','nsa-authentication','nsa-message-security','nsa-ldap','nsa-method-security','nsa-web']
|
def ignoredIds = ['nsa-any-user-service','nsa-any-user-service-parents','nsa-authentication','nsa-websocket-security','nsa-ldap','nsa-method-security','nsa-web']
|
||||||
@Shared def reference = new File('../docs/manual/src/docs/asciidoc/index.adoc')
|
@Shared def reference = new File('../docs/manual/src/docs/asciidoc/index.adoc')
|
||||||
|
|
||||||
@Shared File schema31xDocument = new File('src/main/resources/org/springframework/security/config/spring-security-3.1.xsd')
|
@Shared File schema31xDocument = new File('src/main/resources/org/springframework/security/config/spring-security-3.1.xsd')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.springframework.security.config.message
|
package org.springframework.security.config.websocket
|
||||||
|
|
||||||
import org.springframework.beans.BeansException
|
import org.springframework.beans.BeansException
|
||||||
import org.springframework.beans.factory.config.BeanDefinition
|
import org.springframework.beans.factory.config.BeanDefinition
|
||||||
|
@ -47,7 +47,7 @@ import org.springframework.security.core.context.SecurityContextHolder
|
||||||
*
|
*
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
*/
|
*/
|
||||||
class MessagesConfigTests extends AbstractXmlConfigTests {
|
class WebSocketMessageBrokerConfigTests extends AbstractXmlConfigTests {
|
||||||
Authentication messageUser = new TestingAuthenticationToken('user','pass','ROLE_USER')
|
Authentication messageUser = new TestingAuthenticationToken('user','pass','ROLE_USER')
|
||||||
boolean useSockJS = false
|
boolean useSockJS = false
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
SecurityContextHolder.clearContext()
|
SecurityContextHolder.clearContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
def 'messages with no id automatically integrates with clientInboundChannel'() {
|
def 'websocket with no id automatically integrates with clientInboundChannel'() {
|
||||||
setup:
|
setup:
|
||||||
messages {
|
websocket {
|
||||||
'message-interceptor'(pattern:'/permitAll',access:'permitAll')
|
'intercept-message'(pattern:'/permitAll',access:'permitAll')
|
||||||
'message-interceptor'(pattern:'/denyAll',access:'denyAll')
|
'intercept-message'(pattern:'/denyAll',access:'denyAll')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,9 +76,9 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
|
|
||||||
def 'anonymous authentication supported'() {
|
def 'anonymous authentication supported'() {
|
||||||
setup:
|
setup:
|
||||||
messages {
|
websocket {
|
||||||
'message-interceptor'(pattern:'/permitAll',access:'permitAll')
|
'intercept-message'(pattern:'/permitAll',access:'permitAll')
|
||||||
'message-interceptor'(pattern:'/denyAll',access:'denyAll')
|
'intercept-message'(pattern:'/denyAll',access:'denyAll')
|
||||||
}
|
}
|
||||||
messageUser = null
|
messageUser = null
|
||||||
|
|
||||||
|
@ -94,8 +94,8 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
def id = 'authenticationController'
|
def id = 'authenticationController'
|
||||||
bean(id,MyController)
|
bean(id,MyController)
|
||||||
bean('inPostProcessor',InboundExecutorPostProcessor)
|
bean('inPostProcessor',InboundExecutorPostProcessor)
|
||||||
messages {
|
websocket {
|
||||||
'message-interceptor'(pattern:'/**',access:'permitAll')
|
'intercept-message'(pattern:'/**',access:'permitAll')
|
||||||
}
|
}
|
||||||
|
|
||||||
when: 'message is sent to the authentication endpoint'
|
when: 'message is sent to the authentication endpoint'
|
||||||
|
@ -111,8 +111,8 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
def id = 'authenticationController'
|
def id = 'authenticationController'
|
||||||
bean(id,MyController)
|
bean(id,MyController)
|
||||||
bean('inPostProcessor',InboundExecutorPostProcessor)
|
bean('inPostProcessor',InboundExecutorPostProcessor)
|
||||||
messages {
|
websocket {
|
||||||
'message-interceptor'(pattern:'/**',access:'permitAll')
|
'intercept-message'(pattern:'/**',access:'permitAll')
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT)
|
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT)
|
||||||
|
@ -142,8 +142,8 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
def id = 'authenticationController'
|
def id = 'authenticationController'
|
||||||
bean(id,MyController)
|
bean(id,MyController)
|
||||||
bean('inPostProcessor',InboundExecutorPostProcessor)
|
bean('inPostProcessor',InboundExecutorPostProcessor)
|
||||||
messages {
|
websocket {
|
||||||
'message-interceptor'(pattern:'/**',access:'permitAll')
|
'intercept-message'(pattern:'/**',access:'permitAll')
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT)
|
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT)
|
||||||
|
@ -175,11 +175,11 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
def id = 'authenticationController'
|
def id = 'authenticationController'
|
||||||
bean(id,MyController)
|
bean(id,MyController)
|
||||||
bean('inPostProcessor',InboundExecutorPostProcessor)
|
bean('inPostProcessor',InboundExecutorPostProcessor)
|
||||||
messages {
|
websocket {
|
||||||
'message-interceptor'(pattern:'/**',access:'permitAll')
|
'intercept-message'(pattern:'/**',access:'permitAll')
|
||||||
}
|
}
|
||||||
|
|
||||||
when: 'message of type CONNECTION is sent without CsrfTOken'
|
when: 'websocket of type CONNECTION is sent without CsrfTOken'
|
||||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT)
|
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT)
|
||||||
Message<?> message = message(headers,'/authentication')
|
Message<?> message = message(headers,'/authentication')
|
||||||
clientInboundChannel.send(message)
|
clientInboundChannel.send(message)
|
||||||
|
@ -189,7 +189,7 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
expected.cause instanceof MissingCsrfTokenException
|
expected.cause instanceof MissingCsrfTokenException
|
||||||
}
|
}
|
||||||
|
|
||||||
def 'messages with no id does not override customArgumentResolvers'() {
|
def 'websocket with no id does not override customArgumentResolvers'() {
|
||||||
setup:
|
setup:
|
||||||
def id = 'authenticationController'
|
def id = 'authenticationController'
|
||||||
bean(id,MyController)
|
bean(id,MyController)
|
||||||
|
@ -205,11 +205,11 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
'b:ref'(bean:'mcar')
|
'b:ref'(bean:'mcar')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
messages {
|
websocket {
|
||||||
'message-interceptor'(pattern:'/**',access:'permitAll')
|
'intercept-message'(pattern:'/**',access:'permitAll')
|
||||||
}
|
}
|
||||||
|
|
||||||
when: 'message is sent to the myCustom endpoint'
|
when: 'websocket is sent to the myCustom endpoint'
|
||||||
clientInboundChannel.send(message('/myCustom'))
|
clientInboundChannel.send(message('/myCustom'))
|
||||||
|
|
||||||
then: 'myCustomArgument is resolved'
|
then: 'myCustomArgument is resolved'
|
||||||
|
@ -217,10 +217,10 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
controller.myCustomArgument!= null
|
controller.myCustomArgument!= null
|
||||||
}
|
}
|
||||||
|
|
||||||
def 'messages with id does not integrate with clientInboundChannel'() {
|
def 'websocket with id does not integrate with clientInboundChannel'() {
|
||||||
setup:
|
setup:
|
||||||
messages([id:'inCsi']) {
|
websocket([id:'inCsi']) {
|
||||||
'message-interceptor'(pattern:'/**',access:'denyAll')
|
'intercept-message'(pattern:'/**',access:'denyAll')
|
||||||
}
|
}
|
||||||
|
|
||||||
when:
|
when:
|
||||||
|
@ -231,8 +231,8 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def 'messages with id can be explicitly integrated with clientInboundChannel'() {
|
def 'websocket with id can be explicitly integrated with clientInboundChannel'() {
|
||||||
setup: 'message security explicitly setup'
|
setup: 'websocket security explicitly setup'
|
||||||
xml.'websocket:message-broker' {
|
xml.'websocket:message-broker' {
|
||||||
'websocket:transport' {}
|
'websocket:transport' {}
|
||||||
'websocket:stomp-endpoint'(path:'/app') {
|
'websocket:stomp-endpoint'(path:'/app') {
|
||||||
|
@ -246,8 +246,8 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xml.messages(id:'inCsi') {
|
xml.'websocket-message-broker'(id:'inCsi') {
|
||||||
'message-interceptor'(pattern:'/**',access:'denyAll')
|
'intercept-message'(pattern:'/**',access:'denyAll')
|
||||||
}
|
}
|
||||||
createAppContext()
|
createAppContext()
|
||||||
|
|
||||||
|
@ -276,9 +276,9 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xml.messages {
|
xml.'websocket-message-broker' {
|
||||||
'message-interceptor'(pattern:'/denyAll',access:'denyAll')
|
'intercept-message'(pattern:'/denyAll',access:'denyAll')
|
||||||
'message-interceptor'(pattern:'/permitAll',access:'permitAll')
|
'intercept-message'(pattern:'/permitAll',access:'permitAll')
|
||||||
}
|
}
|
||||||
createAppContext()
|
createAppContext()
|
||||||
ChannelInterceptor mci = appContext.getBean('mci')
|
ChannelInterceptor mci = appContext.getBean('mci')
|
||||||
|
@ -291,7 +291,7 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def messages(Map<String,Object> attrs=[:], Closure c) {
|
def websocket(Map<String,Object> attrs=[:], Closure c) {
|
||||||
bean('testHandler', TestHandshakeHandler)
|
bean('testHandler', TestHandshakeHandler)
|
||||||
xml.'websocket:message-broker' {
|
xml.'websocket:message-broker' {
|
||||||
'websocket:transport' {}
|
'websocket:transport' {}
|
||||||
|
@ -306,7 +306,7 @@ class MessagesConfigTests extends AbstractXmlConfigTests {
|
||||||
}
|
}
|
||||||
'websocket:simple-broker'(prefix:"/queue, /topic"){}
|
'websocket:simple-broker'(prefix:"/queue, /topic"){}
|
||||||
}
|
}
|
||||||
xml.messages(attrs, c)
|
xml.'websocket-message-broker'(attrs, c)
|
||||||
createAppContext()
|
createAppContext()
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,12 +127,12 @@ public class SecurityNamespaceHandlerTests {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void messageNotFoundExceptionNoMessageBlock() throws Exception {
|
public void websocketNotFoundExceptionNoMessageBlock() throws Exception {
|
||||||
String className = FILTER_CHAIN_PROXY_CLASSNAME;
|
String className = FILTER_CHAIN_PROXY_CLASSNAME;
|
||||||
spy(ClassUtils.class);
|
spy(ClassUtils.class);
|
||||||
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class,"forName",eq(Message.class.getName()),any(ClassLoader.class));
|
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class,"forName",eq(Message.class.getName()),any(ClassLoader.class));
|
||||||
new InMemoryXmlApplicationContext(
|
new InMemoryXmlApplicationContext(
|
||||||
XML_AUTHENTICATION_MANAGER);
|
XML_AUTHENTICATION_MANAGER);
|
||||||
// should load just fine since no message block
|
// should load just fine since no websocket block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7790,15 +7790,15 @@ Enables the use of expressions in the 'access' attributes in <intercept-url> ele
|
||||||
|
|
||||||
* <<nsa-intercept-url,intercept-url>>
|
* <<nsa-intercept-url,intercept-url>>
|
||||||
|
|
||||||
[[nsa-message-security]]
|
[[nsa-websocket-security]]
|
||||||
=== Message/WebSocket Security
|
=== WebSocket Security
|
||||||
|
|
||||||
Spring Security 4.0+ provides support for authorizing messages. One concrete example of where this is useful is to provide authorization in WebSocket based applications.
|
Spring Security 4.0+ provides support for authorizing messages. One concrete example of where this is useful is to provide authorization in WebSocket based applications.
|
||||||
|
|
||||||
[[nsa-messages]]
|
[[nsa-websocket-message-broker]]
|
||||||
==== <messages>
|
==== <websocket-message-broker>
|
||||||
|
|
||||||
The messages attribute has two different modes. If the <<nsa-messages-id>> is not specified, then it will do the following things:
|
The websocket-message-broker element has two different modes. If the <<nsa-websocket-id>> is not specified, then it will do the following things:
|
||||||
|
|
||||||
* Ensure that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver. This allows the use of `@AuthenticationPrincipal` to resolve the principal of the current `Authentication`
|
* Ensure that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver. This allows the use of `@AuthenticationPrincipal` to resolve the principal of the current `Authentication`
|
||||||
* Ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel. This populates the SecurityContextHolder with the user that is found in the Message
|
* Ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel. This populates the SecurityContextHolder with the user that is found in the Message
|
||||||
|
@ -7809,38 +7809,38 @@ The messages attribute has two different modes. If the <<nsa-messages-id>> is no
|
||||||
If additional control is necessary, the id can be specified and a ChannelSecurityInterceptor will be assigned to the specified id. All the wiring with Spring's messaging infrastructure can then be done manually. This is more cumbersome, but provides greater control over the configuration.
|
If additional control is necessary, the id can be specified and a ChannelSecurityInterceptor will be assigned to the specified id. All the wiring with Spring's messaging infrastructure can then be done manually. This is more cumbersome, but provides greater control over the configuration.
|
||||||
|
|
||||||
|
|
||||||
[[nsa-messages-attributes]]
|
[[nsa-websocket-message-broker-attributes]]
|
||||||
===== <messages> Attributes
|
===== <websocket-message-broker> Attributes
|
||||||
|
|
||||||
[[nsa-messages-id]]
|
[[nsa-websocket-message-broker-id]]
|
||||||
* **id** A bean identifier, used for referring to the ChannelSecurityInterceptor bean elsewhere in the context. If specified, Spring Security requires explicit configuration within Spring Messaging. If not specified, Spring Security will automatically integrate with the messaging infrastructure as described in <<nsa-messages>>
|
* **id** A bean identifier, used for referring to the ChannelSecurityInterceptor bean elsewhere in the context. If specified, Spring Security requires explicit configuration within Spring Messaging. If not specified, Spring Security will automatically integrate with the messaging infrastructure as described in <<nsa-websocket-message-broker>>
|
||||||
|
|
||||||
[[nsa-messages-children]]
|
[[nsa-websocket-message-broker-children]]
|
||||||
===== Child Elements of <messages>
|
===== Child Elements of <websocket-message-broker>
|
||||||
|
|
||||||
|
|
||||||
* <<nsa-message-interceptor,message-interceptor>>
|
* <<nsa-intercept-message,intercept-message>>
|
||||||
|
|
||||||
[[nsa-message-interceptor]]
|
[[nsa-intercept-message]]
|
||||||
==== <message-interceptor>
|
==== <intercept-message>
|
||||||
|
|
||||||
Defines an authorization rule for a message.
|
Defines an authorization rule for a message.
|
||||||
|
|
||||||
|
|
||||||
[[nsa-message-interceptor-parents]]
|
[[nsa-intercept-message-parents]]
|
||||||
===== Parent Elements of <message-interceptor>
|
===== Parent Elements of <intercept-message>
|
||||||
|
|
||||||
|
|
||||||
* <<nsa-messages,messages>>
|
* <<nsa-websocket-message-broker,websocket-message-broker>>
|
||||||
|
|
||||||
|
|
||||||
[[nsa-message-interceptor-attributes]]
|
[[nsa-intercept-message-attributes]]
|
||||||
===== <message-interceptor> Attributes
|
===== <intercept-message> Attributes
|
||||||
|
|
||||||
[[nsa-message-interceptor-pattern]]
|
[[nsa-intercept-message-pattern]]
|
||||||
* **pattern** An ant based pattern that matches on the Message destination. For example, "/**" matches any Message with a destination; "/admin/**" matches any Message that has a destination that starts with "/admin/**".
|
* **pattern** An ant based pattern that matches on the Message destination. For example, "/**" matches any Message with a destination; "/admin/**" matches any Message that has a destination that starts with "/admin/**".
|
||||||
|
|
||||||
[[nsa-message-interceptor-access]]
|
[[nsa-intercept-message-access]]
|
||||||
* **access** The expression used to secure the Message. For example, "denyAll" will deny access to all of the matching Messages; "permitAll" will grant access to all of the matching Messages; "hasRole('ADMIN') requires the current user to have the role 'ROLE_ADMIN' for the matching Messages.
|
* **access** The expression used to secure the Message. For example, "denyAll" will deny access to all of the matching Messages; "permitAll" will grant access to all of the matching Messages; "hasRole('ADMIN') requires the current user to have the role 'ROLE_ADMIN' for the matching Messages.
|
||||||
|
|
||||||
[[nsa-authentication]]
|
[[nsa-authentication]]
|
||||||
|
|
|
@ -197,7 +197,7 @@ public class SecurityContextChannelInterceptorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a user sends a message when processing another message
|
* If a user sends a websocket when processing another websocket
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
|
@ -213,7 +213,7 @@ public class SecurityContextChannelInterceptorTests {
|
||||||
|
|
||||||
assertThat(SecurityContextHolder.getContext().getAuthentication()).isSameAs(authentication);
|
assertThat(SecurityContextHolder.getContext().getAuthentication()).isSameAs(authentication);
|
||||||
|
|
||||||
// start send message
|
// start send websocket
|
||||||
messageBuilder.setHeader(SimpMessageHeaderAccessor.USER_HEADER, null);
|
messageBuilder.setHeader(SimpMessageHeaderAccessor.USER_HEADER, null);
|
||||||
interceptor.beforeHandle(messageBuilder.build(), channel, handler);
|
interceptor.beforeHandle(messageBuilder.build(), channel, handler);
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ public class SecurityContextChannelInterceptorTests {
|
||||||
interceptor.afterMessageHandled(messageBuilder.build(), channel, handler, null);
|
interceptor.afterMessageHandled(messageBuilder.build(), channel, handler, null);
|
||||||
|
|
||||||
assertThat(SecurityContextHolder.getContext().getAuthentication()).isSameAs(authentication);
|
assertThat(SecurityContextHolder.getContext().getAuthentication()).isSameAs(authentication);
|
||||||
// end send message
|
// end send websocket
|
||||||
|
|
||||||
interceptor.afterMessageHandled(messageBuilder.build(), channel, handler, null);
|
interceptor.afterMessageHandled(messageBuilder.build(), channel, handler, null);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue