parent
							
								
									e23134c3ed
								
							
						
					
					
						commit
						9ea4df5b5d
					
				|  | @ -0,0 +1,73 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2017 the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package org.springframework.security.core.context; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | import org.springframework.security.core.Authentication; | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | import reactor.util.context.Context; | ||||||
|  | 
 | ||||||
|  | import java.util.function.Function; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Allows getting and setting the Spring {@link SecurityContext} into a {@link Context}. | ||||||
|  |  * | ||||||
|  |  * @author Rob Winch | ||||||
|  |  * @since 5.0 | ||||||
|  |  */ | ||||||
|  | public class ReactiveSecurityContextHolder { | ||||||
|  | 	private static final Class<?> SECURITY_CONTEXT_KEY = SecurityContext.class; | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the {@code Mono<SecurityContext>} from Reactor {@link Context} | ||||||
|  | 	 * @return the {@code Mono<SecurityContext>} | ||||||
|  | 	 */ | ||||||
|  | 	public static Mono<SecurityContext> getContext() { | ||||||
|  | 		return Mono.subscriberContext() | ||||||
|  | 			.filter( c -> c.hasKey(SECURITY_CONTEXT_KEY)) | ||||||
|  | 			.flatMap( c-> c.<Mono<SecurityContext>>get(SECURITY_CONTEXT_KEY)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Clears the {@code Mono<SecurityContext>} from Reactor {@link Context} | ||||||
|  | 	 * @return Return a {@code Mono<Void>} which only replays complete and error signals | ||||||
|  | 	 * from clearing the context. | ||||||
|  | 	 */ | ||||||
|  | 	public static Function<Context,Context> clearContext() { | ||||||
|  | 		return context -> context.delete(SECURITY_CONTEXT_KEY); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Creates a Reactor {@link Context} that contains the {@code Mono<SecurityContext>} | ||||||
|  | 	 * that can be merged into another {@link Context} | ||||||
|  | 	 * @param securityContext the {@code Mono<SecurityContext>} to set in the returned | ||||||
|  | 	 * Reactor {@link Context} | ||||||
|  | 	 * @return a Reactor {@link Context} that contains the {@code Mono<SecurityContext>} | ||||||
|  | 	 */ | ||||||
|  | 	public static Context withSecurityContext(Mono<? extends SecurityContext> securityContext) { | ||||||
|  | 		return Context.of(SECURITY_CONTEXT_KEY, securityContext); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * A shortcut for {@link #withSecurityContext(Mono)} | ||||||
|  | 	 * @param authentication the {@link Authentication} to be used | ||||||
|  | 	 * @return a Reactor {@link Context} that contains the {@code Mono<SecurityContext>} | ||||||
|  | 	 */ | ||||||
|  | 	public static Context withAuthentication(Authentication authentication) { | ||||||
|  | 		return withSecurityContext(Mono.just(new SecurityContextImpl(authentication))); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,81 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2017 the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package org.springframework.security.core.context; | ||||||
|  | 
 | ||||||
|  | import org.junit.Test; | ||||||
|  | import org.springframework.security.authentication.TestingAuthenticationToken; | ||||||
|  | import org.springframework.security.core.Authentication; | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | import reactor.test.StepVerifier; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author Rob Winch | ||||||
|  |  * @since 5.0 | ||||||
|  |  */ | ||||||
|  | public class ReactiveSecurityContextHolderTests { | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void getContextWhenEmpty() { | ||||||
|  | 		Mono<SecurityContext> context = ReactiveSecurityContextHolder.getContext(); | ||||||
|  | 
 | ||||||
|  | 		StepVerifier.create(context) | ||||||
|  | 			.verifyComplete(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void setContextAndGetContextThenEmitsContext() { | ||||||
|  | 		SecurityContext expectedContext = new SecurityContextImpl( | ||||||
|  | 			new TestingAuthenticationToken("user", "password", "ROLE_USER")); | ||||||
|  | 
 | ||||||
|  | 		Mono<SecurityContext> context = Mono.subscriberContext() | ||||||
|  | 			.flatMap( c -> ReactiveSecurityContextHolder.getContext()) | ||||||
|  | 			.subscriberContext(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(expectedContext))); | ||||||
|  | 
 | ||||||
|  | 		StepVerifier.create(context) | ||||||
|  | 			.expectNext(expectedContext) | ||||||
|  | 			.verifyComplete(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void setContextAndClearAndGetContextThenEmitsEmpty() { | ||||||
|  | 		SecurityContext expectedContext = new SecurityContextImpl( | ||||||
|  | 			new TestingAuthenticationToken("user", "password", "ROLE_USER")); | ||||||
|  | 
 | ||||||
|  | 		Mono<SecurityContext> context = Mono.subscriberContext() | ||||||
|  | 			.flatMap( c -> ReactiveSecurityContextHolder.getContext()) | ||||||
|  | 			.subscriberContext(ReactiveSecurityContextHolder.clearContext()) | ||||||
|  | 			.subscriberContext(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(expectedContext))); | ||||||
|  | 
 | ||||||
|  | 		StepVerifier.create(context) | ||||||
|  | 			.verifyComplete(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void setAuthenticationAndGetContextThenEmitsContext() { | ||||||
|  | 		Authentication expectedAuthentication = new TestingAuthenticationToken("user", | ||||||
|  | 			"password", "ROLE_USER"); | ||||||
|  | 
 | ||||||
|  | 		Mono<Authentication> authentication = Mono.subscriberContext() | ||||||
|  | 			.flatMap( c -> ReactiveSecurityContextHolder.getContext()) | ||||||
|  | 			.map(SecurityContext::getAuthentication) | ||||||
|  | 			.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(expectedAuthentication)); | ||||||
|  | 
 | ||||||
|  | 		StepVerifier.create(authentication) | ||||||
|  | 			.expectNext(expectedAuthentication) | ||||||
|  | 			.verifyComplete(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue