Skip to content

Signed SSO with HTTP-REDIRECT Binding [was: cert field not read?] #713

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

Closed
errrken opened this issue Sep 2, 2020 · 20 comments
Closed

Signed SSO with HTTP-REDIRECT Binding [was: cert field not read?] #713

errrken opened this issue Sep 2, 2020 · 20 comments

Comments

@errrken
Copy link

errrken commented Sep 2, 2020

Hi,

Using pysaml2 as an SP, any my metadata is:

'metadata': { 'remote': [ { "url": a-remote-url "cert": a-file }, ] },

The thing is that it feels like the cert field is not being used - I can have any value here (a string, a file, a file that does not exist) and it does not affect the workflow at all. Does this field not work when the remote host is localhost?

Code Version

6.1.0

Expected Behavior

Read the value of the cert field

Current Behavior

Any value of the cert field works

@peppelinux
Copy link
Member

Hi, is that remote endpoint under https and probably without a valid certificate.
Probably you'll see in the error log that SSL/TLS validation failed.
Try to put disable_ssl_certificate_validation in your sp configuration

Something like:

  # where the remote metadata is stored, local, remote or mdq server.
  # One metadatastore or many ...
  'metadata': {
      'local': [path.join(BASEDIR, 'remote_metadata.xml')],
      'remote': [{"url": "https://idp.testunical.it/idp/shibboleth",
                  "disable_ssl_certificate_validation": True},],
      'mdq': [{"url": "https://ds.testunical.it",
               "cert": "certficates/others/ds.testunical.it.cert",
               "disable_ssl_certificate_validation": True}]
      },

This example is available in djangosaml2 README.

@errrken
Copy link
Author

errrken commented Sep 3, 2020

@peppelinux Hi, the remote endpoint is under https and does have a valid certificate. What I am curios of is that it is never complaining of the contents in the field - if I enter a file that does not exist, a file that does exist, or anything - nothing produces a warning such as "can't find file" or similar - as happens if I enter a wrong location for e.g. "key_file" and "cert_file".

So I am a bit confused of what to actually put in the "cert" field?

@peppelinux
Copy link
Member

That cert would be needed to verify metadata signature. If that's not signed that parameter Is useless

@peppelinux
Copy link
Member

Follow It with a breakpoint() here

:params cert: CertificMDloaderate used to sign the metadata

You'll see what happens

@errrken
Copy link
Author

errrken commented Sep 4, 2020

@peppelinux Okay thanks. The thing is I am getting:

Unsuccessful operation: <ns0:Status xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol"><ns0:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Requester" /><ns0:StatusMessage>Signature required</ns0:StatusMessage></ns0:Status> Signature required from None

It is all working with a local IDP server, but when we try to connect to PingfederateIDP it is not. IDP initiated login works fine, but SP initiated logins generate above error message as long as authn_requests_signed: True

Any ideas?

@peppelinux
Copy link
Member

peppelinux commented Sep 4, 2020

Yes, we completely went out of route 😎
That's not regard metadata stores.
If you're trying to sign authn request via http-redirect this could be faulty. I saw this in the past but I'd have to check. Sign authn request only with http-post, otherwise disable request signatures.

In federations we do not use to sign requests, that's to prevent resource consuming with signature validation (DoS) but if you want It use http-post with pysaml2 and It will work

Please update metadata as well

@errrken
Copy link
Author

errrken commented Sep 4, 2020

@peppelinux yes :)

Hmm okay, so settings are:

    'name': saml_connection.company.name,
    'metadata': {  
        'local': ['metadata.xml']
    },
    'key_file': settings.PRIVATE_KEY_LOCATION,
    'cert_file': settings.PUBLIC_CERT_LOCATION,
    'service': {
        'sp': {
            'endpoints': {
                'assertion_consumer_service': [
                    (acs_url, BINDING_HTTP_POST)
                ],
            },
            'allow_unsolicited': True,
            'authn_requests_signed': True,
            'want_assertions_signed': False,
            'want_response_signed': True,
        },
    },
    'entityid': saml_connection.entity_id
}

Still generates the same error. Am I missing something? :)

@peppelinux
Copy link
Member

peppelinux commented Sep 4, 2020

The question is, are you using djangosaml2? (I see settings.stuffs)

Probably your IdP wants autn request signed in http-redirect?
Or, simply, the SP needs signed responses but gets unsigned one?

Give us the url of the idp metadata, I'll take a look.
If you're using djangosaml2 this would be linked to:
IdentityPython/djangosaml2#193

It would be the time to face this definitively, with a smart code refactor as well

@errrken
Copy link
Author

errrken commented Sep 4, 2020

@peppelinux Yes, correct - the IdP needs authn request signed in http-redirect

I am not using djangosaml2 but only pysaml2.

IDP metadata:

<md:EntityDescriptor ID="rDSLeES8vPW_vUQ0dVJo7qfL" cacheDuration="PT1440M" entityID="theEntityID">
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" WantAuthnRequestsSigned="true">
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIGkjC..
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://blabla/idp/SSO.saml2"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://blabla/idp/SSO.saml2"/>
<saml:Attribute Name="company" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"/>
<saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"/>
</md:IDPSSODescriptor>
<md:ContactPerson contactType="administrative"/>
</md:EntityDescriptor>

So it seems like the signature must be appended to the request as a query parameter, am I right? Do you have any idea how this can be done? :)

@peppelinux
Copy link
Member

I would dig to get this working but I see:

<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://blabla/idp/SSO.saml2"/>

Ok, get your SP to make authn request via POST and everything will works great.
Unfortunately http-redirect often is the first choice :(

Digging more on http-redirect, it would be:
?SAMLRequest={val1}&Signature={val2}&SigAlg={val3}

See "3.4.8 Example SAML Message Exchange Using HTTP Redirect" in https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf

now we have to check if pysaml2 works fine with this specification in http-redirect signed binding ... going further ...

@errrken
Copy link
Author

errrken commented Sep 4, 2020

@peppelinux Yeah, they say "all their other SP's use GET" so they think we should too. Exactly, it seems like it should be like: ?SAMLRequest={val1}&Signature={val2}&SigAlg={val3}

with the Signature and SigAlg as query params.

Can pysaml2 do this? Or is it us doing something wrong? It feels like this is a very common scenario - someone must have reached this error before?

Thanks a lot for digging into this!!

@peppelinux
Copy link
Member

peppelinux commented Sep 4, 2020

And yes,

I configured uniauth (a fairly unknow saml2 idp based on pysaml2) with http-redirect only and mandatory signed requests.
then I made a request from a djangosaml2 sp, I see:

http://idp1.testunical.it:9000/idp/sso/redirect?SAMLRequest=jVLRTsJAEPyV5t7LHRUDbGiTKlFIUAlUTHw72hMuaffq7dbo39uCGowJ8fF2ZnZmNjchXZU1pA3vcWVeG0McvFclEnRALBqP4DRZAtSVIeAc1undAqKeAk1kPFuH4kRSn9fU3rHLXSmC9Ft97ZCayvi18W82N4%2BrRSz2zDVISXW%2Fx22kBm2uy55lGCmlZOcTSZ2TFMG0hS3qbtGPzBZ%2FdONO184lkZPeFNabnEUwn8bCFuH9avO0Gc%2B2o9Rf7iwOb1uEqDFzJNbIsYhUpEI1DtUg61%2BAGsBg%2BCyC5VeZK4uFxd355tsjiWCWZctw%2BbDORLAxng7BW4JIJl0vOBj74Mb5SvP5ld2kTf9yoIJBtvwhkv%2FcrjKsC81aTuSJaXJ8%2Ff4OySc%3D&RelayState=%2Fsaml2%2Fecho_attributes

And this helped me to get the decision to patch this definitely in djangosaml2.
By my side this behaviour was produced by djangosaml2. After this commit I'm getting the right behaviour. :
IdentityPython/djangosaml2@de1ac98

The only ugliness but entirely relative is that the signature now appears both in url args and request.body (post).

Now I have

http://idp1.testunical.it:9000/idp/sso/redirect?SAMLRequest=nVZZk6JIF32vX2HYj0QVi6hodNVEsoiIyCqibykkiLLJLr%2F%2BQ6u6orpnvo6eebw3z93OybyR3%2F9q42hQo7wI0%2BR1SL4Qw7%2Fenr4XMI6yOajKU2Kga4WKctDjkmLuFa%2FDU1lmcxxvmualGb2keYBTBEHgxAzvMV4RBt%2BGH%2Bh7mtdhlSfzFBZhMU9gjIp56c5NoKzn1Asxh0WB8rKv%2FTUk%2B31Mlqdl6qbRcAB%2BRHNpUlQxyk2U16GLtsb6s80iI1%2FKfoAqCV0YvYTlnLl3e69D4dAt8OGA74%2FDBJYPCj7CQu9vcbN7XO%2FHiyLFc%2BSFOXLL4UDiX4eh97x27NbTRorgg8hkyN24PymKCklJUcKkfB1SBEU8E7NngrbI0Zwi5qPRYTjQPoZhw8QLk%2BD3kx%2FfQcV8aVnas6aa1nBg%2F9CuBwzfHsrNH4XzwSLNY1j%2BPuXd03fvP6BzlJRheRu%2B%2FQl3MSqhB0uIf8e%2FFH377hVzMwx6OqscDSTvdfhpkcPPU%2BRJiZ8%2BTA4m6SN%2F2D0kUFB5Sr0BiII0D8tT%2FH8uHImTxP3CPaPWfXZJOvk2xH8u%2FoeJfrq5eQGfixMkP3IZyEc5Slw02BrS6%2FDbP%2Br8QFo5TIo7i8XP5r8rj5IaRWmGvOfixxQfnfx5wn8mBv97j3wY9Nr%2BF5a%2BMPSexIZRhd58AnNko%2FY3kR1b7JWLzWh6UNvs2rqvjwa%2Bgh%2BOT37fzV9uxqeS7xF2MWGKVh7pAow5oUoWR9w5WZPICppu1RxidqGnXnTaewfWXsZHUbMdrZwUZ76Sqarddk%2BTpda0x%2BNo50TiZh2k%2FFmDiJB3FONKU70DZbpOVNeu29KkcrnAj6WP7ZTUDTG%2FiK%2Bl%2F6TLG3etRK3sXAIyxOu%2BHhVG1YRhwT5b7WQOAzdG2bcpvl%2BJy8MCzC4ZSmeba65hne7gT1fv0m4EMS5aL92Jsih3NjvB2VNGtNtlzeZgFlb7c3RNRLlts91tfUa%2BqJ%2BPx6lRCt7t9LTPDaeyFqvKXd3KYF2vKt7wYDK2jobM6IyDkxadiAElhPxIaJc56UBMNlB%2B1IpoYpDw6YTpdEMerPqATYyrI8pBnIvN6%2Bsn%2F18Iv2sgo9unHs6YmPH9i%2F80uPv29fu3W6I3RZJ4weI44McBaCQWBNJWa0hKvJQ0DNhyzSalNzU6a9esZbBveH2%2FktODdKrdDdCFNauDRuSFncLqIiC3AmiajTsC7TqxK7jbnI7cOPN4gBYN0aoW6JQzaDe80iqWDXvf7eGz3E%2Bfwgbt4gy2bLCxWaAovLNpFHNMHuPovN81FXT0JgiEUAGEyJlX0ZSOI14XWKBvAaAllm%2FA%2FVwGaT%2BLzp0JtlPLMSNwhdlYBD07SqeYJ7Lpldhj9HrqnvO6Xu1dxZouDwJWHlVamVTZxUk0bBTUWma4LhTKZpV6cBTsu3oxGttKlxE%2Bt5uqsSMZjLsqb6bkdxcvjtUR02vaRhl5NtrDTS9dKtE6TkY23Ub6RggTPZ%2FRiTQtlYWBeHQ%2BO3Jjjg3AXhhZV1JKmTItnBn6rb3yHImIMEW2bhhUGsxm%2FmJU4Tt1ha9YCgqW5ddSki%2Bk2wKMHZbIU5a%2FKTTNTKeJIe%2BRwnr0xb70b4C%2BVZPLIZ7uVGe5dRZr2aicNbJb4XjYd6apnBO3YMntaKyCElO7S4aR1BVeFWB7oqxhbZGOOhHk%2BBhwE67SkhwECguAeN52rKGwxF13jw%2F0HcsaE8NI4Vns08Ver5FsxkG2Hhk8EXfAv2u6NBVB5MEu%2BD1We2D77MBnBNYCPNCX%2BK%2Bac8275kBnO2MLMcwihNDAFlc6tDJZuvU7z8ZIDilHE6vIFdTURHH8XXxMVdXm8%2BUpCctj5rcxZmZH6GtWRxPWsvSbmSDXBlLOG0gvdbpesEpzKOP9gc5C0Rxr%2FfJb8F2%2FsETSM3Gqdjkd0PwN4sZkOnZk4cR6O5VZ%2BVt1TUqxkq5YOD5gINsyKndhTlm42toEvGTN9AwwW2Uw26AszFxioxPFyGq%2B8XK4S7vDbLaRr%2BxU3C5c2KYVVC%2BaMI1DZnUDwfqgHOoVRDpaCVtpVviwNtdxzRb%2BsSoA4s6LPWcrM0WZVodNLU8CieC7LIuwfDOtjZ3LLrB0fwtNUnBmZ0q8iuRt53pivZ8Q4qoaC%2Fk49B7L5deF8el8Xyn412Xz0zJ6e%2F9g%2FPwffXv6Hw%3D%3D&RelayState=%2Fsaml2%2Fecho_attributes&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature=eu70N8Ae9Ew3hCKUU8UtKhrFb7L3YWQkI7GRi5hQfb45%2FZkE03mbIg888o8bdJWrsXagrFEW2vU4%2FPCO9T5QxJuFhAfhhOVpQVj5LivsKPtrtXro5vo6a0jnutq2O%2FS6wjHD3zNWBlvDK204IDMG9qBIkSDafyMmg0%2BYlZ8UoZNvbFR4ie6ZXHLoa9VJRbNpC3Yj%2BcFbICmN4Ti4uGykk0reko70upcABty%2BBNZxZQJtHKSVxuc3s0UKnNviDM9EGghaVLjsuydqbH0I9XbLOpAuYdWagKPb2RpksdWrrj8Dc0IlIkdj2NfuuvR8G8uPc80Bgi0jyp8T50xYaTJ5eA%3D%3D````

Take a look about how you're dealing with SSO initialization in your SP, probably that djangosaml2's commit would help you to have a snippet to work on. let us know 

@peppelinux
Copy link
Member

Can you see the http-redirect url with the signature in it?
Wouldn't be the SignAlg parameter the faulty element...? I mean that I don't know if PingFederation still supports SHA1 as default alg!

@peppelinux
Copy link
Member

@peppelinux Yeah, they say "all their other SP's use GET" so they think we should too. Exactly, it seems like it should be like: ?SAMLRequest={val1}&Signature={val2}&SigAlg={val3}

with the Signature and SigAlg as query params.

Can pysaml2 do this? Or is it us doing something wrong? It feels like this is a very common scenario - someone must have reached this error before?

Thanks a lot for digging into this!!

Yes, pysaml2 does it in the right way, see your SP implementation. This should be similar to djangosaml2 login initialization, so you would find there an example implementation.

And, at last but not least, the IdP's metadata doesn't show the supported algs. Does it support sha1 for signatures?

@peppelinux peppelinux changed the title cert field not read? Signed HTTP-REDIRECT [was: cert field not read?] Sep 4, 2020
@peppelinux peppelinux changed the title Signed HTTP-REDIRECT [was: cert field not read?] Signed SSO with HTTP-REDIRECT Binding [was: cert field not read?] Sep 4, 2020
@errrken
Copy link
Author

errrken commented Sep 4, 2020

@peppelinux One strange thing is that when I do:
_, info = saml_client.prepare_for_authenticate(sign=True,kwargs={"sigalg": ds.SIG_RSA_SHA1})

The generated URL has no Signature nor sigalg query param. Do you have any idea why?

@peppelinux
Copy link
Member

@peppelinux One strange thing is that when I do:
_, info = saml_client.prepare_for_authenticate(sign=True,kwargs={"sigalg": ds.SIG_RSA_SHA1})

The generated URL has no Signature nor sigalg query param. Do you have any idea why?

just have this as reference:
https://github.com/knaperek/djangosaml2/blob/997be32287ae195b1f1dd7e8697c9c4731c5957e/djangosaml2/views.py#L199

it simply works

@errrken
Copy link
Author

errrken commented Sep 4, 2020

@peppelinux Right, got it working now. Thanks for all your support! ❤️

@c00kiemon5ter
Copy link
Member

c00kiemon5ter commented Sep 4, 2020

@peppelinux One strange thing is that when I do:
_, info = saml_client.prepare_for_authenticate(sign=True,kwargs={"sigalg": ds.SIG_RSA_SHA1})

The generated URL has no Signature nor sigalg query param. Do you have any idea why?

I think this is actually a bug that we should fix.

@peppelinux thanks for the support ;) 👍

@peppelinux
Copy link
Member

peppelinux commented Sep 4, 2020

@peppelinux One strange thing is that when I do:
_, info = saml_client.prepare_for_authenticate(sign=True,kwargs={"sigalg": ds.SIG_RSA_SHA1})
The generated URL has no Signature nor sigalg query param. Do you have any idea why?

I think this is actually a bug that we should fix.

@peppelinux thanks for the support ;) +1

Hi @c00kiemon5ter, not so bad, I wouldn't see this as a bug, the only ugliness is that the signature now appears both in url args and request.body (post). But it works.

The bug would instead with a pysaml2 IdP and Shibboleth SP. ShibSP doesn't put signature also in saml2 request (but only in http-redirect url arg, as it would have to be). So pysaml2 IdP rejects the authn request because it can't find the signature in Saml2.

@c00kiemon5ter
Copy link
Member

This is now fixed by 2f756ba

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

3 participants