spring-security icon indicating copy to clipboard operation
spring-security copied to clipboard

Migration path for Spring SAML Extension users

Open rajn opened this issue 4 years ago • 18 comments

Expected Behavior

We currently are using Spring SAML Extension 1.0.10 in SP mode. We integrate with different IDPs like OAM, OKTA, ADFS etc and it works smoothly. Now, we need to upgrade as the underlying OpenSAML is quite old. I see that Spring Security Core is the new place for SAML support and Spring SAML will not be available as a separate library. It seems not all functionality from Spring SAML has been ported to Spring Security. We are specifically interested in SP Metadata generation and Single Logout. When will this be available in Spring Security SAML? Is there a document that can be used for this migration path? ie From Spring SAML Extension to Spring Security SAML Feature set.

Current Behavior

Documentation for existing users of Spring SAML Extension is limited/ unable to find.

Context

rajn avatar Jun 12 '20 06:06 rajn

@rajn, thanks for reaching out about this. I think it makes sense to provide support for metadata generation as well as single logout.

Based on your feedback, I've added https://github.com/spring-projects/spring-security/issues/8693 to track Spring Security's SP Metadata support.

Would you mind creating a ticket that indicates what you feel is needed to address your single logout use case?

As far as laying out a migration path, that's still a todo. I'll leave this ticket open for adding the appropriate documentation.

jzheaux avatar Jun 15 '20 20:06 jzheaux

I created #8731 for the "trigger a Single Logout" part, which is pretty important I think.

The other part would be receiving a Single Logout request from the IdP (i.e. the Single Logout was triggered from another SP), but I think it's less important (at least I for one have never used this)

jeanblanchard avatar Jun 19 '20 09:06 jeanblanchard

@jzheaux is there a place for developers that are going through the migration to share common workarounds, supported / unsupported scenarios, etc? To aid in the meantime, until there's time for an official migration path.

fpagliar avatar Jun 26 '20 05:06 fpagliar

@fpagliar, if it's a use case that you feel ought to be supported by Spring Security, then it's probably best to log a ticket about it. Then workarounds can be placed there. If there's an existing ticket, you can use that.

If it's a scenario that you don't feel should be supported by Spring Security, I'm not sure if there would be an official place inside Spring Security, but feel free to ping me on Gitter if you want help sorting through them.

jzheaux avatar Jun 29 '20 15:06 jzheaux

Hello Spring Security Team,

I jump on this topic to add few more requirements.

We plan to use Spring Security to integrate with several IdPs using distincts protocols (OIDC, SAML2, LDAP, etc.).

By now, after some prototyping using Spring Security 5.3 with SAML2, we are facing several limitations due to some not yet supported features:

High Priority

  • Single Sign-out See https://github.com/spring-projects/spring-security/issues/8731

  • Generate dynamically SP Metadata document See https://github.com/spring-projects/spring-security/issues/8693

  • Ability to specify AuthNRequest signing algorytm We have some customers requiring to use RSA_SHA1

  • Ability to configure NameID Format Some IdPs requires specifying a NameID Format

  • Support SAML response with unsigned assertions

Low Priority

  • Generate SP configuration from/driven by IDP Metadata document

  • Ability to configure Authentication Context Class Reference

Would it be possible to have ETA for those features?

Thanks

nlenoire avatar Jul 27 '20 15:07 nlenoire

Thanks for sharing this list, @nlenoire.

I've got a question about one of them:

Support SAML response with unsigned assertions

I believe it's already possible to have a signed SAML response with unsigned assertions. Is this what you are looking for? I don't think we want to add first-class support for both the response and assertions being unsigned.

Otherwise, on the surface, several of the features sound reasonable, but I think I'd need more detail to know for sure. Would you be able to write up individual tickets for the features that you need, explaining each use case in greater detail?

jzheaux avatar Jul 31 '20 21:07 jzheaux

I've got a question about one of them:

Support SAML response with unsigned assertions

This requirement comes from a customer that is using an IDP that does not sign encrypted assertions, would it be a valid requirement for spring-security to support unsigned encrypted assertions ?

amergey avatar Aug 10 '20 17:08 amergey

@amergey, I don't think we want to support unsigned encrypted assertions. Can the provider sign the response as an alternative?

jzheaux avatar Aug 13 '20 17:08 jzheaux

The customer will not accept any other alternative than its current configuration: Signed response, with encrypted unsigned assertions.

nlenoire avatar Aug 24 '20 15:08 nlenoire

@nlenoire, that is a supported setup. So long as the response is signed, the assertions do not have to be signed.

jzheaux avatar Aug 25 '20 17:08 jzheaux

  • Ability to configure NameID Format Some IdPs requires specifying a NameID Format

I'm currently started to use the new SingleLogout feature from 5.6.0 and it looks like, my IDP requires specifying the NameID format.

Is there are a way to hack this feature into the OpenSamlLogoutRequestResolver or somewhere else until it's supported? Or should I roll-out my on LogoutFilter?

Edit: I figured out how to change the NameID Format:

// Set the parameters consumer
OpenSaml4LogoutRequestResolver resolver = new OpenSaml4LogoutRequestResolver(relyingPartyRegistrationResolver());
resolver.setParametersConsumer(saml2LogoutParameterConsumer());
// ...
// and set the resolver in the configure(HttpSecurity http) method:
http.saml2Logout(saml2Logout -> saml2Logout.logoutRequest(request -> request.logoutRequestResolver(openSaml4LogoutRequestResolver)))

scho avatar Nov 23 '21 10:11 scho

Thanks, @scho! Glad you found it. Note that this is covered here: https://docs.spring.io/spring-security/reference/servlet/saml2/logout.html#_customizing_saml2logoutrequest_resolution

jzheaux avatar Dec 13 '21 22:12 jzheaux

Has there been any update on the migration document or guide to migrate from 1.0.10 to 2.0+?

t4colingough avatar Mar 03 '22 16:03 t4colingough

Good morning,

First of all thanks for all the effort that is put into this upgrade. The old saml extension works fine with the following setup:

        <spring.version>5.3.15</spring.version>
        <spring.boot.version>2.5.6</spring.boot.version>
        <spring.samlsecurity.version>1.0.10.RELEASE</spring.samlsecurity.version>
        <spring.security.version>5.6.1</spring.security.version>

But upgrading to the latest Spring Boot seems to break the loading of the saml plugin;

        <spring.boot.version>2.6.3</spring.boot.version>

This is why I spent some time investigating this new version of the saml extension. I think the problem for all of us is that the new extension should be 100% feature complete, as we are otherwise not able to upgrade under the hood (without sysadmins needing to change configuration).

In our case, we need the following components before we can upgrade:

  • [x] Users log in to our REST API via a http post binding
  • [ ] Script users log in via Python to our REST API, using the soap binding
  • [ ] The sp metadata is described in an xml. I was not able to find out how this xml can be read. I found the sample with yml configuration, but it would be nice if the current sp metadata can be reused, as this includes the signing key as well.
  • [ ] We support multiple idps, where the xml files are read from a directory in the Spring SP. This is our own extension on the IDPMetadataManager, but loading multiple idps from a directory works very well for us. The name RelyingPartyRegistration is new for me (as that name was not used in the old extension), but I believe this can be achieved with https://github.com/spring-projects/spring-security/blob/50a3bcf7283cc2e7ea75c9b97f9ff2d99273a8de/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistrations.java#L127

That's it for now, thanks again for the effort

gertjanal avatar Mar 18 '22 09:03 gertjanal

Hello, we're using SAML in our application for functionalities like login, logout and single logout through various IDPs like Okta, Lastpass etc. The library we use right now is org.springframework.security.extensions:spring-security-saml2-core:1.0.10.

We now need to move away from this library, and as suggested by spring, want to move to the new spring security (5.7.x) jars.

I've a few queries regarding this migration :-

  1. In our service provider metadata file that's used in the IDP configuration on the clients' end, we have references to SAML endpoints like '/saml/SingleLogout' and '/saml/SSO'. In the spring security 5.7.x, the equivalent endpoints I see are '/logout/saml2/slo' (for Single Logout) and '/saml2/sso'. If we migrate to the new jar, is there a way to retain the earlier endpoints like '/saml/singleLogout' (by customization)? Else, there'll be changes required in the configuration of all our clients, which would not be feasible.

  2. Do the new spring security jars have all the SAML functionalities that were offered by the extensions 1.0.10 jar? We won't want to miss any use-cases that we have now.

  3. Is there any comprehensive guide for this migration (from spring-security-saml2-core:1.0.10 to spring security 5.7.x)? Or is such a document/guide in plans? Since the two jars are very different in implementation, a guide will be incredibly helpful.

akhil-lm avatar Sep 05 '22 04:09 akhil-lm

Hi, @akhil-lm. Answering your questions:

  1. There are multiple ways to achieve that. One would be changing the loginUrl and logoutUrl in the SAML2 DSL to the old URLs. Another way would be to create a filter that listen to requests to /saml/SingleLogout, for example, and forward them to /logout/saml2/slo, this way you don't need to change the default configuration. I was working on an example for the latter but I had to pause it for now since there were some higher priorities tasks for the upcoming releases.
  2. There is a summary of the changes here.
  3. There is the Migration Guide that is still a WIP. As I mentioned, we had to pause the work on that for now but I plan to resume the work on it soon.

marcusdacoregio avatar Sep 05 '22 12:09 marcusdacoregio

Thanks @marcusdacoregio I was looking into the migration guide for how the login and the logout functionalities are implemented with the spring security :- https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/saml2/login

I ran the sample, and accessed the application at localhost:8080 which then redirected me to the Okta IDP. The following endpoints in the sample application were invoked on signing in through Okta, and then signing out :-

  1. http://localhost:8080/saml2/authenticate/one
  2. http://localhost:8080/logout

I was expecting to find these endpoints in the source code in the sample application, but didn't find them. Could you please guide me towards how are these endpoints configured, that get called when logging in and out through Okta?

akhil-lm avatar Sep 12 '22 16:09 akhil-lm

Hi @akhil-lm,

The best place to start is from the reference docs, there is a SAML Login Overview that may help you.

If you take a look at the Saml2LoginConfigurer#configure and Saml2LogoutConfigurer#configure you will also find out how the filters are built.

marcusdacoregio avatar Sep 13 '22 13:09 marcusdacoregio

In our case, we need to handle multiple sites in the same domain. Some sites could use SAML2 (each has a separate SP & IdP configuration) while others are not.

In the extension, we were able to do this to set up the filter so that for each request we can determine if it is using SAML2 or not as well as what the configuration is via the current site context. The entry point is selected at runtime.

saml2Login and saml2Logout DSL seem to enable SAML2 at start-up so it does not work well with this case. Is there an approach to using Spring Security SAML for this?

phuongnq avatar Nov 04 '22 04:11 phuongnq

Hi @akhil-lm, I think that this sample can help you given your needs. https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/saml2/custom-urls

Let me know if it works for you.

marcusdacoregio avatar Nov 04 '22 14:11 marcusdacoregio

Hi @marcusdacoregio, thanks for the above sample.

I've come across another challenge. In our existing saml implementation using the saml-extensions jar, we used to set up the Profile Options. We used to set the relay state in the SAMLEntryPoint, before the authentication request used to go to the IdP.

The SAMLEntryPoint had the 'getProfileOptions' method, that we'd implemented / overridden in our application to achieve the Profile Options set up. I didn't find this class or its equivalent so far in the new framework for SAML.

Request your input on how the Profile Customization can be achieved with the new saml support in Spring Security. What's the new substitute for SAMLEntryPoint? Thanks so much.

akhil-lm avatar Nov 16 '22 15:11 akhil-lm

I think what you are looking for is a way to customize the AuthnRequest instance which is what the WebSSOProfileOptions does. To do that you can refer to this section of the docs, you have the whole AuthnRequest instance available to customize.

marcusdacoregio avatar Nov 16 '22 16:11 marcusdacoregio

Hi @marcusdacoregio, thanks for the above input.

For my login implementation, I've written my custom MyAuthSuccessHandler class that implements the AuthenticationSuccessHandler interface in Spring. I've overriding the onAuthenticationSuccess() and writing the custom logic here that I want to have in my app once the Asserting Party successfully authenticates a user.

So, ultimately, after successful authentication, I want to land into my onAuthenticationSuccess() method.

Right now, the Asserting Party (Okta) calls the '/saml/SSO/' endpoint in my application. Previously, this used to be mapped to the class 'org.springframework.security.saml.SAMLProcessingFilter' (of artifact extensions 1.0.10) in my spring xml configurations.

Even in the new implementation, Okta will call the '/saml/SSO' endpoint after successful authentication. I'm guessing this is the one I need to map to my custom handler whose onAuthenticationSuccess() method I want to invoke.

My configurations so far :-

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .anyRequest().authenticated()
                )


                .saml2Login()
                    .successHandler(new MyAuthenticationSuccessHandler())
                    .relyingPartyRegistrationRepository(relyingPartyRegistrations());

        return http.build();
    }

I am setting my custom handler in the successHandler() method, in the hope that it gets called after the successful authentication.

And my relying party registration looks like :-

    @Bean
    public RelyingPartyRegistrationRepository relyingPartyRegistrations() {

        RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("mycompany")
                .assertionConsumerServiceLocation("/login/saml2/sso/mycompany")
                .assertingPartyDetails(party -> party
                        .entityId("https://trial-6100123.okta.com")
                        .singleSignOnServiceLocation("https://trial-6100123.okta.com/app/trial-6100123_localmycompany_1/exk3dmunf4rkOEynb697/sso/saml")
                )
                .build();

        return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
    }

But I am stuck at the challenge that when '/saml/SSO' is called after the successful authentication, how do I get my onAuthenticationSuccess() method of the custom handler MyAuthenticationSuccessHandler invoked? Request your input on the same, and also please let me know if you see I've got some configuration wrong so far.

akhil-lm avatar Nov 22 '22 15:11 akhil-lm

Is your Saml2WebSsoAuthenticationFilter being invoked by the IdP? Did you map the /saml/SSO to the /login/saml2/sso/{registrationId} or changed the loginProcessingUrl? It's hard to tell what is happening without a reproducible sample.

marcusdacoregio avatar Nov 22 '22 17:11 marcusdacoregio

Hi @marcusdacoregio

  1. "Is your Saml2WebSsoAuthenticationFilter being invoked by the IdP" - My IdP calls '/saml/SSO' that was previously (in the saml extensions based implementation) mapped to Saml2WebSsoAuthenticationFilter in the xml config :- <security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>

The /saml/SSO endpoint would still be called since the Okta is already configured for my relying party, but now it needs to be routed to my success handler I think.

  1. "Did you map the /saml/SSO to the /login/saml2/sso/{registrationId} or changed the loginProcessingUrl" :- This part is where I am struggling at. I am thinking this is where I've to make use of the SamlExtensionUrlForwardingFilter? I was thinking maybe I can use one of the .addFilterAfter() or .addFilterBefore() on my HttpSecurity instance and pass in my SamlExtensionUrlForwardingFilter? Request your input on this mapping part.

akhil-lm avatar Nov 22 '22 18:11 akhil-lm

Hi @marcusdacoregio, I tried to run my application, and the error I'm getting stuck at is that ContextLoaderListener.getCurrentWebApplicationContext(); returns me null.

Previously I had the springContext.xml file (now deleted) which was picked by the Listener. How do I configure the same with the SecurityConfiguration.java file? My web.xml has an entry for the Listener :-

<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener

akhil-lm avatar Nov 23 '22 15:11 akhil-lm

This part is where I am struggling at. I am thinking this is where I've to make use of the SamlExtensionUrlForwardingFilter? I was thinking maybe I can use one of the .addFilterAfter() or .addFilterBefore() on my HttpSecurity instance and pass in my SamlExtensionUrlForwardingFilter

Yes, you do not need to add the custom filter to the SecurityFilterChain, instead, it can stay on the regular filter chain but should be invoked before FilterChainProxy. Register it as a @Component and use a @Order, like you can see in the code:

@Component
@Order(-101) // To run before FilterChainProxy
public class SamlExtensionUrlForwardingFilter extends OncePerRequestFilter {
  // ...
}

marcusdacoregio avatar Nov 23 '22 15:11 marcusdacoregio

Hi @marcusdacoregio, thanks for your reply.

Another query I have is that by looking at the migration guide, I have come to a conclusion that I can implement the SSO using the new libraries with Java+Spring itself, and do not compulsorily need Spring boot. Could you please let me know if that's a correct understanding? Actually, our application do not have Spring boot yet, and we don't have plans to use it.

akhil-lm avatar Nov 24 '22 14:11 akhil-lm

Hi @marcusdacoregio, I got some success with the new implementation, and when I now try to access my application without authorization, I'm redirected to the configured IdP (Okta) and asked for the IdP credentials.

When I enter my credentials, Okta calls the '/saml/SSO/' endpoint in my application. The problem I am facing right now is that for some reason, the status code for the POST call to '/saml/SSO/' is 403.

This request should ideally be re-directed to the '/login/saml2/sso/{registrationId}' as per the SamlExtensionUrlForwardingFilter, but I am stuck at the 403 error for '/saml/SSO/'.

The SamlExtensionUrlForwardingFilter is working for the '/saml/login' ----> /saml2/authenticate/{registrationId}' routing, so the filter seems to be correctly configured.

Request your inputs on what may be causing the 403 error for '/saml/SSO/', and why the request is not routing to the '/login/saml2/sso/{registrationId}' endpoint.

akhil-lm avatar Nov 25 '22 08:11 akhil-lm

looks like the answer is in your question :) why is Okta sending to /saml/sso it should send to saml2/sso right? please check the destination url in okta

rajn avatar Nov 25 '22 08:11 rajn

Hi @rajn, destination url is something my team can't change in Okta, since many clients of our application already have it set to '/saml/SSO' in their existing Okta configurations.

This is why I am using the SamlExtensionUrlForwardingFilter introduced in the spring sample to redirect/forward the '/saml/SSO' request to the correct url as per the new spring security saml2 support. Link to the sample :- https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/saml2/custom-urls

akhil-lm avatar Nov 25 '22 09:11 akhil-lm