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

Honour nbf claim if present in ID token #210

Merged
merged 1 commit into from Aug 15, 2019
Merged

Honour nbf claim if present in ID token #210

merged 1 commit into from Aug 15, 2019

Conversation

anderseknert
Copy link
Contributor

As promised :) Not new to the domain but very new to Go programming, so bear with me.

verify.go Outdated
return nil, fmt.Errorf("oidc: failed to unmarshal claims: %v", err)
}
if nbfRaw := claimsMap["nbf"]; nbfRaw != nil {
nbf, ok := nbfRaw.(float64)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add NotBeforeField to IDToken starting from here:

go-oidc/oidc.go

Line 323 in 8ae1da5

IssuedAt jsonTime `json:"iat"`

since it's a public claim.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My rationale was that the nbf claim is not ID Token specific but a more "common" claim which none of the other ones listed so far is - perhaps there is some value of keeping a distinction between the two? If not I'll add a NotBeforeField as you suggest.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That struct isn't exported, it's solely used for this method and validation :) Feel free to add any fields to it.

You can also use a pointer to determine presence

type idToken struct {
    IssuedAt  jsonTime  `json:"iat"`
    NotBefore *jsonTime `json:"nbf"`
}

// ...

var t idToken
// ... unmarshal

if t.NotBefore != nil {
    // "nbf" is present. Evaluate it
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one! Thanks 👍 Check looking so much simpler now.

verify.go Outdated
@@ -276,6 +279,32 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok
}
}

// If nbf claim is provided in token, ensure that it is indeed in the past.
if !v.config.SkipNbfCheck {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ericchiang is this worth a seperate check or should we fold this into SkipExpiryCheck?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, just group it under SkipExpiryCheck. No need to add another public flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - simpler for sure, though the tests got a little more verbose as I now had to include an exp in all of the nbf test claims or they'd fail.

verify.go Outdated
if v.config.Now != nil {
now = v.config.Now
}
nowTime := now()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we go with SkipExpiryCheck, move:

go-oidc/verify.go

Lines 269 to 272 in 274971e

now := time.Now
if v.config.Now != nil {
now = v.config.Now
}

Up one block and reuse now so both checks work of the same time.

verify.go Outdated
}
nowTime := now()

if nowTime.Before(nbfTime) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a minute of leeway here to forgive some clock skew. nowTime.Add(1*time.Minute).Before(nbfTime).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, did so and added a test case for that.

verify_test.go Outdated
@@ -107,6 +107,16 @@ func TestVerify(t *testing.T) {
},
signKey: newRSAKey(t),
},
{
name: "nbf",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need a positive and negative test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@anderseknert
Copy link
Contributor Author

Thanks for all the great feedback guys! I think I've addressed your points - let me know if not :)

verify.go Outdated
leeway := 1 * time.Minute

if nowTime.Add(leeway).Before(nbfTime) {
return nil, fmt.Errorf("oidc: current time %d before the nbf (not before) time: %d", nowTime.Unix(), nbfTime.Unix())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: for consistency with the token expiry above, just used %v for the time formatting

return nil, fmt.Errorf("oidc: current time %v before nbf (not before) time: %v", nowTime, nbfTime)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think there's a point to be made for printing the values in the same form as they come in the token, but consistency is key of course. Fixed.

verify.go Outdated
// If nbf claim is provided in token, ensure that it is indeed in the past.
if token.NotBefore != nil {
nbfTime := time.Time(*token.NotBefore)
nowTime := now()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another nit: make sure nowTime is the same for the Expiry and NotBefore check

nowTime := now()
if t.Expiry.Before(nowTime) {
    // handle error
}
if token.NotBefore != nil {
    nbfTime := time.Time(*token.NotBefore)
    leeay := 1 * time.Minute
    if nowTime.Add(leeway).Before(nbfTime) {
        // handle error.
    }
}

Copy link
Collaborator

@ericchiang ericchiang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a couple nits

please squash your commits into a single commit :)

@anderseknert
Copy link
Contributor Author

Thanks for guiding me through this one @ericchiang @mikedanese . Much appreciated 👍

@ericchiang ericchiang merged commit 2be1c5b into coreos:v2 Aug 15, 2019
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

Successfully merging this pull request may close these issues.

None yet

3 participants