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