Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Security: Why Authentication is extending Principal?

Spring Security has the assumption of Authentication is a Principal.

public interface Authentication extends Principal, Serializable {}

HttpServletRequest has the method of getUserPrincipal which is responsible for accessing principal object.

Let's consider this case:

public interface RealPrincipal extends Principal {
   public Integer getId();
}

Common Module A has Real Principal interface and implementation.

Module A uses Common Module A, Servlet Api and does not depend on Spring Security:

Module B uses Common Module A, Servlet Api and configures Spring Security. This module responsible for security and UserDetails implementation.

Web A uses Module A and Module B.

In order to use request methods, I am ending up with such an implementation:

public ModelAndView someRequestHandler(Principal principal) {
   User activeUser = (User) ((Authentication) principal).getPrincipal();
   ...
}

This is forcing me to have dependency of Spring Security for the Module A and other modules. I believe that a proper servlet api abstraction should not depend on spring security. request.getUserPrincipal should return real principal.

Please explain why org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper returns

Authentication instead of Real Principal.

Edit: I have added Common Module A to my scenario and updated that Module B is responsible for security.

like image 557
Cemo Avatar asked Jul 19 '13 10:07

Cemo


1 Answers

As Luke stated, Spring Security uses the Authentication for the Principal because it implements Principal. It does not use the Authentication#getPrincipal() because it is not guaranteed to be a Principal (it is an Object). In fact, in most situations Spring Security's Authentication#getPrincipal() returns a User (does not implement Principal), a custom UserDetails provided by users of the framework, or a String.

If you want Spring Security to handle this, you will likely need to implement this logic using an HttpServletRequestWrapper as Luke suggested. For example, you could do the following:

public RealPrincipalFilter extends OncePerRequestFilter {

    public void doFiter(HttpServletRequest request, HttpServletResponse response, FilterChain) {
        chain.doFilter(new RealPrincipalRequestWrapper(request), response);
    }

    private static final class RealPrincipalRequestWrapper 
          extends HttpServletRequestWrapper {
        public Principal getUserPrincipal() {
            Authentication auth = (Authentication) super.getPrincipal();
            return auth == null ? null : (RealPrincipal) auth.getPrincipal()
        }
    }
}

@Configuration
@EnableWebSecurity
public WebSecurityConfig extends WebSecurityConfigurerAdapter {
    public configure(HttpSecurity http) {
        http
            // ... other config ...
            .addFilterAfter(new RealPrincipalFilter(), SecurityContextHolderAwareRequestFilter.class);
    }
    ...
}

Alternatively, take a look at my answer on your other question for options to integrate with Spring MVC - Injecting Custom Principal to Controllers by Spring Security

like image 176
Rob Winch Avatar answered Nov 10 '22 06:11

Rob Winch