2
0
Эх сурвалжийг харах

Allow Custom PayloadInterceptor to be Added

Fixes gh-7362
Rob Winch 6 жил өмнө
parent
commit
316380e622

+ 67 - 0
config/src/main/java/org/springframework/security/config/annotation/rsocket/PayloadInterceptorOrder.java

@@ -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;
+	}
+}

+ 39 - 8
config/src/main/java/org/springframework/security/config/annotation/rsocket/RSocketSecurity.java

@@ -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) {

+ 11 - 1
rsocket/src/main/java/org/springframework/security/rsocket/authentication/AnonymousPayloadInterceptor.java

@@ -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) {

+ 13 - 1
rsocket/src/main/java/org/springframework/security/rsocket/authentication/AuthenticationPayloadInterceptor.java

@@ -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

+ 13 - 1
rsocket/src/main/java/org/springframework/security/rsocket/authorization/AuthorizationPayloadInterceptor.java

@@ -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()