diff --git a/autorest/adal/token.go b/autorest/adal/token.go index 559fc6653..55361139a 100644 --- a/autorest/adal/token.go +++ b/autorest/adal/token.go @@ -33,6 +33,9 @@ const ( // managedIdentitySettingsPath is the path to the MSI Extension settings file (to discover the endpoint) managedIdentitySettingsPath = "/var/lib/waagent/ManagedIdentity-Settings" + + // metadataHeader is the header required by MSI extension + metadataHeader = "Metadata" ) var expirationBase time.Time @@ -364,6 +367,9 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error { req.ContentLength = int64(len(s)) req.Header.Set(contentType, mimeTypeFormPost) + if _, ok := spt.secret.(*ServicePrincipalMSISecret); ok { + req.Header.Set(metadataHeader, "true") + } resp, err := spt.sender.Do(req) if err != nil { return fmt.Errorf("adal: Failed to execute the refresh request. Error = '%v'", err) diff --git a/autorest/adal/token_test.go b/autorest/adal/token_test.go index 9c92f4198..d63a9cdc3 100644 --- a/autorest/adal/token_test.go +++ b/autorest/adal/token_test.go @@ -133,6 +133,67 @@ func TestServicePrincipalTokenRefreshUsesPOST(t *testing.T) { } } +func TestServicePrincipalTokenFromMSIRefreshUsesPOST(t *testing.T) { + resource := "https://resource" + + cb := func(token Token) error { return nil } + tempSettingsFile, err := ioutil.TempFile("", "ManagedIdentity-Settings") + if err != nil { + t.Fatal("Couldn't write temp settings file") + } + defer os.Remove(tempSettingsFile.Name()) + + settingsContents := []byte(`{ + "url": "http://msiendpoint/" + }`) + + if _, err := tempSettingsFile.Write(settingsContents); err != nil { + t.Fatal("Couldn't fill temp settings file") + } + + oauthConfig, err := NewOAuthConfig("http://adendpoint", "1-2-3-4") + if err != nil { + t.Fatal("Failed to construct oauthconfig") + } + + spt, err := newServicePrincipalTokenFromMSI( + *oauthConfig, + resource, + tempSettingsFile.Name(), + cb) + if err != nil { + t.Fatalf("Failed to get MSI SPT: %v", err) + } + + body := mocks.NewBody(newTokenJSON("test", "test")) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK") + + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + if r.Method != "POST" { + t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set HTTP method -- expected %v, received %v", "POST", r.Method) + } + if h := r.Header.Get("Metadata"); h != "true" { + t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set Metadata header for MSI") + } + return resp, nil + }) + } + })()) + spt.SetSender(s) + err = spt.Refresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err) + } + + if body.IsOpen() { + t.Fatalf("the response was not closed!") + } +} + func TestServicePrincipalTokenRefreshSetsMimeType(t *testing.T) { spt := newServicePrincipalToken()