2

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?

Mahesh S
  • 159
  • 2
  • 13
  • Can you provide a little bit more detail? For example, is the token you receive from Ping Access a SAML token? If not, what kind of token is it and how would it get verified? It it's a saml token, take a look at `spring-security-saml`. As for looking up via LDAP, you should be able to query a user details service just by the principal value (e.g. the subject). Perhaps with more detail I can be more helpful. – jzheaux Aug 13 '18 at 22:09
  • @jzheaux, it's a jwt token. I'm able to validate this token with Ping Access. The username is in the 'sub' field of the header. I have extended the OncePerRequestFilter class. In the doFilterInternal method I want to map the username to the ldap principal so i can create a new Authentication object – Vibhav Agaskar Aug 13 '18 at 23:23

1 Answers1

1

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.

jzheaux
  • 7,042
  • 3
  • 22
  • 36