Skip to content

Commit 5210814

Browse files
authored
AzureCLICredential reports token expiration time in UTC (#19761)
1 parent 2679c6b commit 5210814

File tree

3 files changed

+21
-30
lines changed

3 files changed

+21
-30
lines changed

sdk/azidentity/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
### Breaking Changes
1010

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

1314
### Other Changes
1415
* `AzureCLICredential` imposes its default timeout only when the `Context`

sdk/azidentity/azure_cli_credential.go

+4-19
Original file line numberDiff line numberDiff line change
@@ -162,32 +162,17 @@ func (c *AzureCLICredential) createAccessToken(tk []byte) (azcore.AccessToken, e
162162
return azcore.AccessToken{}, err
163163
}
164164

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

170171
converted := azcore.AccessToken{
171172
Token: t.AccessToken,
172-
ExpiresOn: *tokenExpirationDate,
173+
ExpiresOn: exp.UTC(),
173174
}
174175
return converted, nil
175176
}
176177

177-
// parseExpirationDate parses either a Azure CLI or CloudShell date into a time object
178-
func parseExpirationDate(input string) (*time.Time, error) {
179-
// CloudShell (and potentially the Azure CLI in future)
180-
expirationDate, cloudShellErr := time.Parse(time.RFC3339, input)
181-
if cloudShellErr != nil {
182-
// Azure CLI (Python) e.g. 2017-08-31 19:48:57.998857 (plus the local timezone)
183-
const cliFormat = "2006-01-02 15:04:05.999999"
184-
expirationDate, cliErr := time.ParseInLocation(cliFormat, input, time.Local)
185-
if cliErr != nil {
186-
return nil, fmt.Errorf("Error parsing expiration date %q.\n\nCloudShell Error: \n%+v\n\nCLI Error:\n%+v", input, cloudShellErr, cliErr)
187-
}
188-
return &expirationDate, nil
189-
}
190-
return &expirationDate, nil
191-
}
192-
193178
var _ azcore.TokenCredential = (*AzureCLICredential)(nil)

sdk/azidentity/azure_cli_credential_test.go

+16-11
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,21 @@ import (
1010
"context"
1111
"errors"
1212
"testing"
13+
"time"
1314

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

1718
var (
1819
mockCLITokenProviderSuccess = func(ctx context.Context, resource string, tenantID string) ([]byte, error) {
19-
return []byte(" {\"accessToken\":\"mocktoken\" , " +
20-
"\"expiresOn\": \"2007-01-01 01:01:01.079627\"," +
21-
"\"subscription\": \"mocksub\"," +
22-
"\"tenant\": \"mocktenant\"," +
23-
"\"tokenType\": \"mocktype\"}"), nil
20+
return []byte(`{
21+
"accessToken": "mocktoken",
22+
"expiresOn": "2001-02-03 04:05:06.000007",
23+
"subscription": "mocksub",
24+
"tenant": "mocktenant",
25+
"tokenType": "Bearer"
26+
}
27+
`), nil
2428
}
2529
mockCLITokenProviderFailure = func(ctx context.Context, resource string, tenantID string) ([]byte, error) {
2630
return nil, errors.New("provider failure message")
@@ -32,17 +36,18 @@ func TestAzureCLICredential_GetTokenSuccess(t *testing.T) {
3236
options.tokenProvider = mockCLITokenProviderSuccess
3337
cred, err := NewAzureCLICredential(&options)
3438
if err != nil {
35-
t.Fatalf("Unable to create credential. Received: %v", err)
39+
t.Fatal(err)
3640
}
3741
at, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{Scopes: []string{liveTestScope}})
3842
if err != nil {
39-
t.Fatalf("Expected an empty error but received: %v", err)
40-
}
41-
if len(at.Token) == 0 {
42-
t.Fatalf(("Did not receive a token"))
43+
t.Fatal(err)
4344
}
4445
if at.Token != "mocktoken" {
45-
t.Fatalf(("Did not receive the correct access token"))
46+
t.Fatalf("unexpected access token %q", at.Token)
47+
}
48+
expected := time.Date(2001, 2, 3, 4, 5, 6, 7000, time.Local).UTC()
49+
if actual := at.ExpiresOn; !actual.Equal(expected) || actual.Location() != time.UTC {
50+
t.Fatalf("expected %q, got %q", expected, actual)
4651
}
4752
}
4853

0 commit comments

Comments
 (0)