From 591d1edc7d54fe893cb70c133fd703e705ca67cd Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Fri, 17 Jun 2022 14:01:36 -0500 Subject: [PATCH] Cache SecurityContextRepository.loadContext(HttpServletRequest) Result Closes gh-11390 --- .../context/SecurityContextRepository.java | 3 +- .../SecurityContextRepositoryTests.java | 53 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 web/src/test/java/org/springframework/security/web/context/SecurityContextRepositoryTests.java diff --git a/web/src/main/java/org/springframework/security/web/context/SecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/context/SecurityContextRepository.java index 1e1805c81dc..b9034e36c48 100644 --- a/web/src/main/java/org/springframework/security/web/context/SecurityContextRepository.java +++ b/web/src/main/java/org/springframework/security/web/context/SecurityContextRepository.java @@ -22,6 +22,7 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.context.SecurityContext; +import org.springframework.util.function.SingletonSupplier; /** * Strategy used for persisting a {@link SecurityContext} between requests. @@ -76,7 +77,7 @@ public interface SecurityContextRepository { * @since 5.7 */ default Supplier loadContext(HttpServletRequest request) { - return () -> loadContext(new HttpRequestResponseHolder(request, null)); + return SingletonSupplier.of(() -> loadContext(new HttpRequestResponseHolder(request, null))); } /** diff --git a/web/src/test/java/org/springframework/security/web/context/SecurityContextRepositoryTests.java b/web/src/test/java/org/springframework/security/web/context/SecurityContextRepositoryTests.java new file mode 100644 index 00000000000..b28d61c8896 --- /dev/null +++ b/web/src/test/java/org/springframework/security/web/context/SecurityContextRepositoryTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.context; + +import java.util.function.Supplier; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.jupiter.api.Test; + +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextImpl; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +/** + * @author Rob Winch + */ +class SecurityContextRepositoryTests { + + SecurityContextRepository repository = spy(SecurityContextRepository.class); + + @Test + void loadContextHttpRequestResponseHolderWhenInvokeSupplierTwiceThenOnlyInvokesLoadContextOnce() { + given(this.repository.loadContext(any(HttpRequestResponseHolder.class))).willReturn(new SecurityContextImpl()); + Supplier deferredContext = this.repository.loadContext(mock(HttpServletRequest.class)); + verify(this.repository).loadContext(any(HttpServletRequest.class)); + deferredContext.get(); + verify(this.repository).loadContext(any(HttpRequestResponseHolder.class)); + deferredContext.get(); + verifyNoMoreInteractions(this.repository); + } + +}