diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index e5decfa4..2c2f1aab 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,6 @@ { "ImportPath": "k8s.io/client-go", - "GoVersion": "go1.10", + "GoVersion": "go1.9", "GodepVersion": "v80", "Packages": [ "./..." @@ -16,19 +16,19 @@ }, { "ImportPath": "github.com/Azure/go-autorest/autorest", - "Rev": "d4e6b95c12a08b4de2d48b45d5b4d594e5d32fab" + "Rev": "1ff28809256a84bb6966640ff3d0371af82ccba4" }, { "ImportPath": "github.com/Azure/go-autorest/autorest/adal", - "Rev": "d4e6b95c12a08b4de2d48b45d5b4d594e5d32fab" + "Rev": "1ff28809256a84bb6966640ff3d0371af82ccba4" }, { "ImportPath": "github.com/Azure/go-autorest/autorest/azure", - "Rev": "d4e6b95c12a08b4de2d48b45d5b4d594e5d32fab" + "Rev": "1ff28809256a84bb6966640ff3d0371af82ccba4" }, { "ImportPath": "github.com/Azure/go-autorest/autorest/date", - "Rev": "d4e6b95c12a08b4de2d48b45d5b4d594e5d32fab" + "Rev": "1ff28809256a84bb6966640ff3d0371af82ccba4" }, { "ImportPath": "github.com/davecgh/go-spew/spew", @@ -368,215 +368,215 @@ }, { "ImportPath": "k8s.io/apimachinery/pkg/api/equality", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/errors", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/meta", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/resource", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/testing", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/testing/fuzzer", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/testing/roundtrip", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/apimachinery", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1beta1", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/conversion", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/fields", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/labels", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/selection", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/types", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/cache", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/clock", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/diff", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/errors", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/framer", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/intstr", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/json", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/net", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/runtime", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/sets", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/validation", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/wait", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/yaml", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/version", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/pkg/watch", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", - "Rev": "b39a8bdff32033fd1f645f17f1625f3b691124b6" + "Rev": "6ad68b3c504c71a07c48328779d8b5aabe2e4dd9" }, { "ImportPath": "k8s.io/kube-openapi/pkg/util/proto", diff --git a/plugin/pkg/client/auth/azure/azure.go b/plugin/pkg/client/auth/azure/azure.go index e14dc8d9..60304b0f 100644 --- a/plugin/pkg/client/auth/azure/azure.go +++ b/plugin/pkg/client/auth/azure/azure.go @@ -297,7 +297,7 @@ func (ts *azureTokenSource) refreshToken(token *azureToken) (*azureToken, error) } return &azureToken{ - token: spt.Token, + token: spt.Token(), clientID: token.clientID, tenantID: token.tenantID, apiserverID: token.apiserverID, diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/README.md b/vendor/github.com/Azure/go-autorest/autorest/adal/README.md index 08966c9c..7b0c4bc4 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/README.md +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/README.md @@ -1,19 +1,24 @@ -# Azure Active Directory library for Go +# Azure Active Directory authentication for Go -This project provides a stand alone Azure Active Directory library for Go. The code was extracted -from [go-autorest](https://github.com/Azure/go-autorest/) project, which is used as a base for -[azure-sdk-for-go](https://github.com/Azure/azure-sdk-for-go). +This is a standalone package for authenticating with Azure Active +Directory from other Go libraries and applications, in particular the [Azure SDK +for Go](https://github.com/Azure/azure-sdk-for-go). +Note: Despite the package's name it is not related to other "ADAL" libraries +maintained in the [github.com/AzureAD](https://github.com/AzureAD) org. Issues +should be opened in [this repo's](https://github.com/Azure/go-autorest/issues) +or [the SDK's](https://github.com/Azure/azure-sdk-for-go/issues) issue +trackers. -## Installation +## Install -``` +```bash go get -u github.com/Azure/go-autorest/autorest/adal ``` ## Usage -An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) follow these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli). +An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) by following these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli). ### Register an Azure AD Application with secret diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/msi.go b/vendor/github.com/Azure/go-autorest/autorest/adal/msi.go deleted file mode 100644 index 5e02d52a..00000000 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/msi.go +++ /dev/null @@ -1,20 +0,0 @@ -// +build !windows - -package adal - -// Copyright 2017 Microsoft Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// msiPath is the path to the MSI Extension settings file (to discover the endpoint) -var msiPath = "/var/lib/waagent/ManagedIdentity-Settings" diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/msi_windows.go b/vendor/github.com/Azure/go-autorest/autorest/adal/msi_windows.go deleted file mode 100644 index 261b5688..00000000 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/msi_windows.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build windows - -package adal - -// Copyright 2017 Microsoft Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import ( - "os" - "strings" -) - -// msiPath is the path to the MSI Extension settings file (to discover the endpoint) -var msiPath = strings.Join([]string{os.Getenv("SystemDrive"), "WindowsAzure/Config/ManagedIdentity-Settings"}, "/") diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/token.go b/vendor/github.com/Azure/go-autorest/autorest/adal/token.go index 941af281..24641b62 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/token.go +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/token.go @@ -54,6 +54,9 @@ const ( // metadataHeader is the header required by MSI extension metadataHeader = "Metadata" + + // msiEndpoint is the well known endpoint for getting MSI authentications tokens + msiEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token" ) // OAuthTokenProvider is an interface which should be implemented by an access token retriever @@ -243,16 +246,15 @@ func (secret *ServicePrincipalCertificateSecret) SetAuthenticationValues(spt *Se // ServicePrincipalToken encapsulates a Token created for a Service Principal. type ServicePrincipalToken struct { - Token - - secret ServicePrincipalSecret - oauthConfig OAuthConfig - clientID string - resource string - autoRefresh bool - autoRefreshLock *sync.Mutex - refreshWithin time.Duration - sender Sender + token Token + secret ServicePrincipalSecret + oauthConfig OAuthConfig + clientID string + resource string + autoRefresh bool + refreshLock *sync.RWMutex + refreshWithin time.Duration + sender Sender refreshCallbacks []TokenRefreshCallback } @@ -284,7 +286,7 @@ func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, reso clientID: id, resource: resource, autoRefresh: true, - autoRefreshLock: &sync.Mutex{}, + refreshLock: &sync.RWMutex{}, refreshWithin: defaultRefresh, sender: &http.Client{}, refreshCallbacks: callbacks, @@ -316,7 +318,7 @@ func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID s return nil, err } - spt.Token = token + spt.token = token return spt, nil } @@ -442,24 +444,7 @@ func NewServicePrincipalTokenFromAuthorizationCode(oauthConfig OAuthConfig, clie // GetMSIVMEndpoint gets the MSI endpoint on Virtual Machines. func GetMSIVMEndpoint() (string, error) { - return getMSIVMEndpoint(msiPath) -} - -func getMSIVMEndpoint(path string) (string, error) { - // Read MSI settings - bytes, err := ioutil.ReadFile(path) - if err != nil { - return "", err - } - msiSettings := struct { - URL string `json:"url"` - }{} - err = json.Unmarshal(bytes, &msiSettings) - if err != nil { - return "", err - } - - return msiSettings.URL, nil + return msiEndpoint, nil } // NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension. @@ -492,17 +477,22 @@ func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedI return nil, err } - oauthConfig, err := NewOAuthConfig(msiEndpointURL.String(), "") - if err != nil { - return nil, err + v := url.Values{} + v.Set("resource", resource) + v.Set("api-version", "2018-02-01") + if userAssignedID != nil { + v.Set("client_id", *userAssignedID) } + msiEndpointURL.RawQuery = v.Encode() spt := &ServicePrincipalToken{ - oauthConfig: *oauthConfig, + oauthConfig: OAuthConfig{ + TokenEndpoint: *msiEndpointURL, + }, secret: &ServicePrincipalMSISecret{}, resource: resource, autoRefresh: true, - autoRefreshLock: &sync.Mutex{}, + refreshLock: &sync.RWMutex{}, refreshWithin: defaultRefresh, sender: &http.Client{}, refreshCallbacks: callbacks, @@ -538,12 +528,12 @@ func newTokenRefreshError(message string, resp *http.Response) TokenRefreshError // EnsureFresh will refresh the token if it will expire within the refresh window (as set by // RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use. func (spt *ServicePrincipalToken) EnsureFresh() error { - if spt.autoRefresh && spt.WillExpireIn(spt.refreshWithin) { - // take the lock then check to see if the token was already refreshed - spt.autoRefreshLock.Lock() - defer spt.autoRefreshLock.Unlock() - if spt.WillExpireIn(spt.refreshWithin) { - return spt.Refresh() + if spt.autoRefresh && spt.token.WillExpireIn(spt.refreshWithin) { + // take the write lock then check to see if the token was already refreshed + spt.refreshLock.Lock() + defer spt.refreshLock.Unlock() + if spt.token.WillExpireIn(spt.refreshWithin) { + return spt.refreshInternal(spt.resource) } } return nil @@ -553,7 +543,7 @@ func (spt *ServicePrincipalToken) EnsureFresh() error { func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error { if spt.refreshCallbacks != nil { for _, callback := range spt.refreshCallbacks { - err := callback(spt.Token) + err := callback(spt.token) if err != nil { return fmt.Errorf("adal: TokenRefreshCallback handler failed. Error = '%v'", err) } @@ -565,12 +555,16 @@ func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error { // Refresh obtains a fresh token for the Service Principal. // This method is not safe for concurrent use and should be syncrhonized. func (spt *ServicePrincipalToken) Refresh() error { + spt.refreshLock.Lock() + defer spt.refreshLock.Unlock() return spt.refreshInternal(spt.resource) } // RefreshExchange refreshes the token, but for a different resource. // This method is not safe for concurrent use and should be syncrhonized. func (spt *ServicePrincipalToken) RefreshExchange(resource string) error { + spt.refreshLock.Lock() + defer spt.refreshLock.Unlock() return spt.refreshInternal(resource) } @@ -585,35 +579,54 @@ func (spt *ServicePrincipalToken) getGrantType() string { } } -func (spt *ServicePrincipalToken) refreshInternal(resource string) error { - v := url.Values{} - v.Set("client_id", spt.clientID) - v.Set("resource", resource) - - if spt.RefreshToken != "" { - v.Set("grant_type", OAuthGrantTypeRefreshToken) - v.Set("refresh_token", spt.RefreshToken) - } else { - v.Set("grant_type", spt.getGrantType()) - err := spt.secret.SetAuthenticationValues(spt, &v) - if err != nil { - return err - } +func isIMDS(u url.URL) bool { + imds, err := url.Parse(msiEndpoint) + if err != nil { + return false } + return u.Host == imds.Host && u.Path == imds.Path +} - s := v.Encode() - body := ioutil.NopCloser(strings.NewReader(s)) - req, err := http.NewRequest(http.MethodPost, spt.oauthConfig.TokenEndpoint.String(), body) +func (spt *ServicePrincipalToken) refreshInternal(resource string) error { + req, err := http.NewRequest(http.MethodPost, spt.oauthConfig.TokenEndpoint.String(), nil) if err != nil { return fmt.Errorf("adal: Failed to build the refresh request. Error = '%v'", err) } - req.ContentLength = int64(len(s)) - req.Header.Set(contentType, mimeTypeFormPost) + if !isIMDS(spt.oauthConfig.TokenEndpoint) { + v := url.Values{} + v.Set("client_id", spt.clientID) + v.Set("resource", resource) + + if spt.token.RefreshToken != "" { + v.Set("grant_type", OAuthGrantTypeRefreshToken) + v.Set("refresh_token", spt.token.RefreshToken) + } else { + v.Set("grant_type", spt.getGrantType()) + err := spt.secret.SetAuthenticationValues(spt, &v) + if err != nil { + return err + } + } + + s := v.Encode() + body := ioutil.NopCloser(strings.NewReader(s)) + req.ContentLength = int64(len(s)) + req.Header.Set(contentType, mimeTypeFormPost) + req.Body = body + } + if _, ok := spt.secret.(*ServicePrincipalMSISecret); ok { + req.Method = http.MethodGet req.Header.Set(metadataHeader, "true") } - resp, err := spt.sender.Do(req) + + var resp *http.Response + if isIMDS(spt.oauthConfig.TokenEndpoint) { + resp, err = retry(spt.sender, req) + } else { + resp, err = spt.sender.Do(req) + } if err != nil { return fmt.Errorf("adal: Failed to execute the refresh request. Error = '%v'", err) } @@ -640,11 +653,84 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error { return fmt.Errorf("adal: Failed to unmarshal the service principal token during refresh. Error = '%v' JSON = '%s'", err, string(rb)) } - spt.Token = token + spt.token = token return spt.InvokeRefreshCallbacks(token) } +func retry(sender Sender, req *http.Request) (resp *http.Response, err error) { + retries := []int{ + http.StatusRequestTimeout, // 408 + http.StatusTooManyRequests, // 429 + http.StatusInternalServerError, // 500 + http.StatusBadGateway, // 502 + http.StatusServiceUnavailable, // 503 + http.StatusGatewayTimeout, // 504 + } + // Extra retry status codes requered + retries = append(retries, http.StatusNotFound, + // all remaining 5xx + http.StatusNotImplemented, + http.StatusHTTPVersionNotSupported, + http.StatusVariantAlsoNegotiates, + http.StatusInsufficientStorage, + http.StatusLoopDetected, + http.StatusNotExtended, + http.StatusNetworkAuthenticationRequired) + + attempt := 0 + maxAttempts := 5 + + for attempt < maxAttempts { + resp, err = sender.Do(req) + if err != nil { + return + } + + if resp.StatusCode == http.StatusOK { + return + } + if containsInt(retries, resp.StatusCode) { + delayed := false + if resp.StatusCode == http.StatusTooManyRequests { + delayed = delay(resp, req.Cancel) + } + if !delayed { + time.Sleep(time.Second) + attempt++ + } + } else { + return + } + } + return +} + +func containsInt(ints []int, n int) bool { + for _, i := range ints { + if i == n { + return true + } + } + return false +} + +func delay(resp *http.Response, cancel <-chan struct{}) bool { + if resp == nil { + return false + } + retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After")) + if resp.StatusCode == http.StatusTooManyRequests && retryAfter > 0 { + select { + case <-time.After(time.Duration(retryAfter) * time.Second): + return true + case <-cancel: + return false + } + } + return false +} + // SetAutoRefresh enables or disables automatic refreshing of stale tokens. func (spt *ServicePrincipalToken) SetAutoRefresh(autoRefresh bool) { spt.autoRefresh = autoRefresh @@ -660,3 +746,17 @@ func (spt *ServicePrincipalToken) SetRefreshWithin(d time.Duration) { // SetSender sets the http.Client used when obtaining the Service Principal token. An // undecorated http.Client is used by default. func (spt *ServicePrincipalToken) SetSender(s Sender) { spt.sender = s } + +// OAuthToken implements the OAuthTokenProvider interface. It returns the current access token. +func (spt *ServicePrincipalToken) OAuthToken() string { + spt.refreshLock.RLock() + defer spt.refreshLock.RUnlock() + return spt.token.OAuthToken() +} + +// Token returns a copy of the current token. +func (spt *ServicePrincipalToken) Token() Token { + spt.refreshLock.RLock() + defer spt.refreshLock.RUnlock() + return spt.token +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/authorization.go b/vendor/github.com/Azure/go-autorest/autorest/authorization.go index 4a602f67..c51eac0a 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/authorization.go +++ b/vendor/github.com/Azure/go-autorest/autorest/authorization.go @@ -104,10 +104,6 @@ func NewBearerAuthorizer(tp adal.OAuthTokenProvider) *BearerAuthorizer { return &BearerAuthorizer{tokenProvider: tp} } -func (ba *BearerAuthorizer) withBearerAuthorization() PrepareDecorator { - return WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", ba.tokenProvider.OAuthToken())) -} - // WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose // value is "Bearer " followed by the token. // @@ -115,19 +111,23 @@ func (ba *BearerAuthorizer) withBearerAuthorization() PrepareDecorator { func (ba *BearerAuthorizer) WithAuthorization() PrepareDecorator { return func(p Preparer) Preparer { return PreparerFunc(func(r *http.Request) (*http.Request, error) { - refresher, ok := ba.tokenProvider.(adal.Refresher) - if ok { - err := refresher.EnsureFresh() - if err != nil { - var resp *http.Response - if tokError, ok := err.(adal.TokenRefreshError); ok { - resp = tokError.Response() + r, err := p.Prepare(r) + if err == nil { + refresher, ok := ba.tokenProvider.(adal.Refresher) + if ok { + err := refresher.EnsureFresh() + if err != nil { + var resp *http.Response + if tokError, ok := err.(adal.TokenRefreshError); ok { + resp = tokError.Response() + } + return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", resp, + "Failed to refresh the Token for request to %s", r.URL) } - return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", resp, - "Failed to refresh the Token for request to %s", r.URL) } + return Prepare(r, WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", ba.tokenProvider.OAuthToken()))) } - return (ba.withBearerAuthorization()(p)).Prepare(r) + return r, err }) } } @@ -157,25 +157,28 @@ func NewBearerAuthorizerCallback(sender Sender, callback BearerAuthorizerCallbac func (bacb *BearerAuthorizerCallback) WithAuthorization() PrepareDecorator { return func(p Preparer) Preparer { return PreparerFunc(func(r *http.Request) (*http.Request, error) { - // make a copy of the request and remove the body as it's not - // required and avoids us having to create a copy of it. - rCopy := *r - removeRequestBody(&rCopy) + r, err := p.Prepare(r) + if err == nil { + // make a copy of the request and remove the body as it's not + // required and avoids us having to create a copy of it. + rCopy := *r + removeRequestBody(&rCopy) - resp, err := bacb.sender.Do(&rCopy) - if err == nil && resp.StatusCode == 401 { - defer resp.Body.Close() - if hasBearerChallenge(resp) { - bc, err := newBearerChallenge(resp) - if err != nil { - return r, err - } - if bacb.callback != nil { - ba, err := bacb.callback(bc.values[tenantID], bc.values["resource"]) + resp, err := bacb.sender.Do(&rCopy) + if err == nil && resp.StatusCode == 401 { + defer resp.Body.Close() + if hasBearerChallenge(resp) { + bc, err := newBearerChallenge(resp) if err != nil { return r, err } - return ba.WithAuthorization()(p).Prepare(r) + if bacb.callback != nil { + ba, err := bacb.callback(bc.values[tenantID], bc.values["resource"]) + if err != nil { + return r, err + } + return Prepare(r, ba.WithAuthorization()) + } } } } diff --git a/vendor/github.com/Azure/go-autorest/autorest/autorest.go b/vendor/github.com/Azure/go-autorest/autorest/autorest.go index f86b66a4..aafdf021 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/autorest.go +++ b/vendor/github.com/Azure/go-autorest/autorest/autorest.go @@ -72,6 +72,7 @@ package autorest // limitations under the License. import ( + "context" "net/http" "time" ) @@ -130,3 +131,20 @@ func NewPollingRequest(resp *http.Response, cancel <-chan struct{}) (*http.Reque return req, nil } + +// NewPollingRequestWithContext allocates and returns a new http.Request with the specified context to poll for the passed response. +func NewPollingRequestWithContext(ctx context.Context, resp *http.Response) (*http.Request, error) { + location := GetLocation(resp) + if location == "" { + return nil, NewErrorWithResponse("autorest", "NewPollingRequestWithContext", resp, "Location header missing from response that requires polling") + } + + req, err := Prepare((&http.Request{}).WithContext(ctx), + AsGet(), + WithBaseURL(location)) + if err != nil { + return nil, NewErrorWithError(err, "autorest", "NewPollingRequestWithContext", nil, "Failure creating poll request to %s", location) + } + + return req, nil +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/async.go b/vendor/github.com/Azure/go-autorest/autorest/azure/async.go index 366fc537..a58e5ef3 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/async.go +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/async.go @@ -78,13 +78,39 @@ func (f *Future) Done(sender autorest.Sender) (bool, error) { if f.ps.hasTerminated() { return true, f.errorInfo() } - resp, err := sender.Do(f.req) f.resp = resp - if err != nil || !autorest.ResponseHasStatusCode(resp, pollingCodes[:]...) { + if err != nil { return false, err } + if !autorest.ResponseHasStatusCode(resp, pollingCodes[:]...) { + // check response body for error content + if resp.Body != nil { + type respErr struct { + ServiceError ServiceError `json:"error"` + } + re := respErr{} + + defer resp.Body.Close() + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return false, err + } + err = json.Unmarshal(b, &re) + if err != nil { + return false, err + } + return false, re.ServiceError + } + + // try to return something meaningful + return false, ServiceError{ + Code: fmt.Sprintf("%v", resp.StatusCode), + Message: resp.Status, + } + } + err = updatePollingState(resp, &f.ps) if err != nil { return false, err @@ -185,6 +211,12 @@ func (f *Future) UnmarshalJSON(data []byte) error { return err } +// PollingURL returns the URL used for retrieving the status of the long-running operation. +// For LROs that use the Location header the final URL value is used to retrieve the result. +func (f Future) PollingURL() string { + return f.ps.URI +} + // DoPollForAsynchronous returns a SendDecorator that polls if the http.Response is for an Azure // long-running operation. It will delay between requests for the duration specified in the // RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled by @@ -217,7 +249,7 @@ func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator { if err != nil { return resp, err } - r.Cancel = resp.Request.Cancel + r = r.WithContext(resp.Request.Context()) delay = autorest.GetRetryAfter(resp, delay) resp, err = autorest.SendWithSender(s, r, @@ -300,7 +332,9 @@ func (ps provisioningStatus) hasTerminated() bool { } func (ps provisioningStatus) hasProvisioningError() bool { - return ps.ProvisioningError != ServiceError{} + // code and message are required fields so only check them + return len(ps.ProvisioningError.Code) > 0 || + len(ps.ProvisioningError.Message) > 0 } // PollingMethodType defines a type used for enumerating polling mechanisms. @@ -321,8 +355,7 @@ type pollingState struct { PollingMethod PollingMethodType `json:"pollingMethod"` URI string `json:"uri"` State string `json:"state"` - Code string `json:"code"` - Message string `json:"message"` + ServiceError *ServiceError `json:"error,omitempty"` } func (ps pollingState) hasSucceeded() bool { @@ -338,7 +371,11 @@ func (ps pollingState) hasFailed() bool { } func (ps pollingState) Error() string { - return fmt.Sprintf("Long running operation terminated with status '%s': Code=%q Message=%q", ps.State, ps.Code, ps.Message) + s := fmt.Sprintf("Long running operation terminated with status '%s'", ps.State) + if ps.ServiceError != nil { + s = fmt.Sprintf("%s: %+v", s, *ps.ServiceError) + } + return s } // updatePollingState maps the operation status -- retrieved from either a provisioningState @@ -430,18 +467,14 @@ func updatePollingState(resp *http.Response, ps *pollingState) error { // -- Response // -- Otherwise, Unknown if ps.hasFailed() { - if ps.PollingMethod == PollingAsyncOperation { - or := pt.(*operationResource) - ps.Code = or.OperationError.Code - ps.Message = or.OperationError.Message + if or, ok := pt.(*operationResource); ok { + ps.ServiceError = &or.OperationError + } else if p, ok := pt.(*provisioningStatus); ok && p.hasProvisioningError() { + ps.ServiceError = &p.ProvisioningError } else { - p := pt.(*provisioningStatus) - if p.hasProvisioningError() { - ps.Code = p.ProvisioningError.Code - ps.Message = p.ProvisioningError.Message - } else { - ps.Code = "Unknown" - ps.Message = "None" + ps.ServiceError = &ServiceError{ + Code: "Unknown", + Message: "None", } } } diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go b/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go index fa183564..18d02952 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go @@ -1,8 +1,5 @@ -/* -Package azure provides Azure-specific implementations used with AutoRest. - -See the included examples for more detail. -*/ +// Package azure provides Azure-specific implementations used with AutoRest. +// See the included examples for more detail. package azure // Copyright 2017 Microsoft Corporation @@ -24,7 +21,9 @@ import ( "fmt" "io/ioutil" "net/http" + "regexp" "strconv" + "strings" "github.com/Azure/go-autorest/autorest" ) @@ -43,21 +42,88 @@ const ( ) // ServiceError encapsulates the error response from an Azure service. +// It adhears to the OData v4 specification for error responses. type ServiceError struct { - Code string `json:"code"` - Message string `json:"message"` - Details *[]interface{} `json:"details"` + Code string `json:"code"` + Message string `json:"message"` + Target *string `json:"target"` + Details []map[string]interface{} `json:"details"` + InnerError map[string]interface{} `json:"innererror"` } func (se ServiceError) Error() string { - if se.Details != nil { - d, err := json.Marshal(*(se.Details)) - if err != nil { - return fmt.Sprintf("Code=%q Message=%q Details=%v", se.Code, se.Message, *se.Details) - } - return fmt.Sprintf("Code=%q Message=%q Details=%v", se.Code, se.Message, string(d)) + result := fmt.Sprintf("Code=%q Message=%q", se.Code, se.Message) + + if se.Target != nil { + result += fmt.Sprintf(" Target=%q", *se.Target) } - return fmt.Sprintf("Code=%q Message=%q", se.Code, se.Message) + + if se.Details != nil { + d, err := json.Marshal(se.Details) + if err != nil { + result += fmt.Sprintf(" Details=%v", se.Details) + } + result += fmt.Sprintf(" Details=%v", string(d)) + } + + if se.InnerError != nil { + d, err := json.Marshal(se.InnerError) + if err != nil { + result += fmt.Sprintf(" InnerError=%v", se.InnerError) + } + result += fmt.Sprintf(" InnerError=%v", string(d)) + } + + return result +} + +// UnmarshalJSON implements the json.Unmarshaler interface for the ServiceError type. +func (se *ServiceError) UnmarshalJSON(b []byte) error { + // per the OData v4 spec the details field must be an array of JSON objects. + // unfortunately not all services adhear to the spec and just return a single + // object instead of an array with one object. so we have to perform some + // shenanigans to accommodate both cases. + // http://docs.oasis-open.org/odata/odata-json-format/v4.0/os/odata-json-format-v4.0-os.html#_Toc372793091 + + type serviceError1 struct { + Code string `json:"code"` + Message string `json:"message"` + Target *string `json:"target"` + Details []map[string]interface{} `json:"details"` + InnerError map[string]interface{} `json:"innererror"` + } + + type serviceError2 struct { + Code string `json:"code"` + Message string `json:"message"` + Target *string `json:"target"` + Details map[string]interface{} `json:"details"` + InnerError map[string]interface{} `json:"innererror"` + } + + se1 := serviceError1{} + err := json.Unmarshal(b, &se1) + if err == nil { + se.populate(se1.Code, se1.Message, se1.Target, se1.Details, se1.InnerError) + return nil + } + + se2 := serviceError2{} + err = json.Unmarshal(b, &se2) + if err == nil { + se.populate(se2.Code, se2.Message, se2.Target, nil, se2.InnerError) + se.Details = append(se.Details, se2.Details) + return nil + } + return err +} + +func (se *ServiceError) populate(code, message string, target *string, details []map[string]interface{}, inner map[string]interface{}) { + se.Code = code + se.Message = message + se.Target = target + se.Details = details + se.InnerError = inner } // RequestError describes an error response returned by Azure service. @@ -83,6 +149,41 @@ func IsAzureError(e error) bool { return ok } +// Resource contains details about an Azure resource. +type Resource struct { + SubscriptionID string + ResourceGroup string + Provider string + ResourceType string + ResourceName string +} + +// ParseResourceID parses a resource ID into a ResourceDetails struct. +// See https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-resource#return-value-4. +func ParseResourceID(resourceID string) (Resource, error) { + + const resourceIDPatternText = `(?i)subscriptions/(.+)/resourceGroups/(.+)/providers/(.+?)/(.+?)/(.+)` + resourceIDPattern := regexp.MustCompile(resourceIDPatternText) + match := resourceIDPattern.FindStringSubmatch(resourceID) + + if len(match) == 0 { + return Resource{}, fmt.Errorf("parsing failed for %s. Invalid resource Id format", resourceID) + } + + v := strings.Split(match[5], "/") + resourceName := v[len(v)-1] + + result := Resource{ + SubscriptionID: match[1], + ResourceGroup: match[2], + Provider: match[3], + ResourceType: match[4], + ResourceName: resourceName, + } + + return result, nil +} + // NewErrorWithError creates a new Error conforming object from the // passed packageType, method, statusCode of the given resp (UndefinedStatusCode // if resp is nil), message, and original error. message is treated as a format diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go b/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go index 93683649..7e41f7fd 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go @@ -44,6 +44,8 @@ type Environment struct { GalleryEndpoint string `json:"galleryEndpoint"` KeyVaultEndpoint string `json:"keyVaultEndpoint"` GraphEndpoint string `json:"graphEndpoint"` + ServiceBusEndpoint string `json:"serviceBusEndpoint"` + BatchManagementEndpoint string `json:"batchManagementEndpoint"` StorageEndpointSuffix string `json:"storageEndpointSuffix"` SQLDatabaseDNSSuffix string `json:"sqlDatabaseDNSSuffix"` TrafficManagerDNSSuffix string `json:"trafficManagerDNSSuffix"` @@ -52,6 +54,7 @@ type Environment struct { ServiceManagementVMDNSSuffix string `json:"serviceManagementVMDNSSuffix"` ResourceManagerVMDNSSuffix string `json:"resourceManagerVMDNSSuffix"` ContainerRegistryDNSSuffix string `json:"containerRegistryDNSSuffix"` + TokenAudience string `json:"tokenAudience"` } var ( @@ -66,14 +69,17 @@ var ( GalleryEndpoint: "https://gallery.azure.com/", KeyVaultEndpoint: "https://vault.azure.net/", GraphEndpoint: "https://graph.windows.net/", + ServiceBusEndpoint: "https://servicebus.windows.net/", + BatchManagementEndpoint: "https://batch.core.windows.net/", StorageEndpointSuffix: "core.windows.net", SQLDatabaseDNSSuffix: "database.windows.net", TrafficManagerDNSSuffix: "trafficmanager.net", KeyVaultDNSSuffix: "vault.azure.net", - ServiceBusEndpointSuffix: "servicebus.azure.com", + ServiceBusEndpointSuffix: "servicebus.windows.net", ServiceManagementVMDNSSuffix: "cloudapp.net", ResourceManagerVMDNSSuffix: "cloudapp.azure.com", ContainerRegistryDNSSuffix: "azurecr.io", + TokenAudience: "https://management.azure.com/", } // USGovernmentCloud is the cloud environment for the US Government @@ -87,6 +93,8 @@ var ( GalleryEndpoint: "https://gallery.usgovcloudapi.net/", KeyVaultEndpoint: "https://vault.usgovcloudapi.net/", GraphEndpoint: "https://graph.windows.net/", + ServiceBusEndpoint: "https://servicebus.usgovcloudapi.net/", + BatchManagementEndpoint: "https://batch.core.usgovcloudapi.net/", StorageEndpointSuffix: "core.usgovcloudapi.net", SQLDatabaseDNSSuffix: "database.usgovcloudapi.net", TrafficManagerDNSSuffix: "usgovtrafficmanager.net", @@ -95,6 +103,7 @@ var ( ServiceManagementVMDNSSuffix: "usgovcloudapp.net", ResourceManagerVMDNSSuffix: "cloudapp.windowsazure.us", ContainerRegistryDNSSuffix: "azurecr.io", + TokenAudience: "https://management.usgovcloudapi.net/", } // ChinaCloud is the cloud environment operated in China @@ -108,14 +117,17 @@ var ( GalleryEndpoint: "https://gallery.chinacloudapi.cn/", KeyVaultEndpoint: "https://vault.azure.cn/", GraphEndpoint: "https://graph.chinacloudapi.cn/", + ServiceBusEndpoint: "https://servicebus.chinacloudapi.cn/", + BatchManagementEndpoint: "https://batch.chinacloudapi.cn/", StorageEndpointSuffix: "core.chinacloudapi.cn", SQLDatabaseDNSSuffix: "database.chinacloudapi.cn", TrafficManagerDNSSuffix: "trafficmanager.cn", KeyVaultDNSSuffix: "vault.azure.cn", - ServiceBusEndpointSuffix: "servicebus.chinacloudapi.net", + ServiceBusEndpointSuffix: "servicebus.chinacloudapi.cn", ServiceManagementVMDNSSuffix: "chinacloudapp.cn", ResourceManagerVMDNSSuffix: "cloudapp.azure.cn", ContainerRegistryDNSSuffix: "azurecr.io", + TokenAudience: "https://management.chinacloudapi.cn/", } // GermanCloud is the cloud environment operated in Germany @@ -129,6 +141,8 @@ var ( GalleryEndpoint: "https://gallery.cloudapi.de/", KeyVaultEndpoint: "https://vault.microsoftazure.de/", GraphEndpoint: "https://graph.cloudapi.de/", + ServiceBusEndpoint: "https://servicebus.cloudapi.de/", + BatchManagementEndpoint: "https://batch.cloudapi.de/", StorageEndpointSuffix: "core.cloudapi.de", SQLDatabaseDNSSuffix: "database.cloudapi.de", TrafficManagerDNSSuffix: "azuretrafficmanager.de", @@ -137,6 +151,7 @@ var ( ServiceManagementVMDNSSuffix: "azurecloudapp.de", ResourceManagerVMDNSSuffix: "cloudapp.microsoftazure.de", ContainerRegistryDNSSuffix: "azurecr.io", + TokenAudience: "https://management.microsoftazure.de/", } ) diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/metadata_environment.go b/vendor/github.com/Azure/go-autorest/autorest/azure/metadata_environment.go new file mode 100644 index 00000000..507f9e95 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/metadata_environment.go @@ -0,0 +1,245 @@ +package azure + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" +) + +// Copyright 2017 Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +type audience []string + +type authentication struct { + LoginEndpoint string `json:"loginEndpoint"` + Audiences audience `json:"audiences"` +} + +type environmentMetadataInfo struct { + GalleryEndpoint string `json:"galleryEndpoint"` + GraphEndpoint string `json:"graphEndpoint"` + PortalEndpoint string `json:"portalEndpoint"` + Authentication authentication `json:"authentication"` +} + +// EnvironmentProperty represent property names that clients can override +type EnvironmentProperty string + +const ( + // EnvironmentName ... + EnvironmentName EnvironmentProperty = "name" + // EnvironmentManagementPortalURL .. + EnvironmentManagementPortalURL EnvironmentProperty = "managementPortalURL" + // EnvironmentPublishSettingsURL ... + EnvironmentPublishSettingsURL EnvironmentProperty = "publishSettingsURL" + // EnvironmentServiceManagementEndpoint ... + EnvironmentServiceManagementEndpoint EnvironmentProperty = "serviceManagementEndpoint" + // EnvironmentResourceManagerEndpoint ... + EnvironmentResourceManagerEndpoint EnvironmentProperty = "resourceManagerEndpoint" + // EnvironmentActiveDirectoryEndpoint ... + EnvironmentActiveDirectoryEndpoint EnvironmentProperty = "activeDirectoryEndpoint" + // EnvironmentGalleryEndpoint ... + EnvironmentGalleryEndpoint EnvironmentProperty = "galleryEndpoint" + // EnvironmentKeyVaultEndpoint ... + EnvironmentKeyVaultEndpoint EnvironmentProperty = "keyVaultEndpoint" + // EnvironmentGraphEndpoint ... + EnvironmentGraphEndpoint EnvironmentProperty = "graphEndpoint" + // EnvironmentServiceBusEndpoint ... + EnvironmentServiceBusEndpoint EnvironmentProperty = "serviceBusEndpoint" + // EnvironmentBatchManagementEndpoint ... + EnvironmentBatchManagementEndpoint EnvironmentProperty = "batchManagementEndpoint" + // EnvironmentStorageEndpointSuffix ... + EnvironmentStorageEndpointSuffix EnvironmentProperty = "storageEndpointSuffix" + // EnvironmentSQLDatabaseDNSSuffix ... + EnvironmentSQLDatabaseDNSSuffix EnvironmentProperty = "sqlDatabaseDNSSuffix" + // EnvironmentTrafficManagerDNSSuffix ... + EnvironmentTrafficManagerDNSSuffix EnvironmentProperty = "trafficManagerDNSSuffix" + // EnvironmentKeyVaultDNSSuffix ... + EnvironmentKeyVaultDNSSuffix EnvironmentProperty = "keyVaultDNSSuffix" + // EnvironmentServiceBusEndpointSuffix ... + EnvironmentServiceBusEndpointSuffix EnvironmentProperty = "serviceBusEndpointSuffix" + // EnvironmentServiceManagementVMDNSSuffix ... + EnvironmentServiceManagementVMDNSSuffix EnvironmentProperty = "serviceManagementVMDNSSuffix" + // EnvironmentResourceManagerVMDNSSuffix ... + EnvironmentResourceManagerVMDNSSuffix EnvironmentProperty = "resourceManagerVMDNSSuffix" + // EnvironmentContainerRegistryDNSSuffix ... + EnvironmentContainerRegistryDNSSuffix EnvironmentProperty = "containerRegistryDNSSuffix" + // EnvironmentTokenAudience ... + EnvironmentTokenAudience EnvironmentProperty = "tokenAudience" +) + +// OverrideProperty represents property name and value that clients can override +type OverrideProperty struct { + Key EnvironmentProperty + Value string +} + +// EnvironmentFromURL loads an Environment from a URL +// This function is particularly useful in the Hybrid Cloud model, where one may define their own +// endpoints. +func EnvironmentFromURL(resourceManagerEndpoint string, properties ...OverrideProperty) (environment Environment, err error) { + var metadataEnvProperties environmentMetadataInfo + + if resourceManagerEndpoint == "" { + return environment, fmt.Errorf("Metadata resource manager endpoint is empty") + } + + if metadataEnvProperties, err = retrieveMetadataEnvironment(resourceManagerEndpoint); err != nil { + return environment, err + } + + // Give priority to user's override values + overrideProperties(&environment, properties) + + if environment.Name == "" { + environment.Name = "HybridEnvironment" + } + stampDNSSuffix := environment.StorageEndpointSuffix + if stampDNSSuffix == "" { + stampDNSSuffix = strings.TrimSuffix(strings.TrimPrefix(strings.Replace(resourceManagerEndpoint, strings.Split(resourceManagerEndpoint, ".")[0], "", 1), "."), "/") + environment.StorageEndpointSuffix = stampDNSSuffix + } + if environment.KeyVaultDNSSuffix == "" { + environment.KeyVaultDNSSuffix = fmt.Sprintf("%s.%s", "vault", stampDNSSuffix) + } + if environment.KeyVaultEndpoint == "" { + environment.KeyVaultEndpoint = fmt.Sprintf("%s%s", "https://", environment.KeyVaultDNSSuffix) + } + if environment.TokenAudience == "" { + environment.TokenAudience = metadataEnvProperties.Authentication.Audiences[0] + } + if environment.ActiveDirectoryEndpoint == "" { + environment.ActiveDirectoryEndpoint = metadataEnvProperties.Authentication.LoginEndpoint + } + if environment.ResourceManagerEndpoint == "" { + environment.ResourceManagerEndpoint = resourceManagerEndpoint + } + if environment.GalleryEndpoint == "" { + environment.GalleryEndpoint = metadataEnvProperties.GalleryEndpoint + } + if environment.GraphEndpoint == "" { + environment.GraphEndpoint = metadataEnvProperties.GraphEndpoint + } + + return environment, nil +} + +func overrideProperties(environment *Environment, properties []OverrideProperty) { + for _, property := range properties { + switch property.Key { + case EnvironmentName: + { + environment.Name = property.Value + } + case EnvironmentManagementPortalURL: + { + environment.ManagementPortalURL = property.Value + } + case EnvironmentPublishSettingsURL: + { + environment.PublishSettingsURL = property.Value + } + case EnvironmentServiceManagementEndpoint: + { + environment.ServiceManagementEndpoint = property.Value + } + case EnvironmentResourceManagerEndpoint: + { + environment.ResourceManagerEndpoint = property.Value + } + case EnvironmentActiveDirectoryEndpoint: + { + environment.ActiveDirectoryEndpoint = property.Value + } + case EnvironmentGalleryEndpoint: + { + environment.GalleryEndpoint = property.Value + } + case EnvironmentKeyVaultEndpoint: + { + environment.KeyVaultEndpoint = property.Value + } + case EnvironmentGraphEndpoint: + { + environment.GraphEndpoint = property.Value + } + case EnvironmentServiceBusEndpoint: + { + environment.ServiceBusEndpoint = property.Value + } + case EnvironmentBatchManagementEndpoint: + { + environment.BatchManagementEndpoint = property.Value + } + case EnvironmentStorageEndpointSuffix: + { + environment.StorageEndpointSuffix = property.Value + } + case EnvironmentSQLDatabaseDNSSuffix: + { + environment.SQLDatabaseDNSSuffix = property.Value + } + case EnvironmentTrafficManagerDNSSuffix: + { + environment.TrafficManagerDNSSuffix = property.Value + } + case EnvironmentKeyVaultDNSSuffix: + { + environment.KeyVaultDNSSuffix = property.Value + } + case EnvironmentServiceBusEndpointSuffix: + { + environment.ServiceBusEndpointSuffix = property.Value + } + case EnvironmentServiceManagementVMDNSSuffix: + { + environment.ServiceManagementVMDNSSuffix = property.Value + } + case EnvironmentResourceManagerVMDNSSuffix: + { + environment.ResourceManagerVMDNSSuffix = property.Value + } + case EnvironmentContainerRegistryDNSSuffix: + { + environment.ContainerRegistryDNSSuffix = property.Value + } + case EnvironmentTokenAudience: + { + environment.TokenAudience = property.Value + } + } + } +} + +func retrieveMetadataEnvironment(endpoint string) (environment environmentMetadataInfo, err error) { + client := autorest.NewClientWithUserAgent("") + managementEndpoint := fmt.Sprintf("%s%s", strings.TrimSuffix(endpoint, "/"), "/metadata/endpoints?api-version=1.0") + req, _ := http.NewRequest("GET", managementEndpoint, nil) + response, err := client.Do(req) + if err != nil { + return environment, err + } + defer response.Body.Close() + jsonResponse, err := ioutil.ReadAll(response.Body) + if err != nil { + return environment, err + } + err = json.Unmarshal(jsonResponse, &environment) + return environment, err +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/rp.go b/vendor/github.com/Azure/go-autorest/autorest/azure/rp.go index b6b95d6f..65ad0afc 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/rp.go +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/rp.go @@ -70,11 +70,8 @@ func DoRetryWithRegistration(client autorest.Client) autorest.SendDecorator { } func getProvider(re RequestError) (string, error) { - if re.ServiceError != nil { - if re.ServiceError.Details != nil && len(*re.ServiceError.Details) > 0 { - detail := (*re.ServiceError.Details)[0].(map[string]interface{}) - return detail["target"].(string), nil - } + if re.ServiceError != nil && len(re.ServiceError.Details) > 0 { + return re.ServiceError.Details[0]["target"].(string), nil } return "", errors.New("provider was not found in the response") } @@ -118,7 +115,7 @@ func register(client autorest.Client, originalReq *http.Request, re RequestError if err != nil { return err } - req.Cancel = originalReq.Cancel + req = req.WithContext(originalReq.Context()) resp, err := autorest.SendWithSender(client, req, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...), @@ -157,7 +154,7 @@ func register(client autorest.Client, originalReq *http.Request, re RequestError if err != nil { return err } - req.Cancel = originalReq.Cancel + req = req.WithContext(originalReq.Context()) resp, err := autorest.SendWithSender(client, req, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...), @@ -181,9 +178,9 @@ func register(client autorest.Client, originalReq *http.Request, re RequestError break } - delayed := autorest.DelayWithRetryAfter(resp, originalReq.Cancel) - if !delayed { - autorest.DelayForBackoff(client.PollingDelay, 0, originalReq.Cancel) + delayed := autorest.DelayWithRetryAfter(resp, originalReq.Context().Done()) + if !delayed && !autorest.DelayForBackoff(client.PollingDelay, 0, originalReq.Context().Done()) { + return originalReq.Context().Err() } } if !(time.Since(now) < client.PollingDuration) { diff --git a/vendor/github.com/Azure/go-autorest/autorest/client.go b/vendor/github.com/Azure/go-autorest/autorest/client.go index d329cb73..4e92dcad 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/client.go +++ b/vendor/github.com/Azure/go-autorest/autorest/client.go @@ -203,9 +203,10 @@ func (c Client) Do(r *http.Request) (*http.Response, error) { r, _ = Prepare(r, WithUserAgent(c.UserAgent)) } + // NOTE: c.WithInspection() must be last in the list so that it can inspect all preceding operations r, err := Prepare(r, - c.WithInspection(), - c.WithAuthorization()) + c.WithAuthorization(), + c.WithInspection()) if err != nil { var resp *http.Response if detErr, ok := err.(DetailedError); ok { diff --git a/vendor/github.com/Azure/go-autorest/autorest/sender.go b/vendor/github.com/Azure/go-autorest/autorest/sender.go index c5efd59a..b4f76232 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/sender.go +++ b/vendor/github.com/Azure/go-autorest/autorest/sender.go @@ -86,7 +86,7 @@ func SendWithSender(s Sender, r *http.Request, decorators ...SendDecorator) (*ht func AfterDelay(d time.Duration) SendDecorator { return func(s Sender) Sender { return SenderFunc(func(r *http.Request) (*http.Response, error) { - if !DelayForBackoff(d, 0, r.Cancel) { + if !DelayForBackoff(d, 0, r.Context().Done()) { return nil, fmt.Errorf("autorest: AfterDelay canceled before full delay") } return s.Do(r) @@ -165,7 +165,7 @@ func DoPollForStatusCodes(duration time.Duration, delay time.Duration, codes ... resp, err = s.Do(r) if err == nil && ResponseHasStatusCode(resp, codes...) { - r, err = NewPollingRequest(resp, r.Cancel) + r, err = NewPollingRequestWithContext(r.Context(), resp) for err == nil && ResponseHasStatusCode(resp, codes...) { Respond(resp, @@ -198,7 +198,9 @@ func DoRetryForAttempts(attempts int, backoff time.Duration) SendDecorator { if err == nil { return resp, err } - DelayForBackoff(backoff, attempt, r.Cancel) + if !DelayForBackoff(backoff, attempt, r.Context().Done()) { + return nil, r.Context().Err() + } } return resp, err }) @@ -226,9 +228,9 @@ func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) Se if err == nil && !ResponseHasStatusCode(resp, codes...) || IsTokenRefreshError(err) { return resp, err } - delayed := DelayWithRetryAfter(resp, r.Cancel) - if !delayed { - DelayForBackoff(backoff, attempt, r.Cancel) + delayed := DelayWithRetryAfter(resp, r.Context().Done()) + if !delayed && !DelayForBackoff(backoff, attempt, r.Context().Done()) { + return nil, r.Context().Err() } // don't count a 429 against the number of attempts // so that we continue to retry until it succeeds @@ -277,7 +279,9 @@ func DoRetryForDuration(d time.Duration, backoff time.Duration) SendDecorator { if err == nil { return resp, err } - DelayForBackoff(backoff, attempt, r.Cancel) + if !DelayForBackoff(backoff, attempt, r.Context().Done()) { + return nil, r.Context().Err() + } } return resp, err }) diff --git a/vendor/github.com/Azure/go-autorest/autorest/version.go b/vendor/github.com/Azure/go-autorest/autorest/version.go index a19c0d35..4ad7754a 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/version.go +++ b/vendor/github.com/Azure/go-autorest/autorest/version.go @@ -14,36 +14,7 @@ package autorest // See the License for the specific language governing permissions and // limitations under the License. -import ( - "bytes" - "fmt" - "strings" - "sync" -) - -const ( - major = 9 - minor = 8 - patch = 1 - tag = "" -) - -var once sync.Once -var version string - // Version returns the semantic version (see http://semver.org). func Version() string { - once.Do(func() { - semver := fmt.Sprintf("%d.%d.%d", major, minor, patch) - verBuilder := bytes.NewBufferString(semver) - if tag != "" && tag != "-" { - updated := strings.TrimPrefix(tag, "-") - _, err := verBuilder.WriteString("-" + updated) - if err == nil { - verBuilder = bytes.NewBufferString(semver) - } - } - version = verBuilder.String() - }) - return version + return "v10.5.0" }