Sustainsys / Saml2

Saml2 Authentication services for ASP.NET
Other
944 stars 605 forks source link

Best way to handle UnexpectedInResponseToException when user clicks Browser Back button after SSO login #666

Open kb99 opened 7 years ago

kb99 commented 7 years ago

We are getting a number of the errors below in our prod environment as users are clicking the 'Back' button in their browser after logging into our site via SSO.

Received message contains unexpected InResponseTo "idaa12692a7ce24a59a18fcaa24d6fee0f". No RelayState was detected so message was not expected to have an InResponseTo attribute.

What is the best way to handle this issue? Is it just to catch the UnexpectedInResponseToException exception that AuthServices throws and redirect the user or is there anything else that can/should be done instead?

AndersAbel commented 7 years ago

This is a really good question. The problem is with how the SAML2 protocol is designed. If you click back, you will end up at the Idp page that auto-posts the form with the data to AuthServices. Which will react as described.

If I remember correctly we've discussed previously that we maybe should detect this situation and ignore it. @albinsunnanbo do you remember if we said anything?

albinsunnanbo commented 7 years ago

Haven't been up to date lately, @bzzn might be more informed. But the last thing I remember is that we got replay detection exceptions in this scenario. But IIRC AuthServices has changed implementation in this area, so this might be the same problem in a new shape. What we did was to create a custom middleware to catch the exception and render a blank html page with a javascript history.go(-2) or something like that. (-2) to jump past the page autoposting the old request again.

kb99 commented 7 years ago

Ok - we'll implement the custom middleware to handle the exception so and redirect the user.

AndersAbel commented 7 years ago

We'll keep this issue open. It might make sense to include this functionality in the library itself (with a possibility to disable it through a compatibility setting)

albinsunnanbo commented 7 years ago

I once hade an idea that one could check if the user is already authenticated with the same user id that is in the AuthnResponse and in that case just let them pass in again.

AndersAbel commented 7 years ago

@albinsunnanbo Probably should check against the LogoutNameIdentifier in that case, as the application often alters other claims. I think that the technical behaviour should be to ignore the second AuthnResponse and keep the session already established. The second one could be some kind of forgery and should not be evaluated/trusted.

rpmansion commented 7 years ago

I'm also having the same issue in our production but not on our dev and stage environment.

UnexpectedInResponseToException: Received message contains unexpected InResponseTo "id2b4f0709933c41059da2bd57cf5eddc1". No RelayState was detected so message was not expected to have an InResponseTo attribute.]

The issue occurs without clicking browser back button.

alohaninja commented 6 years ago

We are also receiving the same error with our SAML configurations... No RelayState was detected so message was not expected to have an InResponseTo attribute. Any word on the fix?

premnathj commented 6 years ago

We are also having the same issue wherein sporadically we get this error. Requesting you to give us the workaround or fix.

prashanthbachu commented 6 years ago

I am also seeing this issue but it's random and not easy to recreate. Occurs without clicking back button.

AndersAbel commented 6 years ago

@premnathj That's not how open source work. Either you help out by finding a reliable reproduction that we can use to test it, or you get in touch with me to do the work as payed consultancy work. But I don't have time to just do things for free.

@prashanthbachu Are you sure it only occurs when clicking the back button?

prashanthbachu commented 6 years ago

@AndersAbel it occurs even if back button is not clicked.

AndersAbel commented 6 years ago

@prashanthbachu That is interesting, because this is something we've heard of for a long time but never been able to reproduce. Can you please clearly document how to trigger this without using the back button?

rpmansion commented 6 years ago

@AndersAbel this might help. We have a web app that has multiple subdomains. Each subdomain is designated to one of our clients. During development of implementing SAML2, the metadata is using the main domain that we use for internal or any users who are not our client. So basically one of the clients has the URL: https://client.company.com requesting to their Idp from our SP however in the metadata the URL configure is http://company.com. That is when the exception shows up.

I have fixed this by dynamically change the URLs in the metadata depending on the clients URL.

AndersAbel commented 6 years ago

@robertpmansion Thanks, this is a solid pointer to where to look.

thomaslevesque commented 5 years ago

I have the same exception, with the following message:

Received message contains unexpected InResponseTo "id8cbbb49a8691462fbc1292c841805347". No cookie preserving state from the request was found so the message was not expected to have an InResponseTo attribute. This error typically occurs if the cookie set when doing SP-initiated sign on have been lost.

Any idea what could be causing this?

I can't reproduce it in my own environment (App Service in Azure, Azure AD as the IdP), but I have a client who gets this error every time (identical Azure App Service, IdP on the client's internal network, not accessible from outside). In my environment, I see the cookie mentioned in the error; I assume that it's somehow lost when using the client's IdP.

AndersAbel commented 5 years ago

I've seen this at a customer recently. In that case the cookie was set on the outbound redirect to the Idp, but the browser didn't include it when responding back. The problem that time turned out to be a http/https issue. The SP was running on HTTPS, the Idp as well. But the Idp was configured to respond to http://sp.example.com/Saml2/Acs. And that cause the browser to not include the cookie!

So first, check that all the config is https all the way - if that doesn't help, please get back here.

thomaslevesque commented 5 years ago

Thanks for the quick reply @AndersAbel! I'll check that and get back to you.

thomaslevesque commented 5 years ago

@AndersAbel I just understood what the problem is. I had the GDPR consent banner (from the ASP.NET Core app template) enabled. If I didn't click "Accept", the Saml2 cookie wasn't being sent. As soon as I clicked "Accept", it started working (so it has nothing to do with the environment I was running in).

The cookie consent only applies to non-essential cookies, and the Saml2 cookie is essential, so it should be marked as such, but it's not. I'll send a PR.

AndersAbel commented 5 years ago

Thanks, that explains the issue for Asp.Net Core. The cookie setting code is at https://github.com/Sustainsys/Saml2/blob/8545f963edf646b09ba8c2a56af63be9a5fb6cfb/Sustainsys.Saml2.AspNetCore2/CommandResultExtensions.cs#L32

thomaslevesque commented 5 years ago

Yes, I found it, thanks! I guess the issue doesn't exist for OWIN since it doesn't have the concept of cookie consent.

AndersAbel commented 5 years ago

No, this must be unique to Asp.Net Core. So if the problem occurs in Sustainsys.Saml2.Owin, Sustainsys.Saml2.Mvc or Sustainsys.Saml2.HttpModule it's another error.

thomaslevesque commented 5 years ago

@AndersAbel I just realized the fix isn't that simple... The library references ASP.NET Core 2.0, but the GDPR cookie consent feature was added in 2.1, so I can't set the CookieOptions.IsEssential property since it doesn't exist in 2.0...

I see a few options, none of which is ideal...

What do you think?

AndersAbel commented 5 years ago

@thomaslevesque This really turned out to be something different that the original issue. Please open a new issue/bug that we can use to discuss the cookie consent/essential cookie fix.

varadharajanmadhav commented 4 years ago

@AndersAbel

Hi, I am having same issue in HttpModule. After SLO, on click of browser back buttton, it goes to Acs page, throwing exception "InResponseTo".

PS: I am using .NET Framework 7.0

varadharajanmadhav commented 4 years ago

I got the issue. We were restricting caches for responses. Now it is solved.

Just have a question. Is there a way we can do this SSO without storing caches in the browser and always initiate new request?

AndersAbel commented 4 years ago

Three years later, we're back at this because it still happens in cases that are not easily explained. I ask everyone seeing this in production to help out diagnosing by implementing extensive logging in the new notification enabled by #1173.

JohnnyFun commented 4 years ago

This just started happening to us this morning on Sustainsys.Saml2.AspNetCore2" Version="2.4.0". I'll try updating to 2.7.0, but looks like some changes might apply to the problem, so I'll let you guys know if it resolves our issue.

I think it timed up with a chrome update, so maybe they changed something.

I of course can't reproduce it locally, but c'est la vie.

JohnnyFun commented 4 years ago

One thing I noticed in Firefox was a warning "Cookie “idp_sid” will be soon rejected because it has the “sameSite” attribute set to “none” or an invalid value, without the “secure” attribute. To know more about the “sameSite“ attribute, read https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite"

But I was able to complete the sign in without issue. But our testing IDP is on HTTP, so maybe that's why it was allowed (not sure).

I don't know what Cookie “idp_sid” is from, but maybe one of you know?

MatiSanchez commented 3 years ago

Hi guys, any news about this??

One month ago we don't had problems.. but today i need to test something (we have 2 login methods) and when i press Log In in https://stubidp.sustainsys.com/ show the error.

In Edge there is no problem, only in Chrome.

Our application is Net Core 3.1 and is using Sustainsys.Saml2.AspNetCore2 2.7.0

Solved I just see the error when use http and https.. The weird of this that one month ago we dont had this problem.. Maybe something changed in the last versions in Chrome.

antibarbie commented 3 years ago

Chrome refuses to set a cookie with SameSite=None and not Secure. (The cookie is notified as blocked in the dev tools)

So this error is because the cookie was not set properly, because of plain http. Switching IDP and SP in https solved this.

toddlucas commented 2 years ago

We have been seeing this error while adding support for Azure AD. We are manually constructing the SAML request, containing an ID attribute (for example <samlp:AuthnRequest ID="_eaaeb07d-67ce-4747-8004-db0080668e40"...). Azure responds by posting with an InResponseTo attribute containing that value (e.g., <samlp:Response ... InResponseTo="_eaaeb07d-67ce-4747-8004-db0080668e40"...). We built the binding manually since it wasn't clear whether this library support constructing AuthnRequests yet or not.

AndersAbel commented 2 years ago

@toddlucas The library perfectly supports building AuthnRequests. You should use one of the API modules Sustainsys.Saml2.AspNetCore2 or Sustainsys.Saml2.Owin etc.

The lower level API entry point is SignInCommand.

AndersAbel commented 2 years ago

Found another case today that triggered this: The idp didn't return the RelayState field. It posted the SamlResponse field, but no RelayState which means the cookie is not read. The good point with it was that it was easy to troubleshoot - it happened consistently with this one Idp, for all users, all browsers.

I guess it's not a common reason, but writing it down in case it is the cause for someone else.

toddlucas commented 2 years ago

OK, thanks. That wasn't clear from the documentation. In any case, if someone constructs their own AuthnRequest, it will trigger this exception. If that's not a supported scenario, I understand.

AndersAbel commented 2 years ago

@toddlucas The library and the packages offer several levels of APIs. It is supported to work with one of the lower levels directly, but usually that is not a good idea. And it requires a more in depth understanding for the protocol and how the library's validation logic work. The recommendation is to use one of the API packages (Sustainsys.Saml2.HttpModule/Owin/AspNetCore2).