Spring Security is part of Spring Ecosystem that will help manage an application's Authentication and Authorization requirements, as well as protection against common exploits.

The authentication validates WHO can enter the application, and the authorization verifies WHAT the authorized user can access. Some techniques used to authenticate a user are Password-based authentication, Passwordless authentication, Single sign-on (SSO) and Social authentication. Some techniques of authorization are Role-based access controls (RBAC), JSON web token (JWT), SAML, OpenID and OAuth.

Spring Security is a powerful and highly customizable authentication and access-control framework. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements [1]
What is Spring Security Authentication vs authorization


Dependencies

spring-security-core gives support to authentication and access control. It supports non-web applications, method level security and JDBC. Web security infrastructure is available using spring-security-web dependency. The spring-security-config dependency is necessary to use Spring Security XML namespace and annotations. The different ways to guarantee the secirity have their own dependencies: spring-security-ldap, spring-security-acl, spring-security-cas, spring-security-oauth, spring-security-openid.

With Spring Boot

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
  <version>${spring-security.version}</version>
</dependency>

Without Spring Boot

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-core</artifactId>
  <version>${spring-security.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-web</artifactId>
  <version>${spring-security.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-config</artifactId>
  <version>${spring-security.version}</version>
</dependency>

All modules you can see here.


Initial Config

The first step is to create a class that extends from WebSecurityConfigurerAdapter and with annotation @EnableWebSecurity in case you need integration with MVC. After that we can override the method to use the HttpSecurity instance.

The example bellow says to any request the user have to be authenticated, and the way to authenticate is HTTP Basic. You also can use formLogin.

public class MySecurityConfig extends WebSecurityConfigurerAdapter{

  @Override
  public void configure(final HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().authenticated()
      .and()
      .httpBasic();
      //.formLogin();
  }

  @Override
  public void configure(AuthenticationManagerBuilder builder) throws Exception {
    builder.inMemoryAuthentication()
      .withUser("maria").password("123").roles("USER")
      .and()
      .withUser("jose").password("123").roles("USER");
    }
}

The example use in-memory authentication to test, that's why we also override the second configure method. After that you can run the app and do your first test.

httpBasic() formLogin()

In case to improve the access rules you can add it in the configure method. In this case you start to work with authorization.

@Override
public void configure(final HttpSecurity http) throws Exception {
  http.authorizeRequests()
      .antMatchers("/test/**").hasRole("USER")
      .antMatchers("/anonymous*").anonymous()
      .antMatchers("/login*").permitAll()
  .anyRequest().authenticated().and().httpBasic();
}
Config Authentication - AuthenticationManagerBuilder Config Authorization - HttpSecurity


Improve the Configs

In case to use JDBC, one example of how to authenticate the use is below, where you inform the datasource, some encoder and you queries.

@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
  builder
      .jdbcAuthentication()
      .dataSource(dataSource)
      .passwordEncoder(new BCryptPasswordEncoder())
      .usersByUsernameQuery(<YOUR_QUERY>)
      .authoritiesByUsernameQuery(<YOUR_QUERY>)
      .groupAuthoritiesByUsername(<YOUR_QUERY>)
      .rolePrefix("ROLE_");
}

That example use passwordEncoder. It is a way to allow the password to be stored securely. Before Spring Security 5.0, the default was NoOpPasswordEncoder, now it can be BCryptPasswordEncoder. The Spring Security has DelegatingPasswordEncoder to make possible work with legacy and modern formats. Here the example gotten from spring doc.

String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("sha256", new StandardPasswordEncoder());

PasswordEncoder passwordEncoder =
    new DelegatingPasswordEncoder(idForEncode, encoders);

// Test the pws by comparation
String result = encoders.get(idForEncode).encode("myPassword");
assertTrue(encoder.matches("myPassword", result));

However, many application use JPA. In this case, the application can use the UserDetailsService interface. The override method search by user and Spring Security will validate the password.

public class MyUserDetailsService implements UserDetailsService{
  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = usersRepository.findByLogin(username);
    if(user == null) {
      throw new RuntimeException();
    }
    return new MyUserSystem(user.getLogin(), user.getPassword(), searchPermission(user));
  }
}
JDBC JPA LDAP


Architecture

The Spring architecture is based on Servlet Filters.

The client sends a request to the application, and the container creates a FilterChain which contains the Filters and Servlet that should process the HttpServletRequest based on the path of the request URI. In a Spring MVC application the Servlet is an instance of DispatcherServlet. At most one Servlet can handle a single HttpServletRequest and HttpServletResponse

The DelegatingFilterProxy is one filter implemented by Sprint to delegate all the work to a Spring Bean. It allows the controls by ApplicationContext.

The FilterChainProxy is a filter to delegate Filter instances through SecurityFilterChain, which is responsible to define the Spring Security Filter (beans registered with FilterChainProxy) to be invoked. The ExceptionTranslationFilter (translation of AccessDeniedException and AuthenticationException into HTTP Response) is inserted into the FilterChainProxy.


Components and Mechanisms

The support to authentication on Spring is possible by many components as SecurityContextHolder, Authentication, ProviderManager.

Furthermore, Spring gives support to a few sorts of authentication mechanisms as:

  • Username/Password - has different ways to read data from HttpServletRequest: by Form Login, Basic Authentication and Digest Authentication. The mechanism to storage those data are In-Memory Authentication, JDBC Authentication, UserDetailsService and LDAP Authentication
  • OAuth 2.0: capability to have users log in to the application by using existing account (e.g. google account)
  • Remember Me - remember the identity of a principal between sessions
  • Central Authentication Server (CAS) - enterprise-wide single sign on system
  • SAML (Security Assertion Markup Language): enables single sign-on (SSO)
  • JAAS (Java Authentication and Authorization Service) - extension library that use the standard Pluggable Authentication Module (PAM)
  • OpenID - as form-based login but adding openid provider
  • X.509 - when server use ssl: using certificate

All the components and Authentication Mechanisms you can find here.

The Spring Security can be integrated with all the other parts os Spring as Spring Data and Spring MVC. More detail about the integration you can see here. If you need to test methods based security you can find more information here


Protection agains CSRF

Sprint give supports to protect your application agains the common exploits as CSRF (Cross Site Request Forgery). You will see in one of my previous post about vulnerability that CSRF is a vulnerability which permits an attacker to force another logged-in user of the app to perform actions.

"This attack is possible because the HTTP request from the victim’s website and the request from the attacker’s website are exactly the same. To protect against CSRF attacks we need to ensure there is something in the request that the evil site is unable to provide so we can differentiate the two requests."[1]

Resources provided by Spring:

  • Synchronizer Token Patter: The HTTP request have to have the session cookie and the CSRF token, a secure random generated value.
  • Same Site Attribute: "A server can specify the SameSite attribute when setting a cookie to indicate that the cookie should not be sent when coming from external sites".

Other ponints of exploits protection are: Security HTTP Response Headers (defaults, cache, content type, etc), also give support to HTTPS.


Conclusion

All the play list of the videos shown in this post you will find here.

References