- Notifications
You must be signed in to change notification settings - Fork 1.3k
Add check for assertion expiration during the SAML auth flow #42915
base: main
Are you sure you want to change the base?
Conversation
| unnormalizedUsername: "bob@example.com", | ||
| displayName: "Bob Yang", | ||
| expirationTime: "2018-05-20T17:13:04.795Z", | ||
| }); !reflect.DeepEqual(info, want) { |
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.
Would love to add a test case for when Conditons.NotOnOrAfter is not present as this is an optional field. But I couldn't figure out how the certificates and config used in the existing tests were set so I could do the same... 🤔
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 think it's just set in the testAuthnResponse at the bottom. Search for "NotOnOrAfter" and you'll see it there. You can maybe just make a testAuthnResponseNoExpiry and then take that part of the response out
| // It uses github.com/russellhaering/gosaml2 and (unlike authHandler1) makes it possible to support | ||
| // multiple auth providers with SAML and expose more SAML functionality. | ||
| func authHandler(db database.DB, w http.ResponseWriter, r *http.Request, next http.Handler, isAPIRequest bool) { | ||
| // Delegate to SAML ACS and metadata endpoint handlers. |
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.
This is a new idea that I need to validate. Not sure if this will work, but I think it is worth trying as it could allow us to refresh expired assertions without the user having to be asked to re-login.
- In
func authHandler, check if the current session was SAML initiated. - Check whether the assertion has expired (look into
user_external_accounts>accountData>NotOnOrAfterfield) - if the assertion has expired and this is not an API request, do a redirect to the authn request url using
isPassive = true - The user won't see any 401 and won't be asked to log in again; a new assertion will be generated
(Also I need to double check if isPassive is supported by the main IdPs)
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.
So the user, when auto-logged-out would simply be redirected to the identity-provider to login again and then back to sourcegraph? That would be nice.
| (I fear I know too little of SAML to be of value here. I'll need to get more context to accurately judge this) |
| if info.expirationTime != "" { | ||
| exp = time.Until(t) | ||
| } |
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.
You'll want to do this check before the time.Parse, since if it is empty, then the time.Parse would already have errored and returned a 500
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.
oops, totally! thanks for pointing this out!
| if decodedResponse.Assertions[0].Conditions != nil && decodedResponse.Assertions[0].Conditions.NotOnOrAfter != "" { | ||
| notOnOrAfter = decodedResponse.Assertions[0].Conditions.NotOnOrAfter | ||
| } |
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.
| if decodedResponse.Assertions[0].Conditions != nil && decodedResponse.Assertions[0].Conditions.NotOnOrAfter != "" { | |
| notOnOrAfter = decodedResponse.Assertions[0].Conditions.NotOnOrAfter | |
| } | |
| if decodedResponse.Assertions[0].Conditions != nil { | |
| notOnOrAfter = decodedResponse.Assertions[0].Conditions.NotOnOrAfter | |
| } |
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.
NotOnOrAfter can also be optional, so we also need to check if it is present or we will have a nil pointer issue.
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.
NotOnOrAfter is defined as a string, so it can't be nil, it can only be "". But you can remove this check here, because the local variable notOnOrAfter is also defined as a string, so worst case you'll be assigning the empty string to an empty string, meaning it stays the same anyways. But it's one less thing for the reader of the code to process mentally
@mrnugget , I realized that my PR description didn't help much in providing context, so I updated it giving with more details and context. Hopefully, I am not creating more confusion. https://github.com/sourcegraph/sourcegraph/pull/42915#issuecomment-1277690014 |
Now that's a nice PR description!! Well done! |
mrnugget left a comment
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.
LGTM, but I wonder whether we shouldn't implemented what you sketched out here first https://github.com/sourcegraph/sourcegraph/pull/42915/files#r994093907 to not ruin UX?
| if err != nil { | ||
| return nil, errors.Errorf("parsing SAML encoded response: %+v", err) | ||
| } | ||
| if decodedResponse.Assertions[0].Conditions != nil && decodedResponse.Assertions[0].Conditions.NotOnOrAfter != "" { |
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.
Do we need a if len(decodedResponse.Assertions) > 0 check here? Have to admit that the [0] make me a bit light-headed.
Issues #42827 and #36148
This PR is related to the investigation and work to support refresh tokens for different auth providers.
It sets an expiration date/time for sessions based on the value
Conditions.NotOnOrAfterwhich can be present in a SAML response and informs when an assertion will expire.Context:
Currently, we support refresh tokens for GL, and there’s work to be merged that will add support for GH.
But what about other auth providers? Do their tokens used in the auth flow expire? Can these tokens be refreshed? Can we support this?
While investigating if SAML uses refresh tokens and, in case it doesn’t, what can expire in an auth flow with SAML, I confirmed that:
I opened this PR based on the idea that we should respect the assertion expiration time.
Test plan
Unit tests updated and passed. Manually tested that, when an assertion expires, the user has to re-login.