Skip to content
This repository was archived by the owner on Feb 12, 2025. It is now read-only.

Commit c8219f8

Browse files
committed
v10.0.0, merge branch 'dev'
2 parents fc3b03a + 07b95bc commit c8219f8

23 files changed

+865
-327
lines changed

.travis.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@ language: go
55
go:
66
- 1.9
77
- 1.8
8-
- 1.7
98

109
install:
1110
- go get -u github.com/golang/lint/golint
12-
- go get -u github.com/Masterminds/glide
11+
- go get -u github.com/golang/dep/cmd/dep
1312
- go get -u github.com/stretchr/testify
1413
- go get -u github.com/GoASTScanner/gas
15-
- glide install
14+
- dep ensure
1615

1716
script:
1817
- grep -L -r --include *.go --exclude-dir vendor -P "Copyright (\d{4}|\(c\)) Microsoft" ./ | tee /dev/stderr | test -z "$(< /dev/stdin)"

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
# CHANGELOG
22

3+
## v10.0.0
4+
5+
### New Features
6+
7+
- Added target and innererror fields to ServiceError to comply with OData v4 spec.
8+
- The Done() method on futures will now return a ServiceError object when available (it used to return a partial value of such errors).
9+
- Added helper methods for obtaining authorizers.
10+
- Expose the polling URL for futures.
11+
12+
### Bug Fixes
13+
14+
- Switched from glide to dep for dependency management.
15+
- Fixed unmarshaling of ServiceError for JSON bodies that don't conform to the OData spec.
16+
- Fixed a race condition in token refresh.
17+
18+
### Breaking Changes
19+
20+
- The ServiceError.Details field type has been changed to match the OData v4 spec.
21+
- Go v1.7 has been dropped from CI.
22+
- API parameter validation failures will now return a unique error type validation.Error.
23+
- The adal.Token type has been decomposed from adal.ServicePrincipalToken (this was necessary in order to fix the token refresh race).
24+
325
## v9.10.0
426
- Fix the Service Bus suffix in Azure public env
527
- Add Service Bus Endpoint (AAD ResourceURI) for use in [Azure Service Bus RBAC Preview](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-role-based-access-control)

Gopkg.lock

Lines changed: 51 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Gopkg.toml example
2+
#
3+
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
4+
# for detailed Gopkg.toml documentation.
5+
#
6+
# required = ["github.com/user/thing/cmd/thing"]
7+
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
8+
#
9+
# [[constraint]]
10+
# name = "github.com/user/project"
11+
# version = "1.0.0"
12+
#
13+
# [[constraint]]
14+
# name = "github.com/user/project2"
15+
# branch = "dev"
16+
# source = "github.com/myfork/project2"
17+
#
18+
# [[override]]
19+
# name = "github.com/x/y"
20+
# version = "2.4.0"
21+
22+
23+
[[constraint]]
24+
name = "github.com/dgrijalva/jwt-go"
25+
version = "3.1.0"
26+
27+
[[constraint]]
28+
branch = "master"
29+
name = "github.com/dimchansky/utfbom"
30+
31+
[[constraint]]
32+
branch = "master"
33+
name = "github.com/mitchellh/go-homedir"
34+
35+
[[constraint]]
36+
name = "github.com/stretchr/testify"
37+
version = "1.2.0"
38+
39+
[[constraint]]
40+
branch = "master"
41+
name = "golang.org/x/crypto"

autorest/adal/cmd/adal.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ func main() {
281281
resource,
282282
callback)
283283
if err == nil {
284-
err = saveToken(spt.Token)
284+
err = saveToken(spt.Token())
285285
}
286286
case refreshMode:
287287
_, err = refreshToken(

autorest/adal/token.go

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -243,16 +243,15 @@ func (secret *ServicePrincipalCertificateSecret) SetAuthenticationValues(spt *Se
243243

244244
// ServicePrincipalToken encapsulates a Token created for a Service Principal.
245245
type ServicePrincipalToken struct {
246-
Token
247-
248-
secret ServicePrincipalSecret
249-
oauthConfig OAuthConfig
250-
clientID string
251-
resource string
252-
autoRefresh bool
253-
autoRefreshLock *sync.Mutex
254-
refreshWithin time.Duration
255-
sender Sender
246+
token Token
247+
secret ServicePrincipalSecret
248+
oauthConfig OAuthConfig
249+
clientID string
250+
resource string
251+
autoRefresh bool
252+
refreshLock *sync.RWMutex
253+
refreshWithin time.Duration
254+
sender Sender
256255

257256
refreshCallbacks []TokenRefreshCallback
258257
}
@@ -284,7 +283,7 @@ func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, reso
284283
clientID: id,
285284
resource: resource,
286285
autoRefresh: true,
287-
autoRefreshLock: &sync.Mutex{},
286+
refreshLock: &sync.RWMutex{},
288287
refreshWithin: defaultRefresh,
289288
sender: &http.Client{},
290289
refreshCallbacks: callbacks,
@@ -316,7 +315,7 @@ func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID s
316315
return nil, err
317316
}
318317

319-
spt.Token = token
318+
spt.token = token
320319

321320
return spt, nil
322321
}
@@ -502,7 +501,7 @@ func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedI
502501
secret: &ServicePrincipalMSISecret{},
503502
resource: resource,
504503
autoRefresh: true,
505-
autoRefreshLock: &sync.Mutex{},
504+
refreshLock: &sync.RWMutex{},
506505
refreshWithin: defaultRefresh,
507506
sender: &http.Client{},
508507
refreshCallbacks: callbacks,
@@ -538,12 +537,12 @@ func newTokenRefreshError(message string, resp *http.Response) TokenRefreshError
538537
// EnsureFresh will refresh the token if it will expire within the refresh window (as set by
539538
// RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use.
540539
func (spt *ServicePrincipalToken) EnsureFresh() error {
541-
if spt.autoRefresh && spt.WillExpireIn(spt.refreshWithin) {
542-
// take the lock then check to see if the token was already refreshed
543-
spt.autoRefreshLock.Lock()
544-
defer spt.autoRefreshLock.Unlock()
545-
if spt.WillExpireIn(spt.refreshWithin) {
546-
return spt.Refresh()
540+
if spt.autoRefresh && spt.token.WillExpireIn(spt.refreshWithin) {
541+
// take the write lock then check to see if the token was already refreshed
542+
spt.refreshLock.Lock()
543+
defer spt.refreshLock.Unlock()
544+
if spt.token.WillExpireIn(spt.refreshWithin) {
545+
return spt.refreshInternal(spt.resource)
547546
}
548547
}
549548
return nil
@@ -553,7 +552,7 @@ func (spt *ServicePrincipalToken) EnsureFresh() error {
553552
func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error {
554553
if spt.refreshCallbacks != nil {
555554
for _, callback := range spt.refreshCallbacks {
556-
err := callback(spt.Token)
555+
err := callback(spt.token)
557556
if err != nil {
558557
return fmt.Errorf("adal: TokenRefreshCallback handler failed. Error = '%v'", err)
559558
}
@@ -565,12 +564,16 @@ func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error {
565564
// Refresh obtains a fresh token for the Service Principal.
566565
// This method is not safe for concurrent use and should be syncrhonized.
567566
func (spt *ServicePrincipalToken) Refresh() error {
567+
spt.refreshLock.Lock()
568+
defer spt.refreshLock.Unlock()
568569
return spt.refreshInternal(spt.resource)
569570
}
570571

571572
// RefreshExchange refreshes the token, but for a different resource.
572573
// This method is not safe for concurrent use and should be syncrhonized.
573574
func (spt *ServicePrincipalToken) RefreshExchange(resource string) error {
575+
spt.refreshLock.Lock()
576+
defer spt.refreshLock.Unlock()
574577
return spt.refreshInternal(resource)
575578
}
576579

@@ -590,9 +593,9 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
590593
v.Set("client_id", spt.clientID)
591594
v.Set("resource", resource)
592595

593-
if spt.RefreshToken != "" {
596+
if spt.token.RefreshToken != "" {
594597
v.Set("grant_type", OAuthGrantTypeRefreshToken)
595-
v.Set("refresh_token", spt.RefreshToken)
598+
v.Set("refresh_token", spt.token.RefreshToken)
596599
} else {
597600
v.Set("grant_type", spt.getGrantType())
598601
err := spt.secret.SetAuthenticationValues(spt, &v)
@@ -640,7 +643,7 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
640643
return fmt.Errorf("adal: Failed to unmarshal the service principal token during refresh. Error = '%v' JSON = '%s'", err, string(rb))
641644
}
642645

643-
spt.Token = token
646+
spt.token = token
644647

645648
return spt.InvokeRefreshCallbacks(token)
646649
}
@@ -660,3 +663,17 @@ func (spt *ServicePrincipalToken) SetRefreshWithin(d time.Duration) {
660663
// SetSender sets the http.Client used when obtaining the Service Principal token. An
661664
// undecorated http.Client is used by default.
662665
func (spt *ServicePrincipalToken) SetSender(s Sender) { spt.sender = s }
666+
667+
// OAuthToken implements the OAuthTokenProvider interface. It returns the current access token.
668+
func (spt *ServicePrincipalToken) OAuthToken() string {
669+
spt.refreshLock.RLock()
670+
defer spt.refreshLock.RUnlock()
671+
return spt.token.OAuthToken()
672+
}
673+
674+
// Token returns a copy of the current token.
675+
func (spt *ServicePrincipalToken) Token() Token {
676+
spt.refreshLock.RLock()
677+
defer spt.refreshLock.RUnlock()
678+
return spt.token
679+
}

autorest/adal/token_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -445,20 +445,20 @@ func TestServicePrincipalTokenRefreshUnmarshals(t *testing.T) {
445445
err := spt.Refresh()
446446
if err != nil {
447447
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
448-
} else if spt.AccessToken != "accessToken" ||
449-
spt.ExpiresIn != "3600" ||
450-
spt.ExpiresOn != expiresOn ||
451-
spt.NotBefore != expiresOn ||
452-
spt.Resource != "resource" ||
453-
spt.Type != "Bearer" {
448+
} else if spt.token.AccessToken != "accessToken" ||
449+
spt.token.ExpiresIn != "3600" ||
450+
spt.token.ExpiresOn != expiresOn ||
451+
spt.token.NotBefore != expiresOn ||
452+
spt.token.Resource != "resource" ||
453+
spt.token.Type != "Bearer" {
454454
t.Fatalf("adal: ServicePrincipalToken#Refresh failed correctly unmarshal the JSON -- expected %v, received %v",
455455
j, *spt)
456456
}
457457
}
458458

459459
func TestServicePrincipalTokenEnsureFreshRefreshes(t *testing.T) {
460460
spt := newServicePrincipalToken()
461-
expireToken(&spt.Token)
461+
expireToken(&spt.token)
462462

463463
body := mocks.NewBody(newTokenJSON("test", "test"))
464464
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
@@ -486,7 +486,7 @@ func TestServicePrincipalTokenEnsureFreshRefreshes(t *testing.T) {
486486

487487
func TestServicePrincipalTokenEnsureFreshSkipsIfFresh(t *testing.T) {
488488
spt := newServicePrincipalToken()
489-
setTokenToExpireIn(&spt.Token, 1000*time.Second)
489+
setTokenToExpireIn(&spt.token, 1000*time.Second)
490490

491491
f := false
492492
c := mocks.NewSender()
@@ -553,7 +553,7 @@ func TestRefreshCallbackErrorPropagates(t *testing.T) {
553553
// This demonstrates the danger of manual token without a refresh token
554554
func TestServicePrincipalTokenManualRefreshFailsWithoutRefresh(t *testing.T) {
555555
spt := newServicePrincipalTokenManual()
556-
spt.RefreshToken = ""
556+
spt.token.RefreshToken = ""
557557
err := spt.Refresh()
558558
if err == nil {
559559
t.Fatalf("adal: ServicePrincipalToken#Refresh should have failed with a ManualTokenSecret without a refresh token")

autorest/authorization_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func TestServicePrincipalTokenWithAuthorizationNoRefresh(t *testing.T) {
7575
req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization())
7676
if err != nil {
7777
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
78-
} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.AccessToken) {
78+
} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.OAuthToken()) {
7979
t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header")
8080
}
8181
}
@@ -120,7 +120,7 @@ func TestServicePrincipalTokenWithAuthorizationRefresh(t *testing.T) {
120120
req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization())
121121
if err != nil {
122122
t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
123-
} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.AccessToken) {
123+
} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.OAuthToken()) {
124124
t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header")
125125
}
126126

0 commit comments

Comments
 (0)