BAEL-9467 Update Spring Security article

- Migrated module to inherit from spring-5 and spring-security-5
- Relevant changes and fixes in code for upgraded spring-security module
This commit is contained in:
Dhawal Kapil 2018-10-16 23:22:04 +05:30
parent da4e0f7bd7
commit 201c3a75c8
13 changed files with 84 additions and 95 deletions

View File

@ -2,7 +2,6 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>spring-security-rest</artifactId> <artifactId>spring-security-rest</artifactId>
<version>0.1-SNAPSHOT</version> <version>0.1-SNAPSHOT</version>
<name>spring-security-rest</name> <name>spring-security-rest</name>
@ -10,9 +9,9 @@
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-spring-4</artifactId> <artifactId>parent-spring-5</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-spring-4</relativePath> <relativePath>../parent-spring-5</relativePath>
</parent> </parent>
<dependencies> <dependencies>
@ -195,13 +194,6 @@
</resources> </resources>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
</plugin>
<plugin> <plugin>
<groupId>org.codehaus.cargo</groupId> <groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId> <artifactId>cargo-maven2-plugin</artifactId>
@ -282,17 +274,17 @@
<properties> <properties>
<!-- Spring --> <!-- Spring -->
<org.springframework.security.version>4.2.6.RELEASE</org.springframework.security.version> <org.springframework.security.version>5.1.0.RELEASE</org.springframework.security.version>
<org.springframework.hateoas.version>0.21.0.RELEASE</org.springframework.hateoas.version> <org.springframework.hateoas.version>0.25.0.RELEASE</org.springframework.hateoas.version>
<!-- various --> <!-- various -->
<javax.servlet-api.version>3.1.0</javax.servlet-api.version> <javax.servlet-api.version>3.1.0</javax.servlet-api.version>
<javax.validation.version>1.1.0.Final</javax.validation.version> <javax.validation.version>1.1.0.Final</javax.validation.version>
<jstl.version>1.2</jstl.version> <jstl.version>1.2</jstl.version>
<jackson.version>2.8.5</jackson.version> <jackson.version>2.9.2</jackson.version>
<!-- util --> <!-- util -->
<guava.version>19.0</guava.version> <guava.version>26.0-jre</guava.version>
<commons-lang3.version>3.5</commons-lang3.version> <commons-lang3.version>3.5</commons-lang3.version>
<commons-fileupload.version>1.3.2</commons-fileupload.version> <commons-fileupload.version>1.3.2</commons-fileupload.version>
@ -303,7 +295,6 @@
<springfox-swagger.version>2.9.2</springfox-swagger.version> <springfox-swagger.version>2.9.2</springfox-swagger.version>
<!-- Maven plugins --> <!-- Maven plugins -->
<maven-war-plugin.version>2.6</maven-war-plugin.version>
<cargo-maven2-plugin.version>1.6.1</cargo-maven2-plugin.version> <cargo-maven2-plugin.version>1.6.1</cargo-maven2-plugin.version>
</properties> </properties>

View File

@ -6,6 +6,8 @@ import javax.validation.constraints.Size;
public class Foo implements Serializable { public class Foo implements Serializable {
private static final long serialVersionUID = -5422285893276747592L;
private long id; private long id;
@Size(min = 5, max = 14) @Size(min = 5, max = 14)

View File

@ -11,8 +11,10 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationSu
import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@Component
public class MySavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { public class MySavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private RequestCache requestCache = new HttpSessionRequestCache(); private RequestCache requestCache = new HttpSessionRequestCache();
@ -33,11 +35,6 @@ public class MySavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAu
} }
clearAuthenticationAttributes(request); clearAuthenticationAttributes(request);
// Use the DefaultSavedRequest URL
// final String targetUrl = savedRequest.getRedirectUrl();
// logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
// getRedirectStrategy().sendRedirect(request, response, targetUrl);
} }
public void setRequestCache(final RequestCache requestCache) { public void setRequestCache(final RequestCache requestCache) {

View File

@ -16,7 +16,11 @@ import org.springframework.stereotype.Component;
public final class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { public final class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override @Override
public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException { public void commence(
final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
} }

View File

@ -2,16 +2,9 @@ package org.baeldung.spring;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@EnableWebMvc @EnableWebMvc
@Configuration @Configuration
public class ClientWebConfig extends WebMvcConfigurerAdapter { public class ClientWebConfig implements WebMvcConfigurer {
public ClientWebConfig() {
super();
}
// API
} }

View File

@ -1,6 +1,7 @@
package org.baeldung.spring; package org.baeldung.spring;
import org.baeldung.security.MySavedRequestAwareAuthenticationSuccessHandler; import org.baeldung.security.MySavedRequestAwareAuthenticationSuccessHandler;
import org.baeldung.security.RestAuthenticationEntryPoint;
import org.baeldung.web.error.CustomAccessDeniedHandler; import org.baeldung.web.error.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -12,6 +13,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
@Configuration @Configuration
@ -20,59 +23,61 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
@ComponentScan("org.baeldung.security") @ComponentScan("org.baeldung.security")
public class SecurityJavaConfig extends WebSecurityConfigurerAdapter { public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PasswordEncoder encoder;
@Autowired @Autowired
private CustomAccessDeniedHandler accessDeniedHandler; private CustomAccessDeniedHandler accessDeniedHandler;
// @Autowired @Autowired
// private RestAuthenticationEntryPoint restAuthenticationEntryPoint; private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
// @Autowired @Autowired
// private MySavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler; private MySavedRequestAwareAuthenticationSuccessHandler mySuccessHandler;
private SimpleUrlAuthenticationFailureHandler myFailureHandler = new SimpleUrlAuthenticationFailureHandler();
public SecurityJavaConfig() { public SecurityJavaConfig() {
super(); super();
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL); SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
} }
//
@Override @Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception { protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("temporary").password("temporary").roles("ADMIN").and().withUser("user").password("userPass").roles("USER"); auth.inMemoryAuthentication()
.withUser("admin").password(encoder.encode("adminPass")).roles("ADMIN")
.and()
.withUser("user").password(encoder.encode("userPass")).roles("USER");
} }
@Override @Override
protected void configure(final HttpSecurity http) throws Exception {// @formatter:off protected void configure(final HttpSecurity http) throws Exception {
http http.csrf().disable()
.csrf().disable() .authorizeRequests()
.authorizeRequests() .and()
.and() .exceptionHandling()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler) .accessDeniedHandler(accessDeniedHandler)
// .authenticationEntryPoint(restAuthenticationEntryPoint) .authenticationEntryPoint(restAuthenticationEntryPoint)
.and() .and()
.authorizeRequests() .authorizeRequests()
.antMatchers("/api/csrfAttacker*").permitAll() .antMatchers("/api/csrfAttacker*").permitAll()
.antMatchers("/api/customer/**").permitAll() .antMatchers("/api/customer/**").permitAll()
.antMatchers("/api/foos/**").authenticated() .antMatchers("/api/foos/**").authenticated()
.antMatchers("/api/async/**").permitAll() .antMatchers("/api/async/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN") .antMatchers("/api/admin/**").hasRole("ADMIN")
.and() .and()
.httpBasic() .formLogin()
// .and() .successHandler(mySuccessHandler)
// .successHandler(authenticationSuccessHandler) .failureHandler(myFailureHandler)
// .failureHandler(new SimpleUrlAuthenticationFailureHandler()) .and()
.and() .httpBasic()
.logout(); .and()
} // @formatter:on .logout();
@Bean
public MySavedRequestAwareAuthenticationSuccessHandler mySuccessHandler() {
return new MySavedRequestAwareAuthenticationSuccessHandler();
} }
@Bean @Bean
public SimpleUrlAuthenticationFailureHandler myFailureHandler() { public PasswordEncoder encoder() {
return new SimpleUrlAuthenticationFailureHandler(); return new BCryptPasswordEncoder();
} }
} }

View File

@ -24,8 +24,19 @@ public class SwaggerConfig {
@Bean @Bean
public Docket api() { public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage("org.baeldung.web.controller")).paths(PathSelectors.ant("/foos/*")).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) return new Docket(DocumentationType.SWAGGER_2).select()
.globalResponseMessage(RequestMethod.GET, newArrayList(new ResponseMessageBuilder().code(500).message("500 message").responseModel(new ModelRef("Error")).build(), new ResponseMessageBuilder().code(403).message("Forbidden!!!!!").build())); .apis(RequestHandlerSelectors.basePackage("org.baeldung.web.controller"))
.paths(PathSelectors.ant("/foos/*"))
.build()
.apiInfo(apiInfo())
.useDefaultResponseMessages(false)
.globalResponseMessage(RequestMethod.GET, newArrayList(new ResponseMessageBuilder().code(500)
.message("500 message")
.responseModel(new ModelRef("Error"))
.build(),
new ResponseMessageBuilder().code(403)
.message("Forbidden!!!!!")
.build()));
} }
private ApiInfo apiInfo() { private ApiInfo apiInfo() {

View File

@ -8,18 +8,14 @@ import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration @Configuration
@ComponentScan("org.baeldung.web") @ComponentScan("org.baeldung.web")
@EnableWebMvc @EnableWebMvc
@EnableAsync @EnableAsync
public class WebConfig extends WebMvcConfigurerAdapter { public class WebConfig implements WebMvcConfigurer {
public WebConfig() {
super();
}
@Override @Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) { public void addResourceHandlers(final ResourceHandlerRegistry registry) {
@ -38,7 +34,6 @@ public class WebConfig extends WebMvcConfigurerAdapter {
@Override @Override
public void addViewControllers(final ViewControllerRegistry registry) { public void addViewControllers(final ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/csrfAttacker.html"); registry.addViewController("/csrfAttacker.html");
} }

View File

@ -24,9 +24,9 @@ public class AsyncController {
@RequestMapping(method = RequestMethod.GET, value = "/async") @RequestMapping(method = RequestMethod.GET, value = "/async")
@ResponseBody @ResponseBody
public Object standardProcessing() throws Exception { public Object standardProcessing() throws Exception {
log.info("Outside the @Async logic - before the async call: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); log.info("Outside the @Async logic - before the async call: {}", SecurityContextHolder.getContext().getAuthentication().getPrincipal());
asyncService.asyncCall(); asyncService.asyncCall();
log.info("Inside the @Async logic - after the async call: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); log.info("Inside the @Async logic - after the async call: {}", SecurityContextHolder.getContext().getAuthentication().getPrincipal());
return SecurityContextHolder.getContext().getAuthentication().getPrincipal(); return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
} }

View File

@ -48,7 +48,7 @@ public class CustomerController {
} }
Link link =linkTo(methodOn(CustomerController.class).getOrdersForCustomer(customerId)).withSelfRel(); Link link =linkTo(methodOn(CustomerController.class).getOrdersForCustomer(customerId)).withSelfRel();
Resources<Order> result = new Resources<Order>(orders,link); Resources<Order> result = new Resources<>(orders,link);
return result; return result;
} }
@ -67,7 +67,7 @@ public class CustomerController {
} }
Link link =linkTo(CustomerController.class).withSelfRel(); Link link =linkTo(CustomerController.class).withSelfRel();
Resources<Customer> result = new Resources<Customer>(allCustomers,link); Resources<Customer> result = new Resources<>(allCustomers,link);
return result; return result;
} }

View File

@ -7,8 +7,6 @@ import java.util.List;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.baeldung.persistence.model.Foo; import org.baeldung.persistence.model.Foo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
@ -25,17 +23,9 @@ import com.google.common.collect.Lists;
@RequestMapping(value = "/foos") @RequestMapping(value = "/foos")
public class FooController { public class FooController {
@Autowired
private ApplicationEventPublisher eventPublisher;
public FooController() {
super();
}
// API // API
// read - single // read - single
@RequestMapping(value = "/{id}", method = RequestMethod.GET) @RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Foo findById(@PathVariable("id") final Long id, final UriComponentsBuilder uriBuilder, final HttpServletResponse response) { public Foo findById(@PathVariable("id") final Long id, final UriComponentsBuilder uriBuilder, final HttpServletResponse response) {
@ -43,7 +33,6 @@ public class FooController {
} }
// read - multiple // read - multiple
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
@ResponseBody @ResponseBody
public List<Foo> findAll() { public List<Foo> findAll() {

View File

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

View File

@ -9,6 +9,8 @@
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"> http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
<!-- Spring Security Configurations are managed in SecurityJavaConfig class -->
<!--
<http use-expressions="true" entry-point-ref="restAuthenticationEntryPoint"> <http use-expressions="true" entry-point-ref="restAuthenticationEntryPoint">
<intercept-url pattern="/admin/*" access="hasAnyRole('ROLE_ADMIN')"/> <intercept-url pattern="/admin/*" access="hasAnyRole('ROLE_ADMIN')"/>
@ -20,7 +22,7 @@
authentication-failure-handler-ref="myFailureHandler" /> authentication-failure-handler-ref="myFailureHandler" />
<!-- <access-denied-handler error-page="/my-error-page" /> --> <access-denied-handler error-page="/my-error-page" />
<access-denied-handler ref="customAccessDeniedHandler" /> <access-denied-handler ref="customAccessDeniedHandler" />
@ -44,5 +46,5 @@
</authentication-manager> </authentication-manager>
<global-method-security pre-post-annotations="enabled"/> <global-method-security pre-post-annotations="enabled"/>
-->
</beans:beans> </beans:beans>