Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MultiSamlStrategy and InResponseTo are Incompatible by Default #334

Closed
gluxon opened this issue Jan 6, 2019 · 15 comments
Closed

MultiSamlStrategy and InResponseTo are Incompatible by Default #334

gluxon opened this issue Jan 6, 2019 · 15 comments

Comments

@gluxon
Copy link

gluxon commented Jan 6, 2019

For every HTTP request, MultiSamlStrategy creates a brand new SAML object. This in turn creates a new InMemoryCacheProvider.

Meaning by default, the InResponseTo setting will always cause the middleware to fail with "InResponseTo is not valid". Cache keys will never persist beyond the life time of a single HTTP request unless a custom cacheProvider is supplied.

I don't think the usage of two officially supported parts of the library should silently break. There are a 2 ways to fix this (that I see):

  1. Add an error if a custom cacheProvider isn't supplied by the user when using the MultiSamlStrategy. Forcing users to reconfigure this library with an external cache store would workaround this issue.
  2. Have MultiSamlStrategy hold onto its ownInMemoryCacheProvider objects by default that it passes to new SAML instances. To do this securely, it would need to persist caches for each identity provider.

I lean towards 2, but unfortunately the current API design doesn't require each identity provider to be uniquely keyed. The endpoint SAML option gets close, but that can change with binding methods.

Edit: To be clear, I'm just hoping to open a discussion on how to best resolve this. I'm not demanding it to be fixed or trying to force a solution. I may be able to submit a pull request once we agree on something.

@gluxon
Copy link
Author

gluxon commented Jan 6, 2019

Actually, I forgot that the optional idpIssuer parameter existed. That would satisfy the requirement for uniquely identifying IdPs.

@stavros-wb
Copy link
Contributor

@gluxon nice issue description. Would it be a problem to implement 2 without partitioning the cache per provider?

@gluxon
Copy link
Author

gluxon commented Jan 7, 2019

I'm not sure how big of a problem it would be in practice, but it would allow a malicious identity provider to respond to an authentication request made to a different identity provider (assuming SAML response signing is off). If response signing is enforced, then not partitioning the cache should be fine.

@stavros-wb I just realized that you wrote MultiSamlStrategy. Thanks for that! It's been very useful to me.

@stavros-wb
Copy link
Contributor

another option would be to hash the provider's data. given that the values don't change, it could be a poor man's id @markstos wdyt?

stavros-wb added a commit to stavros-wb/passport-saml that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

node-saml#334
stavros-wb added a commit to stavros-wb/passport-saml that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

node-saml#334
stavros-wb added a commit to stavros-wb/passport-saml that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

node-saml#334
stavros-wb added a commit to stavros-wb/passport-saml that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

node-saml#334
stavros-wb added a commit to stavros-wb/passport-saml that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

node-saml#334
stavros-wb added a commit to stavros-wb/passport-saml that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

node-saml#334
stavros-wb added a commit to stavros-wb/passport-saml that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

node-saml#334
stavros-wb added a commit to stavros-wb/passport-saml that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

node-saml#334
stavros-wb added a commit to stavros-wb/passport-saml that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

node-saml#334
markstos pushed a commit that referenced this issue Feb 8, 2019
Either use cache provided by user, or a default memory
cache to store InResponse parameters. This cache is not
yet partitioned per provider, which means a malicious
provider could do replay attacks by using anothers
unconsummed `InResponse` values

#334
@stavros-wb
Copy link
Contributor

@gluxon can you try with the latest master?

@gluxon
Copy link
Author

gluxon commented Apr 18, 2019

@stavros-wb Sorry for the late response, but this works! Thank you!

@gluxon gluxon closed this as completed Apr 18, 2019
@crossan007
Copy link

crossan007 commented Nov 16, 2021

It seems like 3.2.0 no longer defaults to InMemoryCacheProvider for MultiSamlStrategy (possibly as of 224f25f).

Any ideas if this was an intentional change?

I am still able to explicitly define a InMemoryCacheProvider in my initialization options as cacheProvider

i.e.

import { CacheProvider } from "passport-saml/lib/node-saml/inmemory-cache-provider";

...
const SAMLCacheProvider = new CacheProvider({
  keyExpirationPeriodMs: 5000
});
...

passport.use(new MultiSamlStrategy({
  getSamlOptions: getSamlOptions,
  maxAssertionAgeMs: 5000,
  acceptedClockSkewMs: 5000,
  validateInResponseTo: true,
  wantAssertionsSigned: true,
  audience: appVars.saml.SPEntityId,
  signatureAlgorithm: "sha256",
  digestAlgorithm: "sha256",
  cacheProvider: SAMLCacheProvider
},
...

@cjbarth
Copy link
Collaborator

cjbarth commented Nov 17, 2021

What is the last version that worked as you expected @crossan007 ?

@crossan007
Copy link

I'm not actually sure.

I'm working on a new project and attempting to use the library.

I was searching through issues when I found the addition of the default cache provider for multi saml, and then dug through the commit history to locate where the default cache provider was removed when I realized what was added doesn't seem to work

@cjbarth
Copy link
Collaborator

cjbarth commented Nov 17, 2021

If my memory serves me correctly, this was removed because we want consumers to be explicit about which cache provider they use. Feel free to specify an InMemoryCacheProvider yourself during construction. I see that this change was made for the 3.0.0 release. It is possible that some documentation is out of date. Please feel free to create a PR to fix any documentation.

@rfossella
Copy link

Hi. I know this post/issue is really old, but was wondering if I was bumping into something similar with "@node-saml/passport-saml": "^5.0.0"
Is it necessary to create my own custom cache with multiple IdPs? Do the later (latest) version of MultiSamlStrategy handle this?

The issue I sometimes face is logging in a user via one Idp (MS Entra) successfully; then a few seconds later logging into another IdP with different user (also MS Entra, but different credentials) and MS throws message stating it can't find FIRST user in the SECOND IdP.

Is this related to this issue at all? Something else?

@srd90
Copy link

srd90 commented Dec 5, 2024

The issue I sometimes face is logging in a user via one Idp (MS Entra) successfully; then a few seconds later logging into another IdP with different user (also MS Entra, but different credentials) and MS throws message stating it can't find FIRST user in the SECOND IdP.

Is this related to this issue at all? Something else?

Speculation:

Are those MS Entra IdPs behind same domain name / path? If so and due to how your chaos stress testing(*) is not cleaning/teardown browser state while changing user (nor performing SLO) situation could be that your SP triggered SSO login to MS Entra but your browser delivered IdPs session cookie of first IdP to also to second IdP and second one tried find session of such user to perform auto login to new SP but failed to find such user from second IdP

(*) for anyone else trying to solve this puzzle see backround information from:

  1. Getting old profile when retrieving different users node-saml#379
  2. Using MultiSamlStrategy and handling sessions #944

IMHO second part of your comment is not related to inresponse cache implementation.

@rfossella
Copy link

Are those MS Entra IdPs behind same domain name / path?

No, they are different domains which is the cause of confusion/concern. Granted, a "regular" user will typically only be logging into their (single) domain. My stress testing is meant to simulate an in-house user and outside user.

FYI: I did try the caching approach just to be sure and it had no affect. I have since removed it.

@srd90
Copy link

srd90 commented Dec 5, 2024

So you are saying that once the control has shifted to IdP it presents login screen instead of trying to reuse existing SSO session (which might have happened due to already communicated reasons)? passport-saml does not fill username and password on behalf of the user or on behalf of your testcase.

You are in charge of providing SAML options (address of IdP etc) per request for passport-saml MultiSamlStrategy based on whatever policy you choose to implement furthermore you are in charge of providing some sort of username and password or similar to IdP once it presents a challenge for you. So...I fail to see how passport-saml would be involved when your robotframework, selenium, whatever provides incorrect username for IdP.

Unless you provide full traffic log there is no way for any outsider to see whats actually going on. By full traffic log I mean all HTTP request / responses with all headers and payloads.

FYI: I did try the caching approach just to be sure and it had no affect. I have since removed it.

I get a feeling that you did not quite understand what inresponseto cache is used for/what it contains. It does not cache responses. It caches ID values of authentication requests delivered to IdP. When IdP ships authn response via front channel (typically via HTTP POST binding in case if authnresponse) passport-saml shall check whether authnresponse is response to any request it has triggered. It is used to block e.g. replay attacks (e.g. someone catches SAML authnresponse and posts it again/multiple times to SP's ACS callback to create multiple login sessions within limits of NotOnOrAfter restriction).

@rfossella
Copy link

I get a feeling that you did not quite understand what inresponseto cache is used for/what it contains. It does not cache responses. It caches ID values of authentication requests delivered to IdP.

Yes, I originally thought it was caching responses and then realized it was meant to cache IDs/keys of auth requests. I did get that working but since it did not address my primary issue I removed it. Thanks for clarifying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants