springspring-bootspring-securityfederatedpingaccess

How do I authenticate a preauthenticated LDAP user using spring security using ping access and username passed in the header?


I was previously using basic auth but I need to switch to federated auth using Ping Access. The user is already authenticated and the username along with the token are sent in the request header. How do I link the username to an ldap user principal using spring security?


Solution

  • So, there are a number of things to consider as you are considering your implementation. Here is a very basic rundown of the pieces in play.

    Filter Chain

    The filter chain is typically for differentiating between servlets and the rest of the app. If you have extended OncePerRequestFilter then you are likely already on the right path.

    If you intend to follow the typical Spring Security model, this filter would prepare an Authentication object that can then be authenticated in an AuthenticationManager. You might try and use an existing Authentication implementation like PreAuthenticatedAuthenticationToken, or you might create your own and call it JwtAuthenticationToken.

    Authentication Manager

    AuthenticationManager is essentially a collection of providers that can authenticate a token, like your Jwt token. Their contract is separate from servlets and are therefore a bit more flexible.

    You would probably create a JwtAuthenticationProvider that would validate the token and then invoke a UserDetailsService to get the underlying user.

    Spring Security doesn't have dedicated support for JWTs, but they do have some libraries that use Nimbus. You could check out the code in spring-security-oauth2-resource-server to see how they are verifying JWTs using a JWK Set Uri. You wouldn't want to depend on that library since it is focused on OAuth, but it might give you some ideas.

    User Details Service

    A UserDetailsService implementation is responsible for querying a backend and retrieving from it a user. For example, there is LdapUserDetailsService that you could possibly use.

    Summary

    So, with all of that said, here is a summary of what I would probably do:

    1. Create a JwtAuthenticationToken object that can house the jwt token and possibly represent a successful authentication when Spring Security completes the verification process.

    2. Create a JwtAuthenticationFilter that reads the token from the request and populates JwtAuthenticationToken, sending it to an AuthenticationManager.

    3. Create a JwtAuthenticationProvider that reads a JwtAuthenticationToken and sends it to Nimbus (or Auth0 or some other jwt library) for validation. You will need to decide how you trust that token--Nimbus is capable of checking remotely via a JWK Set Uri or locally via a pre-configured set of public or symmetric keys. (Lots to think about here, too!)

    4. Use the LdapUserDetailsService, passing it the name of the parsed subject. The UserDetails that comes back can be supplied as the principal for the Authentication object that your provider returns.

    Alternatives

    So, let's say that you don't want/need to follow the Spring Security development model, but just want to get something working asap.

    The two things that you ultimately need to accomplish are

    1. Decide whether or not the token is valid. Spring Security has no OAuth2-free support for this yet, so you will need to roll your own using Nimbus or the like.
    2. Configure and invoke LdapUserDetailsService. From the UserDetails this gives you, you can build an Authentication object that you can set on the SecurityContextHolder.

    Such would be not as flexible over time, but it might get you started a bit faster.

    Other things to think about

    You didn't ask about this, but I wonder what you are planning on doing if the token is somehow invalid. For those cases, you may want to look at AuthenticationEntryPoints and AccessDeniedHandlers.