Skip to content

Commit 316380e

Browse files
committed
Allow Custom PayloadInterceptor to be Added
Fixes gh-7362
1 parent ee0d7f6 commit 316380e

5 files changed

Lines changed: 143 additions & 11 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2019 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 org.springframework.core.Ordered;
20+
import org.springframework.security.config.Customizer;
21+
22+
/**
23+
* The standard order for {@link org.springframework.security.rsocket.PayloadInterceptor} to be
24+
* sorted. The actual values might change, so users should use the {@link #getOrder()} method to
25+
* calculate the position dynamically rather than copy values.
26+
*
27+
* @author Rob Winch
28+
* @since 5.2
29+
*/
30+
public enum PayloadInterceptorOrder implements Ordered {
31+
/**
32+
* Where basic authentication is placed.
33+
* @see RSocketSecurity#basicAuthentication(Customizer)
34+
*/
35+
BASIC_AUTHENTICATION,
36+
/**
37+
* Where JWT based authentication is performed.
38+
* @see RSocketSecurity#jwt(Customizer)
39+
*/
40+
JWT_AUTHENTICATION,
41+
/**
42+
* A generic placeholder for other types of authentication.
43+
* @see org.springframework.security.rsocket.authentication.AuthenticationPayloadInterceptor
44+
*/
45+
AUTHENTICATION,
46+
/**
47+
* Where anonymous authentication is placed.
48+
*/
49+
ANONYMOUS,
50+
/**
51+
* Where authorization is placed.
52+
* @see org.springframework.security.rsocket.authorization.AuthorizationPayloadInterceptor
53+
*/
54+
AUTHORIZATION;
55+
56+
private static final int INTERVAL = 100;
57+
58+
private int order;
59+
60+
PayloadInterceptorOrder() {
61+
this.order = ordinal() * INTERVAL;
62+
}
63+
64+
public int getOrder() {
65+
return this.order;
66+
}
67+
}

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

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.beans.BeansException;
2020
import org.springframework.context.ApplicationContext;
2121
import org.springframework.core.ResolvableType;
22+
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
2223
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
2324
import org.springframework.security.authentication.ReactiveAuthenticationManager;
2425
import org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager;
@@ -107,6 +108,8 @@
107108
*/
108109
public class RSocketSecurity {
109110

111+
private List<PayloadInterceptor> payloadInterceptors = new ArrayList<>();
112+
110113
private BasicAuthenticationSpec basicAuthSpec;
111114

112115
private JwtSpec jwtSpec;
@@ -117,6 +120,22 @@ public class RSocketSecurity {
117120

118121
private ReactiveAuthenticationManager authenticationManager;
119122

123+
/**
124+
* Adds a {@link PayloadInterceptor} to be used. This is typically only used
125+
* when using the DSL does not meet a users needs. In order to ensure the
126+
* {@link PayloadInterceptor} is done in the proper order the {@link PayloadInterceptor} should
127+
* either implement {@link org.springframework.core.Ordered} or be annotated with
128+
* {@link org.springframework.core.annotation.Order}.
129+
*
130+
* @param interceptor
131+
* @return the builder for additional customizations
132+
* @see PayloadInterceptorOrder
133+
*/
134+
public RSocketSecurity addPayloadInterceptor(PayloadInterceptor interceptor) {
135+
this.payloadInterceptors.add(interceptor);
136+
return this;
137+
}
138+
120139
public RSocketSecurity authenticationManager(ReactiveAuthenticationManager authenticationManager) {
121140
this.authenticationManager = authenticationManager;
122141
return this;
@@ -147,7 +166,9 @@ private ReactiveAuthenticationManager getAuthenticationManager() {
147166

148167
protected AuthenticationPayloadInterceptor build() {
149168
ReactiveAuthenticationManager manager = getAuthenticationManager();
150-
return new AuthenticationPayloadInterceptor(manager);
169+
AuthenticationPayloadInterceptor result = new AuthenticationPayloadInterceptor(manager);
170+
result.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder());
171+
return result;
151172
}
152173

153174
private BasicAuthenticationSpec() {}
@@ -185,6 +206,7 @@ protected AuthenticationPayloadInterceptor build() {
185206
ReactiveAuthenticationManager manager = getAuthenticationManager();
186207
AuthenticationPayloadInterceptor result = new AuthenticationPayloadInterceptor(manager);
187208
result.setAuthenticationConverter(new BearerPayloadExchangeConverter());
209+
result.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder());
188210
return result;
189211
}
190212

@@ -209,20 +231,27 @@ public PayloadSocketAcceptorInterceptor build() {
209231
}
210232

211233
private List<PayloadInterceptor> payloadInterceptors() {
212-
List<PayloadInterceptor> payloadInterceptors = new ArrayList<>();
234+
List<PayloadInterceptor> result = new ArrayList<>(this.payloadInterceptors);
213235

214236
if (this.basicAuthSpec != null) {
215-
payloadInterceptors.add(this.basicAuthSpec.build());
237+
result.add(this.basicAuthSpec.build());
216238
}
217239
if (this.jwtSpec != null) {
218-
payloadInterceptors.add(this.jwtSpec.build());
240+
result.add(this.jwtSpec.build());
219241
}
220-
payloadInterceptors.add(new AnonymousPayloadInterceptor("anonymousUser"));
242+
result.add(anonymous());
221243

222244
if (this.authorizePayload != null) {
223-
payloadInterceptors.add(this.authorizePayload.build());
245+
result.add(this.authorizePayload.build());
224246
}
225-
return payloadInterceptors;
247+
AnnotationAwareOrderComparator.sort(result);
248+
return result;
249+
}
250+
251+
private AnonymousPayloadInterceptor anonymous() {
252+
AnonymousPayloadInterceptor result = new AnonymousPayloadInterceptor("anonymousUser");
253+
result.setOrder(PayloadInterceptorOrder.ANONYMOUS.getOrder());
254+
return result;
226255
}
227256

228257
public class AuthorizePayloadsSpec {
@@ -239,7 +268,9 @@ public Access anyRequest() {
239268
}
240269

241270
protected AuthorizationPayloadInterceptor build() {
242-
return new AuthorizationPayloadInterceptor(this.authzBuilder.build());
271+
AuthorizationPayloadInterceptor result = new AuthorizationPayloadInterceptor(this.authzBuilder.build());
272+
result.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder());
273+
return result;
243274
}
244275

245276
public Access route(String pattern) {

rsocket/src/main/java/org/springframework/security/rsocket/authentication/AnonymousPayloadInterceptor.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.security.rsocket.authentication;
1818

19+
import org.springframework.core.Ordered;
1920
import org.springframework.security.authentication.AnonymousAuthenticationToken;
2021
import org.springframework.security.core.GrantedAuthority;
2122
import org.springframework.security.core.authority.AuthorityUtils;
@@ -35,12 +36,13 @@
3536
* @author Rob Winch
3637
* @since 5.2
3738
*/
38-
public class AnonymousPayloadInterceptor implements PayloadInterceptor {
39+
public class AnonymousPayloadInterceptor implements PayloadInterceptor, Ordered {
3940

4041
private String key;
4142
private Object principal;
4243
private List<GrantedAuthority> authorities;
4344

45+
private int order;
4446

4547
/**
4648
* Creates a filter with a principal named "anonymousUser" and the single authority
@@ -67,6 +69,14 @@ public AnonymousPayloadInterceptor(String key, Object principal,
6769
this.authorities = authorities;
6870
}
6971

72+
@Override
73+
public int getOrder() {
74+
return this.order;
75+
}
76+
77+
public void setOrder(int order) {
78+
this.order = order;
79+
}
7080

7181
@Override
7282
public Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain) {

rsocket/src/main/java/org/springframework/security/rsocket/authentication/AuthenticationPayloadInterceptor.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.security.rsocket.authentication;
1818

19+
import org.springframework.core.Ordered;
1920
import org.springframework.security.authentication.ReactiveAuthenticationManager;
2021
import org.springframework.security.core.Authentication;
2122
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
@@ -33,10 +34,12 @@
3334
* @author Rob Winch
3435
* @since 5.2
3536
*/
36-
public class AuthenticationPayloadInterceptor implements PayloadInterceptor {
37+
public class AuthenticationPayloadInterceptor implements PayloadInterceptor, Ordered {
3738

3839
private final ReactiveAuthenticationManager authenticationManager;
3940

41+
private int order;
42+
4043
private PayloadExchangeAuthenticationConverter authenticationConverter =
4144
new BasicAuthenticationPayloadExchangeConverter();
4245

@@ -49,6 +52,15 @@ public AuthenticationPayloadInterceptor(ReactiveAuthenticationManager authentica
4952
this.authenticationManager = authenticationManager;
5053
}
5154

55+
@Override
56+
public int getOrder() {
57+
return this.order;
58+
}
59+
60+
public void setOrder(int order) {
61+
this.order = order;
62+
}
63+
5264
/**
5365
* Sets the convert to be used
5466
* @param authenticationConverter

rsocket/src/main/java/org/springframework/security/rsocket/authorization/AuthorizationPayloadInterceptor.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.security.rsocket.authorization;
1818

19+
import org.springframework.core.Ordered;
1920
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
2021
import org.springframework.security.authorization.ReactiveAuthorizationManager;
2122
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
@@ -32,15 +33,26 @@
3233
* @author Rob Winch
3334
* @since 5.2
3435
*/
35-
public class AuthorizationPayloadInterceptor implements PayloadInterceptor {
36+
public class AuthorizationPayloadInterceptor implements PayloadInterceptor, Ordered {
3637
private final ReactiveAuthorizationManager<PayloadExchange> authorizationManager;
3738

39+
private int order;
40+
3841
public AuthorizationPayloadInterceptor(
3942
ReactiveAuthorizationManager<PayloadExchange> authorizationManager) {
4043
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
4144
this.authorizationManager = authorizationManager;
4245
}
4346

47+
@Override
48+
public int getOrder() {
49+
return this.order;
50+
}
51+
52+
public void setOrder(int order) {
53+
this.order = order;
54+
}
55+
4456
@Override
4557
public Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain) {
4658
return ReactiveSecurityContextHolder.getContext()

0 commit comments

Comments
 (0)