Setting up Spring Security

To install Spring Security, let's add the following dependency to pom.xml:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
...
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>

We add spring-security-test so that we can use it in the unit test to make sure the endpoints of our application have permission configured correctly. In order to see what Spring Security does, let's turn on the debug-level logging by adding the following configuration to src/main/resources/application.properties:

logging.level.org.springframework.security=DEBUG

Now, let's add Spring Security configuration. To do that, we will extend Spring Security's WebSecurityConfigurerAdapter class and apply the @EnableWebSecurity annotation to our customization class. Here is how com.taskagile.config.SecurityConfiguration looks:

...
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

private static final String[] PUBLIC = new String[]{
"/error", "/login", "/logout", "/register", "/api/registrations"};

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(PUBLIC).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logged-out")
.and()
.csrf().disable();
}

@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/static/**", "/js/**", "/css/**", "/images/**", "/favicon.ico");
}
}

As you can see, SecurityConfiguration overrides two configure() methods from WebSecurityConfigurerAdapter. In the first configure(HttpSecurity) method, we call the authorizeRequests() method to let Spring Security know that we’re restricting access based on HTTP requests. The return result of this method is an instance of ExpressionInterceptUrlRegistry, which allows us to use antMatchers() to specify the paths of requests that we want Spring Security to process. In our case, we want all of the paths defined in PUBLIC to be allowed by anyone. Then, we say any other requests can be accessed by an authenticated user. After that, we use the and() method to restore the chain back to the http object. The formLogin() method tells Spring Security that our application uses form-based authentication and the loginPage() method specifies the path of our login page. The logout() method is for defining the logout behavior. In fact, we don't have to define this method here because, with WebSecurityConfigurerAdapter, by default, Spring Security provides the support of logging a user out at path /logout and redirect the user afterwards to path /login?success. In our configuration, we choose to use path /login?logged-out. At the end of this chain, we tell Spring Security to disable the Cross-Site Request Forgery (CSRF) feature. Now, we have this configuration in place. The configuration will be automatically picked up by Spring Boot when we run the application. You can start the application with the mvn spring-boot:run command and try to access http://localhost:8080, and you will be redirected to the http://localhost:8080/login page. Our settings are working now.

However, in our RegistrationApiControllerTests test, things are a little different. With the @WebMvcTest annotation, in this test, only RegistrationApiController and Spring Security will be instantiated. But our SecurityConfiguration won't be picked up in the test. We need to use the @ContextConfiguration annotation to apply our customization, like this:

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {SecurityConfiguration.class})
@WebMvcTest(RegistrationApiController.class)
@ActiveProfiles("test")
public class RegistrationApiControllerTests {

Let's run the test method, register_blankForm_shouldFail(). It failed again, and the test result says Response status expected:<400> but was :<404>. After checking the test output, we do not see a log about the mapping of the /api/registrants endpoint to the handler that RequestMappingHandlerAdapter printed out anymore. This doesn't make sense. Looks like we need to do more troubleshooting. Since this happens right after we apply the @ContextConfiguration annotation, it must have something to do with that. After checking its JavaDoc, we can find the following description:

  • @ContextConfiguration defines class-level metadata that is used to determine how to load and configure ApplicationContext for integration tests.
  • @ContextConfiguration can be used to declare the annotated classes. The term annotated class can refer to any of the following:
    • A class annotated with @Configuration
    • A component (a class annotated with @Component, @Service, @Repository, and so on)

It looks like, after applying the @ContextConfiguration annotation, RegistrationApiController.class that we add to @WebMvcTest doesn't work anymore. To fix this issue, we will need to change the annotations as the following:

@ContextConfiguration(classes = {SecurityConfiguration.class, RegistrationApiController.class})
@WebMvcTest

Now, let's run the test and you can see it passed. Running the mvn clean install command will also produce a successful build. Let's commit this and the following is the commit record:

Figure 10.5: Add Spring Security commit
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.79.84