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

Handle expires_on in int format #698

Merged
merged 6 commits into from May 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 18 additions & 8 deletions autorest/adal/token.go
Expand Up @@ -1104,8 +1104,8 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource

// AAD returns expires_in as a string, ADFS returns it as an int
ExpiresIn json.Number `json:"expires_in"`
// expires_on can be in two formats, a UTC time stamp or the number of seconds.
ExpiresOn string `json:"expires_on"`
// expires_on can be in three formats, a UTC time stamp, or the number of seconds as a string *or* int.
ExpiresOn interface{} `json:"expires_on"`
NotBefore json.Number `json:"not_before"`

Resource string `json:"resource"`
Expand All @@ -1118,7 +1118,7 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
}
expiresOn := json.Number("")
// ADFS doesn't include the expires_on field
if token.ExpiresOn != "" {
if token.ExpiresOn != nil {
if expiresOn, err = parseExpiresOn(token.ExpiresOn); err != nil {
return newTokenRefreshError(fmt.Sprintf("adal: failed to parse expires_on: %v value '%s'", err, token.ExpiresOn), resp)
}
Expand All @@ -1135,18 +1135,28 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
}

// converts expires_on to the number of seconds
func parseExpiresOn(s string) (json.Number, error) {
func parseExpiresOn(s interface{}) (json.Number, error) {
// the JSON unmarshaler treats JSON numbers unmarshaled into an interface{} as float64
asFloat64, ok := s.(float64)
if ok {
// this is the number of seconds as int case
return json.Number(strconv.FormatInt(int64(asFloat64), 10)), nil
}
asStr, ok := s.(string)
if !ok {
return "", fmt.Errorf("unexpected expires_on type %T", s)
}
// convert the expiration date to the number of seconds from now
timeToDuration := func(t time.Time) json.Number {
dur := t.Sub(time.Now().UTC())
return json.Number(strconv.FormatInt(int64(dur.Round(time.Second).Seconds()), 10))
}
if _, err := strconv.ParseInt(s, 10, 64); err == nil {
if _, err := json.Number(asStr).Int64(); err == nil {
// this is the number of seconds case, no conversion required
return json.Number(s), nil
} else if eo, err := time.Parse(expiresOnDateFormatPM, s); err == nil {
return json.Number(asStr), nil
} else if eo, err := time.Parse(expiresOnDateFormatPM, asStr); err == nil {
return timeToDuration(eo), nil
} else if eo, err := time.Parse(expiresOnDateFormat, s); err == nil {
} else if eo, err := time.Parse(expiresOnDateFormat, asStr); err == nil {
return timeToDuration(eo), nil
} else {
// unknown format
Expand Down
45 changes: 45 additions & 0 deletions autorest/adal/token_test.go
Expand Up @@ -891,6 +891,34 @@ func TestServicePrincipalTokenEnsureFreshRefreshes(t *testing.T) {
}
}

func TestServicePrincipalTokenEnsureFreshWithIntExpiresOn(t *testing.T) {
spt := newServicePrincipalToken()
expireToken(&spt.inner.Token)

body := mocks.NewBody(newTokenJSONIntExpiresOn(`"3600"`, 12345, "test"))
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")

f := false
c := mocks.NewSender()
s := DecorateSender(c,
(func() SendDecorator {
return func(s Sender) Sender {
return SenderFunc(func(r *http.Request) (*http.Response, error) {
f = true
return resp, nil
})
}
})())
spt.SetSender(s)
err := spt.EnsureFresh()
if err != nil {
t.Fatalf("adal: ServicePrincipalToken#EnsureFresh returned an unexpected error (%v)", err)
}
if !f {
t.Fatal("adal: ServicePrincipalToken#EnsureFresh failed to call Refresh for stale token")
}
}

func TestServicePrincipalTokenEnsureFreshFails1(t *testing.T) {
spt := newServicePrincipalToken()
expireToken(&spt.inner.Token)
Expand Down Expand Up @@ -1461,6 +1489,23 @@ func newTokenJSON(expiresIn, expiresOn, resource string) string {
expiresIn, expiresOn, nb, resource)
}

func newTokenJSONIntExpiresOn(expiresIn string, expiresOn int, resource string) string {
/*nb, err := parseExpiresOn(expiresOn)
jhendrixMSFT marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
panic(err)
}*/
return fmt.Sprintf(`{
"access_token" : "accessToken",
"expires_in" : %s,
"expires_on" : %d,
"not_before" : "%d",
"resource" : "%s",
"token_type" : "Bearer",
"refresh_token": "ABC123"
}`,
expiresIn, expiresOn, expiresOn, resource)
}

func newADFSTokenJSON(expiresIn int) string {
return fmt.Sprintf(`{
"access_token" : "accessToken",
Expand Down