21 changed files with 571 additions and 43 deletions
@ -0,0 +1,34 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ Copyright 2002-2018 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. |
||||||
|
--> |
||||||
|
|
||||||
|
<b:beans xmlns:b="http://www.springframework.org/schema/beans" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xmlns="http://www.springframework.org/schema/security" |
||||||
|
xsi:schemaLocation=" |
||||||
|
http://www.springframework.org/schema/security |
||||||
|
https://www.springframework.org/schema/security/spring-security.xsd |
||||||
|
http://www.springframework.org/schema/beans |
||||||
|
https://www.springframework.org/schema/beans/spring-beans.xsd"> |
||||||
|
|
||||||
|
<http security-context-explicit-save="true"> |
||||||
|
<form-login/> |
||||||
|
<intercept-url pattern="/**" access="authenticated"/> |
||||||
|
</http> |
||||||
|
|
||||||
|
<b:import resource="MiscHttpConfigTests-controllers.xml"/> |
||||||
|
<b:import resource="userservice.xml"/> |
||||||
|
</b:beans> |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ Copyright 2002-2018 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. |
||||||
|
--> |
||||||
|
|
||||||
|
<b:beans xmlns:b="http://www.springframework.org/schema/beans" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xmlns="http://www.springframework.org/schema/security" |
||||||
|
xsi:schemaLocation=" |
||||||
|
http://www.springframework.org/schema/security |
||||||
|
https://www.springframework.org/schema/security/spring-security.xsd |
||||||
|
http://www.springframework.org/schema/beans |
||||||
|
https://www.springframework.org/schema/beans/spring-beans.xsd"> |
||||||
|
|
||||||
|
<http create-session="always" security-context-repository-ref="repo" security-context-explicit-save="true"> |
||||||
|
<form-login/> |
||||||
|
<intercept-url pattern="/**" access="authenticated"/> |
||||||
|
</http> |
||||||
|
|
||||||
|
<b:bean name="repo" class="org.mockito.Mockito" factory-method="mock"> |
||||||
|
<b:constructor-arg value="org.springframework.security.web.context.SecurityContextRepository"/> |
||||||
|
</b:bean> |
||||||
|
|
||||||
|
<b:import resource="MiscHttpConfigTests-controllers.xml"/> |
||||||
|
<b:import resource="userservice.xml"/> |
||||||
|
</b:beans> |
||||||
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
@ -0,0 +1,86 @@ |
|||||||
|
/* |
||||||
|
* 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.io.IOException; |
||||||
|
|
||||||
|
import jakarta.servlet.FilterChain; |
||||||
|
import jakarta.servlet.ServletException; |
||||||
|
import jakarta.servlet.http.HttpServletRequest; |
||||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||||
|
|
||||||
|
import org.springframework.security.core.context.SecurityContext; |
||||||
|
import org.springframework.security.core.context.SecurityContextHolder; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
import org.springframework.web.filter.OncePerRequestFilter; |
||||||
|
|
||||||
|
/** |
||||||
|
* A {@link jakarta.servlet.Filter} that uses the {@link SecurityContextRepository} to |
||||||
|
* obtain the {@link SecurityContext} and set it on the {@link SecurityContextHolder}. |
||||||
|
* This is similar to {@link SecurityContextPersistenceFilter} except that the |
||||||
|
* {@link SecurityContextRepository#saveContext(SecurityContext, HttpServletRequest, HttpServletResponse)} |
||||||
|
* must be explicitly invoked to save the {@link SecurityContext}. This improves the |
||||||
|
* efficiency and provides better flexibility by allowing different authentication |
||||||
|
* mechanisms to choose individually if authentication should be persisted. |
||||||
|
* |
||||||
|
* @author Rob Winch |
||||||
|
* @since 5.7 |
||||||
|
*/ |
||||||
|
public class SecurityContextHolderFilter extends OncePerRequestFilter { |
||||||
|
|
||||||
|
private final SecurityContextRepository securityContextRepository; |
||||||
|
|
||||||
|
private boolean shouldNotFilterErrorDispatch; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new instance. |
||||||
|
* @param securityContextRepository the repository to use. Cannot be null. |
||||||
|
*/ |
||||||
|
public SecurityContextHolderFilter(SecurityContextRepository securityContextRepository) { |
||||||
|
Assert.notNull(securityContextRepository, "securityContextRepository cannot be null"); |
||||||
|
this.securityContextRepository = securityContextRepository; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) |
||||||
|
throws ServletException, IOException { |
||||||
|
SecurityContext securityContext = this.securityContextRepository |
||||||
|
.loadContext(new HttpRequestResponseHolder(request, response)); |
||||||
|
try { |
||||||
|
SecurityContextHolder.setContext(securityContext); |
||||||
|
filterChain.doFilter(request, response); |
||||||
|
} |
||||||
|
finally { |
||||||
|
SecurityContextHolder.clearContext(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean shouldNotFilterErrorDispatch() { |
||||||
|
return this.shouldNotFilterErrorDispatch; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Disables {@link SecurityContextHolderFilter} for error dispatch. |
||||||
|
* @param shouldNotFilterErrorDispatch if the Filter should be disabled for error |
||||||
|
* dispatch. Default is false. |
||||||
|
*/ |
||||||
|
public void setShouldNotFilterErrorDispatch(boolean shouldNotFilterErrorDispatch) { |
||||||
|
this.shouldNotFilterErrorDispatch = shouldNotFilterErrorDispatch; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,95 @@ |
|||||||
|
/* |
||||||
|
* 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 jakarta.servlet.FilterChain; |
||||||
|
import jakarta.servlet.http.HttpServletRequest; |
||||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach; |
||||||
|
import org.junit.jupiter.api.BeforeEach; |
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
import org.junit.jupiter.api.extension.ExtendWith; |
||||||
|
import org.mockito.ArgumentCaptor; |
||||||
|
import org.mockito.Captor; |
||||||
|
import org.mockito.Mock; |
||||||
|
import org.mockito.junit.jupiter.MockitoExtension; |
||||||
|
|
||||||
|
import org.springframework.security.authentication.TestAuthentication; |
||||||
|
import org.springframework.security.core.Authentication; |
||||||
|
import org.springframework.security.core.context.SecurityContext; |
||||||
|
import org.springframework.security.core.context.SecurityContextHolder; |
||||||
|
import org.springframework.security.core.context.SecurityContextImpl; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.mockito.BDDMockito.given; |
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class) |
||||||
|
class SecurityContextHolderFilterTests { |
||||||
|
|
||||||
|
@Mock |
||||||
|
private SecurityContextRepository repository; |
||||||
|
|
||||||
|
@Mock |
||||||
|
private HttpServletRequest request; |
||||||
|
|
||||||
|
@Mock |
||||||
|
private HttpServletResponse response; |
||||||
|
|
||||||
|
@Mock |
||||||
|
private FilterChain chain; |
||||||
|
|
||||||
|
@Captor |
||||||
|
private ArgumentCaptor<HttpRequestResponseHolder> requestResponse; |
||||||
|
|
||||||
|
private SecurityContextHolderFilter filter; |
||||||
|
|
||||||
|
@BeforeEach |
||||||
|
void setup() { |
||||||
|
this.filter = new SecurityContextHolderFilter(this.repository); |
||||||
|
} |
||||||
|
|
||||||
|
@AfterEach |
||||||
|
void cleanup() { |
||||||
|
SecurityContextHolder.clearContext(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void doFilterThenSetsAndClearsSecurityContextHolder() throws Exception { |
||||||
|
Authentication authentication = TestAuthentication.authenticatedUser(); |
||||||
|
SecurityContext expectedContext = new SecurityContextImpl(authentication); |
||||||
|
given(this.repository.loadContext(this.requestResponse.capture())).willReturn(expectedContext); |
||||||
|
FilterChain filterChain = (request, response) -> assertThat(SecurityContextHolder.getContext()) |
||||||
|
.isEqualTo(expectedContext); |
||||||
|
|
||||||
|
this.filter.doFilter(this.request, this.response, filterChain); |
||||||
|
|
||||||
|
assertThat(SecurityContextHolder.getContext()).isEqualTo(SecurityContextHolder.createEmptyContext()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void shouldNotFilterErrorDispatchWhenDefault() { |
||||||
|
assertThat(this.filter.shouldNotFilterErrorDispatch()).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void shouldNotFilterErrorDispatchWhenOverridden() { |
||||||
|
this.filter.setShouldNotFilterErrorDispatch(true); |
||||||
|
assertThat(this.filter.shouldNotFilterErrorDispatch()).isTrue(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue