Reformat code using spring-javaformat
Run `./gradlew format` to reformat all java files. Issue gh-8945
This commit is contained in:
@@ -26,6 +26,7 @@ import org.springframework.util.MimeType;
|
||||
* @since 5.2
|
||||
*/
|
||||
public interface PayloadExchange {
|
||||
|
||||
PayloadExchangeType getType();
|
||||
|
||||
Payload getPayload();
|
||||
@@ -33,4 +34,5 @@ public interface PayloadExchange {
|
||||
MimeType getDataMimeType();
|
||||
|
||||
MimeType getMetadataMimeType();
|
||||
|
||||
}
|
||||
|
||||
+9
-6
@@ -23,14 +23,16 @@ package org.springframework.security.rsocket.api;
|
||||
* @since 5.2
|
||||
*/
|
||||
public enum PayloadExchangeType {
|
||||
|
||||
/**
|
||||
* The <a href="https://rsocket.io/docs/Protocol#setup-frame-0x01">Setup</a>. Can
|
||||
* be used to determine if a Payload is part of the connection
|
||||
* The <a href="https://rsocket.io/docs/Protocol#setup-frame-0x01">Setup</a>. Can be
|
||||
* used to determine if a Payload is part of the connection
|
||||
*/
|
||||
SETUP(false),
|
||||
|
||||
/**
|
||||
* A <a href="https://rsocket.io/docs/Protocol#frame-fnf">Fire and Forget</a> exchange.
|
||||
* A <a href="https://rsocket.io/docs/Protocol#frame-fnf">Fire and Forget</a>
|
||||
* exchange.
|
||||
*/
|
||||
FIRE_AND_FORGET(true),
|
||||
|
||||
@@ -41,9 +43,9 @@ public enum PayloadExchangeType {
|
||||
REQUEST_RESPONSE(true),
|
||||
|
||||
/**
|
||||
* A <a href="https://rsocket.io/docs/Protocol#request-stream-frame">Request Stream</a>
|
||||
* exchange. This is only represents the request portion. The {@link #PAYLOAD} type
|
||||
* represents the data that submitted.
|
||||
* A <a href="https://rsocket.io/docs/Protocol#request-stream-frame">Request
|
||||
* Stream</a> exchange. This is only represents the request portion. The
|
||||
* {@link #PAYLOAD} type represents the data that submitted.
|
||||
*/
|
||||
REQUEST_STREAM(true),
|
||||
|
||||
@@ -77,4 +79,5 @@ public enum PayloadExchangeType {
|
||||
public boolean isRequest() {
|
||||
return this.isRequest;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -19,14 +19,15 @@ package org.springframework.security.rsocket.api;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Contract for interception-style, chained processing of Payloads that may
|
||||
* be used to implement cross-cutting, application-agnostic requirements such
|
||||
* as security, timeouts, and others.
|
||||
* Contract for interception-style, chained processing of Payloads that may be used to
|
||||
* implement cross-cutting, application-agnostic requirements such as security, timeouts,
|
||||
* and others.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
*/
|
||||
public interface PayloadInterceptor {
|
||||
|
||||
/**
|
||||
* Process the Web request and (optionally) delegate to the next
|
||||
* {@code PayloadInterceptor} through the given {@link PayloadInterceptorChain}.
|
||||
@@ -35,4 +36,5 @@ public interface PayloadInterceptor {
|
||||
* @return {@code Mono<Void>} to indicate when payload processing is complete
|
||||
*/
|
||||
Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain);
|
||||
|
||||
}
|
||||
|
||||
+4
-2
@@ -19,16 +19,18 @@ package org.springframework.security.rsocket.api;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Contract to allow a {@link PayloadInterceptor} to delegate to the next in the chain.
|
||||
* *
|
||||
* Contract to allow a {@link PayloadInterceptor} to delegate to the next in the chain. *
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
*/
|
||||
public interface PayloadInterceptorChain {
|
||||
|
||||
/**
|
||||
* Process the payload exchange.
|
||||
* @param exchange the current server exchange
|
||||
* @return {@code Mono<Void>} to indicate when request processing is complete
|
||||
*/
|
||||
Mono<Void> next(PayloadExchange exchange);
|
||||
|
||||
}
|
||||
|
||||
+13
-14
@@ -39,7 +39,9 @@ import java.util.List;
|
||||
public class AnonymousPayloadInterceptor implements PayloadInterceptor, Ordered {
|
||||
|
||||
private String key;
|
||||
|
||||
private Object principal;
|
||||
|
||||
private List<GrantedAuthority> authorities;
|
||||
|
||||
private int order;
|
||||
@@ -47,7 +49,6 @@ public class AnonymousPayloadInterceptor implements PayloadInterceptor, Ordered
|
||||
/**
|
||||
* Creates a filter with a principal named "anonymousUser" and the single authority
|
||||
* "ROLE_ANONYMOUS".
|
||||
*
|
||||
* @param key the key to identify tokens created by this filter
|
||||
*/
|
||||
public AnonymousPayloadInterceptor(String key) {
|
||||
@@ -55,12 +56,11 @@ public class AnonymousPayloadInterceptor implements PayloadInterceptor, Ordered
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key key the key to identify tokens created by this filter
|
||||
* @param principal the principal which will be used to represent anonymous users
|
||||
* @param key key the key to identify tokens created by this filter
|
||||
* @param principal the principal which will be used to represent anonymous users
|
||||
* @param authorities the authority list for anonymous users
|
||||
*/
|
||||
public AnonymousPayloadInterceptor(String key, Object principal,
|
||||
List<GrantedAuthority> authorities) {
|
||||
public AnonymousPayloadInterceptor(String key, Object principal, List<GrantedAuthority> authorities) {
|
||||
Assert.hasLength(key, "key cannot be null or empty");
|
||||
Assert.notNull(principal, "Anonymous authentication principal must be set");
|
||||
Assert.notNull(authorities, "Anonymous authorities must be set");
|
||||
@@ -80,14 +80,13 @@ public class AnonymousPayloadInterceptor implements PayloadInterceptor, Ordered
|
||||
|
||||
@Override
|
||||
public Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain) {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.switchIfEmpty(Mono.defer(() -> {
|
||||
AnonymousAuthenticationToken authentication = new AnonymousAuthenticationToken(
|
||||
this.key, this.principal, this.authorities);
|
||||
return chain.next(exchange)
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
|
||||
.then(Mono.empty());
|
||||
}))
|
||||
.flatMap(securityContext -> chain.next(exchange));
|
||||
return ReactiveSecurityContextHolder.getContext().switchIfEmpty(Mono.defer(() -> {
|
||||
AnonymousAuthenticationToken authentication = new AnonymousAuthenticationToken(this.key, this.principal,
|
||||
this.authorities);
|
||||
return chain.next(exchange)
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
|
||||
.then(Mono.empty());
|
||||
})).flatMap(securityContext -> chain.next(exchange));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
-12
@@ -36,29 +36,32 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Converts from the {@link PayloadExchange} for
|
||||
* <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Authentication.md">Authentication Extension</a>.
|
||||
* For
|
||||
* <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md">Simple</a>
|
||||
* a {@link UsernamePasswordAuthenticationToken} is returned. For
|
||||
* <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md">Bearer</a>
|
||||
* Converts from the {@link PayloadExchange} for <a href=
|
||||
* "https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Authentication.md">Authentication
|
||||
* Extension</a>. For <a href=
|
||||
* "https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md">Simple</a>
|
||||
* a {@link UsernamePasswordAuthenticationToken} is returned. For <a href=
|
||||
* "https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md">Bearer</a>
|
||||
* a {@link BearerTokenAuthenticationToken} is returned.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.3
|
||||
*/
|
||||
public class AuthenticationPayloadExchangeConverter implements PayloadExchangeAuthenticationConverter {
|
||||
private static final MimeType COMPOSITE_METADATA_MIME_TYPE = MimeTypeUtils.parseMimeType(
|
||||
WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
private static final MimeType AUTHENTICATION_MIME_TYPE = MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString());
|
||||
private static final MimeType COMPOSITE_METADATA_MIME_TYPE = MimeTypeUtils
|
||||
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
private static final MimeType AUTHENTICATION_MIME_TYPE = MimeTypeUtils
|
||||
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString());
|
||||
|
||||
private MetadataExtractor metadataExtractor = createDefaultExtractor();
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> convert(PayloadExchange exchange) {
|
||||
return Mono.fromCallable(() -> this.metadataExtractor
|
||||
.extract(exchange.getPayload(), this.COMPOSITE_METADATA_MIME_TYPE))
|
||||
return Mono
|
||||
.fromCallable(
|
||||
() -> this.metadataExtractor.extract(exchange.getPayload(), this.COMPOSITE_METADATA_MIME_TYPE))
|
||||
.flatMap(metadata -> Mono.justOrEmpty(authentication(metadata)));
|
||||
}
|
||||
|
||||
@@ -74,7 +77,8 @@ public class AuthenticationPayloadExchangeConverter implements PayloadExchangeAu
|
||||
WellKnownAuthType wellKnownAuthType = AuthMetadataCodec.readWellKnownAuthType(rawAuthentication);
|
||||
if (WellKnownAuthType.SIMPLE.equals(wellKnownAuthType)) {
|
||||
return simple(rawAuthentication);
|
||||
} else if (WellKnownAuthType.BEARER.equals(wellKnownAuthType)) {
|
||||
}
|
||||
else if (WellKnownAuthType.BEARER.equals(wellKnownAuthType)) {
|
||||
return bearer(rawAuthentication);
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown Mime Type " + wellKnownAuthType);
|
||||
@@ -99,4 +103,5 @@ public class AuthenticationPayloadExchangeConverter implements PayloadExchangeAu
|
||||
result.metadataToExtract(AUTHENTICATION_MIME_TYPE, byte[].class, "authentication");
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-10
@@ -40,8 +40,7 @@ public class AuthenticationPayloadInterceptor implements PayloadInterceptor, Ord
|
||||
|
||||
private int order;
|
||||
|
||||
private PayloadExchangeAuthenticationConverter authenticationConverter =
|
||||
new BasicAuthenticationPayloadExchangeConverter();
|
||||
private PayloadExchangeAuthenticationConverter authenticationConverter = new BasicAuthenticationPayloadExchangeConverter();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
@@ -65,22 +64,19 @@ public class AuthenticationPayloadInterceptor implements PayloadInterceptor, Ord
|
||||
* Sets the convert to be used
|
||||
* @param authenticationConverter
|
||||
*/
|
||||
public void setAuthenticationConverter(
|
||||
PayloadExchangeAuthenticationConverter authenticationConverter) {
|
||||
public void setAuthenticationConverter(PayloadExchangeAuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
public Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain) {
|
||||
return this.authenticationConverter.convert(exchange)
|
||||
.switchIfEmpty(chain.next(exchange).then(Mono.empty()))
|
||||
.flatMap(a -> this.authenticationManager.authenticate(a))
|
||||
.flatMap(a -> onAuthenticationSuccess(chain.next(exchange), a));
|
||||
return this.authenticationConverter.convert(exchange).switchIfEmpty(chain.next(exchange).then(Mono.empty()))
|
||||
.flatMap(a -> this.authenticationManager.authenticate(a))
|
||||
.flatMap(a -> onAuthenticationSuccess(chain.next(exchange), a));
|
||||
}
|
||||
|
||||
private Mono<Void> onAuthenticationSuccess(Mono<Void> payload, Authentication authentication) {
|
||||
return payload
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication));
|
||||
return payload.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-7
@@ -38,23 +38,26 @@ import reactor.core.publisher.Mono;
|
||||
*/
|
||||
public class BasicAuthenticationPayloadExchangeConverter implements PayloadExchangeAuthenticationConverter {
|
||||
|
||||
private MimeType metadataMimetype = MimeTypeUtils.parseMimeType(
|
||||
WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
private MimeType metadataMimetype = MimeTypeUtils
|
||||
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
private MetadataExtractor metadataExtractor = createDefaultExtractor();
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> convert(PayloadExchange exchange) {
|
||||
return Mono.fromCallable(() -> this.metadataExtractor
|
||||
.extract(exchange.getPayload(), this.metadataMimetype))
|
||||
.flatMap(metadata -> Mono.justOrEmpty(metadata.get(UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE.toString())))
|
||||
return Mono.fromCallable(() -> this.metadataExtractor.extract(exchange.getPayload(), this.metadataMimetype))
|
||||
.flatMap(metadata -> Mono
|
||||
.justOrEmpty(metadata.get(UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE.toString())))
|
||||
.cast(UsernamePasswordMetadata.class)
|
||||
.map(credentials -> new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword()));
|
||||
.map(credentials -> new UsernamePasswordAuthenticationToken(credentials.getUsername(),
|
||||
credentials.getPassword()));
|
||||
}
|
||||
|
||||
private static MetadataExtractor createDefaultExtractor() {
|
||||
DefaultMetadataExtractor result = new DefaultMetadataExtractor(new BasicAuthenticationDecoder());
|
||||
result.metadataToExtract(UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE, UsernamePasswordMetadata.class, (String) null);
|
||||
result.metadataToExtract(UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE,
|
||||
UsernamePasswordMetadata.class, (String) null);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-6
@@ -27,16 +27,16 @@ import reactor.core.publisher.Mono;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Converts from the {@link PayloadExchange} to a
|
||||
* {@link BearerTokenAuthenticationToken} by extracting
|
||||
* {@link BearerTokenMetadata#BEARER_AUTHENTICATION_MIME_TYPE} from the metadata.
|
||||
* @author Rob Winch
|
||||
* Converts from the {@link PayloadExchange} to a {@link BearerTokenAuthenticationToken}
|
||||
* by extracting {@link BearerTokenMetadata#BEARER_AUTHENTICATION_MIME_TYPE} from the
|
||||
* metadata.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
*/
|
||||
public class BearerPayloadExchangeConverter implements PayloadExchangeAuthenticationConverter {
|
||||
|
||||
private static final String BEARER_MIME_TYPE_VALUE =
|
||||
BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE.toString();
|
||||
private static final String BEARER_MIME_TYPE_VALUE = BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE.toString();
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> convert(PayloadExchange exchange) {
|
||||
@@ -51,4 +51,5 @@ public class BearerPayloadExchangeConverter implements PayloadExchangeAuthentica
|
||||
}
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -22,9 +22,12 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Converts from a {@link PayloadExchange} to an {@link Authentication}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
*/
|
||||
public interface PayloadExchangeAuthenticationConverter {
|
||||
|
||||
Mono<Authentication> convert(PayloadExchange exchange);
|
||||
|
||||
}
|
||||
|
||||
+6
-5
@@ -34,12 +34,12 @@ import org.springframework.security.rsocket.api.PayloadInterceptor;
|
||||
* @since 5.2
|
||||
*/
|
||||
public class AuthorizationPayloadInterceptor implements PayloadInterceptor, Ordered {
|
||||
|
||||
private final ReactiveAuthorizationManager<PayloadExchange> authorizationManager;
|
||||
|
||||
private int order;
|
||||
|
||||
public AuthorizationPayloadInterceptor(
|
||||
ReactiveAuthorizationManager<PayloadExchange> authorizationManager) {
|
||||
public AuthorizationPayloadInterceptor(ReactiveAuthorizationManager<PayloadExchange> authorizationManager) {
|
||||
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
|
||||
this.authorizationManager = authorizationManager;
|
||||
}
|
||||
@@ -55,11 +55,12 @@ public class AuthorizationPayloadInterceptor implements PayloadInterceptor, Orde
|
||||
|
||||
@Override
|
||||
public Mono<Void> intercept(PayloadExchange exchange, PayloadInterceptorChain chain) {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.filter(c -> c.getAuthentication() != null)
|
||||
return ReactiveSecurityContextHolder.getContext().filter(c -> c.getAuthentication() != null)
|
||||
.map(SecurityContext::getAuthentication)
|
||||
.switchIfEmpty(Mono.error(() -> new AuthenticationCredentialsNotFoundException("An Authentication (possibly AnonymousAuthenticationToken) is required.")))
|
||||
.switchIfEmpty(Mono.error(() -> new AuthenticationCredentialsNotFoundException(
|
||||
"An Authentication (possibly AnonymousAuthenticationToken) is required.")))
|
||||
.as(authentication -> this.authorizationManager.verify(authentication, exchange))
|
||||
.then(chain.next(exchange));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-11
@@ -32,15 +32,18 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Maps a @{code List} of {@link PayloadExchangeMatcher} instances to
|
||||
* @{code ReactiveAuthorizationManager} instances.
|
||||
*
|
||||
* @{code ReactiveAuthorizationManager} instances.
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
*/
|
||||
public class PayloadExchangeMatcherReactiveAuthorizationManager implements ReactiveAuthorizationManager<PayloadExchange> {
|
||||
public class PayloadExchangeMatcherReactiveAuthorizationManager
|
||||
implements ReactiveAuthorizationManager<PayloadExchange> {
|
||||
|
||||
private final List<PayloadExchangeMatcherEntry<ReactiveAuthorizationManager<PayloadExchangeAuthorizationContext>>> mappings;
|
||||
|
||||
private PayloadExchangeMatcherReactiveAuthorizationManager(List<PayloadExchangeMatcherEntry<ReactiveAuthorizationManager<PayloadExchangeAuthorizationContext>>> mappings) {
|
||||
private PayloadExchangeMatcherReactiveAuthorizationManager(
|
||||
List<PayloadExchangeMatcherEntry<ReactiveAuthorizationManager<PayloadExchangeAuthorizationContext>>> mappings) {
|
||||
Assert.notEmpty(mappings, "mappings cannot be null");
|
||||
this.mappings = mappings;
|
||||
}
|
||||
@@ -49,14 +52,10 @@ public class PayloadExchangeMatcherReactiveAuthorizationManager implements React
|
||||
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, PayloadExchange exchange) {
|
||||
return Flux.fromIterable(this.mappings)
|
||||
.concatMap(mapping -> mapping.getMatcher().matches(exchange)
|
||||
.filter(PayloadExchangeMatcher.MatchResult::isMatch)
|
||||
.map(r -> r.getVariables())
|
||||
.flatMap(variables -> mapping.getEntry()
|
||||
.check(authentication, new PayloadExchangeAuthorizationContext(exchange, variables))
|
||||
)
|
||||
)
|
||||
.next()
|
||||
.switchIfEmpty(Mono.fromCallable(() -> new AuthorizationDecision(false)));
|
||||
.filter(PayloadExchangeMatcher.MatchResult::isMatch).map(r -> r.getVariables())
|
||||
.flatMap(variables -> mapping.getEntry().check(authentication,
|
||||
new PayloadExchangeAuthorizationContext(exchange, variables))))
|
||||
.next().switchIfEmpty(Mono.fromCallable(() -> new AuthorizationDecision(false)));
|
||||
}
|
||||
|
||||
public static PayloadExchangeMatcherReactiveAuthorizationManager.Builder builder() {
|
||||
@@ -64,6 +63,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManager implements React
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final List<PayloadExchangeMatcherEntry<ReactiveAuthorizationManager<PayloadExchangeAuthorizationContext>>> mappings = new ArrayList<>();
|
||||
|
||||
private Builder() {
|
||||
@@ -78,5 +78,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManager implements React
|
||||
public PayloadExchangeMatcherReactiveAuthorizationManager build() {
|
||||
return new PayloadExchangeMatcherReactiveAuthorizationManager(this.mappings);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-9
@@ -26,8 +26,9 @@ import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
* A {@link PayloadInterceptorChain} which exposes the Reactor {@link Context} via a member variable.
|
||||
* This class is not Thread safe, so a new instance must be created for each Thread.
|
||||
* A {@link PayloadInterceptorChain} which exposes the Reactor {@link Context} via a
|
||||
* member variable. This class is not Thread safe, so a new instance must be created for
|
||||
* each Thread.
|
||||
*
|
||||
* Internally {@code ContextPayloadInterceptorChain} is used to ensure that the Reactor
|
||||
* {@code Context} is captured so it can be transferred to subscribers outside of this
|
||||
@@ -72,13 +73,8 @@ class ContextPayloadInterceptorChain implements PayloadInterceptorChain {
|
||||
}
|
||||
|
||||
public Mono<Void> next(PayloadExchange exchange) {
|
||||
return Mono.defer(() ->
|
||||
shouldIntercept() ?
|
||||
this.currentInterceptor.intercept(exchange, this.next) :
|
||||
Mono.subscriberContext()
|
||||
.doOnNext(c -> this.context = c)
|
||||
.then()
|
||||
);
|
||||
return Mono.defer(() -> shouldIntercept() ? this.currentInterceptor.intercept(exchange, this.next)
|
||||
: Mono.subscriberContext().doOnNext(c -> this.context = c).then());
|
||||
}
|
||||
|
||||
Context getContext() {
|
||||
@@ -96,4 +92,5 @@ class ContextPayloadInterceptorChain implements PayloadInterceptorChain {
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "[currentInterceptor=" + this.currentInterceptor + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -69,4 +69,5 @@ public class DefaultPayloadExchange implements PayloadExchange {
|
||||
public MimeType getDataMimeType() {
|
||||
return this.dataMimeType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-39
@@ -31,10 +31,12 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Combines the {@link PayloadInterceptor} with an {@link RSocketProxy}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
*/
|
||||
class PayloadInterceptorRSocket extends RSocketProxy {
|
||||
|
||||
private final List<PayloadInterceptor> interceptors;
|
||||
|
||||
private final MimeType metadataMimeType;
|
||||
@@ -43,14 +45,12 @@ class PayloadInterceptorRSocket extends RSocketProxy {
|
||||
|
||||
private final Context context;
|
||||
|
||||
PayloadInterceptorRSocket(RSocket delegate,
|
||||
List<PayloadInterceptor> interceptors, MimeType metadataMimeType,
|
||||
PayloadInterceptorRSocket(RSocket delegate, List<PayloadInterceptor> interceptors, MimeType metadataMimeType,
|
||||
MimeType dataMimeType) {
|
||||
this(delegate, interceptors, metadataMimeType, dataMimeType, Context.empty());
|
||||
}
|
||||
|
||||
PayloadInterceptorRSocket(RSocket delegate,
|
||||
List<PayloadInterceptor> interceptors, MimeType metadataMimeType,
|
||||
PayloadInterceptorRSocket(RSocket delegate, List<PayloadInterceptor> interceptors, MimeType metadataMimeType,
|
||||
MimeType dataMimeType, Context context) {
|
||||
super(delegate);
|
||||
this.metadataMimeType = metadataMimeType;
|
||||
@@ -71,71 +71,52 @@ class PayloadInterceptorRSocket extends RSocketProxy {
|
||||
@Override
|
||||
public Mono<Void> fireAndForget(Payload payload) {
|
||||
return intercept(PayloadExchangeType.FIRE_AND_FORGET, payload)
|
||||
.flatMap(context ->
|
||||
this.source.fireAndForget(payload)
|
||||
.subscriberContext(context)
|
||||
);
|
||||
.flatMap(context -> this.source.fireAndForget(payload).subscriberContext(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Payload> requestResponse(Payload payload) {
|
||||
return intercept(PayloadExchangeType.REQUEST_RESPONSE, payload)
|
||||
.flatMap(context ->
|
||||
this.source.requestResponse(payload)
|
||||
.subscriberContext(context)
|
||||
);
|
||||
.flatMap(context -> this.source.requestResponse(payload).subscriberContext(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Payload> requestStream(Payload payload) {
|
||||
return intercept(PayloadExchangeType.REQUEST_STREAM, payload)
|
||||
.flatMapMany(context ->
|
||||
this.source.requestStream(payload)
|
||||
.subscriberContext(context)
|
||||
);
|
||||
.flatMapMany(context -> this.source.requestStream(payload).subscriberContext(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Payload> requestChannel(Publisher<Payload> payloads) {
|
||||
return Flux.from(payloads)
|
||||
.switchOnFirst((signal, innerFlux) -> {
|
||||
Payload firstPayload = signal.get();
|
||||
return intercept(PayloadExchangeType.REQUEST_CHANNEL, firstPayload)
|
||||
.flatMapMany(context ->
|
||||
innerFlux
|
||||
.skip(1)
|
||||
.flatMap(p -> intercept(PayloadExchangeType.PAYLOAD, p).thenReturn(p))
|
||||
return Flux.from(payloads).switchOnFirst((signal, innerFlux) -> {
|
||||
Payload firstPayload = signal.get();
|
||||
return intercept(PayloadExchangeType.REQUEST_CHANNEL, firstPayload).flatMapMany(
|
||||
context -> innerFlux.skip(1).flatMap(p -> intercept(PayloadExchangeType.PAYLOAD, p).thenReturn(p))
|
||||
.transform(securedPayloads -> Flux.concat(Flux.just(firstPayload), securedPayloads))
|
||||
.transform(securedPayloads -> this.source.requestChannel(securedPayloads))
|
||||
.subscriberContext(context)
|
||||
);
|
||||
});
|
||||
.subscriberContext(context));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> metadataPush(Payload payload) {
|
||||
return intercept(PayloadExchangeType.METADATA_PUSH, payload)
|
||||
.flatMap(c -> this.source
|
||||
.metadataPush(payload)
|
||||
.subscriberContext(c)
|
||||
);
|
||||
.flatMap(c -> this.source.metadataPush(payload).subscriberContext(c));
|
||||
}
|
||||
|
||||
private Mono<Context> intercept(PayloadExchangeType type, Payload payload) {
|
||||
return Mono.defer(() -> {
|
||||
ContextPayloadInterceptorChain chain = new ContextPayloadInterceptorChain(this.interceptors);
|
||||
DefaultPayloadExchange exchange = new DefaultPayloadExchange(type, payload,
|
||||
this.metadataMimeType, this.dataMimeType);
|
||||
return chain.next(exchange)
|
||||
.then(Mono.fromCallable(() -> chain.getContext()))
|
||||
.defaultIfEmpty(Context.empty())
|
||||
.subscriberContext(this.context);
|
||||
DefaultPayloadExchange exchange = new DefaultPayloadExchange(type, payload, this.metadataMimeType,
|
||||
this.dataMimeType);
|
||||
return chain.next(exchange).then(Mono.fromCallable(() -> chain.getContext()))
|
||||
.defaultIfEmpty(Context.empty()).subscriberContext(this.context);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "[source=" + this.source + ",interceptors="
|
||||
+ this.interceptors + "]";
|
||||
return getClass().getSimpleName() + "[source=" + this.source + ",interceptors=" + this.interceptors + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-8
@@ -38,6 +38,7 @@ import java.util.List;
|
||||
* @since 5.2
|
||||
*/
|
||||
class PayloadSocketAcceptor implements SocketAcceptor {
|
||||
|
||||
private final SocketAcceptor delegate;
|
||||
|
||||
private final List<PayloadInterceptor> interceptors;
|
||||
@@ -45,8 +46,8 @@ class PayloadSocketAcceptor implements SocketAcceptor {
|
||||
@Nullable
|
||||
private MimeType defaultDataMimeType;
|
||||
|
||||
private MimeType defaultMetadataMimeType =
|
||||
MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
private MimeType defaultMetadataMimeType = MimeTypeUtils
|
||||
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
PayloadSocketAcceptor(SocketAcceptor delegate, List<PayloadInterceptor> interceptors) {
|
||||
Assert.notNull(delegate, "delegate cannot be null");
|
||||
@@ -70,10 +71,11 @@ class PayloadSocketAcceptor implements SocketAcceptor {
|
||||
|
||||
// FIXME do we want to make the sendingSocket available in the PayloadExchange
|
||||
return intercept(setup, dataMimeType, metadataMimeType)
|
||||
.flatMap(ctx -> this.delegate.accept(setup, sendingSocket)
|
||||
.map(acceptingSocket -> new PayloadInterceptorRSocket(acceptingSocket, this.interceptors, metadataMimeType, dataMimeType, ctx))
|
||||
.subscriberContext(ctx)
|
||||
);
|
||||
.flatMap(
|
||||
ctx -> this.delegate.accept(setup, sendingSocket)
|
||||
.map(acceptingSocket -> new PayloadInterceptorRSocket(acceptingSocket,
|
||||
this.interceptors, metadataMimeType, dataMimeType, ctx))
|
||||
.subscriberContext(ctx));
|
||||
}
|
||||
|
||||
private Mono<Context> intercept(Payload payload, MimeType dataMimeType, MimeType metadataMimeType) {
|
||||
@@ -81,8 +83,7 @@ class PayloadSocketAcceptor implements SocketAcceptor {
|
||||
ContextPayloadInterceptorChain chain = new ContextPayloadInterceptorChain(this.interceptors);
|
||||
DefaultPayloadExchange exchange = new DefaultPayloadExchange(PayloadExchangeType.SETUP, payload,
|
||||
metadataMimeType, dataMimeType);
|
||||
return chain.next(exchange)
|
||||
.then(Mono.fromCallable(() -> chain.getContext()))
|
||||
return chain.next(exchange).then(Mono.fromCallable(() -> chain.getContext()))
|
||||
.defaultIfEmpty(Context.empty());
|
||||
});
|
||||
}
|
||||
@@ -99,4 +100,5 @@ class PayloadSocketAcceptor implements SocketAcceptor {
|
||||
Assert.notNull(defaultMetadataMimeType, "defaultMetadataMimeType cannot be null");
|
||||
this.defaultMetadataMimeType = defaultMetadataMimeType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-4
@@ -40,8 +40,8 @@ public class PayloadSocketAcceptorInterceptor implements SocketAcceptorIntercept
|
||||
@Nullable
|
||||
private MimeType defaultDataMimeType;
|
||||
|
||||
private MimeType defaultMetadataMimeType =
|
||||
MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
private MimeType defaultMetadataMimeType = MimeTypeUtils
|
||||
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
public PayloadSocketAcceptorInterceptor(List<PayloadInterceptor> interceptors) {
|
||||
this.interceptors = interceptors;
|
||||
@@ -49,8 +49,7 @@ public class PayloadSocketAcceptorInterceptor implements SocketAcceptorIntercept
|
||||
|
||||
@Override
|
||||
public SocketAcceptor apply(SocketAcceptor socketAcceptor) {
|
||||
PayloadSocketAcceptor acceptor = new PayloadSocketAcceptor(
|
||||
socketAcceptor, this.interceptors);
|
||||
PayloadSocketAcceptor acceptor = new PayloadSocketAcceptor(socketAcceptor, this.interceptors);
|
||||
acceptor.setDefaultDataMimeType(this.defaultDataMimeType);
|
||||
acceptor.setDefaultMetadataMimeType(this.defaultMetadataMimeType);
|
||||
return acceptor;
|
||||
@@ -64,4 +63,5 @@ public class PayloadSocketAcceptorInterceptor implements SocketAcceptorIntercept
|
||||
Assert.notNull(defaultMetadataMimeType, "defaultMetadataMimeType cannot be null");
|
||||
this.defaultMetadataMimeType = defaultMetadataMimeType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-2
@@ -21,13 +21,15 @@ import io.rsocket.plugins.SocketAcceptorInterceptor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A SocketAcceptorInterceptor that applies Security through a delegate {@link SocketAcceptorInterceptor}. This allows
|
||||
* security to be applied lazily to an application.
|
||||
* A SocketAcceptorInterceptor that applies Security through a delegate
|
||||
* {@link SocketAcceptorInterceptor}. This allows security to be applied lazily to an
|
||||
* application.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
*/
|
||||
public class SecuritySocketAcceptorInterceptor implements SocketAcceptorInterceptor {
|
||||
|
||||
private final SocketAcceptorInterceptor acceptorInterceptor;
|
||||
|
||||
public SecuritySocketAcceptorInterceptor(SocketAcceptorInterceptor acceptorInterceptor) {
|
||||
@@ -39,4 +41,5 @@ public class SecuritySocketAcceptorInterceptor implements SocketAcceptorIntercep
|
||||
public SocketAcceptor apply(SocketAcceptor socketAcceptor) {
|
||||
return this.acceptorInterceptor.apply(socketAcceptor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+30
-31
@@ -31,48 +31,47 @@ import java.util.Map;
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
* @deprecated Basic Authentication did not evolve into a standard. Use Simple Authentication instead.
|
||||
* @deprecated Basic Authentication did not evolve into a standard. Use Simple
|
||||
* Authentication instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class BasicAuthenticationDecoder extends AbstractDecoder<UsernamePasswordMetadata> {
|
||||
|
||||
public BasicAuthenticationDecoder() {
|
||||
super(UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<UsernamePasswordMetadata> decode(Publisher<DataBuffer> input,
|
||||
ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
|
||||
return Flux.from(input)
|
||||
.map(DataBuffer::asByteBuffer)
|
||||
.map(byteBuffer -> {
|
||||
byte[] sizeBytes = new byte[4];
|
||||
byteBuffer.get(sizeBytes);
|
||||
public Flux<UsernamePasswordMetadata> decode(Publisher<DataBuffer> input, ResolvableType elementType,
|
||||
MimeType mimeType, Map<String, Object> hints) {
|
||||
return Flux.from(input).map(DataBuffer::asByteBuffer).map(byteBuffer -> {
|
||||
byte[] sizeBytes = new byte[4];
|
||||
byteBuffer.get(sizeBytes);
|
||||
|
||||
int usernameSize = 4;
|
||||
byte[] usernameBytes = new byte[usernameSize];
|
||||
byteBuffer.get(usernameBytes);
|
||||
byte[] passwordBytes = new byte[byteBuffer.remaining()];
|
||||
byteBuffer.get(passwordBytes);
|
||||
String username = new String(usernameBytes);
|
||||
String password = new String(passwordBytes);
|
||||
return new UsernamePasswordMetadata(username, password);
|
||||
});
|
||||
int usernameSize = 4;
|
||||
byte[] usernameBytes = new byte[usernameSize];
|
||||
byteBuffer.get(usernameBytes);
|
||||
byte[] passwordBytes = new byte[byteBuffer.remaining()];
|
||||
byteBuffer.get(passwordBytes);
|
||||
String username = new String(usernameBytes);
|
||||
String password = new String(passwordBytes);
|
||||
return new UsernamePasswordMetadata(username, password);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<UsernamePasswordMetadata> decodeToMono(Publisher<DataBuffer> input,
|
||||
ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
|
||||
return Mono.from(input)
|
||||
.map(DataBuffer::asByteBuffer)
|
||||
.map(byteBuffer -> {
|
||||
int usernameSize = byteBuffer.getInt();
|
||||
byte[] usernameBytes = new byte[usernameSize];
|
||||
byteBuffer.get(usernameBytes);
|
||||
byte[] passwordBytes = new byte[byteBuffer.remaining()];
|
||||
byteBuffer.get(passwordBytes);
|
||||
String username = new String(usernameBytes);
|
||||
String password = new String(passwordBytes);
|
||||
return new UsernamePasswordMetadata(username, password);
|
||||
});
|
||||
public Mono<UsernamePasswordMetadata> decodeToMono(Publisher<DataBuffer> input, ResolvableType elementType,
|
||||
MimeType mimeType, Map<String, Object> hints) {
|
||||
return Mono.from(input).map(DataBuffer::asByteBuffer).map(byteBuffer -> {
|
||||
int usernameSize = byteBuffer.getInt();
|
||||
byte[] usernameBytes = new byte[usernameSize];
|
||||
byteBuffer.get(usernameBytes);
|
||||
byte[] passwordBytes = new byte[byteBuffer.remaining()];
|
||||
byteBuffer.get(passwordBytes);
|
||||
String username = new String(usernameBytes);
|
||||
String password = new String(passwordBytes);
|
||||
return new UsernamePasswordMetadata(username, password);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-13
@@ -34,29 +34,26 @@ import java.util.Map;
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
* @deprecated Basic Authentication did not evolve into a standard. use {@link SimpleAuthenticationEncoder}
|
||||
* @deprecated Basic Authentication did not evolve into a standard. use
|
||||
* {@link SimpleAuthenticationEncoder}
|
||||
*/
|
||||
@Deprecated
|
||||
public class BasicAuthenticationEncoder extends
|
||||
AbstractEncoder<UsernamePasswordMetadata> {
|
||||
public class BasicAuthenticationEncoder extends AbstractEncoder<UsernamePasswordMetadata> {
|
||||
|
||||
public BasicAuthenticationEncoder() {
|
||||
super(UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<DataBuffer> encode(
|
||||
Publisher<? extends UsernamePasswordMetadata> inputStream,
|
||||
DataBufferFactory bufferFactory, ResolvableType elementType,
|
||||
MimeType mimeType, Map<String, Object> hints) {
|
||||
return Flux.from(inputStream).map(credentials ->
|
||||
encodeValue(credentials, bufferFactory, elementType, mimeType, hints));
|
||||
public Flux<DataBuffer> encode(Publisher<? extends UsernamePasswordMetadata> inputStream,
|
||||
DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
|
||||
return Flux.from(inputStream)
|
||||
.map(credentials -> encodeValue(credentials, bufferFactory, elementType, mimeType, hints));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataBuffer encodeValue(UsernamePasswordMetadata credentials,
|
||||
DataBufferFactory bufferFactory, ResolvableType valueType, MimeType mimeType,
|
||||
Map<String, Object> hints) {
|
||||
public DataBuffer encodeValue(UsernamePasswordMetadata credentials, DataBufferFactory bufferFactory,
|
||||
ResolvableType valueType, MimeType mimeType, Map<String, Object> hints) {
|
||||
String username = credentials.getUsername();
|
||||
String password = credentials.getPassword();
|
||||
byte[] usernameBytes = username.getBytes(StandardCharsets.UTF_8);
|
||||
@@ -69,10 +66,12 @@ public class BasicAuthenticationEncoder extends
|
||||
metadata.write(password.getBytes(StandardCharsets.UTF_8));
|
||||
release = false;
|
||||
return metadata;
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
if (release) {
|
||||
DataBufferUtils.release(metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-15
@@ -32,15 +32,17 @@ import reactor.core.publisher.Flux;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Encodes <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md">Bearer Authentication</a>.
|
||||
* Encodes <a href=
|
||||
* "https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md">Bearer
|
||||
* Authentication</a>.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.3
|
||||
*/
|
||||
public class BearerTokenAuthenticationEncoder extends
|
||||
AbstractEncoder<BearerTokenMetadata> {
|
||||
public class BearerTokenAuthenticationEncoder extends AbstractEncoder<BearerTokenMetadata> {
|
||||
|
||||
private static final MimeType AUTHENTICATION_MIME_TYPE = MimeTypeUtils.parseMimeType("message/x.rsocket.authentication.v0");
|
||||
private static final MimeType AUTHENTICATION_MIME_TYPE = MimeTypeUtils
|
||||
.parseMimeType("message/x.rsocket.authentication.v0");
|
||||
|
||||
private NettyDataBufferFactory defaultBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
|
||||
|
||||
@@ -49,23 +51,19 @@ public class BearerTokenAuthenticationEncoder extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<DataBuffer> encode(
|
||||
Publisher<? extends BearerTokenMetadata> inputStream,
|
||||
DataBufferFactory bufferFactory, ResolvableType elementType,
|
||||
MimeType mimeType, Map<String, Object> hints) {
|
||||
return Flux.from(inputStream).map(credentials ->
|
||||
encodeValue(credentials, bufferFactory, elementType, mimeType, hints));
|
||||
public Flux<DataBuffer> encode(Publisher<? extends BearerTokenMetadata> inputStream,
|
||||
DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
|
||||
return Flux.from(inputStream)
|
||||
.map(credentials -> encodeValue(credentials, bufferFactory, elementType, mimeType, hints));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataBuffer encodeValue(BearerTokenMetadata credentials,
|
||||
DataBufferFactory bufferFactory, ResolvableType valueType, MimeType mimeType,
|
||||
Map<String, Object> hints) {
|
||||
public DataBuffer encodeValue(BearerTokenMetadata credentials, DataBufferFactory bufferFactory,
|
||||
ResolvableType valueType, MimeType mimeType, Map<String, Object> hints) {
|
||||
String token = credentials.getToken();
|
||||
NettyDataBufferFactory factory = nettyFactory(bufferFactory);
|
||||
ByteBufAllocator allocator = factory.getByteBufAllocator();
|
||||
ByteBuf simpleAuthentication = AuthMetadataCodec
|
||||
.encodeBearerMetadata(allocator, token.toCharArray());
|
||||
ByteBuf simpleAuthentication = AuthMetadataCodec.encodeBearerMetadata(allocator, token.toCharArray());
|
||||
return factory.wrap(simpleAuthentication);
|
||||
}
|
||||
|
||||
@@ -75,4 +73,5 @@ public class BearerTokenAuthenticationEncoder extends
|
||||
}
|
||||
return this.defaultBufferFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-5
@@ -14,28 +14,30 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.springframework.security.rsocket.metadata;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Represents a bearer token that has been encoded into a
|
||||
* {@link Payload#metadata()}.
|
||||
* Represents a bearer token that has been encoded into a {@link Payload#metadata()}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
*/
|
||||
public class BearerTokenMetadata {
|
||||
|
||||
/**
|
||||
* Represents a bearer token which is encoded as a String.
|
||||
*
|
||||
* See <a href="https://github.com/rsocket/rsocket/issues/272">rsocket/rsocket#272</a>
|
||||
* @deprecated Basic did not evolve into the standard. Instead use Simple Authentication MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString())
|
||||
* @deprecated Basic did not evolve into the standard. Instead use Simple
|
||||
* Authentication
|
||||
* MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString())
|
||||
*/
|
||||
@Deprecated
|
||||
public static final MimeType BEARER_AUTHENTICATION_MIME_TYPE = new MediaType("message", "x.rsocket.authentication.bearer.v0");
|
||||
public static final MimeType BEARER_AUTHENTICATION_MIME_TYPE = new MediaType("message",
|
||||
"x.rsocket.authentication.bearer.v0");
|
||||
|
||||
private final String token;
|
||||
|
||||
@@ -46,4 +48,5 @@ public class BearerTokenMetadata {
|
||||
public String getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-16
@@ -32,17 +32,17 @@ import reactor.core.publisher.Flux;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Encodes
|
||||
* <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md">Simple</a>
|
||||
* Encodes <a href=
|
||||
* "https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md">Simple</a>
|
||||
* Authentication.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.3
|
||||
*/
|
||||
public class SimpleAuthenticationEncoder extends
|
||||
AbstractEncoder<UsernamePasswordMetadata> {
|
||||
public class SimpleAuthenticationEncoder extends AbstractEncoder<UsernamePasswordMetadata> {
|
||||
|
||||
private static final MimeType AUTHENTICATION_MIME_TYPE = MimeTypeUtils.parseMimeType("message/x.rsocket.authentication.v0");
|
||||
private static final MimeType AUTHENTICATION_MIME_TYPE = MimeTypeUtils
|
||||
.parseMimeType("message/x.rsocket.authentication.v0");
|
||||
|
||||
private NettyDataBufferFactory defaultBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
|
||||
|
||||
@@ -51,24 +51,21 @@ public class SimpleAuthenticationEncoder extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<DataBuffer> encode(
|
||||
Publisher<? extends UsernamePasswordMetadata> inputStream,
|
||||
DataBufferFactory bufferFactory, ResolvableType elementType,
|
||||
MimeType mimeType, Map<String, Object> hints) {
|
||||
return Flux.from(inputStream).map(credentials ->
|
||||
encodeValue(credentials, bufferFactory, elementType, mimeType, hints));
|
||||
public Flux<DataBuffer> encode(Publisher<? extends UsernamePasswordMetadata> inputStream,
|
||||
DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
|
||||
return Flux.from(inputStream)
|
||||
.map(credentials -> encodeValue(credentials, bufferFactory, elementType, mimeType, hints));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataBuffer encodeValue(UsernamePasswordMetadata credentials,
|
||||
DataBufferFactory bufferFactory, ResolvableType valueType, MimeType mimeType,
|
||||
Map<String, Object> hints) {
|
||||
public DataBuffer encodeValue(UsernamePasswordMetadata credentials, DataBufferFactory bufferFactory,
|
||||
ResolvableType valueType, MimeType mimeType, Map<String, Object> hints) {
|
||||
String username = credentials.getUsername();
|
||||
String password = credentials.getPassword();
|
||||
NettyDataBufferFactory factory = nettyFactory(bufferFactory);
|
||||
ByteBufAllocator allocator = factory.getByteBufAllocator();
|
||||
ByteBuf simpleAuthentication = AuthMetadataCodec
|
||||
.encodeSimpleMetadata(allocator, username.toCharArray(), password.toCharArray());
|
||||
ByteBuf simpleAuthentication = AuthMetadataCodec.encodeSimpleMetadata(allocator, username.toCharArray(),
|
||||
password.toCharArray());
|
||||
return factory.wrap(simpleAuthentication);
|
||||
}
|
||||
|
||||
@@ -78,4 +75,5 @@ public class SimpleAuthenticationEncoder extends
|
||||
}
|
||||
return this.defaultBufferFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-2
@@ -28,15 +28,19 @@ import org.springframework.util.MimeType;
|
||||
* @since 5.2
|
||||
*/
|
||||
public final class UsernamePasswordMetadata {
|
||||
|
||||
/**
|
||||
* Represents a username password which is encoded as
|
||||
* {@code ${username-bytes-length}${username-bytes}${password-bytes}}.
|
||||
*
|
||||
* See <a href="https://github.com/rsocket/rsocket/issues/272">rsocket/rsocket#272</a>
|
||||
* @deprecated Basic did not evolve into the standard. Instead use Simple Authentication MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString())
|
||||
* @deprecated Basic did not evolve into the standard. Instead use Simple
|
||||
* Authentication
|
||||
* MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString())
|
||||
*/
|
||||
@Deprecated
|
||||
public static final MimeType BASIC_AUTHENTICATION_MIME_TYPE = new MediaType("message", "x.rsocket.authentication.basic.v0");
|
||||
public static final MimeType BASIC_AUTHENTICATION_MIME_TYPE = new MediaType("message",
|
||||
"x.rsocket.authentication.basic.v0");
|
||||
|
||||
private final String username;
|
||||
|
||||
@@ -54,4 +58,5 @@ public final class UsernamePasswordMetadata {
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -26,7 +26,9 @@ import java.util.Map;
|
||||
* @since 5.2
|
||||
*/
|
||||
public class PayloadExchangeAuthorizationContext {
|
||||
|
||||
private final PayloadExchange exchange;
|
||||
|
||||
private final Map<String, Object> variables;
|
||||
|
||||
public PayloadExchangeAuthorizationContext(PayloadExchange exchange) {
|
||||
@@ -45,4 +47,5 @@ public class PayloadExchangeAuthorizationContext {
|
||||
public Map<String, Object> getVariables() {
|
||||
return Collections.unmodifiableMap(this.variables);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-1
@@ -24,6 +24,7 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* An interface for determining if a {@link PayloadExchangeMatcher} matches.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
*/
|
||||
@@ -40,7 +41,9 @@ public interface PayloadExchangeMatcher {
|
||||
* The result of matching
|
||||
*/
|
||||
class MatchResult {
|
||||
|
||||
private final boolean match;
|
||||
|
||||
private final Map<String, Object> variables;
|
||||
|
||||
private MatchResult(boolean match, Map<String, Object> variables) {
|
||||
@@ -70,7 +73,8 @@ public interface PayloadExchangeMatcher {
|
||||
|
||||
/**
|
||||
*
|
||||
* Creates an instance of {@link MatchResult} that is a match with the specified variables
|
||||
* Creates an instance of {@link MatchResult} that is a match with the specified
|
||||
* variables
|
||||
* @param variables
|
||||
* @return
|
||||
*/
|
||||
@@ -85,5 +89,7 @@ public interface PayloadExchangeMatcher {
|
||||
public static Mono<MatchResult> notMatch() {
|
||||
return Mono.just(new MatchResult(false, Collections.emptyMap()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -20,7 +20,9 @@ package org.springframework.security.rsocket.util.matcher;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class PayloadExchangeMatcherEntry<T> {
|
||||
|
||||
private final PayloadExchangeMatcher matcher;
|
||||
|
||||
private final T entry;
|
||||
|
||||
public PayloadExchangeMatcherEntry(PayloadExchangeMatcher matcher, T entry) {
|
||||
@@ -35,4 +37,5 @@ public class PayloadExchangeMatcherEntry<T> {
|
||||
public T getEntry() {
|
||||
return this.entry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-7
@@ -28,9 +28,8 @@ public abstract class PayloadExchangeMatchers {
|
||||
public static PayloadExchangeMatcher setup() {
|
||||
return new PayloadExchangeMatcher() {
|
||||
public Mono<MatchResult> matches(PayloadExchange exchange) {
|
||||
return PayloadExchangeType.SETUP.equals(exchange.getType()) ?
|
||||
MatchResult.match() :
|
||||
MatchResult.notMatch();
|
||||
return PayloadExchangeType.SETUP.equals(exchange.getType()) ? MatchResult.match()
|
||||
: MatchResult.notMatch();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -38,9 +37,7 @@ public abstract class PayloadExchangeMatchers {
|
||||
public static PayloadExchangeMatcher anyRequest() {
|
||||
return new PayloadExchangeMatcher() {
|
||||
public Mono<MatchResult> matches(PayloadExchange exchange) {
|
||||
return exchange.getType().isRequest() ?
|
||||
MatchResult.match() :
|
||||
MatchResult.notMatch();
|
||||
return exchange.getType().isRequest() ? MatchResult.match() : MatchResult.notMatch();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -53,5 +50,7 @@ public abstract class PayloadExchangeMatchers {
|
||||
};
|
||||
}
|
||||
|
||||
private PayloadExchangeMatchers() {}
|
||||
private PayloadExchangeMatchers() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-9
@@ -27,7 +27,7 @@ import java.util.Optional;
|
||||
|
||||
/**
|
||||
* FIXME: Pay attention to the package this goes into. It requires spring-messaging for
|
||||
* the MetadataExtractor.
|
||||
* the MetadataExtractor.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.2
|
||||
@@ -40,8 +40,7 @@ public class RoutePayloadExchangeMatcher implements PayloadExchangeMatcher {
|
||||
|
||||
private final RouteMatcher routeMatcher;
|
||||
|
||||
public RoutePayloadExchangeMatcher(MetadataExtractor metadataExtractor,
|
||||
RouteMatcher routeMatcher, String pattern) {
|
||||
public RoutePayloadExchangeMatcher(MetadataExtractor metadataExtractor, RouteMatcher routeMatcher, String pattern) {
|
||||
Assert.notNull(pattern, "pattern cannot be null");
|
||||
this.metadataExtractor = metadataExtractor;
|
||||
this.routeMatcher = routeMatcher;
|
||||
@@ -50,12 +49,12 @@ public class RoutePayloadExchangeMatcher implements PayloadExchangeMatcher {
|
||||
|
||||
@Override
|
||||
public Mono<MatchResult> matches(PayloadExchange exchange) {
|
||||
Map<String, Object> metadata = this.metadataExtractor
|
||||
.extract(exchange.getPayload(), exchange.getMetadataMimeType());
|
||||
Map<String, Object> metadata = this.metadataExtractor.extract(exchange.getPayload(),
|
||||
exchange.getMetadataMimeType());
|
||||
return Optional.ofNullable((String) metadata.get(MetadataExtractor.ROUTE_KEY))
|
||||
.map(routeValue -> this.routeMatcher.parseRoute(routeValue))
|
||||
.map(route -> this.routeMatcher.matchAndExtract(this.pattern, route))
|
||||
.map(v -> MatchResult.match(v))
|
||||
.orElse(MatchResult.notMatch());
|
||||
.map(routeValue -> this.routeMatcher.parseRoute(routeValue))
|
||||
.map(route -> this.routeMatcher.matchAndExtract(this.pattern, route)).map(v -> MatchResult.match(v))
|
||||
.orElse(MatchResult.notMatch());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-12
@@ -38,6 +38,7 @@ import static org.assertj.core.api.Assertions.*;
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AnonymousPayloadInterceptorTests {
|
||||
|
||||
@Mock
|
||||
private PayloadExchange exchange;
|
||||
|
||||
@@ -51,31 +52,27 @@ public class AnonymousPayloadInterceptorTests {
|
||||
@Test
|
||||
public void constructorKeyWhenKeyNullThenException() {
|
||||
String key = null;
|
||||
assertThatCode(() -> new AnonymousPayloadInterceptor(key))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatCode(() -> new AnonymousPayloadInterceptor(key)).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorKeyPrincipalAuthoritiesWhenKeyNullThenException() {
|
||||
String key = null;
|
||||
assertThatCode(() -> new AnonymousPayloadInterceptor(key, "principal",
|
||||
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"))).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorKeyPrincipalAuthoritiesWhenPrincipalNullThenException() {
|
||||
Object principal = null;
|
||||
assertThatCode(() -> new AnonymousPayloadInterceptor("key", principal,
|
||||
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"))).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorKeyPrincipalAuthoritiesWhenAuthoritiesNullThenException() {
|
||||
List<GrantedAuthority> authorities = null;
|
||||
assertThatCode(() -> new AnonymousPayloadInterceptor("key", "principal",
|
||||
authorities))
|
||||
assertThatCode(() -> new AnonymousPayloadInterceptor("key", "principal", authorities))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@@ -93,15 +90,14 @@ public class AnonymousPayloadInterceptorTests {
|
||||
@Test
|
||||
public void interceptWhenAuthenticationThenOriginalAuthentication() {
|
||||
AuthenticationPayloadInterceptorChain chain = new AuthenticationPayloadInterceptorChain();
|
||||
TestingAuthenticationToken expected =
|
||||
new TestingAuthenticationToken("test", "password");
|
||||
TestingAuthenticationToken expected = new TestingAuthenticationToken("test", "password");
|
||||
|
||||
this.interceptor.intercept(this.exchange, chain)
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(expected))
|
||||
.block();
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(expected)).block();
|
||||
|
||||
Authentication authentication = chain.getAuthentication();
|
||||
|
||||
assertThat(authentication).isEqualTo(expected);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -27,6 +27,7 @@ import org.springframework.security.rsocket.api.PayloadExchange;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class AuthenticationPayloadInterceptorChain implements PayloadInterceptorChain {
|
||||
|
||||
private Authentication authentication;
|
||||
|
||||
@Override
|
||||
@@ -42,4 +43,5 @@ class AuthenticationPayloadInterceptorChain implements PayloadInterceptorChain {
|
||||
public void setAuthentication(Authentication authentication) {
|
||||
this.authentication = authentication;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+22
-32
@@ -62,8 +62,10 @@ import static org.mockito.Mockito.when;
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AuthenticationPayloadInterceptorTests {
|
||||
static final MimeType COMPOSITE_METADATA = MimeTypeUtils.parseMimeType(
|
||||
WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
static final MimeType COMPOSITE_METADATA = MimeTypeUtils
|
||||
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
@Mock
|
||||
ReactiveAuthenticationManager authenticationManager;
|
||||
|
||||
@@ -72,50 +74,41 @@ public class AuthenticationPayloadInterceptorTests {
|
||||
|
||||
@Test
|
||||
public void constructorWhenAuthenticationManagerNullThenException() {
|
||||
assertThatCode(() -> new AuthenticationPayloadInterceptor(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatCode(() -> new AuthenticationPayloadInterceptor(null)).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void interceptWhenBasicCredentialsThenAuthenticates() {
|
||||
AuthenticationPayloadInterceptor interceptor = new AuthenticationPayloadInterceptor(
|
||||
this.authenticationManager);
|
||||
AuthenticationPayloadInterceptor interceptor = new AuthenticationPayloadInterceptor(this.authenticationManager);
|
||||
PayloadExchange exchange = createExchange();
|
||||
TestingAuthenticationToken expectedAuthentication =
|
||||
new TestingAuthenticationToken("user", "password");
|
||||
when(this.authenticationManager.authenticate(any())).thenReturn(Mono.just(
|
||||
expectedAuthentication));
|
||||
TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken("user", "password");
|
||||
when(this.authenticationManager.authenticate(any())).thenReturn(Mono.just(expectedAuthentication));
|
||||
|
||||
AuthenticationPayloadInterceptorChain authenticationPayloadChain = new AuthenticationPayloadInterceptorChain();
|
||||
interceptor.intercept(exchange, authenticationPayloadChain)
|
||||
.block();
|
||||
interceptor.intercept(exchange, authenticationPayloadChain).block();
|
||||
|
||||
Authentication authentication = authenticationPayloadChain.getAuthentication();
|
||||
|
||||
verify(this.authenticationManager).authenticate(this.authenticationArg.capture());
|
||||
assertThat(this.authenticationArg.getValue()).isEqualToComparingFieldByField(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
assertThat(this.authenticationArg.getValue())
|
||||
.isEqualToComparingFieldByField(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
assertThat(authentication).isEqualTo(expectedAuthentication);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void interceptWhenAuthenticationSuccessThenChainSubscribedOnce() {
|
||||
AuthenticationPayloadInterceptor interceptor = new AuthenticationPayloadInterceptor(
|
||||
this.authenticationManager);
|
||||
AuthenticationPayloadInterceptor interceptor = new AuthenticationPayloadInterceptor(this.authenticationManager);
|
||||
|
||||
PayloadExchange exchange = createExchange();
|
||||
TestingAuthenticationToken expectedAuthentication =
|
||||
new TestingAuthenticationToken("user", "password");
|
||||
when(this.authenticationManager.authenticate(any())).thenReturn(Mono.just(
|
||||
expectedAuthentication));
|
||||
TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken("user", "password");
|
||||
when(this.authenticationManager.authenticate(any())).thenReturn(Mono.just(expectedAuthentication));
|
||||
|
||||
PublisherProbe<Void> voidResult = PublisherProbe.empty();
|
||||
PayloadInterceptorChain chain = mock(PayloadInterceptorChain.class);
|
||||
when(chain.next(any())).thenReturn(voidResult.mono());
|
||||
|
||||
|
||||
StepVerifier.create(interceptor.intercept(exchange, chain))
|
||||
.then(() -> assertThat(voidResult.subscribeCount()).isEqualTo(1))
|
||||
.verifyComplete();
|
||||
.then(() -> assertThat(voidResult.subscribeCount()).isEqualTo(1)).verifyComplete();
|
||||
}
|
||||
|
||||
private Payload createRequestPayload() {
|
||||
@@ -123,25 +116,22 @@ public class AuthenticationPayloadInterceptorTests {
|
||||
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
|
||||
BasicAuthenticationEncoder encoder = new BasicAuthenticationEncoder();
|
||||
DefaultDataBufferFactory factory = new DefaultDataBufferFactory();
|
||||
ResolvableType elementType = ResolvableType
|
||||
.forClass(UsernamePasswordMetadata.class);
|
||||
ResolvableType elementType = ResolvableType.forClass(UsernamePasswordMetadata.class);
|
||||
MimeType mimeType = UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE;
|
||||
Map<String, Object> hints = null;
|
||||
DataBuffer dataBuffer = encoder.encodeValue(credentials, factory,
|
||||
elementType, mimeType, hints);
|
||||
DataBuffer dataBuffer = encoder.encodeValue(credentials, factory, elementType, mimeType, hints);
|
||||
|
||||
ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
|
||||
CompositeByteBuf metadata = allocator.compositeBuffer();
|
||||
CompositeMetadataCodec.encodeAndAddMetadata(
|
||||
metadata, allocator, mimeType.toString(), NettyDataBufferFactory.toByteBuf(dataBuffer));
|
||||
CompositeMetadataCodec.encodeAndAddMetadata(metadata, allocator, mimeType.toString(),
|
||||
NettyDataBufferFactory.toByteBuf(dataBuffer));
|
||||
|
||||
return DefaultPayload.create(allocator.buffer(),
|
||||
metadata);
|
||||
return DefaultPayload.create(allocator.buffer(), metadata);
|
||||
}
|
||||
|
||||
private PayloadExchange createExchange() {
|
||||
return new DefaultPayloadExchange(PayloadExchangeType.REQUEST_RESPONSE, createRequestPayload(), COMPOSITE_METADATA,
|
||||
MediaType.APPLICATION_JSON);
|
||||
return new DefaultPayloadExchange(PayloadExchangeType.REQUEST_RESPONSE, createRequestPayload(),
|
||||
COMPOSITE_METADATA, MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-23
@@ -42,6 +42,7 @@ import static org.springframework.security.authorization.AuthorityReactiveAuthor
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AuthorizationPayloadInterceptorTests {
|
||||
|
||||
@Mock
|
||||
private ReactiveAuthorizationManager<PayloadExchange> authorizationManager;
|
||||
|
||||
@@ -59,42 +60,35 @@ public class AuthorizationPayloadInterceptorTests {
|
||||
public void interceptWhenAuthenticationEmptyAndSubscribedThenException() {
|
||||
when(this.chain.next(any())).thenReturn(this.chainResult.mono());
|
||||
|
||||
AuthorizationPayloadInterceptor interceptor =
|
||||
new AuthorizationPayloadInterceptor(authenticated());
|
||||
AuthorizationPayloadInterceptor interceptor = new AuthorizationPayloadInterceptor(authenticated());
|
||||
|
||||
StepVerifier.create(interceptor.intercept(this.exchange, this.chain))
|
||||
.then(() -> this.chainResult.assertWasNotSubscribed())
|
||||
.verifyError(AuthenticationCredentialsNotFoundException.class);
|
||||
.then(() -> this.chainResult.assertWasNotSubscribed())
|
||||
.verifyError(AuthenticationCredentialsNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void interceptWhenAuthenticationNotSubscribedAndEmptyThenCompletes() {
|
||||
when(this.chain.next(any())).thenReturn(this.chainResult.mono());
|
||||
when(this.authorizationManager.verify(any(), any()))
|
||||
.thenReturn(this.managerResult.mono());
|
||||
when(this.authorizationManager.verify(any(), any())).thenReturn(this.managerResult.mono());
|
||||
|
||||
AuthorizationPayloadInterceptor interceptor =
|
||||
new AuthorizationPayloadInterceptor(this.authorizationManager);
|
||||
AuthorizationPayloadInterceptor interceptor = new AuthorizationPayloadInterceptor(this.authorizationManager);
|
||||
|
||||
StepVerifier.create(interceptor.intercept(this.exchange, this.chain))
|
||||
.then(() -> this.chainResult.assertWasSubscribed())
|
||||
.verifyComplete();
|
||||
.then(() -> this.chainResult.assertWasSubscribed()).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void interceptWhenNotAuthorizedThenException() {
|
||||
when(this.chain.next(any())).thenReturn(this.chainResult.mono());
|
||||
|
||||
AuthorizationPayloadInterceptor interceptor =
|
||||
new AuthorizationPayloadInterceptor(hasRole("USER"));
|
||||
AuthorizationPayloadInterceptor interceptor = new AuthorizationPayloadInterceptor(hasRole("USER"));
|
||||
Context userContext = ReactiveSecurityContextHolder
|
||||
.withAuthentication(new TestingAuthenticationToken("user", "password"));
|
||||
|
||||
Mono<Void> intercept = interceptor.intercept(this.exchange, this.chain)
|
||||
.subscriberContext(userContext);
|
||||
Mono<Void> intercept = interceptor.intercept(this.exchange, this.chain).subscriberContext(userContext);
|
||||
|
||||
StepVerifier.create(intercept)
|
||||
.then(() -> this.chainResult.assertWasNotSubscribed())
|
||||
StepVerifier.create(intercept).then(() -> this.chainResult.assertWasNotSubscribed())
|
||||
.verifyError(AccessDeniedException.class);
|
||||
}
|
||||
|
||||
@@ -102,16 +96,13 @@ public class AuthorizationPayloadInterceptorTests {
|
||||
public void interceptWhenAuthorizedThenContinues() {
|
||||
when(this.chain.next(any())).thenReturn(this.chainResult.mono());
|
||||
|
||||
AuthorizationPayloadInterceptor interceptor =
|
||||
new AuthorizationPayloadInterceptor(authenticated());
|
||||
AuthorizationPayloadInterceptor interceptor = new AuthorizationPayloadInterceptor(authenticated());
|
||||
Context userContext = ReactiveSecurityContextHolder
|
||||
.withAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
|
||||
Mono<Void> intercept = interceptor.intercept(this.exchange, this.chain)
|
||||
.subscriberContext(userContext);
|
||||
Mono<Void> intercept = interceptor.intercept(this.exchange, this.chain).subscriberContext(userContext);
|
||||
|
||||
StepVerifier.create(intercept)
|
||||
.then(() -> this.chainResult.assertWasSubscribed())
|
||||
.verifyComplete();
|
||||
StepVerifier.create(intercept).then(() -> this.chainResult.assertWasSubscribed()).verifyComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+23
-34
@@ -51,58 +51,47 @@ public class PayloadExchangeMatcherReactiveAuthorizationManagerTests {
|
||||
@Test
|
||||
public void checkWhenGrantedThenGranted() {
|
||||
AuthorizationDecision expected = new AuthorizationDecision(true);
|
||||
when(this.authz.check(any(), any())).thenReturn(Mono.just(
|
||||
expected));
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager manager =
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager.builder()
|
||||
.add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz))
|
||||
.build();
|
||||
when(this.authz.check(any(), any())).thenReturn(Mono.just(expected));
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager
|
||||
.builder().add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz))
|
||||
.build();
|
||||
|
||||
assertThat(manager.check(Mono.empty(), this.exchange).block())
|
||||
.isEqualTo(expected);
|
||||
assertThat(manager.check(Mono.empty(), this.exchange).block()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenDeniedThenDenied() {
|
||||
AuthorizationDecision expected = new AuthorizationDecision(false);
|
||||
when(this.authz.check(any(), any())).thenReturn(Mono.just(
|
||||
expected));
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager manager =
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager.builder()
|
||||
.add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz))
|
||||
.build();
|
||||
when(this.authz.check(any(), any())).thenReturn(Mono.just(expected));
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager
|
||||
.builder().add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz))
|
||||
.build();
|
||||
|
||||
assertThat(manager.check(Mono.empty(), this.exchange).block())
|
||||
.isEqualTo(expected);
|
||||
assertThat(manager.check(Mono.empty(), this.exchange).block()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenFirstMatchThenSecondUsed() {
|
||||
AuthorizationDecision expected = new AuthorizationDecision(true);
|
||||
when(this.authz.check(any(), any())).thenReturn(Mono.just(
|
||||
expected));
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager manager =
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager.builder()
|
||||
.add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz))
|
||||
.add(new PayloadExchangeMatcherEntry<>(e -> PayloadExchangeMatcher.MatchResult.notMatch(), this.authz2))
|
||||
.build();
|
||||
when(this.authz.check(any(), any())).thenReturn(Mono.just(expected));
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager
|
||||
.builder().add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz))
|
||||
.add(new PayloadExchangeMatcherEntry<>(e -> PayloadExchangeMatcher.MatchResult.notMatch(), this.authz2))
|
||||
.build();
|
||||
|
||||
assertThat(manager.check(Mono.empty(), this.exchange).block())
|
||||
.isEqualTo(expected);
|
||||
assertThat(manager.check(Mono.empty(), this.exchange).block()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenSecondMatchThenSecondUsed() {
|
||||
AuthorizationDecision expected = new AuthorizationDecision(true);
|
||||
when(this.authz2.check(any(), any())).thenReturn(Mono.just(
|
||||
expected));
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager manager =
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager.builder()
|
||||
.add(new PayloadExchangeMatcherEntry<>(e -> PayloadExchangeMatcher.MatchResult.notMatch(), this.authz))
|
||||
.add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz2))
|
||||
.build();
|
||||
when(this.authz2.check(any(), any())).thenReturn(Mono.just(expected));
|
||||
PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager
|
||||
.builder()
|
||||
.add(new PayloadExchangeMatcherEntry<>(e -> PayloadExchangeMatcher.MatchResult.notMatch(), this.authz))
|
||||
.add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz2)).build();
|
||||
|
||||
assertThat(manager.check(Mono.empty(), this.exchange).block())
|
||||
.isEqualTo(expected);
|
||||
assertThat(manager.check(Mono.empty(), this.exchange).block()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-3
@@ -25,10 +25,13 @@ import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
|
||||
/**
|
||||
* A {@link SocketAcceptor} that captures the {@link SecurityContext} and then continues with the {@link RSocket}
|
||||
* A {@link SocketAcceptor} that captures the {@link SecurityContext} and then continues
|
||||
* with the {@link RSocket}
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class CaptureSecurityContextSocketAcceptor implements SocketAcceptor {
|
||||
|
||||
private final RSocket accept;
|
||||
|
||||
private SecurityContext securityContext;
|
||||
@@ -40,11 +43,11 @@ class CaptureSecurityContextSocketAcceptor implements SocketAcceptor {
|
||||
@Override
|
||||
public Mono<RSocket> accept(ConnectionSetupPayload setup, RSocket sendingSocket) {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.doOnNext(securityContext -> this.securityContext = securityContext)
|
||||
.thenReturn(this.accept);
|
||||
.doOnNext(securityContext -> this.securityContext = securityContext).thenReturn(this.accept);
|
||||
}
|
||||
|
||||
public SecurityContext getSecurityContext() {
|
||||
return this.securityContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+46
-79
@@ -64,8 +64,8 @@ import static org.mockito.Mockito.when;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PayloadInterceptorRSocketTests {
|
||||
|
||||
static final MimeType COMPOSITE_METADATA = MimeTypeUtils.parseMimeType(
|
||||
WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
static final MimeType COMPOSITE_METADATA = MimeTypeUtils
|
||||
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
@Mock
|
||||
RSocket delegate;
|
||||
@@ -95,26 +95,22 @@ public class PayloadInterceptorRSocketTests {
|
||||
this.delegate = null;
|
||||
List<PayloadInterceptor> interceptors = Arrays.asList(this.interceptor);
|
||||
assertThatCode(() -> {
|
||||
new PayloadInterceptorRSocket(this.delegate, interceptors,
|
||||
metadataMimeType, dataMimeType);
|
||||
})
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
new PayloadInterceptorRSocket(this.delegate, interceptors, metadataMimeType, dataMimeType);
|
||||
}).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenNullInterceptorsThenException() {
|
||||
List<PayloadInterceptor> interceptors = null;
|
||||
assertThatCode(() -> new PayloadInterceptorRSocket(this.delegate, interceptors,
|
||||
metadataMimeType, dataMimeType))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatCode(() -> new PayloadInterceptorRSocket(this.delegate, interceptors, metadataMimeType, dataMimeType))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenEmptyInterceptorsThenException() {
|
||||
List<PayloadInterceptor> interceptors = Collections.emptyList();
|
||||
assertThatCode(() -> new PayloadInterceptorRSocket(this.delegate, interceptors,
|
||||
metadataMimeType, dataMimeType))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatCode(() -> new PayloadInterceptorRSocket(this.delegate, interceptors, metadataMimeType, dataMimeType))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
// single interceptor
|
||||
@@ -127,9 +123,8 @@ public class PayloadInterceptorRSocketTests {
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(this.delegate,
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.fireAndForget(this.payload))
|
||||
.then(() -> this.voidResult.assertWasSubscribed())
|
||||
.verifyComplete();
|
||||
StepVerifier.create(interceptor.fireAndForget(this.payload)).then(() -> this.voidResult.assertWasSubscribed())
|
||||
.verifyComplete();
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -144,8 +139,8 @@ public class PayloadInterceptorRSocketTests {
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.fireAndForget(this.payload))
|
||||
.then(() -> this.voidResult.assertWasNotSubscribed())
|
||||
.verifyErrorSatisfies(e -> assertThat(e).isEqualTo(expected));
|
||||
.then(() -> this.voidResult.assertWasNotSubscribed())
|
||||
.verifyErrorSatisfies(e -> assertThat(e).isEqualTo(expected));
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -160,8 +155,7 @@ public class PayloadInterceptorRSocketTests {
|
||||
RSocket assertAuthentication = new RSocketProxy(this.delegate) {
|
||||
@Override
|
||||
public Mono<Void> fireAndForget(Payload payload) {
|
||||
return assertAuthentication(authentication)
|
||||
.flatMap(a -> super.fireAndForget(payload));
|
||||
return assertAuthentication(authentication).flatMap(a -> super.fireAndForget(payload));
|
||||
}
|
||||
};
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(assertAuthentication,
|
||||
@@ -183,10 +177,8 @@ public class PayloadInterceptorRSocketTests {
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.requestResponse(this.payload))
|
||||
.then(() -> this.payloadResult.assertSubscribers())
|
||||
.then(() -> this.payloadResult.emit(this.payload))
|
||||
.expectNext(this.payload)
|
||||
.verifyComplete();
|
||||
.then(() -> this.payloadResult.assertSubscribers()).then(() -> this.payloadResult.emit(this.payload))
|
||||
.expectNext(this.payload).verifyComplete();
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -217,18 +209,15 @@ public class PayloadInterceptorRSocketTests {
|
||||
RSocket assertAuthentication = new RSocketProxy(this.delegate) {
|
||||
@Override
|
||||
public Mono<Payload> requestResponse(Payload payload) {
|
||||
return assertAuthentication(authentication)
|
||||
.flatMap(a -> super.requestResponse(payload));
|
||||
return assertAuthentication(authentication).flatMap(a -> super.requestResponse(payload));
|
||||
}
|
||||
};
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(assertAuthentication,
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.requestResponse(this.payload))
|
||||
.then(() -> this.payloadResult.assertSubscribers())
|
||||
.then(() -> this.payloadResult.emit(this.payload))
|
||||
.expectNext(this.payload)
|
||||
.verifyComplete();
|
||||
.then(() -> this.payloadResult.assertSubscribers()).then(() -> this.payloadResult.emit(this.payload))
|
||||
.expectNext(this.payload).verifyComplete();
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -243,11 +232,8 @@ public class PayloadInterceptorRSocketTests {
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(this.delegate,
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.requestStream(this.payload))
|
||||
.then(() -> this.payloadResult.assertSubscribers())
|
||||
.then(() -> this.payloadResult.emit(this.payload))
|
||||
.expectNext(this.payload)
|
||||
.verifyComplete();
|
||||
StepVerifier.create(interceptor.requestStream(this.payload)).then(() -> this.payloadResult.assertSubscribers())
|
||||
.then(() -> this.payloadResult.emit(this.payload)).expectNext(this.payload).verifyComplete();
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -262,8 +248,8 @@ public class PayloadInterceptorRSocketTests {
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.requestStream(this.payload))
|
||||
.then(() -> this.payloadResult.assertNoSubscribers())
|
||||
.verifyErrorSatisfies(e -> assertThat(e).isEqualTo(expected));
|
||||
.then(() -> this.payloadResult.assertNoSubscribers())
|
||||
.verifyErrorSatisfies(e -> assertThat(e).isEqualTo(expected));
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -278,18 +264,14 @@ public class PayloadInterceptorRSocketTests {
|
||||
RSocket assertAuthentication = new RSocketProxy(this.delegate) {
|
||||
@Override
|
||||
public Flux<Payload> requestStream(Payload payload) {
|
||||
return assertAuthentication(authentication)
|
||||
.flatMapMany(a -> super.requestStream(payload));
|
||||
return assertAuthentication(authentication).flatMapMany(a -> super.requestStream(payload));
|
||||
}
|
||||
};
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(assertAuthentication,
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.requestStream(this.payload))
|
||||
.then(() -> this.payloadResult.assertSubscribers())
|
||||
.then(() -> this.payloadResult.emit(this.payload))
|
||||
.expectNext(this.payload)
|
||||
.verifyComplete();
|
||||
StepVerifier.create(interceptor.requestStream(this.payload)).then(() -> this.payloadResult.assertSubscribers())
|
||||
.then(() -> this.payloadResult.emit(this.payload)).expectNext(this.payload).verifyComplete();
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -305,10 +287,8 @@ public class PayloadInterceptorRSocketTests {
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.requestChannel(Flux.just(this.payload)))
|
||||
.then(() -> this.payloadResult.assertSubscribers())
|
||||
.then(() -> this.payloadResult.emit(this.payload))
|
||||
.expectNext(this.payload)
|
||||
.verifyComplete();
|
||||
.then(() -> this.payloadResult.assertSubscribers()).then(() -> this.payloadResult.emit(this.payload))
|
||||
.expectNext(this.payload).verifyComplete();
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -324,8 +304,8 @@ public class PayloadInterceptorRSocketTests {
|
||||
Arrays.asList(this.interceptor), this.metadataMimeType, this.dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.requestChannel(Flux.just(this.payload)))
|
||||
.then(() -> this.payloadResult.assertNoSubscribers())
|
||||
.verifyErrorSatisfies(e -> assertThat(e).isEqualTo(expected));
|
||||
.then(() -> this.payloadResult.assertNoSubscribers())
|
||||
.verifyErrorSatisfies(e -> assertThat(e).isEqualTo(expected));
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -341,18 +321,14 @@ public class PayloadInterceptorRSocketTests {
|
||||
RSocket assertAuthentication = new RSocketProxy(this.delegate) {
|
||||
@Override
|
||||
public Flux<Payload> requestChannel(Publisher<Payload> payload) {
|
||||
return assertAuthentication(authentication)
|
||||
.flatMapMany(a -> super.requestChannel(payload));
|
||||
return assertAuthentication(authentication).flatMapMany(a -> super.requestChannel(payload));
|
||||
}
|
||||
};
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(assertAuthentication,
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.requestChannel(payload))
|
||||
.then(() -> this.payloadResult.assertSubscribers())
|
||||
.then(() -> this.payloadResult.emit(this.payload))
|
||||
.expectNext(this.payload)
|
||||
.verifyComplete();
|
||||
StepVerifier.create(interceptor.requestChannel(payload)).then(() -> this.payloadResult.assertSubscribers())
|
||||
.then(() -> this.payloadResult.emit(this.payload)).expectNext(this.payload).verifyComplete();
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -367,9 +343,8 @@ public class PayloadInterceptorRSocketTests {
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(this.delegate,
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.metadataPush(this.payload))
|
||||
.then(() -> this.voidResult.assertWasSubscribed())
|
||||
.verifyComplete();
|
||||
StepVerifier.create(interceptor.metadataPush(this.payload)).then(() -> this.voidResult.assertWasSubscribed())
|
||||
.verifyComplete();
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -383,9 +358,8 @@ public class PayloadInterceptorRSocketTests {
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(this.delegate,
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.metadataPush(this.payload))
|
||||
.then(() -> this.voidResult.assertWasNotSubscribed())
|
||||
.verifyErrorSatisfies(e -> assertThat(e).isEqualTo(expected));
|
||||
StepVerifier.create(interceptor.metadataPush(this.payload)).then(() -> this.voidResult.assertWasNotSubscribed())
|
||||
.verifyErrorSatisfies(e -> assertThat(e).isEqualTo(expected));
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -400,15 +374,13 @@ public class PayloadInterceptorRSocketTests {
|
||||
RSocket assertAuthentication = new RSocketProxy(this.delegate) {
|
||||
@Override
|
||||
public Mono<Void> metadataPush(Payload payload) {
|
||||
return assertAuthentication(authentication)
|
||||
.flatMap(a -> super.metadataPush(payload));
|
||||
return assertAuthentication(authentication).flatMap(a -> super.metadataPush(payload));
|
||||
}
|
||||
};
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(assertAuthentication,
|
||||
Arrays.asList(this.interceptor), metadataMimeType, dataMimeType);
|
||||
|
||||
StepVerifier.create(interceptor.metadataPush(this.payload))
|
||||
.verifyComplete();
|
||||
StepVerifier.create(interceptor.metadataPush(this.payload)).verifyComplete();
|
||||
|
||||
verify(this.interceptor).intercept(this.exchange.capture(), any());
|
||||
assertThat(this.exchange.getValue().getPayload()).isEqualTo(this.payload);
|
||||
@@ -425,8 +397,7 @@ public class PayloadInterceptorRSocketTests {
|
||||
when(this.delegate.fireAndForget(any())).thenReturn(this.voidResult.mono());
|
||||
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(this.delegate,
|
||||
Arrays.asList(this.interceptor, this.interceptor2), metadataMimeType,
|
||||
dataMimeType);
|
||||
Arrays.asList(this.interceptor, this.interceptor2), metadataMimeType, dataMimeType);
|
||||
|
||||
interceptor.fireAndForget(this.payload).block();
|
||||
|
||||
@@ -435,7 +406,6 @@ public class PayloadInterceptorRSocketTests {
|
||||
this.voidResult.assertWasSubscribed();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void fireAndForgetWhenInterceptorsMutatesPayloadThenDelegateInvoked() {
|
||||
when(this.interceptor.intercept(any(), any())).thenAnswer(withChainNext());
|
||||
@@ -443,8 +413,7 @@ public class PayloadInterceptorRSocketTests {
|
||||
when(this.delegate.fireAndForget(any())).thenReturn(this.voidResult.mono());
|
||||
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(this.delegate,
|
||||
Arrays.asList(this.interceptor, this.interceptor2), metadataMimeType,
|
||||
dataMimeType);
|
||||
Arrays.asList(this.interceptor, this.interceptor2), metadataMimeType, dataMimeType);
|
||||
|
||||
interceptor.fireAndForget(this.payload).block();
|
||||
|
||||
@@ -461,8 +430,7 @@ public class PayloadInterceptorRSocketTests {
|
||||
when(this.interceptor.intercept(any(), any())).thenReturn(Mono.error(expected));
|
||||
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(this.delegate,
|
||||
Arrays.asList(this.interceptor, this.interceptor2), metadataMimeType,
|
||||
dataMimeType);
|
||||
Arrays.asList(this.interceptor, this.interceptor2), metadataMimeType, dataMimeType);
|
||||
|
||||
assertThatCode(() -> interceptor.fireAndForget(this.payload).block()).isEqualTo(expected);
|
||||
|
||||
@@ -479,8 +447,7 @@ public class PayloadInterceptorRSocketTests {
|
||||
when(this.interceptor2.intercept(any(), any())).thenReturn(Mono.error(expected));
|
||||
|
||||
PayloadInterceptorRSocket interceptor = new PayloadInterceptorRSocket(this.delegate,
|
||||
Arrays.asList(this.interceptor, this.interceptor2), metadataMimeType,
|
||||
dataMimeType);
|
||||
Arrays.asList(this.interceptor, this.interceptor2), metadataMimeType, dataMimeType);
|
||||
|
||||
assertThatCode(() -> interceptor.fireAndForget(this.payload).block()).isEqualTo(expected);
|
||||
|
||||
@@ -491,16 +458,15 @@ public class PayloadInterceptorRSocketTests {
|
||||
}
|
||||
|
||||
private Mono<Authentication> assertAuthentication(Authentication authentication) {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(SecurityContext::getAuthentication)
|
||||
return ReactiveSecurityContextHolder.getContext().map(SecurityContext::getAuthentication)
|
||||
.doOnNext(a -> assertThat(a).isEqualTo(authentication));
|
||||
}
|
||||
|
||||
private Answer<Object> withAuthenticated(Authentication authentication) {
|
||||
return invocation -> {
|
||||
PayloadInterceptorChain c = (PayloadInterceptorChain) invocation.getArguments()[1];
|
||||
return c.next(new DefaultPayloadExchange(PayloadExchangeType.REQUEST_CHANNEL, this.payload, this.metadataMimeType,
|
||||
this.dataMimeType))
|
||||
return c.next(new DefaultPayloadExchange(PayloadExchangeType.REQUEST_CHANNEL, this.payload,
|
||||
this.metadataMimeType, this.dataMimeType))
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication));
|
||||
};
|
||||
}
|
||||
@@ -512,4 +478,5 @@ public class PayloadInterceptorRSocketTests {
|
||||
return chain.next(exchange);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-4
@@ -48,6 +48,7 @@ import static org.mockito.Mockito.when;
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PayloadSocketAcceptorInterceptorTests {
|
||||
|
||||
@Mock
|
||||
private PayloadInterceptor interceptor;
|
||||
|
||||
@@ -79,7 +80,8 @@ public class PayloadSocketAcceptorInterceptorTests {
|
||||
|
||||
PayloadExchange exchange = captureExchange();
|
||||
|
||||
assertThat(exchange.getMetadataMimeType().toString()).isEqualTo(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
assertThat(exchange.getMetadataMimeType().toString())
|
||||
.isEqualTo(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
assertThat(exchange.getDataMimeType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@@ -100,7 +102,8 @@ public class PayloadSocketAcceptorInterceptorTests {
|
||||
|
||||
PayloadExchange exchange = captureExchange();
|
||||
|
||||
assertThat(exchange.getMetadataMimeType().toString()).isEqualTo(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
assertThat(exchange.getMetadataMimeType().toString())
|
||||
.isEqualTo(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
assertThat(exchange.getDataMimeType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@@ -117,9 +120,9 @@ public class PayloadSocketAcceptorInterceptorTests {
|
||||
|
||||
result.fireAndForget(this.payload).block();
|
||||
|
||||
ArgumentCaptor<PayloadExchange> exchangeArg =
|
||||
ArgumentCaptor.forClass(PayloadExchange.class);
|
||||
ArgumentCaptor<PayloadExchange> exchangeArg = ArgumentCaptor.forClass(PayloadExchange.class);
|
||||
verify(this.interceptor, times(2)).intercept(exchangeArg.capture(), any());
|
||||
return exchangeArg.getValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-12
@@ -100,8 +100,8 @@ public class PayloadSocketAcceptorTests {
|
||||
|
||||
@Test
|
||||
public void acceptWhenDataMimeTypeNullThenException() {
|
||||
assertThatCode(() -> this.acceptor.accept(this.setupPayload, this.rSocket)
|
||||
.block()).isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatCode(() -> this.acceptor.accept(this.setupPayload, this.rSocket).block())
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -132,8 +132,8 @@ public class PayloadSocketAcceptorTests {
|
||||
|
||||
PayloadExchange exchange = captureExchange();
|
||||
|
||||
assertThat(exchange.getMetadataMimeType()
|
||||
.toString()).isEqualTo(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
assertThat(exchange.getMetadataMimeType().toString())
|
||||
.isEqualTo(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
assertThat(exchange.getDataMimeType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@@ -148,18 +148,19 @@ public class PayloadSocketAcceptorTests {
|
||||
assertThat(exchange.getDataMimeType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
// gh-8654
|
||||
public void acceptWhenDelegateAcceptRequiresReactiveSecurityContext() {
|
||||
when(this.setupPayload.metadataMimeType()).thenReturn(MediaType.TEXT_PLAIN_VALUE);
|
||||
when(this.setupPayload.dataMimeType()).thenReturn(MediaType.APPLICATION_JSON_VALUE);
|
||||
SecurityContext expectedSecurityContext = new SecurityContextImpl(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
CaptureSecurityContextSocketAcceptor captureSecurityContext = new CaptureSecurityContextSocketAcceptor(this.rSocket);
|
||||
SecurityContext expectedSecurityContext = new SecurityContextImpl(
|
||||
new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
CaptureSecurityContextSocketAcceptor captureSecurityContext = new CaptureSecurityContextSocketAcceptor(
|
||||
this.rSocket);
|
||||
PayloadInterceptor authenticateInterceptor = (exchange, chain) -> {
|
||||
Context withSecurityContext = ReactiveSecurityContextHolder.withSecurityContext(Mono.just(expectedSecurityContext));
|
||||
return chain.next(exchange)
|
||||
.subscriberContext(withSecurityContext);
|
||||
Context withSecurityContext = ReactiveSecurityContextHolder
|
||||
.withSecurityContext(Mono.just(expectedSecurityContext));
|
||||
return chain.next(exchange).subscriberContext(withSecurityContext);
|
||||
};
|
||||
List<PayloadInterceptor> interceptors = Arrays.asList(authenticateInterceptor);
|
||||
this.acceptor = new PayloadSocketAcceptor(captureSecurityContext, interceptors);
|
||||
@@ -181,9 +182,9 @@ public class PayloadSocketAcceptorTests {
|
||||
|
||||
result.fireAndForget(this.payload).block();
|
||||
|
||||
ArgumentCaptor<PayloadExchange> exchangeArg =
|
||||
ArgumentCaptor.forClass(PayloadExchange.class);
|
||||
ArgumentCaptor<PayloadExchange> exchangeArg = ArgumentCaptor.forClass(PayloadExchange.class);
|
||||
verify(this.interceptor, times(2)).intercept(exchangeArg.capture(), any());
|
||||
return exchangeArg.getValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-6
@@ -31,20 +31,18 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class BasicAuthenticationDecoderTests {
|
||||
|
||||
@Test
|
||||
public void basicAuthenticationWhenEncodedThenDecodes() {
|
||||
BasicAuthenticationEncoder encoder = new BasicAuthenticationEncoder();
|
||||
BasicAuthenticationDecoder decoder = new BasicAuthenticationDecoder();
|
||||
UsernamePasswordMetadata expectedCredentials =
|
||||
new UsernamePasswordMetadata("rob", "password");
|
||||
UsernamePasswordMetadata expectedCredentials = new UsernamePasswordMetadata("rob", "password");
|
||||
DefaultDataBufferFactory factory = new DefaultDataBufferFactory();
|
||||
ResolvableType elementType = ResolvableType
|
||||
.forClass(UsernamePasswordMetadata.class);
|
||||
ResolvableType elementType = ResolvableType.forClass(UsernamePasswordMetadata.class);
|
||||
MimeType mimeType = UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE;
|
||||
Map<String, Object> hints = null;
|
||||
|
||||
DataBuffer dataBuffer = encoder.encodeValue(expectedCredentials, factory,
|
||||
elementType, mimeType, hints);
|
||||
DataBuffer dataBuffer = encoder.encodeValue(expectedCredentials, factory, elementType, mimeType, hints);
|
||||
UsernamePasswordMetadata actualCredentials = decoder
|
||||
.decodeToMono(Mono.just(dataBuffer), elementType, mimeType, hints).block();
|
||||
|
||||
|
||||
+7
-6
@@ -44,8 +44,9 @@ import static org.mockito.Mockito.when;
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RoutePayloadExchangeMatcherTests {
|
||||
static final MimeType COMPOSITE_METADATA = MimeTypeUtils.parseMimeType(
|
||||
WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
static final MimeType COMPOSITE_METADATA = MimeTypeUtils
|
||||
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString());
|
||||
|
||||
@Mock
|
||||
private MetadataExtractor metadataExtractor;
|
||||
@@ -69,14 +70,13 @@ public class RoutePayloadExchangeMatcherTests {
|
||||
public void setup() {
|
||||
this.pattern = "a.b";
|
||||
this.matcher = new RoutePayloadExchangeMatcher(this.metadataExtractor, this.routeMatcher, this.pattern);
|
||||
this.exchange = new DefaultPayloadExchange(PayloadExchangeType.REQUEST_CHANNEL, this.payload, COMPOSITE_METADATA,
|
||||
MediaType.APPLICATION_JSON);
|
||||
this.exchange = new DefaultPayloadExchange(PayloadExchangeType.REQUEST_CHANNEL, this.payload,
|
||||
COMPOSITE_METADATA, MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchesWhenNoRouteThenNotMatch() {
|
||||
when(this.metadataExtractor.extract(any(), any()))
|
||||
.thenReturn(Collections.emptyMap());
|
||||
when(this.metadataExtractor.extract(any(), any())).thenReturn(Collections.emptyMap());
|
||||
PayloadExchangeMatcher.MatchResult result = this.matcher.matches(this.exchange).block();
|
||||
assertThat(result.isMatch()).isFalse();
|
||||
}
|
||||
@@ -113,4 +113,5 @@ public class RoutePayloadExchangeMatcherTests {
|
||||
assertThat(result.isMatch()).isTrue();
|
||||
assertThat(result.getVariables()).containsAllEntriesOf(variables);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user