2

I am working on an spring mvc app which needs to do the following authentication

  1. validate the client cert by tomcat cert store
  2. validate additional attributes of the client cert

I try to implement #2 using loadUserByUsername() but don't know how to access the certificate content in loadUserByUsername()?

I found this related. The posted answer is to read it from HttpServletRequest. Can I access HttpServletRequest from loadUserByUsername()?

I tried

SecurityContextHolder.getContext().getAuthentication().getCredentials();

but the Authentication object is not set at in loadUserByUsername().

Community
  • 1
  • 1
Patrick
  • 63
  • 1
  • 8

2 Answers2

2

UPDATE

Having done a little bit of digging, I discovered that the Java Config provides a very easy way to get at the X509Certificate with a simple implementation of the AuthenticationUserDetailsService:

@Configuration
protected static class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**")
            .x509()
            .authenticationUserDetailsService(new X509AuthenticatedUserDetailsService());
    }

    protected static class X509AuthenticatedUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {

        @Override
        public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token)
                throws UsernameNotFoundException {
            X509Certificate certificate = (X509Certificate)token.getCredentials();
            // do your extra checking here...

            // add granted authorities, etc.
            Collection<GrantedAuthority> authorities = Collections.EMPTY_LIST;

            // generate your user how you deem fit
            User user = new User(certificate.getSubjectX500Principal().getName(), null, authorities);
            return user;
        }

    }
}

Note that in the loadUserDetails method you do the same thing really as you would do when implementing UserDetailsService with the exception that this method takes the entire Authentication object.

ORIGINAL

I'm not sure if this is the intended way; however, the X509Certificate is passed along via the authentication token generated in the X509AuthenticationFilter. Invoking PreAuthenticatedAuthenticationToken#getCredentials should get the certificate for you.

Digging a bit through the API shows that the PreAuthenticatedAuthenticationProvider could be configured with a custom UserDetailsChecker and AuthenticatedUserDetailsService. These may be sufficient for you to extract the details from the X509Certificate and verify them.

jzheaux
  • 7,042
  • 3
  • 22
  • 36
  • Thanks for you help. I am using Spring Security 3.0 and I think it doesn't support Java Config. I wonder how I can set up the x509 filtering to call the X509AuthenticatedUserDetailsService in the security.xml – Patrick Oct 15 '15 at 19:50
  • From the documentation, it appears that the user-details-ref wants a UserDetailsService so I don't believe you can use the tag. Instead, you would configure `X509AuthenticationFilter` directly in the xml. You can find a pretty good example here: http://stackoverflow.com/questions/12478589/springsecurity-custom-automatic-authentication where you would replace com.example.MyPreAuthenticatedProcessingFilter with the X509AuthenticationFilter from Spring. – jzheaux Oct 15 '15 at 20:56
  • Thanks Josh! I got it working now by following your suggestion. – Patrick Oct 19 '15 at 18:27
  • This is a great answer that needs more love. Use `AuthenticationUserDetailsService` to access the full object! Thank you – heez Dec 01 '17 at 22:22
  • Thanks a lot, your solutions was fine for me. – Bomberlatinos9 Oct 23 '18 at 09:39
0

In my case, I do get certificate ID from id in the following implementation of UserDetailsService. It is a simple configuration in security.xml public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException { Security.xml

But just in case of the certificate onAuthenticationSuccess is not called in the public class myAuthSuccessHandler implements AuthenticationSuccessHandler {

Any suggestions? ideas?

Dish499
  • 39
  • 4