Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 559b73b

Browse files
therepanicjzheaux
authored andcommitted
Add Disabling Anonymous Authentication in RSocketSecurity
Closes: gh-17132 Signed-off-by: Andrey Litvitski <andrey1010102008@gmail.com> 1 Signed-off-by: Andrey Litvitski <andrey1010102008@gmail.com> 1 Signed-off-by: Andrey Litvitski <andrey1010102008@gmail.com>
1 parent 3278f3a commit 559b73b

File tree

2 files changed

+186
-7
lines changed

2 files changed

+186
-7
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.config.annotation.rsocket;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import io.rsocket.core.RSocketServer;
23+
import io.rsocket.exceptions.RejectedSetupException;
24+
import io.rsocket.frame.decoder.PayloadDecoder;
25+
import io.rsocket.transport.netty.server.CloseableChannel;
26+
import io.rsocket.transport.netty.server.TcpServerTransport;
27+
import org.junit.jupiter.api.AfterEach;
28+
import org.junit.jupiter.api.BeforeEach;
29+
import org.junit.jupiter.api.Test;
30+
import org.junit.jupiter.api.extension.ExtendWith;
31+
32+
import org.springframework.beans.factory.annotation.Autowired;
33+
import org.springframework.context.annotation.Bean;
34+
import org.springframework.context.annotation.Configuration;
35+
import org.springframework.messaging.handler.annotation.MessageMapping;
36+
import org.springframework.messaging.rsocket.RSocketRequester;
37+
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
38+
import org.springframework.security.authentication.AuthenticationTrustResolver;
39+
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
40+
import org.springframework.security.authorization.AuthorizationDecision;
41+
import org.springframework.security.authorization.ReactiveAuthorizationManager;
42+
import org.springframework.security.rsocket.core.PayloadSocketAcceptorInterceptor;
43+
import org.springframework.security.rsocket.core.SecuritySocketAcceptorInterceptor;
44+
import org.springframework.security.rsocket.util.matcher.PayloadExchangeAuthorizationContext;
45+
import org.springframework.stereotype.Controller;
46+
import org.springframework.test.context.ContextConfiguration;
47+
import org.springframework.test.context.junit.jupiter.SpringExtension;
48+
49+
import static org.assertj.core.api.Assertions.assertThat;
50+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
51+
52+
/**
53+
* @author Andrey Litvitski
54+
*/
55+
@ContextConfiguration
56+
@ExtendWith(SpringExtension.class)
57+
public class AnonymousAuthenticationITests {
58+
59+
@Autowired
60+
RSocketMessageHandler handler;
61+
62+
@Autowired
63+
SecuritySocketAcceptorInterceptor interceptor;
64+
65+
@Autowired
66+
ServerController controller;
67+
68+
private CloseableChannel server;
69+
70+
private RSocketRequester requester;
71+
72+
@BeforeEach
73+
public void setup() {
74+
// @formatter:off
75+
this.server = RSocketServer.create()
76+
.payloadDecoder(PayloadDecoder.ZERO_COPY)
77+
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
78+
)
79+
.acceptor(this.handler.responder())
80+
.bind(TcpServerTransport.create("localhost", 0))
81+
.block();
82+
// @formatter:on
83+
}
84+
85+
@AfterEach
86+
public void dispose() {
87+
this.requester.rsocket().dispose();
88+
this.server.dispose();
89+
this.controller.payloads.clear();
90+
}
91+
92+
@Test
93+
public void requestWhenAnonymousDisabledThenRespondsWithForbidden() {
94+
this.requester = RSocketRequester.builder()
95+
.rsocketStrategies(this.handler.getRSocketStrategies())
96+
.connectTcp("localhost", this.server.address().getPort())
97+
.block();
98+
String data = "andrew";
99+
assertThatExceptionOfType(RejectedSetupException.class).isThrownBy(
100+
() -> this.requester.route("secure.retrieve-mono").data(data).retrieveMono(String.class).block());
101+
assertThat(this.controller.payloads).isEmpty();
102+
}
103+
104+
@Configuration
105+
@EnableRSocketSecurity
106+
static class Config {
107+
108+
@Bean
109+
ServerController controller() {
110+
return new ServerController();
111+
}
112+
113+
@Bean
114+
RSocketMessageHandler messageHandler() {
115+
return new RSocketMessageHandler();
116+
}
117+
118+
@Bean
119+
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
120+
AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
121+
ReactiveAuthorizationManager<PayloadExchangeAuthorizationContext> anonymous = (authentication,
122+
exchange) -> authentication.map(trustResolver::isAnonymous).map(AuthorizationDecision::new);
123+
rsocket.authorizePayload((authorize) -> authorize.anyExchange().access(anonymous));
124+
rsocket.anonymousAuthentication((anonymousAuthentication) -> anonymousAuthentication.disable());
125+
return rsocket.build();
126+
}
127+
128+
}
129+
130+
@Controller
131+
static class ServerController {
132+
133+
private List<String> payloads = new ArrayList<>();
134+
135+
@MessageMapping("**")
136+
String retrieveMono(String payload) {
137+
add(payload);
138+
return "Hi " + payload;
139+
}
140+
141+
private void add(String p) {
142+
this.payloads.add(p);
143+
}
144+
145+
}
146+
147+
}

‎config/src/main/java/org/springframework/security/config/annotation/rsocket/RSocketSecurity.java‎

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
* @author Manuel Tejeda
110110
* @author Ebert Toribio
111111
* @author Ngoc Nhan
112+
* @author Andrey Litvitski
112113
* @since 5.2
113114
*/
114115
public class RSocketSecurity {
@@ -119,6 +120,8 @@ public class RSocketSecurity {
119120

120121
private SimpleAuthenticationSpec simpleAuthSpec;
121122

123+
private AnonymousAuthenticationSpec anonymousAuthSpec = new AnonymousAuthenticationSpec(this);
124+
122125
private JwtSpec jwtSpec;
123126

124127
private AuthorizePayloadsSpec authorizePayload;
@@ -164,6 +167,19 @@ public RSocketSecurity simpleAuthentication(Customizer<SimpleAuthenticationSpec>
164167
return this;
165168
}
166169

170+
/**
171+
* Adds anonymous authentication
172+
* @param anonymous a customizer
173+
* @return this instance
174+
*/
175+
public RSocketSecurity anonymousAuthentication(Customizer<AnonymousAuthenticationSpec> anonymous) {
176+
if (this.anonymousAuthSpec == null) {
177+
this.anonymousAuthSpec = new AnonymousAuthenticationSpec(this);
178+
}
179+
anonymous.customize(this.anonymousAuthSpec);
180+
return this;
181+
}
182+
167183
/**
168184
* Adds authentication with BasicAuthenticationPayloadExchangeConverter.
169185
* @param basic
@@ -214,20 +230,16 @@ private List<PayloadInterceptor> payloadInterceptors() {
214230
if (this.jwtSpec != null) {
215231
result.addAll(this.jwtSpec.build());
216232
}
217-
result.add(anonymous());
233+
if (this.anonymousAuthSpec != null) {
234+
result.add(this.anonymousAuthSpec.build());
235+
}
218236
if (this.authorizePayload != null) {
219237
result.add(this.authorizePayload.build());
220238
}
221239
AnnotationAwareOrderComparator.sort(result);
222240
return result;
223241
}
224242

225-
private AnonymousPayloadInterceptor anonymous() {
226-
AnonymousPayloadInterceptor result = new AnonymousPayloadInterceptor("anonymousUser");
227-
result.setOrder(PayloadInterceptorOrder.ANONYMOUS.getOrder());
228-
return result;
229-
}
230-
231243
private <T> T getBean(Class<T> beanClass) {
232244
if (this.context == null) {
233245
return null;
@@ -283,6 +295,26 @@ protected AuthenticationPayloadInterceptor build() {
283295

284296
}
285297

298+
public final class AnonymousAuthenticationSpec {
299+
300+
private RSocketSecurity parent;
301+
302+
private AnonymousAuthenticationSpec(RSocketSecurity parent) {
303+
this.parent = parent;
304+
}
305+
306+
protected AnonymousPayloadInterceptor build() {
307+
AnonymousPayloadInterceptor result = new AnonymousPayloadInterceptor("anonymousUser");
308+
result.setOrder(PayloadInterceptorOrder.ANONYMOUS.getOrder());
309+
return result;
310+
}
311+
312+
public void disable() {
313+
this.parent.anonymousAuthSpec = null;
314+
}
315+
316+
}
317+
286318
public final class BasicAuthenticationSpec {
287319

288320
private ReactiveAuthenticationManager authenticationManager;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /