-
Notifications
You must be signed in to change notification settings - Fork 17
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
Enhancing signature validation in SAML Response #144 #145
base: main
Are you sure you want to change the base?
Enhancing signature validation in SAML Response #144 #145
Conversation
… on signature for saml response & extending tests
Thank you for your submission! We require that all contributors sign our Contributor License Agreement ("CLA") before we can accept the contribution. Read and sign the agreement Learn more about why HashiCorp requires a CLA and what the CLA includes Have you signed the CLA already but the status is still pending? Recheck it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @himran92 👋 Thx a lot for opening this PR.
A general comment:
I think gosaml2
follows the SAML spec and it is not a requirement to sign both Response and Assertions. If the Reponse is signed signature inheritance applies, and if the assertions are signed it leaves only the Response unsigned. The fields in the Response object are not really an issue if tempered. The reason is mainly because relevant fields like the InResponseTo
field is (should be) checked on the service provider. The cap/saml implementation by default requires the InResponseTo
field to be checked and explicitly prefixes the option to leave it out with Insecure
. If additional protection is required.
If we, however, still want to have the entire response to be signed, I'd suggest to make this optional. If this is forced it could lead to be incompatible with identity providers that do not provide the option to signed the full response.
I left a few comments/questions.
saml/response.go
Outdated
@@ -12,6 +12,7 @@ import ( | |||
|
|||
"github.com/jonboulle/clockwork" | |||
saml2 "github.com/russellhaering/gosaml2" | |||
"github.com/russellhaering/gosaml2/types" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use the cap/saml
types instead? https://github.com/hashicorp/cap/blob/main/saml/models/core/response.go#L10-L14
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
saml/response.go
Outdated
|
||
func validateSignature(response *types.Response, op string) error { | ||
// validate child object assertions | ||
for _, assert := range response.Assertions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gosaml2 requires either the response or the assertions to be signed. It doesn't require both.
My qustion would be if we need to sign both (response and assertions)? Because signature inheritance applies (if the parent object is signed, the child object is included).
Having both objects signed makes sense in some instances where the service provider could retrieve the assertion outside of a SAML Response, but that's not the case here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did some further digging on this. There were many threads on the internet were customers required to have both, response
and assertions
to be signed. So there is a customer need for that.
Most SAML IDPs (e.g. Entra ID and Okta) do provide the option to sign both. However, it looks like there are indeed some IDPs that do not provide the option, such as Auth0
. This is from their application settings:
signResponse (bool): Whether or not the SAML Response should be signed. By default the SAML Assertion will be signed, but not the SAML Response. If true, SAML Response will be signed instead of SAML Assertion.
On your edit above in the description:
After few major version, the vault variable will be removed and user will always have to sign both.
Making both a requirement might lead to incompatibilities with some IDPs (like Auth0 for example). So I wonder if supporting all 3 options would be the ideal case:
- Either
Response
orAssertion
has to be signed Response
has to be signed- Both have to be signed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @hcjulz for researching this point.
I do agree that with this point it does not make sense to add just a strict validation option today and make the setting permanent in future version , rather what makes sense is to give user the control to opt for right validation.
I still would need to check with team on thoughts here as it was called out as a gap from trail of bits
. Will update shortly if team aligns with these thoughts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes done to add separate options for all signature validation. Really appreciate for you finding the info on Auth0 as IDP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also btw the options i kept are:
- assertion is at least signed
- response is at least signed
- both are signed
Did not include the either
option as i thought user should makes a known decision relative to their IDP. Also either
is the default case today when you do not opt for any option.
Let me know if you think otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @himran92 sorry for the late response and thx a lot for addressing my comments 🙇
Sounds great. The options makes totally sense.
The default would still be either
, correct?
saml/response.go
Outdated
@@ -151,6 +152,14 @@ func (sp *ServiceProvider) ParseResponse( | |||
} | |||
} | |||
|
|||
if !opts.skipSignatureValidation { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this fully optional? Something like opts.ResponseSigned
or opts.ResponseAndAssertionsSigned
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes agree that we need to make this optional.
I had a discussion internally and moved the PR to draft again to bring the optional field change + test the e2e flow with vault.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made all settings optional.
saml/response.go
Outdated
skipAssertionConditionValidation bool | ||
skipSignatureValidation bool | ||
assertionConsumerServiceURL string | ||
requireSignatureForResponseAndAssertion bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For requireSignatureForResponseAndAssertion
:
On the vault usage side i opted for a name EnableStrictResponseSignatureValidation
as that sounded more user friendly for a user exposed setting. The description will share the impact of the setting. Whereas kept it requireSignatureForResponseAndAssertion
on cap side thinking of it as more of an internal lib so can have any name.
Any preference of using EnableStrictResponseSignatureValidation
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a strong preference. Based on my comment about having all 3 options signature validation, it would just be important to think about the general naming pattern:
- Validate Response And Assertion Signatures =
EnableStrictSignatureValidation
- Validate Response Signature =
EnableResponseSignatureValidation
?
Alternatively, we could use a more explicit naming pattern:
ValidateResponseSignature
ValidateResponseAndAssertionSignatures
I'm ok either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the name of the setting.
The SAML protocol allows signing of a Response, its Assertion(s), neither, or both. Since Assertion(s) are sub-elements of a Response, they are signed if the Response is signed. Today we are depending on the gosaml2 for signature validation. It only checks only one or the other be signed.
For enhancing security, we would like to give user the option to sign just assign response or assertion or both.
Changes in PR include:
Points before/after merging: