Allow Custom PayloadInterceptor to be Added
Fixes gh-7362
This commit is contained in:
parent
ee0d7f6a79
commit
316380e622
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.security.config.annotation.rsocket;
|
||||||
|
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The standard order for {@link org.springframework.security.rsocket.PayloadInterceptor} to be
|
||||||
|
* sorted. The actual values might change, so users should use the {@link #getOrder()} method to
|
||||||
|
* calculate the position dynamically rather than copy values.
|
||||||
|
*
|
||||||
|
* @author Rob Winch
|
||||||
|
* @since 5.2
|
||||||
|
*/
|
||||||
|
public enum PayloadInterceptorOrder implements Ordered {
|
||||||
|
/**
|
||||||
|
* Where basic authentication is placed.
|
||||||
|
* @see RSocketSecurity#basicAuthentication(Customizer)
|
||||||
|
*/
|
||||||
|
BASIC_AUTHENTICATION,
|
||||||
|
/**
|
||||||
|
* Where JWT based authentication is performed.
|
||||||
|
* @see RSocketSecurity#jwt(Customizer)
|
||||||
|
*/
|
||||||
|
JWT_AUTHENTICATION,
|
||||||
|
/**
|
||||||
|
* A generic placeholder for other types of authentication.
|
||||||
|
* @see org.springframework.security.rsocket.authentication.AuthenticationPayloadInterceptor
|
||||||
|
*/
|
||||||
|
AUTHENTICATION,
|
||||||
|
/**
|
||||||
|
* Where anonymous authentication is placed.
|
||||||
|
*/
|
||||||
|
ANONYMOUS,
|
||||||
|
/**
|
||||||
|
* Where authorization is placed.
|
||||||
|
* @see org.springframework.security.rsocket.authorization.AuthorizationPayloadInterceptor
|
||||||
|
*/
|
||||||
|
AUTHORIZATION;
|
||||||
|
|
||||||
|
private static final int INTERVAL = 100;
|
||||||
|
|
||||||
|
private int order;
|
||||||
|
|
||||||
|
PayloadInterceptorOrder() {
|
||||||
|
this.order = ordinal() * INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOrder() {
|
||||||
|
return this.order;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ package org.springframework.security.config.annotation.rsocket;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
|
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||||
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
|
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
|
||||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||||
import org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager;
|
import org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager;
|
||||||
|
@ -107,6 +108,8 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class RSocketSecurity {
|
public class RSocketSecurity {
|
||||||
|
|
||||||
|
private List<PayloadInterceptor> payloadInterceptors = new ArrayList<>();
|
||||||
|
|
||||||
private BasicAuthenticationSpec basicAuthSpec;
|
private BasicAuthenticationSpec basicAuthSpec;
|
||||||
|
|
||||||
private JwtSpec jwtSpec;
|
private JwtSpec jwtSpec;
|
||||||
|
@ -117,6 +120,22 @@ public class RSocketSecurity {
|
||||||
|
|
||||||
private ReactiveAuthenticationManager authenticationManager;
|
private ReactiveAuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a {@link PayloadInterceptor} to be used. This is typically only used
|
||||||
|
* when using the DSL does not meet a users needs. In order to ensure the
|
||||||
|
* {@link PayloadInterceptor} is done in the proper order the {@link PayloadInterceptor} should
|
||||||
|
* either implement {@link org.springframework.core.Ordered} or be annotated with
|
||||||
|
* {@link org.springframework.core.annotation.Order}.
|
||||||
|
*
|
||||||
|
* @param interceptor
|
||||||
|
* @return the builder for additional customizations
|
||||||
|
* @see PayloadInterceptorOrder
|
||||||
|
*/
|
||||||
|
public RSocketSecurity addPayloadInterceptor(PayloadInterceptor interceptor) {
|
||||||
|
this.payloadInterceptors.add(interceptor);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public RSocketSecurity authenticationManager(ReactiveAuthenticationManager authenticationManager) {
|
public RSocketSecurity authenticationManager(ReactiveAuthenticationManager authenticationManager) {
|
||||||
this.authenticationManager = authenticationManager;
|
this.authenticationManager = authenticationManager;
|
||||||
return this;
|
return this;
|
||||||
|
@ -147,7 +166,9 @@ public class RSocketSecurity {
|
||||||
|
|
||||||
protected AuthenticationPayloadInterceptor build() {
|
protected AuthenticationPayloadInterceptor build() {
|
||||||
ReactiveAuthenticationManager manager = getAuthenticationManager();
|
ReactiveAuthenticationManager manager = getAuthenticationManager();
|
||||||
return new AuthenticationPayloadInterceptor(manager);
|
AuthenticationPayloadInterceptor result = new AuthenticationPayloadInterceptor(manager);
|
||||||
|
result.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BasicAuthenticationSpec() {}
|
private BasicAuthenticationSpec() {}
|
||||||
|
@ -185,6 +206,7 @@ public class RSocketSecurity {
|
||||||
ReactiveAuthenticationManager manager = getAuthenticationManager();
|
ReactiveAuthenticationManager manager = getAuthenticationManager();
|
||||||
AuthenticationPayloadInterceptor result = new AuthenticationPayloadInterceptor(manager);
|
AuthenticationPayloadInterceptor result = new AuthenticationPayloadInterceptor(manager);
|
||||||
result.setAuthenticationConverter(new BearerPayloadExchangeConverter());
|
result.setAuthenticationConverter(new BearerPayloadExchangeConverter());
|
||||||
|
result.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,20 +231,27 @@ public class RSocketSecurity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PayloadInterceptor> payloadInterceptors() {
|
private List<PayloadInterceptor> payloadInterceptors() {
|
||||||
List<PayloadInterceptor> payloadInterceptors = new ArrayList<>();
|
List<PayloadInterceptor> result = new ArrayList<>(this.payloadInterceptors);
|
||||||
|
|
||||||
if (this.basicAuthSpec != null) {
|
if (this.basicAuthSpec != null) {
|
||||||
payloadInterceptors.add(this.basicAuthSpec.build());
|
result.add(this.basicAuthSpec.build());
|
||||||
}
|
}
|
||||||
if (this.jwtSpec != null) {
|
if (this.jwtSpec != null) {
|
||||||
payloadInterceptors.add(this.jwtSpec.build());
|
result.add(this.jwtSpec.build());
|
||||||
}
|
}
|
||||||
payloadInterceptors.add(new AnonymousPayloadInterceptor("anonymousUser"));
|
result.add(anonymous());
|
||||||
|
|
||||||
if (this.authorizePayload != null) {
|
if (this.authorizePayload != null) {
|
||||||
payloadInterceptors.add(this.authorizePayload.build());
|
result.add(this.authorizePayload.build());
|
||||||
}
|
}
|
||||||
return payloadInterceptors;
|
AnnotationAwareOrderComparator.sort(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnonymousPayloadInterceptor anonymous() {
|
||||||
|
AnonymousPayloadInterceptor result = new AnonymousPayloadInterceptor("anonymousUser");
|
||||||
|
result.setOrder(PayloadInterceptorOrder.ANONYMOUS.getOrder());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AuthorizePayloadsSpec {
|
public class AuthorizePayloadsSpec {
|
||||||
|
@ -239,7 +268,9 @@ public class RSocketSecurity {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AuthorizationPayloadInterceptor build() {
|
protected AuthorizationPayloadInterceptor build() {
|
||||||
return new AuthorizationPayloadInterceptor(this.authzBuilder.build());
|
AuthorizationPayloadInterceptor result = new AuthorizationPayloadInterceptor(this.authzBuilder.build());
|
||||||
|
result.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Access route(String pattern) {
|
public Access route(String pattern) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.security.rsocket.authentication;
|
package org.springframework.security.rsocket.authentication;
|
||||||
|
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
|
@ -35,12 +36,13 @@ import java.util.List;
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
*/
|
*/
|
||||||
public class AnonymousPayloadInterceptor implements PayloadInterceptor {
|
public class AnonymousPayloadInterceptor implements PayloadInterceptor, Ordered {
|
||||||
|
|
||||||
private String key;
|
private String key;
|
||||||
private Object principal;
|
private Object principal;
|
||||||
private List<GrantedAuthority> authorities;
|
private List<GrantedAuthority> authorities;
|
||||||
|
|
||||||
|
private int order;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a filter with a principal named "anonymousUser" and the single authority
|
* Creates a filter with a principal named "anonymousUser" and the single authority
|
||||||
|
@ -67,6 +69,14 @@ public class AnonymousPayloadInterceptor implements PayloadInterceptor {
|
||||||
this.authorities = authorities;
|
this.authorities = authorities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return this.order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrder(int order) {
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain) {
|
public Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.security.rsocket.authentication;
|
package org.springframework.security.rsocket.authentication;
|
||||||
|
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||||
|
@ -33,10 +34,12 @@ import reactor.core.publisher.Mono;
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
*/
|
*/
|
||||||
public class AuthenticationPayloadInterceptor implements PayloadInterceptor {
|
public class AuthenticationPayloadInterceptor implements PayloadInterceptor, Ordered {
|
||||||
|
|
||||||
private final ReactiveAuthenticationManager authenticationManager;
|
private final ReactiveAuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
private int order;
|
||||||
|
|
||||||
private PayloadExchangeAuthenticationConverter authenticationConverter =
|
private PayloadExchangeAuthenticationConverter authenticationConverter =
|
||||||
new BasicAuthenticationPayloadExchangeConverter();
|
new BasicAuthenticationPayloadExchangeConverter();
|
||||||
|
|
||||||
|
@ -49,6 +52,15 @@ public class AuthenticationPayloadInterceptor implements PayloadInterceptor {
|
||||||
this.authenticationManager = authenticationManager;
|
this.authenticationManager = authenticationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return this.order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrder(int order) {
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the convert to be used
|
* Sets the convert to be used
|
||||||
* @param authenticationConverter
|
* @param authenticationConverter
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.security.rsocket.authorization;
|
package org.springframework.security.rsocket.authorization;
|
||||||
|
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||||
|
@ -32,15 +33,26 @@ import org.springframework.security.rsocket.PayloadInterceptor;
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
*/
|
*/
|
||||||
public class AuthorizationPayloadInterceptor implements PayloadInterceptor {
|
public class AuthorizationPayloadInterceptor implements PayloadInterceptor, Ordered {
|
||||||
private final ReactiveAuthorizationManager<PayloadExchange> authorizationManager;
|
private final ReactiveAuthorizationManager<PayloadExchange> authorizationManager;
|
||||||
|
|
||||||
|
private int order;
|
||||||
|
|
||||||
public AuthorizationPayloadInterceptor(
|
public AuthorizationPayloadInterceptor(
|
||||||
ReactiveAuthorizationManager<PayloadExchange> authorizationManager) {
|
ReactiveAuthorizationManager<PayloadExchange> authorizationManager) {
|
||||||
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
|
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
|
||||||
this.authorizationManager = authorizationManager;
|
this.authorizationManager = authorizationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return this.order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrder(int order) {
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain) {
|
public Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain) {
|
||||||
return ReactiveSecurityContextHolder.getContext()
|
return ReactiveSecurityContextHolder.getContext()
|
||||||
|
|
Loading…
Reference in New Issue