SecurityContextHolder + @Async fixes and improvements (#930)

* @Async and Spring Security

* @Async with SecurityContext propagated

* Spring and @Async

* Simulated Annealing algorithm

* Simulated Annealing algorithm

* Rebase

* Rebase

* SA further fixes

* Slope One plus package refactoring

* SlopeOne refactoring

* Async improvements and fixes

* Remove unnecessary bean

* Final fixes to Spring Security @Async

* Async Spring MVC
This commit is contained in:
maibin 2017-01-02 11:06:44 +01:00 committed by GitHub
parent 7844b1d4e4
commit 4018d45a2c
8 changed files with 46 additions and 57 deletions

View File

@ -1,7 +1,6 @@
package org.baeldung.spring;
import org.baeldung.security.MySavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ -25,6 +24,7 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
public SecurityJavaConfig() {
super();
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
//
@ -47,7 +47,7 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
.antMatchers("/api/csrfAttacker*").permitAll()
.antMatchers("/api/customer/**").permitAll()
.antMatchers("/api/foos/**").authenticated()
.antMatchers("/api/async/**").authenticated()
.antMatchers("/api/async/**").permitAll()
.and()
.httpBasic()
// .and()
@ -66,14 +66,5 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
public SimpleUrlAuthenticationFailureHandler myFailureHandler() {
return new SimpleUrlAuthenticationFailureHandler();
}
@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
return methodInvokingFactoryBean;
}
}

View File

@ -3,6 +3,7 @@ package org.baeldung.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
@ -13,12 +14,13 @@ import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@ComponentScan("org.baeldung.web")
@EnableWebMvc
@EnableAsync
public class WebConfig extends WebMvcConfigurerAdapter {
public WebConfig() {
super();
}
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");

View File

@ -2,6 +2,7 @@ package org.baeldung.web.controller;
import java.util.concurrent.Callable;
import org.apache.log4j.Logger;
import org.baeldung.web.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
@ -9,29 +10,30 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class AsyncController {
private static final Logger log = Logger.getLogger(AsyncService.class);
@Autowired
private AsyncService asyncService;
@RequestMapping(method = RequestMethod.POST, value = "/upload")
public Callable<Boolean> processUpload(final MultipartFile file) {
return new Callable<Boolean>() {
public Boolean call() throws Exception {
// ...
return true;
}
};
}
@RequestMapping(method = RequestMethod.GET, value = "/async")
@ResponseBody
public Boolean checkIfContextPropagated() throws Exception{
return asyncService.checkIfPrincipalPropagated().call() && asyncService.checkIfContextPropagated(SecurityContextHolder.getContext());
public Object standardProcessing() throws Exception {
log.info("Outside the @Async logic - before the async call: "
+ SecurityContextHolder.getContext().getAuthentication().getPrincipal());
asyncService.asyncCall();
log.info("Inside the @Async logic - after the async call: "
+ SecurityContextHolder.getContext().getAuthentication().getPrincipal());
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
@RequestMapping(method = RequestMethod.GET, value = "/async2")
@ResponseBody
public Callable<Boolean> springMVCAsyncTest() {
return asyncService.checkIfPrincipalPropagated();
}
}

View File

@ -4,8 +4,8 @@ import java.util.concurrent.Callable;
public interface AsyncService {
void asyncCall();
Callable<Boolean> checkIfPrincipalPropagated();
Boolean checkIfContextPropagated(Object context);
}

View File

@ -12,25 +12,25 @@ public class AsyncServiceImpl implements AsyncService {
private static final Logger log = Logger.getLogger(AsyncService.class);
@Override
public Callable<Boolean> checkIfPrincipalPropagated() {
Object before = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.info("Before new thread: " + before);
return new Callable<Boolean>() {
public Boolean call() throws Exception {
Object after = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.info("New thread: " + after);
return before == after;
}
};
}
@Async
@Override
public Boolean checkIfContextPropagated(Object context) {
log.info("Before @Async: " + context);
log.info("Inside @Async: " + SecurityContextHolder.getContext());
return context == SecurityContextHolder.getContext();
public void asyncCall() {
log.info("Inside the @Async logic: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal());
}
@Override
public Callable<Boolean> checkIfPrincipalPropagated() {
Object before
= SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.info("Before new thread: " + before);
return new Callable<Boolean>() {
public Boolean call() throws Exception {
Object after
= SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.info("New thread: " + after);
return before == after;
}
};
}
}

View File

@ -34,9 +34,4 @@
</authentication-provider>
</authentication-manager>
<beans:bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
p:targetClass="org.springframework.security.core.context.SecurityContextHolder"
p:targetMethod="setStrategyName" p:arguments="MODE_INHERITABLETHREADLOCAL" />
</beans:beans>

View File

@ -32,6 +32,7 @@
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>api</servlet-name>
@ -42,12 +43,13 @@
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ASYNC</dispatcher>
<dispatcher>ASYNC</dispatcher>
</filter-mapping>
<!-- <welcome-file-list> -->

View File

@ -12,7 +12,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@ -42,10 +41,8 @@ public class AsyncControllerTest {
}
@Test
public void testProcessUpload() throws Exception {
MockMultipartFile jsonFile = new MockMultipartFile("json", "", "application/json",
"{\"json\": \"someValue\"}".getBytes());
mockMvc.perform(MockMvcRequestBuilders.fileUpload("/upload").file(jsonFile)).andExpect(status().isOk());
public void testAsync() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/async")).andExpect(status().is5xxServerError());
}
}