Jun 29th, 2010, 10:44 AM
Advice on multiple authentication scheme (X509 / password)
This is my first time posting here, so let me know if I should be posting differently.
I am implementing a combined X509 authentication / password scheme using spring security 2.0.5 and I was curious if the following setup makes sense.
* Pull username from X509 certificate
* Validate subjectDN contains a specific string
* Confirm that a X509 extension value matches the value saved on the user.
* User has the option to require password identification.
* Extendable scheme as future clients will use X509 authentication with different business rules.
I've narrowed it down to 2 options that make sense to me:
1) X509PreAuthenticatedProcessingFilter combined with a modified AuthenticationProcessingFilter. The AuthenticationManager for the X509 filter has a single provider that extends PreAuthenticatedAuthenticationProvider that, after the userDetails is retrieved, validates the X509 extension value against the retrieved user object. In addition it validates the subjectDN value (this is separate from retrieving the principal from the subjectDN value). The AuthenticationProcessingFilter overrides requiresAuthentication to fire only if the user has chosen to require password authentication.
-- The problem I run into here is that I then need to somehow force the first redirect to the password page so that the AuthenticationProcessingFilter only authenticates on the /j_spring_security_check url. Right now it doesn't redirect because the pre-authentication filter retrieves a valid authentication object so the ExceptionTranslationFilter never fires to redirect to the password page (pre authentication doesn't know anything about the password). Does it make sense to override attemptAuthentication to remove the pre-authentication object if the user requires password authentication? This sticking point lead me to implement option 2)
2) Single AuthenticationProcessingFilter that also retrieves the X509Certificate using the exact same logic as X509PreAuthenticatedProcessingFilter, creates a combined password/certificate credentials and validate the credentials in the provider with a set of certificate validators and a set of password validators. If all validators pass then return the userDetails object. Add a new InvalidPasswordException that is thrown if a password validator fails. The InvalidPasswordException redirects (via the exceptionMappings) to a login page with a single password field. Otherwise redirect to an invalid certificate page on failed authentication.
-- This has the advantage of doing all authentication in a single provider instead of requiring 2 separate providers.
-- The 2 sets of spring injected validators allow different validations for different implementations, allowing it to be more easily extended in the future.
-- This works well, but I feel like the X509ProcessingFilter was deprecated for a reason and I seem to be re-implementing it. Does anyone have insight into why it was deprecated in the first place? Also it has the feel of copy/paste code which I'd like to avoid if possible.
Comments? I'm fishing to see if there are simpler ways to implement the requirements using what spring security already has to offer.
I can post code, but I'm mainly interested in the high level approach, the code I can make work.
Jun 30th, 2010, 03:33 PM
Since it seems like you want both X.509 and username/password, I would go for the single provider approach.
You could inject a custom WebAuthenticationDetailsSource into the AuthenticationProcessingFilter which adds the X.509 certificate to the Authenication.details object (not to be confused with UserDetails). This usually contains information such as IP address etc, thus making this extra information available inside the AuthenticationProvider.
You can then use a custom AutenticationProvider which validates both the username/password and the certificate at the same time.
Jun 30th, 2010, 04:50 PM
Thank you for the response.
That makes sense and is essentially what I have implemented now. The only difference is that I included the certificate and password as part of the credentials instead of the user details.
Tags for this Thread