upgrade Azure/go-autorest/autorest to v0.11.27

update
This commit is contained in:
andyzhangx
2022-06-03 09:20:09 +00:00
parent ca630bc118
commit 7ac98854e2
50 changed files with 2426 additions and 116 deletions

View File

@@ -1,3 +1,5 @@
# NOTE: This module will go out of support by March 31, 2023. For authenticating with Azure AD, use module [azidentity](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity) instead. For help migrating from `adal` to `azidentiy` please consult the [migration guide](https://aka.ms/azsdk/go/identity/migration). General information about the retirement of this and other legacy modules can be found [here](https://azure.microsoft.com/updates/support-for-azure-sdk-libraries-that-do-not-conform-to-our-current-azure-sdk-guidelines-will-be-retired-as-of-31-march-2023/).
# Azure Active Directory authentication for Go
This is a standalone package for authenticating with Azure Active
@@ -18,7 +20,7 @@ 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/) 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).
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/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
@@ -88,7 +90,7 @@ An Active Directory application is required in order to use this library. An app
### Grant the necessary permissions
Azure relies on a Role-Based Access Control (RBAC) model to manage the access to resources at a fine-grained
level. There is a set of [pre-defined roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-built-in-roles)
level. There is a set of [pre-defined roles](https://docs.microsoft.com/azure/active-directory/role-based-access-built-in-roles)
which can be assigned to a service principal of an Azure AD application depending of your needs.
```
@@ -104,7 +106,7 @@ It is also possible to define custom role definitions.
az role definition create --role-definition role-definition.json
```
* Check [custom roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-control-custom-roles) for more details regarding the content of `role-definition.json` file.
* Check [custom roles](https://docs.microsoft.com/azure/active-directory/role-based-access-control-custom-roles) for more details regarding the content of `role-definition.json` file.
### Acquire Access Token

View File

@@ -1,3 +1,4 @@
//go:build modhack
// +build modhack
package adal

View File

@@ -16,9 +16,11 @@ package adal
import (
"crypto/tls"
"net"
"net/http"
"net/http/cookiejar"
"sync"
"time"
"github.com/Azure/go-autorest/tracing"
)
@@ -72,15 +74,18 @@ func sender() Sender {
// note that we can't init defaultSender in init() since it will
// execute before calling code has had a chance to enable tracing
defaultSenderInit.Do(func() {
// Use behaviour compatible with DefaultTransport, but require TLS minimum version.
defaultTransport := http.DefaultTransport.(*http.Transport)
// copied from http.DefaultTransport with a TLS minimum version.
transport := &http.Transport{
Proxy: defaultTransport.Proxy,
DialContext: defaultTransport.DialContext,
MaxIdleConns: defaultTransport.MaxIdleConns,
IdleConnTimeout: defaultTransport.IdleConnTimeout,
TLSHandshakeTimeout: defaultTransport.TLSHandshakeTimeout,
ExpectContinueTimeout: defaultTransport.ExpectContinueTimeout,
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
},

View File

@@ -37,7 +37,7 @@ import (
"github.com/Azure/go-autorest/autorest/date"
"github.com/Azure/go-autorest/logger"
"github.com/form3tech-oss/jwt-go"
"github.com/golang-jwt/jwt/v4"
)
const (
@@ -365,6 +365,25 @@ func (secret ServicePrincipalAuthorizationCodeSecret) MarshalJSON() ([]byte, err
})
}
// ServicePrincipalFederatedSecret implements ServicePrincipalSecret for Federated JWTs.
type ServicePrincipalFederatedSecret struct {
jwt string
}
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
// It will populate the form submitted during OAuth Token Acquisition using a JWT signed by an OIDC issuer.
func (secret *ServicePrincipalFederatedSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
v.Set("client_assertion", secret.jwt)
v.Set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
return nil
}
// MarshalJSON implements the json.Marshaler interface.
func (secret ServicePrincipalFederatedSecret) MarshalJSON() ([]byte, error) {
return nil, errors.New("marshalling ServicePrincipalFederatedSecret is not supported")
}
// ServicePrincipalToken encapsulates a Token created for a Service Principal.
type ServicePrincipalToken struct {
inner servicePrincipalToken
@@ -419,6 +438,8 @@ func (spt *ServicePrincipalToken) UnmarshalJSON(data []byte) error {
spt.inner.Secret = &ServicePrincipalUsernamePasswordSecret{}
case "ServicePrincipalAuthorizationCodeSecret":
spt.inner.Secret = &ServicePrincipalAuthorizationCodeSecret{}
case "ServicePrincipalFederatedSecret":
return errors.New("unmarshalling ServicePrincipalFederatedSecret is not supported")
default:
return fmt.Errorf("unrecognized token type '%s'", secret["type"])
}
@@ -665,6 +686,31 @@ func NewServicePrincipalTokenFromAuthorizationCode(oauthConfig OAuthConfig, clie
)
}
// NewServicePrincipalTokenFromFederatedToken creates a ServicePrincipalToken from the supplied federated OIDC JWT.
func NewServicePrincipalTokenFromFederatedToken(oauthConfig OAuthConfig, clientID string, jwt string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
if err := validateOAuthConfig(oauthConfig); err != nil {
return nil, err
}
if err := validateStringParam(clientID, "clientID"); err != nil {
return nil, err
}
if err := validateStringParam(resource, "resource"); err != nil {
return nil, err
}
if jwt == "" {
return nil, fmt.Errorf("parameter 'jwt' cannot be empty")
}
return NewServicePrincipalTokenWithSecret(
oauthConfig,
clientID,
resource,
&ServicePrincipalFederatedSecret{
jwt: jwt,
},
callbacks...,
)
}
type msiType int
const (
@@ -676,8 +722,6 @@ const (
func (m msiType) String() string {
switch m {
case msiTypeUnavailable:
return "unavailable"
case msiTypeAppServiceV20170901:
return "AppServiceV20170901"
case msiTypeCloudShell:
@@ -699,13 +743,9 @@ func getMSIType() (msiType, string, error) {
}
// if ONLY the env var MSI_ENDPOINT is set the msiType is CloudShell
return msiTypeCloudShell, endpointEnvVar, nil
} else if msiAvailableHook(context.Background(), sender()) {
// if MSI_ENDPOINT is NOT set AND the IMDS endpoint is available the msiType is IMDS. This will timeout after 500 milliseconds
return msiTypeIMDS, msiEndpoint, nil
} else {
// if MSI_ENDPOINT is NOT set and IMDS endpoint is not available Managed Identity is not available
return msiTypeUnavailable, "", errors.New("MSI not available")
}
// if MSI_ENDPOINT is NOT set assume the msiType is IMDS
return msiTypeIMDS, msiEndpoint, nil
}
// GetMSIVMEndpoint gets the MSI endpoint on Virtual Machines.
@@ -800,13 +840,13 @@ func newServicePrincipalTokenFromMSI(msiEndpoint, resource, userAssignedID, iden
}
msiType, endpoint, err := getMSIType()
if err != nil {
logger.Instance.Writef(logger.LogError, "Error determining managed identity environment: %v", err)
logger.Instance.Writef(logger.LogError, "Error determining managed identity environment: %v\n", err)
return nil, err
}
logger.Instance.Writef(logger.LogInfo, "Managed identity environment is %s, endpoint is %s", msiType, endpoint)
logger.Instance.Writef(logger.LogInfo, "Managed identity environment is %s, endpoint is %s\n", msiType, endpoint)
if msiEndpoint != "" {
endpoint = msiEndpoint
logger.Instance.Writef(logger.LogInfo, "Managed identity custom endpoint is %s", endpoint)
logger.Instance.Writef(logger.LogInfo, "Managed identity custom endpoint is %s\n", endpoint)
}
msiEndpointURL, err := url.Parse(endpoint)
if err != nil {
@@ -1064,8 +1104,8 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
// AAD returns expires_in as a string, ADFS returns it as an int
ExpiresIn json.Number `json:"expires_in"`
// expires_on can be in two formats, a UTC time stamp or the number of seconds.
ExpiresOn string `json:"expires_on"`
// expires_on can be in three formats, a UTC time stamp, or the number of seconds as a string *or* int.
ExpiresOn interface{} `json:"expires_on"`
NotBefore json.Number `json:"not_before"`
Resource string `json:"resource"`
@@ -1078,7 +1118,7 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
}
expiresOn := json.Number("")
// ADFS doesn't include the expires_on field
if token.ExpiresOn != "" {
if token.ExpiresOn != nil {
if expiresOn, err = parseExpiresOn(token.ExpiresOn); err != nil {
return newTokenRefreshError(fmt.Sprintf("adal: failed to parse expires_on: %v value '%s'", err, token.ExpiresOn), resp)
}
@@ -1095,18 +1135,27 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
}
// converts expires_on to the number of seconds
func parseExpiresOn(s string) (json.Number, error) {
// convert the expiration date to the number of seconds from now
timeToDuration := func(t time.Time) json.Number {
dur := t.Sub(time.Now().UTC())
return json.Number(strconv.FormatInt(int64(dur.Round(time.Second).Seconds()), 10))
func parseExpiresOn(s interface{}) (json.Number, error) {
// the JSON unmarshaler treats JSON numbers unmarshaled into an interface{} as float64
asFloat64, ok := s.(float64)
if ok {
// this is the number of seconds as int case
return json.Number(strconv.FormatInt(int64(asFloat64), 10)), nil
}
if _, err := strconv.ParseInt(s, 10, 64); err == nil {
asStr, ok := s.(string)
if !ok {
return "", fmt.Errorf("unexpected expires_on type %T", s)
}
// convert the expiration date to the number of seconds from the unix epoch
timeToDuration := func(t time.Time) json.Number {
return json.Number(strconv.FormatInt(t.UTC().Unix(), 10))
}
if _, err := json.Number(asStr).Int64(); err == nil {
// this is the number of seconds case, no conversion required
return json.Number(s), nil
} else if eo, err := time.Parse(expiresOnDateFormatPM, s); err == nil {
return json.Number(asStr), nil
} else if eo, err := time.Parse(expiresOnDateFormatPM, asStr); err == nil {
return timeToDuration(eo), nil
} else if eo, err := time.Parse(expiresOnDateFormat, s); err == nil {
} else if eo, err := time.Parse(expiresOnDateFormat, asStr); err == nil {
return timeToDuration(eo), nil
} else {
// unknown format
@@ -1322,15 +1371,26 @@ func NewMultiTenantServicePrincipalTokenFromCertificate(multiTenantCfg MultiTena
}
// MSIAvailable returns true if the MSI endpoint is available for authentication.
func MSIAvailable(ctx context.Context, sender Sender) bool {
resp, err := getMSIEndpoint(ctx, sender)
func MSIAvailable(ctx context.Context, s Sender) bool {
msiType, _, err := getMSIType()
if err != nil {
return false
}
if msiType != msiTypeIMDS {
return true
}
if s == nil {
s = sender()
}
resp, err := getMSIEndpoint(ctx, s)
if err == nil {
resp.Body.Close()
}
return err == nil
}
// used for testing purposes
var msiAvailableHook = func(ctx context.Context, sender Sender) bool {
return MSIAvailable(ctx, sender)
}

View File

@@ -1,3 +1,4 @@
//go:build go1.13
// +build go1.13
// Copyright 2017 Microsoft Corporation
@@ -24,7 +25,7 @@ import (
)
func getMSIEndpoint(ctx context.Context, sender Sender) (*http.Response, error) {
tempCtx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
tempCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
// http.NewRequestWithContext() was added in Go 1.13
req, _ := http.NewRequestWithContext(tempCtx, http.MethodGet, msiEndpoint, nil)

View File

@@ -1,3 +1,4 @@
//go:build !go1.13
// +build !go1.13
// Copyright 2017 Microsoft Corporation
@@ -23,7 +24,7 @@ import (
)
func getMSIEndpoint(ctx context.Context, sender Sender) (*http.Response, error) {
tempCtx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
tempCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
req, _ := http.NewRequest(http.MethodGet, msiEndpoint, nil)
req = req.WithContext(tempCtx)

View File

@@ -26,6 +26,7 @@ import (
"time"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/logger"
"github.com/Azure/go-autorest/tracing"
)
@@ -215,6 +216,7 @@ func (f *Future) WaitForCompletionRef(ctx context.Context, client autorest.Clien
}
// if the initial response has a Retry-After, sleep for the specified amount of time before starting to poll
if delay, ok := f.GetPollingDelay(); ok {
logger.Instance.Writeln(logger.LogInfo, "WaitForCompletionRef: initial polling delay")
if delayElapsed := autorest.DelayForBackoff(delay, 0, cancelCtx.Done()); !delayElapsed {
err = cancelCtx.Err()
return
@@ -234,12 +236,14 @@ func (f *Future) WaitForCompletionRef(ctx context.Context, client autorest.Clien
var ok bool
delay, ok = f.GetPollingDelay()
if !ok {
logger.Instance.Writeln(logger.LogInfo, "WaitForCompletionRef: Using client polling delay")
delay = client.PollingDelay
}
} else {
// there was an error polling for status so perform exponential
// back-off based on the number of attempts using the client's retry
// duration. update attempts after delayAttempt to avoid off-by-one.
logger.Instance.Writef(logger.LogError, "WaitForCompletionRef: %s\n", err)
delayAttempt = attempts
delay = client.RetryDuration
attempts++

View File

@@ -68,7 +68,7 @@ func (se ServiceError) Error() string {
if err != nil {
result += fmt.Sprintf(" Details=%v", se.Details)
}
result += fmt.Sprintf(" Details=%v", string(d))
result += fmt.Sprintf(" Details=%s", d)
}
if se.InnerError != nil {
@@ -76,7 +76,7 @@ func (se ServiceError) Error() string {
if err != nil {
result += fmt.Sprintf(" InnerError=%v", se.InnerError)
}
result += fmt.Sprintf(" InnerError=%v", string(d))
result += fmt.Sprintf(" InnerError=%s", d)
}
if se.AdditionalInfo != nil {
@@ -84,7 +84,7 @@ func (se ServiceError) Error() string {
if err != nil {
result += fmt.Sprintf(" AdditionalInfo=%v", se.AdditionalInfo)
}
result += fmt.Sprintf(" AdditionalInfo=%v", string(d))
result += fmt.Sprintf(" AdditionalInfo=%s", d)
}
return result
@@ -211,7 +211,7 @@ func (r Resource) String() 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.
// See https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource?tabs=json#resourceid.
func ParseResourceID(resourceID string) (Resource, error) {
const resourceIDPatternText = `(?i)subscriptions/(.+)/resourceGroups/(.+)/providers/(.+?)/(.+?)/(.+)`
@@ -335,13 +335,13 @@ func WithErrorUnlessStatusCode(codes ...int) autorest.RespondDecorator {
b, decodeErr := autorest.CopyAndDecode(encodedAs, resp.Body, &e)
resp.Body = ioutil.NopCloser(&b)
if decodeErr != nil {
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b.String(), decodeErr)
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b, decodeErr)
}
if e.ServiceError == nil {
// Check if error is unwrapped ServiceError
decoder := autorest.NewDecoder(encodedAs, bytes.NewReader(b.Bytes()))
if err := decoder.Decode(&e.ServiceError); err != nil {
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b.String(), err)
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b, err)
}
// for example, should the API return the literal value `null` as the response
@@ -364,7 +364,7 @@ func WithErrorUnlessStatusCode(codes ...int) autorest.RespondDecorator {
rawBody := map[string]interface{}{}
decoder := autorest.NewDecoder(encodedAs, bytes.NewReader(b.Bytes()))
if err := decoder.Decode(&rawBody); err != nil {
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b.String(), err)
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b, err)
}
e.ServiceError = &ServiceError{

View File

@@ -34,8 +34,10 @@ const (
var environments = map[string]Environment{
"AZURECHINACLOUD": ChinaCloud,
"AZUREGERMANCLOUD": GermanCloud,
"AZURECLOUD": PublicCloud,
"AZUREPUBLICCLOUD": PublicCloud,
"AZUREUSGOVERNMENTCLOUD": USGovernmentCloud,
"AZUREUSGOVERNMENT": USGovernmentCloud,
"AZUREUSGOVERNMENTCLOUD": USGovernmentCloud, //TODO: deprecate
}
// ResourceIdentifier contains a set of Azure resource IDs.
@@ -45,9 +47,14 @@ type ResourceIdentifier struct {
Datalake string `json:"datalake"`
Batch string `json:"batch"`
OperationalInsights string `json:"operationalInsights"`
OSSRDBMS string `json:"ossRDBMS"`
Storage string `json:"storage"`
Synapse string `json:"synapse"`
ServiceBus string `json:"serviceBus"`
SQLDatabase string `json:"sqlDatabase"`
CosmosDB string `json:"cosmosDB"`
ManagedHSM string `json:"managedHSM"`
MicrosoftGraph string `json:"microsoftGraph"`
}
// Environment represents a set of endpoints for each of Azure's Clouds.
@@ -60,21 +67,28 @@ type Environment struct {
ActiveDirectoryEndpoint string `json:"activeDirectoryEndpoint"`
GalleryEndpoint string `json:"galleryEndpoint"`
KeyVaultEndpoint string `json:"keyVaultEndpoint"`
ManagedHSMEndpoint string `json:"managedHSMEndpoint"`
GraphEndpoint string `json:"graphEndpoint"`
ServiceBusEndpoint string `json:"serviceBusEndpoint"`
BatchManagementEndpoint string `json:"batchManagementEndpoint"`
MicrosoftGraphEndpoint string `json:"microsoftGraphEndpoint"`
StorageEndpointSuffix string `json:"storageEndpointSuffix"`
CosmosDBDNSSuffix string `json:"cosmosDBDNSSuffix"`
MariaDBDNSSuffix string `json:"mariaDBDNSSuffix"`
MySQLDatabaseDNSSuffix string `json:"mySqlDatabaseDNSSuffix"`
PostgresqlDatabaseDNSSuffix string `json:"postgresqlDatabaseDNSSuffix"`
SQLDatabaseDNSSuffix string `json:"sqlDatabaseDNSSuffix"`
TrafficManagerDNSSuffix string `json:"trafficManagerDNSSuffix"`
KeyVaultDNSSuffix string `json:"keyVaultDNSSuffix"`
ManagedHSMDNSSuffix string `json:"managedHSMDNSSuffix"`
ServiceBusEndpointSuffix string `json:"serviceBusEndpointSuffix"`
ServiceManagementVMDNSSuffix string `json:"serviceManagementVMDNSSuffix"`
ResourceManagerVMDNSSuffix string `json:"resourceManagerVMDNSSuffix"`
ContainerRegistryDNSSuffix string `json:"containerRegistryDNSSuffix"`
CosmosDBDNSSuffix string `json:"cosmosDBDNSSuffix"`
TokenAudience string `json:"tokenAudience"`
APIManagementHostNameSuffix string `json:"apiManagementHostNameSuffix"`
SynapseEndpointSuffix string `json:"synapseEndpointSuffix"`
DatalakeSuffix string `json:"datalakeSuffix"`
ResourceIdentifiers ResourceIdentifier `json:"resourceIdentifiers"`
}
@@ -89,30 +103,42 @@ var (
ActiveDirectoryEndpoint: "https://login.microsoftonline.com/",
GalleryEndpoint: "https://gallery.azure.com/",
KeyVaultEndpoint: "https://vault.azure.net/",
ManagedHSMEndpoint: "https://managedhsm.azure.net/",
GraphEndpoint: "https://graph.windows.net/",
ServiceBusEndpoint: "https://servicebus.windows.net/",
BatchManagementEndpoint: "https://batch.core.windows.net/",
MicrosoftGraphEndpoint: "https://graph.microsoft.com/",
StorageEndpointSuffix: "core.windows.net",
CosmosDBDNSSuffix: "documents.azure.com",
MariaDBDNSSuffix: "mariadb.database.azure.com",
MySQLDatabaseDNSSuffix: "mysql.database.azure.com",
PostgresqlDatabaseDNSSuffix: "postgres.database.azure.com",
SQLDatabaseDNSSuffix: "database.windows.net",
TrafficManagerDNSSuffix: "trafficmanager.net",
KeyVaultDNSSuffix: "vault.azure.net",
ManagedHSMDNSSuffix: "managedhsm.azure.net",
ServiceBusEndpointSuffix: "servicebus.windows.net",
ServiceManagementVMDNSSuffix: "cloudapp.net",
ResourceManagerVMDNSSuffix: "cloudapp.azure.com",
ContainerRegistryDNSSuffix: "azurecr.io",
CosmosDBDNSSuffix: "documents.azure.com",
TokenAudience: "https://management.azure.com/",
APIManagementHostNameSuffix: "azure-api.net",
SynapseEndpointSuffix: "dev.azuresynapse.net",
DatalakeSuffix: "azuredatalakestore.net",
ResourceIdentifiers: ResourceIdentifier{
Graph: "https://graph.windows.net/",
KeyVault: "https://vault.azure.net",
Datalake: "https://datalake.azure.net/",
Batch: "https://batch.core.windows.net/",
OperationalInsights: "https://api.loganalytics.io",
OSSRDBMS: "https://ossrdbms-aad.database.windows.net",
Storage: "https://storage.azure.com/",
Synapse: "https://dev.azuresynapse.net",
ServiceBus: "https://servicebus.azure.net/",
SQLDatabase: "https://database.windows.net/",
CosmosDB: "https://cosmos.azure.com",
ManagedHSM: "https://managedhsm.azure.net",
MicrosoftGraph: "https://graph.microsoft.com/",
},
}
@@ -126,30 +152,42 @@ var (
ActiveDirectoryEndpoint: "https://login.microsoftonline.us/",
GalleryEndpoint: "https://gallery.usgovcloudapi.net/",
KeyVaultEndpoint: "https://vault.usgovcloudapi.net/",
ManagedHSMEndpoint: NotAvailable,
GraphEndpoint: "https://graph.windows.net/",
ServiceBusEndpoint: "https://servicebus.usgovcloudapi.net/",
BatchManagementEndpoint: "https://batch.core.usgovcloudapi.net/",
MicrosoftGraphEndpoint: "https://graph.microsoft.us/",
StorageEndpointSuffix: "core.usgovcloudapi.net",
CosmosDBDNSSuffix: "documents.azure.us",
MariaDBDNSSuffix: "mariadb.database.usgovcloudapi.net",
MySQLDatabaseDNSSuffix: "mysql.database.usgovcloudapi.net",
PostgresqlDatabaseDNSSuffix: "postgres.database.usgovcloudapi.net",
SQLDatabaseDNSSuffix: "database.usgovcloudapi.net",
TrafficManagerDNSSuffix: "usgovtrafficmanager.net",
KeyVaultDNSSuffix: "vault.usgovcloudapi.net",
ManagedHSMDNSSuffix: NotAvailable,
ServiceBusEndpointSuffix: "servicebus.usgovcloudapi.net",
ServiceManagementVMDNSSuffix: "usgovcloudapp.net",
ResourceManagerVMDNSSuffix: "cloudapp.usgovcloudapi.net",
ContainerRegistryDNSSuffix: "azurecr.us",
CosmosDBDNSSuffix: "documents.azure.us",
TokenAudience: "https://management.usgovcloudapi.net/",
APIManagementHostNameSuffix: "azure-api.us",
SynapseEndpointSuffix: NotAvailable,
SynapseEndpointSuffix: "dev.azuresynapse.usgovcloudapi.net",
DatalakeSuffix: NotAvailable,
ResourceIdentifiers: ResourceIdentifier{
Graph: "https://graph.windows.net/",
KeyVault: "https://vault.usgovcloudapi.net",
Datalake: NotAvailable,
Batch: "https://batch.core.usgovcloudapi.net/",
OperationalInsights: "https://api.loganalytics.us",
OSSRDBMS: "https://ossrdbms-aad.database.usgovcloudapi.net",
Storage: "https://storage.azure.com/",
Synapse: NotAvailable,
Synapse: "https://dev.azuresynapse.usgovcloudapi.net",
ServiceBus: "https://servicebus.azure.net/",
SQLDatabase: "https://database.usgovcloudapi.net/",
CosmosDB: "https://cosmos.azure.com",
ManagedHSM: NotAvailable,
MicrosoftGraph: "https://graph.microsoft.us/",
},
}
@@ -163,30 +201,42 @@ var (
ActiveDirectoryEndpoint: "https://login.chinacloudapi.cn/",
GalleryEndpoint: "https://gallery.chinacloudapi.cn/",
KeyVaultEndpoint: "https://vault.azure.cn/",
ManagedHSMEndpoint: NotAvailable,
GraphEndpoint: "https://graph.chinacloudapi.cn/",
ServiceBusEndpoint: "https://servicebus.chinacloudapi.cn/",
BatchManagementEndpoint: "https://batch.chinacloudapi.cn/",
MicrosoftGraphEndpoint: "https://microsoftgraph.chinacloudapi.cn/",
StorageEndpointSuffix: "core.chinacloudapi.cn",
CosmosDBDNSSuffix: "documents.azure.cn",
MariaDBDNSSuffix: "mariadb.database.chinacloudapi.cn",
MySQLDatabaseDNSSuffix: "mysql.database.chinacloudapi.cn",
PostgresqlDatabaseDNSSuffix: "postgres.database.chinacloudapi.cn",
SQLDatabaseDNSSuffix: "database.chinacloudapi.cn",
TrafficManagerDNSSuffix: "trafficmanager.cn",
KeyVaultDNSSuffix: "vault.azure.cn",
ManagedHSMDNSSuffix: NotAvailable,
ServiceBusEndpointSuffix: "servicebus.chinacloudapi.cn",
ServiceManagementVMDNSSuffix: "chinacloudapp.cn",
ResourceManagerVMDNSSuffix: "cloudapp.chinacloudapi.cn",
ContainerRegistryDNSSuffix: "azurecr.cn",
CosmosDBDNSSuffix: "documents.azure.cn",
TokenAudience: "https://management.chinacloudapi.cn/",
APIManagementHostNameSuffix: "azure-api.cn",
SynapseEndpointSuffix: "dev.azuresynapse.azure.cn",
DatalakeSuffix: NotAvailable,
ResourceIdentifiers: ResourceIdentifier{
Graph: "https://graph.chinacloudapi.cn/",
KeyVault: "https://vault.azure.cn",
Datalake: NotAvailable,
Batch: "https://batch.chinacloudapi.cn/",
OperationalInsights: NotAvailable,
OSSRDBMS: "https://ossrdbms-aad.database.chinacloudapi.cn",
Storage: "https://storage.azure.com/",
Synapse: "https://dev.azuresynapse.net",
ServiceBus: "https://servicebus.azure.net/",
SQLDatabase: "https://database.chinacloudapi.cn/",
CosmosDB: "https://cosmos.azure.com",
ManagedHSM: NotAvailable,
MicrosoftGraph: "https://microsoftgraph.chinacloudapi.cn",
},
}
@@ -200,30 +250,42 @@ var (
ActiveDirectoryEndpoint: "https://login.microsoftonline.de/",
GalleryEndpoint: "https://gallery.cloudapi.de/",
KeyVaultEndpoint: "https://vault.microsoftazure.de/",
ManagedHSMEndpoint: NotAvailable,
GraphEndpoint: "https://graph.cloudapi.de/",
ServiceBusEndpoint: "https://servicebus.cloudapi.de/",
BatchManagementEndpoint: "https://batch.cloudapi.de/",
MicrosoftGraphEndpoint: NotAvailable,
StorageEndpointSuffix: "core.cloudapi.de",
CosmosDBDNSSuffix: "documents.microsoftazure.de",
MariaDBDNSSuffix: "mariadb.database.cloudapi.de",
MySQLDatabaseDNSSuffix: "mysql.database.cloudapi.de",
PostgresqlDatabaseDNSSuffix: "postgres.database.cloudapi.de",
SQLDatabaseDNSSuffix: "database.cloudapi.de",
TrafficManagerDNSSuffix: "azuretrafficmanager.de",
KeyVaultDNSSuffix: "vault.microsoftazure.de",
ManagedHSMDNSSuffix: NotAvailable,
ServiceBusEndpointSuffix: "servicebus.cloudapi.de",
ServiceManagementVMDNSSuffix: "azurecloudapp.de",
ResourceManagerVMDNSSuffix: "cloudapp.microsoftazure.de",
ContainerRegistryDNSSuffix: NotAvailable,
CosmosDBDNSSuffix: "documents.microsoftazure.de",
TokenAudience: "https://management.microsoftazure.de/",
APIManagementHostNameSuffix: NotAvailable,
SynapseEndpointSuffix: NotAvailable,
DatalakeSuffix: NotAvailable,
ResourceIdentifiers: ResourceIdentifier{
Graph: "https://graph.cloudapi.de/",
KeyVault: "https://vault.microsoftazure.de",
Datalake: NotAvailable,
Batch: "https://batch.cloudapi.de/",
OperationalInsights: NotAvailable,
OSSRDBMS: "https://ossrdbms-aad.database.cloudapi.de",
Storage: "https://storage.azure.com/",
Synapse: NotAvailable,
ServiceBus: "https://servicebus.azure.net/",
SQLDatabase: "https://database.cloudapi.de/",
CosmosDB: "https://cosmos.azure.com",
ManagedHSM: NotAvailable,
MicrosoftGraph: NotAvailable,
},
}
)

View File

@@ -64,7 +64,7 @@ func DoRetryWithRegistration(client autorest.Client) autorest.SendDecorator {
if re.ServiceError != nil && re.ServiceError.Code == "MissingSubscriptionRegistration" {
regErr := register(client, r, re)
if regErr != nil {
return resp, fmt.Errorf("failed auto registering Resource Provider: %s. Original error: %s", regErr, err)
return resp, fmt.Errorf("failed auto registering Resource Provider: %s. Original error: %w", regErr, err)
}
}
}

View File

@@ -31,7 +31,7 @@ import (
const (
// DefaultPollingDelay is a reasonable delay between polling requests.
DefaultPollingDelay = 60 * time.Second
DefaultPollingDelay = 30 * time.Second
// DefaultPollingDuration is a reasonable total polling duration.
DefaultPollingDuration = 15 * time.Minute

View File

@@ -1,3 +1,4 @@
//go:build modhack
// +build modhack
package autorest

View File

@@ -1,3 +1,4 @@
//go:build modhack
// +build modhack
package mocks

View File

@@ -26,28 +26,25 @@ import (
// Body implements acceptable body over a string.
type Body struct {
s string
b []byte
src []byte
buf []byte
isOpen bool
closeAttempts int
}
// NewBody creates a new instance of Body.
func NewBody(s string) *Body {
return (&Body{s: s}).reset()
return (&Body{src: []byte(s)}).reset()
}
// NewBodyWithBytes creates a new instance of Body.
func NewBodyWithBytes(b []byte) *Body {
return &Body{
b: b,
isOpen: true,
}
return (&Body{src: b}).reset()
}
// NewBodyClose creates a new instance of Body.
func NewBodyClose(s string) *Body {
return &Body{s: s}
return &Body{src: []byte(s)}
}
// Read reads into the passed byte slice and returns the bytes read.
@@ -55,11 +52,11 @@ func (body *Body) Read(b []byte) (n int, err error) {
if !body.IsOpen() {
return 0, fmt.Errorf("ERROR: Body has been closed")
}
if len(body.b) == 0 {
if len(body.buf) == 0 {
return 0, io.EOF
}
n = copy(b, body.b)
body.b = body.b[n:]
n = copy(b, body.buf)
body.buf = body.buf[n:]
return n, nil
}
@@ -84,7 +81,7 @@ func (body *Body) IsOpen() bool {
func (body *Body) reset() *Body {
body.isOpen = true
body.b = []byte(body.s)
body.buf = body.src
return body
}
@@ -93,7 +90,7 @@ func (body *Body) Length() int64 {
if body == nil {
return 0
}
return int64(len(body.b))
return int64(len(body.src))
}
type response struct {

View File

@@ -241,6 +241,8 @@ func WithBaseURL(baseURL string) PrepareDecorator {
return r, fmt.Errorf("autorest: No scheme detected in URL %s", baseURL)
}
if u.RawQuery != "" {
// handle unencoded semicolons (ideally the server would send them already encoded)
u.RawQuery = strings.Replace(u.RawQuery, ";", "%3B", -1)
q, err := url.ParseQuery(u.RawQuery)
if err != nil {
return r, err

View File

@@ -1,3 +1,4 @@
//go:build !go1.8
// +build !go1.8
// Copyright 2017 Microsoft Corporation

View File

@@ -1,3 +1,4 @@
//go:build go1.8
// +build go1.8
// Copyright 2017 Microsoft Corporation

View File

@@ -20,12 +20,14 @@ import (
"fmt"
"log"
"math"
"net"
"net/http"
"net/http/cookiejar"
"strconv"
"sync"
"time"
"github.com/Azure/go-autorest/logger"
"github.com/Azure/go-autorest/tracing"
)
@@ -128,15 +130,18 @@ func sender(renengotiation tls.RenegotiationSupport) Sender {
// note that we can't init defaultSenders in init() since it will
// execute before calling code has had a chance to enable tracing
defaultSenders[renengotiation].init.Do(func() {
// Use behaviour compatible with DefaultTransport, but require TLS minimum version.
defaultTransport := http.DefaultTransport.(*http.Transport)
// copied from http.DefaultTransport with a TLS minimum version.
transport := &http.Transport{
Proxy: defaultTransport.Proxy,
DialContext: defaultTransport.DialContext,
MaxIdleConns: defaultTransport.MaxIdleConns,
IdleConnTimeout: defaultTransport.IdleConnTimeout,
TLSHandshakeTimeout: defaultTransport.TLSHandshakeTimeout,
ExpectContinueTimeout: defaultTransport.ExpectContinueTimeout,
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
Renegotiation: renengotiation,
@@ -271,6 +276,7 @@ func DoRetryForAttempts(attempts int, backoff time.Duration) SendDecorator {
if err == nil {
return resp, err
}
logger.Instance.Writef(logger.LogError, "DoRetryForAttempts: received error for attempt %d: %v\n", attempt+1, err)
if !DelayForBackoff(backoff, attempt, r.Context().Done()) {
return nil, r.Context().Err()
}
@@ -325,6 +331,9 @@ func doRetryForStatusCodesImpl(s Sender, r *http.Request, count429 bool, attempt
if err == nil && !ResponseHasStatusCode(resp, codes...) || IsTokenRefreshError(err) {
return resp, err
}
if err != nil {
logger.Instance.Writef(logger.LogError, "DoRetryForStatusCodes: received error for attempt %d: %v\n", attempt+1, err)
}
delayed := DelayWithRetryAfter(resp, r.Context().Done())
// if this was a 429 set the delay cap as specified.
// applicable only in the absence of a retry-after header.
@@ -391,6 +400,7 @@ func DoRetryForDuration(d time.Duration, backoff time.Duration) SendDecorator {
if err == nil {
return resp, err
}
logger.Instance.Writef(logger.LogError, "DoRetryForDuration: received error for attempt %d: %v\n", attempt+1, err)
if !DelayForBackoff(backoff, attempt, r.Context().Done()) {
return nil, r.Context().Err()
}
@@ -438,6 +448,7 @@ func DelayForBackoffWithCap(backoff, cap time.Duration, attempt int, cancel <-ch
if cap > 0 && d > cap {
d = cap
}
logger.Instance.Writef(logger.LogInfo, "DelayForBackoffWithCap: sleeping for %s\n", d)
select {
case <-time.After(d):
return true

View File

@@ -1,3 +1,4 @@
//go:build go1.13
// +build go1.13
// Copyright 2017 Microsoft Corporation

View File

@@ -1,3 +1,4 @@
//go:build !go1.13
// +build !go1.13
// Copyright 2017 Microsoft Corporation