Spring security Architecture Framework-Component, Service, Filter Analysis

Keywords: Java Spring Database Session Attribute

_To go deep into the authentication (authentication) and access-control workflow of spring security, it must be clear that the main technical points of spring security include how key interfaces, classes and abstract classes work together to implement authentication and access-control.

1.spring security authentication and authorization process

Common authentication and authorization processes can be divided into:

  1. A user is prompted to log in with a username and password (user account password login)
  2. The system (successful) verifies that the password is correct for the username
  3. The context information for that user is obtained (their list of roles and so on). (Get user information context, such as permissions)
  4. A security context is established for the user (creating security context for the user)
  5. The user proceeds, potentially to perform some operations which are potentially protected by an access control mechanism which checks the required permissions for the operation against the current security context information.

1.1 spring security authentication

The first three points mentioned above are spring security authentication and verification.

  1. Usually, the account password is assembled into Authentication implementation class UsernamePassword Authentication Token through AbstractAuthentication Processing Filter filter.
  2. Pass token to Authentication Manager to verify validity, and Authentication Manager usually uses Provider Manager implementation classes to verify validity.
  3. Authentication Manager will return an Authentication object with detailed information (including privilege information, identity information, details information, but passwords are usually removed) after authentication is successful.
  4. Set Authentication to security context through SecurityContextHolder.getContext().getAuthentication().getPrincipal().

1.2 spring security access authorization

  1. Enter through FilterSecurityInterceptor filter entrance.
  2. FilterSecurity Interceptor provides access authorization through its inherited abstract class AbstractSecurity Interceptor. beforeInvocation (Object object) method, which involves class Authentication Manager, Access Decision Manager, Security Metadata Source, etc.

According to the process described above, we will analyze the Component, Service and Filter.

2. Core Component

2.1 SecurityContextHolder

_Security Context Holder provides access to Security Context, stores security context (user information, role permissions, etc.), and has the following storage strategies, i.e. working mode:

  1. SecurityContextHolder.MODE_THREADLOCAL (default): With ThreadLocal, information can be used by all methods under this thread, a thread-binding strategy, which is naturally suitable for Servlet Web applications.
  2. SecurityContextHolder.MODE_GLOBAL: Used for stand-alone applications
  3. SecurityContextHolder.MODE_INHERITABLETHREADLOCAL: Threads with the same security label

There are two ways to modify the working mode of SecurityContextHolder:

  1. Set a system properties: spring. security. strategy;
  2. Call the SecurityContextHolder static method setStrategyName()

In the default ThreadLocal policy, SecurityContextHolder obtains user information for static methods as follows:

  Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
   if (principal instanceof UserDetails) {      
        String username = ((UserDetails)principal).getUsername();
       
   } else {
        String username = principal.toString();
       
   }

But generally it does not need to be acquired by itself.
getAuthentication() returns an Authentication authentication body. Next, the Authentication and UserDetails details are analyzed.

2.2 Authentication

_Spring Security uses an Authentication object to describe the relevant information of the current user, which contains a list of user-owned privilege information, user details (identity information, authentication information). Authentication is the highest level of identity/authentication abstraction of authentication subject in spring security. The common implementation class is UsernamePassword Authentication Token. Authentication interface source code:

public interface Authentication extends Principal, Serializable { 
    //List of permission information, some implementation classes of the default Granted Authority interface
    Collection<? extends GrantedAuthority> getAuthorities(); 
    //Password information
    Object getCredentials();
    //Details. The implementation interface in web applications is usually Web Authentication Details, which records the visitor's ip address and session ID value.
    Object getDetails();
    //Usually the return value is the UserDetails implementation class
    Object getPrincipal();
    boolean isAuthenticated();
    void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

The first two components involved UserDetails, and what exactly is GrantedAuthority? Section 2.3 Analysis.

2.3 UserDetails&GrantedAuthority

_UserDetails provides information needed to build Authentication objects from application DAO s or other secure data sources, including Granted Authority. Its official implementation class is User, and developers can customize the UserDetails implementation class for their interfaces. Its interface source code:

 public interface UserDetails extends Serializable {

     Collection<? extends GrantedAuthority> getAuthorities();

     String getPassword();

     String getUsername();

     boolean isAccountNonExpired();

     boolean isAccountNonLocked();

     boolean isCredentialsNonExpired();

     boolean isEnabled();
}

_UserDetails and Authentication interface functions are similar, in fact, the meaning is Authentication for user submitted certificates (account password), UserDetails for the system user correct authentication credentials, UserByUsername method in UserDetails Service to obtain the correct authentication credentials.
_Where the Granted Authority list obtained in the getAuthorities() method represents the user's access to the scope of application permissions, such permissions are usually "roles" (roles), such as ROLE_ADMINISTRATOR or ROLE_HR_SUPERVISOR. The common implementation class of the GrantedAuthority interface is SimpleGrantedAuthority.

3. Core Services

3.1 Authentication Manager, Provider Manager and Authentication Provider

AuthenticationManager is the core interface of authentication, and is the starting point of certification. But the common authentication process is Authentication Manager implementation class Provider Manager processing, and Provider Manager implementation class maintains Authentication Provider list for different authentication methods based on the principal mode. For example:

  1. The implementation class of DaoAuthentication Provider, which inherits AbstractUser Details Authentication Provider Abstract class, is used as the default authentication method to obtain authentication data information from database.
  2. Visitor Identity Logon Authentication Provider Implementation Class
  3. Obtaining authentication method RememberMeAuthentication Provider implementation class from cookies

Authentication Provider is

Provider Manager source code analysis:

public Authentication authenticate(Authentication authentication)
        throws AuthenticationException {
    Class<? extends Authentication> toTest = authentication.getClass();
    AuthenticationException lastException = null;
    Authentication result = null;
    //Authentication Provider List Authentication
    for (AuthenticationProvider provider : getProviders()) {
        if (!provider.supports(toTest)) {
            continue;
        }
        try {
            //Each Authentication Provider is authenticated
            result = provider.authenticate(authentication)
            if (result != null) {
                copyDetails(authentication, result);
                break;
            }
        }
        ....
        catch (AuthenticationException e) {
            lastException = e;
        }
    }
    //Authentication Provider for Parent Class Authentication
    if (result == null && parent != null) {
        // Allow the parent to try.
        try {
            result = parent.authenticate(authentication);
        }
        catch (AuthenticationException e) {
            lastException = e;
        }
    }
       // If there is Authentication information, return it directly
    if (result != null) {
        if (eraseCredentialsAfterAuthentication
                && (result instanceof CredentialsContainer)) {
                //Password removal
            ((CredentialsContainer) result).eraseCredentials();
        }
        //Publish login success events
        eventPublisher.publishAuthenticationSuccess(result);
        return result;
    }
        //If no authentication succeeds, throw an exception
    if (lastException == null) {
        lastException = new ProviderNotFoundException(messages.getMessage(
                "ProviderManager.providerNotFound",
                new Object[] { toTest.getName() },
                "No AuthenticationProvider found for {0}"));
    }
    prepareException(lastException, authentication);
    throw lastException;
    }  
    

The list of Authentication Providers in Provider Manager will be authenticated in order. By default, only one Authentication Provider authentication is required to be considered a successful login, and Authentication Provider returns an Authentication entity after the Authentication Provider authentication is successful, and clears the password for security purposes. If all authenticators fail to authenticate successfully, ProviderManager throws a ProviderNotFoundException exception.

3.2 UserDetailsService

_UserDetails Service interface function is to obtain authentication data source (account number, password) from a specific place. How to obtain the correct authentication credentials in the system and obtain authentication information by loading UserByUsername (String username), and there is only one way:

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;  

Its common implementation classes are JdbcDaoImpl implementation classes for data acquisition and InMemoryUserDetails Manager implementation classes for memory acquisition. However, we can implement user-defined UserDetails Service implementation classes for its interfaces, as follows:

public class CustomUserService implements UserDetailsService {
 @Autowired
 //User mapper
 private UserInfoMapper userInfoMapper;
 @Autowired
 //User rights mapper
 private PermissionInfoMapper permissionInfoMapper;
 @Override
 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    UserInfoDTO userInfo = userInfoMapper.getUserInfoByUserName(username);
    if (userInfo != null) {
        List<PermissionInfoDTO> permissionInfoDTOS = permissionInfoMapper.findByAdminUserId(userInfo.getId());
        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
        //Assembly authority GrantedAuthority object
        for (PermissionInfoDTO permissionInfoDTO : permissionInfoDTOS) {
            if (permissionInfoDTO != null && permissionInfoDTO.getPermissionName() != null) {
                GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(
                        permissionInfoDTO.getPermissionName());
                grantedAuthorityList.add(grantedAuthority);
            }
        }
        //Return user information
        return new User(userInfo.getUserName(), userInfo.getPasswaord(), grantedAuthorityList);
    }else {
        //Throwing the user does not have an exception
        throw new UsernameNotFoundException("admin" + username + "do not exist");
      }
    }
}   

 
  

3.3 AccessDecisionManager&SecurityMetadataSource

_Access Decision Manager is called by AbstractSecurity Interceptor and is responsible for making final access control decisions.

AccessDecision Manager interface source code:


 //Access Control Decision
  void decide(Authentication authentication, Object secureObject,Collection<ConfigAttribute> attrs) 
        throws AccessDeniedException;
  //Do you support ConfigAttribute for handling delivery?
  boolean supports(ConfigAttribute attribute);
  //Verify that the class is Access Decision Manager
  boolean supports(Class clazz);

_Security Metadata Source contains metadata needed by AbstractSecurity Interceptor to access authorization (dynamic url, data needed for dynamic authorization), and it is integrated with Access Decision Manager to access authorization in AbstractSecurity Interceptor authorization module. It involves ConfigAttribute.
SecurityMetadataSource interface:

Collection<ConfigAttribute> getAttributes(Object object)
        throws IllegalArgumentException;

Collection<ConfigAttribute> getAllConfigAttributes();

boolean supports(Class<?> clazz);

We can also customize the Security Metadata Source data source and implement the interface FilterInvocation Security Metadata Source. Example:

public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    public List<ConfigAttribute> getAttributes(Object object) {
        FilterInvocation fi = (FilterInvocation) object;
        String url = fi.getRequestUrl();
        String httpMethod = fi.getRequest().getMethod();
        List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();

        // Lookup your database (or other source) using this information and populate the
        // list of attributes

        return attributes;
    }

    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

3.4 PasswordEncoder

_For the sake of storage security, passwords are generally encrypted by algorithms, while spring security provides an encrypted PasswordEncoder interface. Its implementation classes include BCrypt Password Encoder implemented by BCrypt hash algorithm and SCrypt hashing algorithm, SCrypt Password Encoder implemented by SCrypt hashing algorithm, which implements visible source code analysis within the class. The PasswordEncoder interface has only two methods:

public interface PasswordEncoder {
    //Cipher encryption
    String encode(CharSequence rawPassword);
    //Password pairing
    boolean matches(CharSequence rawPassword, String encodedPassword);
} 

4 Core Security Filters

4.1 FilterSecurityInterceptor

FilterSecurityInterceptor is the access module of Spring security authorization module, which authorizes access to those resources according to the roles and privileges of the users accessed.
_FilterSecurity Interceptor encapsulates the FilterInvocation object for operation. All requests come to this filter. If the filter has not been executed before, then first execute the Interceptor StatusToken token = super. beforeInvocation (fi) provided by its parent AbstractSecurity Interceptor. In this method, Authentication Manager is used to obtain Authentication. User details, using ConfigAttribute to encapsulate the defined access rights details, and using AccessDecision Manager. Decision () method to control access rights.
FilterSecurity Interceptor source code analysis:

public void invoke(FilterInvocation fi) throws IOException, ServletException {
    if ((fi.getRequest() != null)
            && (fi.getRequest().getAttribute(FILTER_APPLIED) != null)
            && observeOncePerRequest) {
        fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
    }
    else {
        // first time this request being called, so perform security checking
        if (fi.getRequest() != null && observeOncePerRequest) {
            fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
        }
        //Method to call back the abstract class AbstractSecurity Interceptor that it inherits
        InterceptorStatusToken token = super.beforeInvocation(fi);

        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        }
        finally {
            super.finallyInvocation(token);
        }

        super.afterInvocation(token, null);
    }
}

AbstractSecurity Interceptor source code analysis:


protected InterceptorStatusToken beforeInvocation(Object object) {
    ....
    //Get a list of all url-role attributes (defined in the database or elsewhere)
    Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
            .getAttributes(object);
    ....
    //Get the user access information (including url, access rights)
    Authentication authenticated = authenticateIfRequired();

    // Attempt authorization
    try {
        //Authorized access
        this.accessDecisionManager.decide(authenticated, object, attributes);
    }catch
    ....
}

4.2 UsernamePasswordAuthenticationFilter

_Username Password Authentication Filter uses the filters used for username and password form login, and is also the most commonly used filter. Its source code:

public Authentication attemptAuthentication(HttpServletRequest request,
    HttpServletResponse response) throws AuthenticationException {
     //Get the username and password in the form
     String username = obtainUsername(request);
     String password = obtainPassword(request);
     ...
     username = username.trim();
     //token assembled in username+password form
     UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
     username, password);
     // Allow subclasses to set the "details" property
     setDetails(request, authRequest);
     //Give it to the internal Authentication Manager to authenticate and return the authentication information
     return this.getAuthenticationManager().authenticate(authRequest);
}   

The main code is to create Authentication entity of Username Password Authentication Token and call Authentication Manager to authenticate. According to the result of authentication, the successful Authentication or unsuccessful Authentication is executed. Whether successful or unsuccessful, the general implementation is forwarding or redirecting, and the Authentication Success Handler and Authentication Handler are not studied in detail. Authentication Failure Handle. If you are interested, you can study its parent AbstractAuthentication Processing Filter filter.

4.3 AnonymousAuthenticationFilter

Anonymous Authentication Filter is an anonymous login filter, which is located after commonly used identity authentication filters (such as Username Password Authentication Filter, Basic Authentication Filter, RememberMe Authentication Filter), meaning that only after the implementation of the above identity filter, the SecurityContext ual Filter still has no user information. Anonymous Authentication Filter is the filter. Devices make sense -- Based on an anonymous identity of the user.
Anonymous Authentication Filter source code analysis:

public class AnonymousAuthenticationFilter extends GenericFilterBean implements
    InitializingBean {
    ...
    public AnonymousAuthenticationFilter(String key) {
        this(key, "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
    }
        ...
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {

        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            //Create information for anonymous login to Authentication
            SecurityContextHolder.getContext().setAuthentication(
                    createAuthentication((HttpServletRequest) req));
                    ...
        }

        chain.doFilter(req, res);
    }
    //Information method for creating anonymous login Authentication
    protected Authentication createAuthentication(HttpServletRequest request) {
        AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(key,
            principal, authorities);
        auth.setDetails(authenticationDetailsSource.buildDetails(request));
        return auth;
    }
}

4.4 SecurityContextPersistenceFilter

The two main functions of the Security Context Persistence Filter are to create the Security Context security context information and empty the Security Context Holder when the request arrives. Source code follow-up analysis.

Section summary:

AbstractAuthentication Processing Filter: Mainly deals with login
FilterSecurity Interceptor: Handles authentication primarily

summary

After analyzing the core Component, Service and Filter, we learned the working principles of Spring Security and the workflow of authentication and authorization. Spring Security Authentication and Authorization has a lot of responsible processes to understand, so the next time will be more specific workflow analysis and case presentation of authentication module and authorization module. Finally, the above purely personal combination of blog and official document summary, if there is a mistake, please point out!

Finally, you can pay attention to the Public Number (Ccww Notes) and learn together. Jia group, will share dry goods every day, and learn video collection!

Posted by laurton on Tue, 08 Oct 2019 06:24:31 -0700