Skip to content

Commit

Permalink
AzureCLICredential reports token expiration time in UTC (#19761)
Browse files Browse the repository at this point in the history
  • Loading branch information
chlowell committed Jan 6, 2023
1 parent 2679c6b commit 5210814
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 30 deletions.
1 change: 1 addition & 0 deletions sdk/azidentity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Breaking Changes

### Bugs Fixed
* `AzureCLICredential` reports token expiration in local time (should be UTC)

### Other Changes
* `AzureCLICredential` imposes its default timeout only when the `Context`
Expand Down
23 changes: 4 additions & 19 deletions sdk/azidentity/azure_cli_credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,32 +162,17 @@ func (c *AzureCLICredential) createAccessToken(tk []byte) (azcore.AccessToken, e
return azcore.AccessToken{}, err
}

tokenExpirationDate, err := parseExpirationDate(t.ExpiresOn)
// the Azure CLI's "expiresOn" is local time
exp, err := time.ParseInLocation("2006-01-02 15:04:05.999999", t.ExpiresOn, time.Local)
if err != nil {
return azcore.AccessToken{}, fmt.Errorf("Error parsing Token Expiration Date %q: %+v", t.ExpiresOn, err)
return azcore.AccessToken{}, fmt.Errorf("Error parsing token expiration time %q: %v", t.ExpiresOn, err)
}

converted := azcore.AccessToken{
Token: t.AccessToken,
ExpiresOn: *tokenExpirationDate,
ExpiresOn: exp.UTC(),
}
return converted, nil
}

// parseExpirationDate parses either a Azure CLI or CloudShell date into a time object
func parseExpirationDate(input string) (*time.Time, error) {
// CloudShell (and potentially the Azure CLI in future)
expirationDate, cloudShellErr := time.Parse(time.RFC3339, input)
if cloudShellErr != nil {
// Azure CLI (Python) e.g. 2017-08-31 19:48:57.998857 (plus the local timezone)
const cliFormat = "2006-01-02 15:04:05.999999"
expirationDate, cliErr := time.ParseInLocation(cliFormat, input, time.Local)
if cliErr != nil {
return nil, fmt.Errorf("Error parsing expiration date %q.\n\nCloudShell Error: \n%+v\n\nCLI Error:\n%+v", input, cloudShellErr, cliErr)
}
return &expirationDate, nil
}
return &expirationDate, nil
}

var _ azcore.TokenCredential = (*AzureCLICredential)(nil)
27 changes: 16 additions & 11 deletions sdk/azidentity/azure_cli_credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ import (
"context"
"errors"
"testing"
"time"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
)

var (
mockCLITokenProviderSuccess = func(ctx context.Context, resource string, tenantID string) ([]byte, error) {
return []byte(" {\"accessToken\":\"mocktoken\" , " +
"\"expiresOn\": \"2007-01-01 01:01:01.079627\"," +
"\"subscription\": \"mocksub\"," +
"\"tenant\": \"mocktenant\"," +
"\"tokenType\": \"mocktype\"}"), nil
return []byte(`{
"accessToken": "mocktoken",
"expiresOn": "2001-02-03 04:05:06.000007",
"subscription": "mocksub",
"tenant": "mocktenant",
"tokenType": "Bearer"
}
`), nil
}
mockCLITokenProviderFailure = func(ctx context.Context, resource string, tenantID string) ([]byte, error) {
return nil, errors.New("provider failure message")
Expand All @@ -32,17 +36,18 @@ func TestAzureCLICredential_GetTokenSuccess(t *testing.T) {
options.tokenProvider = mockCLITokenProviderSuccess
cred, err := NewAzureCLICredential(&options)
if err != nil {
t.Fatalf("Unable to create credential. Received: %v", err)
t.Fatal(err)
}
at, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{Scopes: []string{liveTestScope}})
if err != nil {
t.Fatalf("Expected an empty error but received: %v", err)
}
if len(at.Token) == 0 {
t.Fatalf(("Did not receive a token"))
t.Fatal(err)
}
if at.Token != "mocktoken" {
t.Fatalf(("Did not receive the correct access token"))
t.Fatalf("unexpected access token %q", at.Token)
}
expected := time.Date(2001, 2, 3, 4, 5, 6, 7000, time.Local).UTC()
if actual := at.ExpiresOn; !actual.Equal(expected) || actual.Location() != time.UTC {
t.Fatalf("expected %q, got %q", expected, actual)
}
}

Expand Down

0 comments on commit 5210814

Please sign in to comment.