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?
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.
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
.
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.
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.
So, with all of that said, here is a summary of what I would probably do:
Create a JwtAuthenticationToken
object that can house the jwt token and possibly represent a successful authentication when Spring Security completes the verification process.
Create a JwtAuthenticationFilter
that reads the token from the request and populates JwtAuthenticationToken
, sending it to an AuthenticationManager
.
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!)
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.
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
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.
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 AuthenticationEntryPoint
s and AccessDeniedHandler
s.