Introduction to Spring Security

Base Classes for Spring Security Implementation

Photo by marcos mayer on Unsplash

To enable HTTP Security in Spring, we need to extend the WebSecurityConfigurerAdapter. The “@EnableWebSecurity” annotation and “WebSecurityConfigurerAdapter” work together to provide web based security.

@Configuration
@EnableWebSecurity
public class ApiSecurityConfig extends WebSecurityConfigurerAdapter {
...
}

By default, the BasicAuthenticationEntryPoint provisioned by Spring Security returns a full HTML representation page for a 401 Unauthorized response back to the client. This is not well suited for REST APIs.

To provide a better Spring Security filter chain management, you should implement your custom class to return an appropriate response content.

It has a “commence” method where you can override to return an unauthorized status code response.

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
throws IOException, ServletException {

log.info(
"[AUTHENTICATION] [ENTRY_POINT] [REQUEST_URI={}] [CLASS={}] [MESSAGE={}]",
request.getRequestURI(), e.getClass().getName(),
e.getLocalizedMessage());

response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}

This filter will intercept a (browser-based HTTP-based authentication) request and attempt to perform authentication from that request if the request url path matches.

You define a request matcher for matching urls (provided with a direct filter url string value or RequestMatcher object), success and fail handlers and an authentication manager inside which the authentication flow will take place, processing the provided authentication request token.

It has a “attemptAuthentication” method where you can build up your custom “AbstractAuthenticationToken” request class and pass to the authentication manager’s “authenticate” method.

Ready to Use Subclasses (within Spring Security):

CasAuthenticationFilter, OpenIDAuthenticationFilter, UsernamePasswordAuthenticationFilter — default responds to the URL “/login” which used to be “/j_spring_security_check” before.

It is a base class for Authentication objects and creates a token with the supplied array of authorities (GrantedAuthority).

It implements Authentication interface and it has a collection of “authorities” you can set for your authenticated account and a “details” object where you can set other info you may use later (like an auth token to set to response header or save in a cache (Redis, etc.) in your custom success handler class).

public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities();

Object getCredentials();

Object getDetails();

Object getPrincipal();

boolean isAuthenticated();

void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

You can provide a list of your custom AuthenticationProvider instances as a chain to AuthenticationManager.

Optionals (Exceptions that extends AccountStatusException):

  • A DisabledException must be thrown if an account is disabled.
  • A LockedException must be thrown if an account is locked.
  • An AccountExpiredException must be thrown if the account has expired.
  • A BadCredentialsException must be thrown if incorrect credentials are provided via authentication request.

It processes an Authentication request. In its “authenticate method, it returns a fully populated Authentication object including granted authorities if authentication is successful.

It has an extra method called “supports” that returns a boolean to allow the caller to query whether it supports a given Authentication type or not.

It has the direct responsibility of deciding what to do after a successful authentication (like controlling the navigation based on the authenticated user’s role to the subsequent destination using a redirect or a forward).

You can also set headers to response or save a token value to a cache or save an audit log as a successful login.

Ready to Use Handlers (within Spring Security):

AbstractAuthenticationTargetUrlRequestHandler, SimpleUrlAuthenticationSuccessHandler

It handles a failed authentication attempt. Just like AuthenticationSuccessHandler, you can redirect the user back to the authentication page to allow them to try again or you can log or save audit (attempts for login for a captcha or account lock scenario)

Optionals:

  • CredentialsExpiredException (extends AccountStatusException) can be thrown based on the expiration conditions to route to a “change-password” page.

Ready to Use Handlers (within Spring Security):

DelegatingAuthenticationFailureHandler, ExceptionMappingAuthenticationFailureHandler, ForwardAuthenticationFailureHandler, SimpleUrlAuthenticationFailureHandler

AuthenticationException is the main Exception class from which AccountStatusException is extended as well as the others that are listed below:

AccountStatusException, ActiveDirectoryAuthenticationException, AuthenticationCancelledException, AuthenticationCredentialsNotFoundException, AuthenticationServiceException, BadCredentialsException, InsufficientAuthenticationException, NonceExpiredException, OAuth2AuthenticationException, PreAuthenticatedCredentialsNotFoundException, ProviderNotFoundException, RememberMeAuthenticationException, Saml2AuthenticationException, SessionAuthenticationException, UsernameNotFoundException

MessageDigestPasswordEncoder is now deprecated to indicate that implementation is considered insecure. Spring Security advises us to use built-in “BCryptPasswordEncoder”, “Pbkdf2PasswordEncoder” or “SCryptPasswordEncoder”. It can have a variety of encoders (one of them will be the default) based on the assigned prefix value (that is at the start of the encoded password) with “DelegatingPasswordEncoder”.

AbstractPasswordEncoder, Argon2PasswordEncoder, BCryptPasswordEncoder, DelegatingPasswordEncoder, LdapShaPasswordEncoder, Md4PasswordEncoder, MessageDigestPasswordEncoder, NoOpPasswordEncoder, Pbkdf2PasswordEncoder, SCryptPasswordEncoder, StandardPasswordEncoder

The UserDetailsService interface is used to retrieve user-related data.

It has a “loadUserByUsername()” method which allows you to override (in your own custom user details service) to get user details as a result of a successful authentication. If not, you can throw a “UsernameNotFoundException”.

public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

You can implement this interface in your database service class (where you get data from your accounts repository with your repository interface) if you already have one.

UserDetails

You should also implement a custom user details object since your custom UserDetails service’s loadUserByUsername method should be returning a custom user object which extends “UserDetails”.

public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();

String getPassword();

String getUsername();

boolean isAccountNonExpired();

boolean isAccountNonLocked();

boolean isCredentialsNonExpired();

boolean isEnabled();
}

You may use your database class “Account” to implement UserDetails and add “@JsonIgnore” over overridden methods that come from UserDetails interface.

Happy Coding!

--

--

I would love to change the world, but they won’t give me the source code | coding 👩🏼‍💻 | coffee ☕️ | jazz 🎷 | anime 🐲 | books 📚 | drawing 🎨

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Nil Seri

I would love to change the world, but they won’t give me the source code | coding 👩🏼‍💻 | coffee ☕️ | jazz 🎷 | anime 🐲 | books 📚 | drawing 🎨