diff --git a/sdk/azidentity/CHANGELOG.md b/sdk/azidentity/CHANGELOG.md index 600579a40419..1b29a4058557 100644 --- a/sdk/azidentity/CHANGELOG.md +++ b/sdk/azidentity/CHANGELOG.md @@ -2,6 +2,7 @@ ## 0.12.0 (Unreleased) ### Breaking Changes +* Raised minimum go version to 1.16 * Removed `NewAuthenticationPolicy()` from credentials. Clients should instead use azcore's `runtime.NewBearerTokenPolicy()` to construct a bearer token authorization policy. * The `AuthorityHost` field in credential options structs is now a custom type, @@ -47,6 +48,9 @@ cred, err := NewManagedIdentityCredential(opts) ``` * `DeviceCodeCredentialOptions.UserPrompt` has a new type: `func(context.Context, DeviceCodeMessage) error` +* Credential options structs now embed `azcore.ClientOptions`. In addition to changing literal initialization + syntax, this change renames `HTTPClient` fields to `Transport`. +* Renamed `LogCredential` to `EventCredential` ### Features Added * Added connection configuration options to `DefaultAzureCredentialOptions` diff --git a/sdk/azidentity/README.md b/sdk/azidentity/README.md index d8efc11e2fab..fbac4fe430e3 100644 --- a/sdk/azidentity/README.md +++ b/sdk/azidentity/README.md @@ -79,7 +79,7 @@ The `DefaultAzureCredential` is appropriate for most scenarios where the applica You can find more examples of using various credentials in [Azure Identity Examples Wiki page](https://github.com/Azure/azure-sdk-for-go/wiki/Azure-Identity-Examples). ### Authenticating with `DefaultAzureCredential` -This example demonstrates authenticating the `ResourcesClient` from the [armresources][armresources_library] module using `DefaultAzureCredential`. +This example demonstrates authenticating the `ResourcesClient` from the armresources module using `DefaultAzureCredential`. ```go // The default credential checks environment variables for configuration. @@ -95,7 +95,7 @@ client := armresources.NewResourcesClient(armcore.NewDefaultConnection(cred, nil See more how to configure the `DefaultAzureCredential` on your workstation or Azure in [Configure DefaultAzureCredential](https://github.com/Azure/azure-sdk-for-go/wiki/Set-up-Your-Environment-for-Authentication#configure-defaultazurecredential). ### Authenticating a user assigned managed identity with `DefaultAzureCredential` -This example demonstrates authenticating the `ResourcesClient` from the [armresources][armresources_library] module using the `DefaultAzureCredential`, deployed to an Azure resource with a user assigned managed identity configured. +This example demonstrates authenticating the `ResourcesClient` from the armresources module using the `DefaultAzureCredential`, deployed to an Azure resource with a user assigned managed identity configured. See more about how to configure a user assigned managed identity for an Azure resource in [Enable managed identity for Azure resources](https://github.com/Azure/azure-sdk-for-go/wiki/Set-up-Your-Environment-for-Authentication#enable-managed-identity-for-azure-resources). @@ -122,7 +122,7 @@ The [Managed identity authentication](https://docs.microsoft.com/azure/active-di ### Examples #### Authenticating in Azure with Managed Identity -This examples demonstrates authenticating the `ResourcesClient` from the [armresources][armresources_library] module using `ManagedIdentityCredential` in a virtual machine, app service, function app, cloud shell, or AKS environment on Azure, with system assigned, or user assigned managed identity enabled. +This examples demonstrates authenticating the `ResourcesClient` from the armresources module using `ManagedIdentityCredential` in a virtual machine, app service, function app, cloud shell, or AKS environment on Azure, with system assigned, or user assigned managed identity enabled. See more about how to configure your Azure resource for managed identity in [Enable managed identity for Azure resources](https://github.com/Azure/azure-sdk-for-go/wiki/Set-up-Your-Environment-for-Authentication#enable-managed-identity-for-azure-resources) @@ -232,7 +232,7 @@ Azure Active Directory ### Logging -This module uses the classification based logging implementation in azcore. To turn on logging set `AZURE_SDK_GO_LOGGING` to `all`. If you only want to include logs for `azidentity`, you must create you own logger and set the log classification as `LogCredential`. +This module uses the classification based logging implementation in azcore. To turn on logging set `AZURE_SDK_GO_LOGGING` to `all`. If you only want to include logs for `azidentity`, you must create you own logger and set the log classification as `EventCredential`. Credentials log basic information only, including `GetToken` success or failure and errors. These log entries do not contain authentication secrets but may contain sensitive information. To obtain more detailed logging, including request/response bodies and header values, make sure to leave the logger as default or enable the `LogRequest` and/or `LogResponse` classifications. A logger that only includes credential logs can be like the following: @@ -245,7 +245,7 @@ azlog.SetListener(func(cls LogClassification, s string) { }) // Include only azidentity credential logs -azlog.SetClassifications(azidentity.LogCredential) +azlog.SetClassifications(azidentity.EventCredential) ``` > CAUTION: logs from credentials contain sensitive information. @@ -280,7 +280,6 @@ or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. [azure_cli]: https://docs.microsoft.com/cli/azure -[armresources_library]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/resources/armresources [azblob]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-go%2Fsdk%2Fidentity%2Fazure-identity%2FREADME.png) diff --git a/sdk/azidentity/aad_identity_client.go b/sdk/azidentity/aad_identity_client.go index 70e156ff6ea8..10eb09bbe45e 100644 --- a/sdk/azidentity/aad_identity_client.go +++ b/sdk/azidentity/aad_identity_client.go @@ -54,13 +54,11 @@ type aadIdentityClient struct { pipeline runtime.Pipeline } -// newAADIdentityClient creates a new instance of the aadIdentityClient with the TokenCredentialOptions -// that are passed into it along with a default pipeline. -// options: TokenCredentialOptions that can configure policies for the pipeline and the authority host that -// will be used to retrieve tokens and authenticate -func newAADIdentityClient(authorityHost string, options pipelineOptions) (*aadIdentityClient, error) { +// newAADIdentityClient creates a new instance of the aadIdentityClient +func newAADIdentityClient(authorityHost string, options *azcore.ClientOptions) (*aadIdentityClient, error) { logEnvVars() - return &aadIdentityClient{authorityHost: authorityHost, pipeline: newDefaultPipeline(options)}, nil + pl := runtime.NewPipeline(component, version, nil, nil, options) + return &aadIdentityClient{authorityHost: authorityHost, pipeline: pl}, nil } // aadAuthenticationError is used to unmarshal error responses received from Azure Active Directory diff --git a/sdk/azidentity/aad_identity_client_test.go b/sdk/azidentity/aad_identity_client_test.go index a05a8372e072..2d83cafaa31e 100644 --- a/sdk/azidentity/aad_identity_client_test.go +++ b/sdk/azidentity/aad_identity_client_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/internal/mock" ) @@ -45,10 +46,8 @@ func TestTelemetryDefaultUserAgent(t *testing.T) { srv, close := mock.NewServer() defer close() srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) - options := pipelineOptions{ - HTTPClient: srv, - } - client, err := newAADIdentityClient(srv.URL(), options) + options := azcore.ClientOptions{Transport: srv} + client, err := newAADIdentityClient(srv.URL(), &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) } @@ -73,11 +72,9 @@ func TestTelemetryCustom(t *testing.T) { srv, close := mock.NewServer() defer close() srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) - options := pipelineOptions{ - HTTPClient: srv, - } + options := azcore.ClientOptions{Transport: srv} options.Telemetry.ApplicationID = customTelemetry - client, err := newAADIdentityClient(srv.URL(), options) + client, err := newAADIdentityClient(srv.URL(), &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) } diff --git a/sdk/azidentity/authorization_code_credential.go b/sdk/azidentity/authorization_code_credential.go index 27c2c8126939..abf70cfe57f2 100644 --- a/sdk/azidentity/authorization_code_credential.go +++ b/sdk/azidentity/authorization_code_credential.go @@ -13,20 +13,13 @@ import ( // AuthorizationCodeCredentialOptions contain optional parameters that can be used to configure the AuthorizationCodeCredential. // All zero-value fields will be initialized with their default values. type AuthorizationCodeCredentialOptions struct { + azcore.ClientOptions + // Gets the client secret that was generated for the App Registration used to authenticate the client. ClientSecret string // The host of the Azure Active Directory authority. The default is AzurePublicCloud. // Leave empty to allow overriding the value from the AZURE_AUTHORITY_HOST environment variable. AuthorityHost AuthorityHost - // HTTPClient sets the transport for making HTTP requests - // Leave this as nil to use the default HTTP transport - HTTPClient policy.Transporter - // Retry configures the built-in retry policy behavior - Retry policy.RetryOptions - // Telemetry configures the built-in telemetry policy behavior - Telemetry policy.TelemetryOptions - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions } // AuthorizationCodeCredential enables authentication to Azure Active Directory using an authorization code @@ -51,18 +44,19 @@ func NewAuthorizationCodeCredential(tenantID string, clientID string, authCode s if !validTenantID(tenantID) { return nil, &CredentialUnavailableError{credentialType: "Authorization Code Credential", message: tenantIDValidationErr} } - if options == nil { - options = &AuthorizationCodeCredentialOptions{} + cp := AuthorizationCodeCredentialOptions{} + if options != nil { + cp = *options } - authorityHost, err := setAuthorityHost(options.AuthorityHost) + authorityHost, err := setAuthorityHost(cp.AuthorityHost) if err != nil { return nil, err } - c, err := newAADIdentityClient(authorityHost, pipelineOptions{HTTPClient: options.HTTPClient, Retry: options.Retry, Telemetry: options.Telemetry, Logging: options.Logging}) + c, err := newAADIdentityClient(authorityHost, &cp.ClientOptions) if err != nil { return nil, err } - return &AuthorizationCodeCredential{tenantID: tenantID, clientID: clientID, authCode: authCode, clientSecret: options.ClientSecret, redirectURI: redirectURL, client: c}, nil + return &AuthorizationCodeCredential{tenantID: tenantID, clientID: clientID, authCode: authCode, clientSecret: cp.ClientSecret, redirectURI: redirectURL, client: c}, nil } // GetToken obtains a token from Azure Active Directory, using the specified authorization code to authenticate. diff --git a/sdk/azidentity/authorization_code_credential_test.go b/sdk/azidentity/authorization_code_credential_test.go index 5ffc42bba45f..477bda1dfa65 100644 --- a/sdk/azidentity/authorization_code_credential_test.go +++ b/sdk/azidentity/authorization_code_credential_test.go @@ -82,7 +82,7 @@ func TestAuthorizationCodeCredential_GetTokenSuccess(t *testing.T) { options := AuthorizationCodeCredentialOptions{} options.ClientSecret = secret options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, testRedirectURI, &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -100,7 +100,7 @@ func TestAuthorizationCodeCredential_GetTokenInvalidCredentials(t *testing.T) { options := AuthorizationCodeCredentialOptions{} options.ClientSecret = secret options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, testRedirectURI, &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -125,7 +125,7 @@ func TestAuthorizationCodeCredential_GetTokenUnexpectedJSON(t *testing.T) { options := AuthorizationCodeCredentialOptions{} options.ClientSecret = secret options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, testRedirectURI, &options) if err != nil { t.Fatalf("Failed to create the credential") diff --git a/sdk/azidentity/azidentity.go b/sdk/azidentity/azidentity.go index 891454c01263..aa63afd11675 100644 --- a/sdk/azidentity/azidentity.go +++ b/sdk/azidentity/azidentity.go @@ -10,11 +10,8 @@ import ( "os" "path" "regexp" - "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo" ) @@ -105,22 +102,6 @@ func (e *CredentialUnavailableError) NonRetriable() { var _ errorinfo.NonRetriable = (*CredentialUnavailableError)(nil) -// pipelineOptions are used to configure how requests are made to Azure Active Directory. -type pipelineOptions struct { - // HTTPClient sets the transport for making HTTP requests - // Leave this as nil to use the default HTTP transport - HTTPClient policy.Transporter - - // Retry configures the built-in retry policy behavior - Retry policy.RetryOptions - - // Telemetry configures the built-in telemetry policy behavior - Telemetry policy.TelemetryOptions - - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions -} - // setAuthorityHost initializes the authority host for credentials. func setAuthorityHost(authorityHost AuthorityHost) (string, error) { host := string(authorityHost) @@ -140,54 +121,6 @@ func setAuthorityHost(authorityHost AuthorityHost) (string, error) { return host, nil } -// newDefaultPipeline creates a pipeline using the specified pipeline options. -func newDefaultPipeline(o pipelineOptions) runtime.Pipeline { - policies := []policy.Policy{} - if !o.Telemetry.Disabled { - policies = append(policies, runtime.NewTelemetryPolicy(component, version, &o.Telemetry)) - } - policies = append(policies, runtime.NewRetryPolicy(&o.Retry)) - policies = append(policies, runtime.NewLogPolicy(&o.Logging)) - return runtime.NewPipeline(o.HTTPClient, policies...) -} - -// newDefaultMSIPipeline creates a pipeline using the specified pipeline options needed -// for a Managed Identity, such as a MSI specific retry policy. -func newDefaultMSIPipeline(o ManagedIdentityCredentialOptions) runtime.Pipeline { - var statusCodes []int - // retry policy for MSI is not end-user configurable - retryOpts := policy.RetryOptions{ - MaxRetries: 5, - MaxRetryDelay: 1 * time.Minute, - RetryDelay: 2 * time.Second, - TryTimeout: 1 * time.Minute, - StatusCodes: append(statusCodes, - // The following status codes are a subset of those found in azcore.StatusCodesForRetry, these are the only ones specifically needed for MSI scenarios - http.StatusRequestTimeout, // 408 - http.StatusTooManyRequests, // 429 - http.StatusInternalServerError, // 500 - http.StatusBadGateway, // 502 - http.StatusGatewayTimeout, // 504 - http.StatusNotFound, //404 - http.StatusGone, //410 - // all remaining 5xx - http.StatusNotImplemented, // 501 - http.StatusHTTPVersionNotSupported, // 505 - http.StatusVariantAlsoNegotiates, // 506 - http.StatusInsufficientStorage, // 507 - http.StatusLoopDetected, // 508 - http.StatusNotExtended, // 510 - http.StatusNetworkAuthenticationRequired), // 511 - } - policies := []policy.Policy{} - if !o.Telemetry.Disabled { - policies = append(policies, runtime.NewTelemetryPolicy(component, version, &o.Telemetry)) - } - policies = append(policies, runtime.NewRetryPolicy(&retryOpts)) - policies = append(policies, runtime.NewLogPolicy(&o.Logging)) - return runtime.NewPipeline(o.HTTPClient, policies...) -} - // validTenantID return true is it receives a valid tenantID, returns false otherwise func validTenantID(tenantID string) bool { match, err := regexp.MatchString("^[0-9a-zA-Z-.]+$", tenantID) diff --git a/sdk/azidentity/azidentity_test.go b/sdk/azidentity/azidentity_test.go index 0c8bb85f1369..1d6698f3b722 100644 --- a/sdk/azidentity/azidentity_test.go +++ b/sdk/azidentity/azidentity_test.go @@ -25,11 +25,8 @@ func defaultTestPipeline(srv policy.Transporter, cred azcore.TokenCredential, sc MaxRetryDelay: 500 * time.Millisecond, RetryDelay: 50 * time.Millisecond, } - return runtime.NewPipeline( - srv, - runtime.NewRetryPolicy(&retryOpts), - runtime.NewBearerTokenPolicy(cred, runtime.AuthenticationOptions{TokenRequest: policy.TokenRequestOptions{Scopes: []string{scope}}}), - runtime.NewLogPolicy(nil)) + b := runtime.NewBearerTokenPolicy(cred, []string{scope}, nil) + return runtime.NewPipeline("azidentity-test", version, nil, []policy.Policy{b}, &azcore.ClientOptions{Retry: retryOpts, Transport: srv}) } // constants for this file diff --git a/sdk/azidentity/chained_token_credential_test.go b/sdk/azidentity/chained_token_credential_test.go index 3b163edb17cd..b4f6ddb31e39 100644 --- a/sdk/azidentity/chained_token_credential_test.go +++ b/sdk/azidentity/chained_token_credential_test.go @@ -71,12 +71,15 @@ func TestChainedTokenCredential_GetTokenSuccess(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := ClientSecretCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv secCred, err := NewClientSecretCredential(tenantID, clientID, secret, &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) } - envCred, err := NewEnvironmentCredential(&EnvironmentCredentialOptions{HTTPClient: srv, AuthorityHost: AuthorityHost(srv.URL())}) + envCred, err := NewEnvironmentCredential(&EnvironmentCredentialOptions{ + ClientOptions: azcore.ClientOptions{Transport: srv}, + AuthorityHost: AuthorityHost(srv.URL()), + }) if err != nil { t.Fatalf("Failed to create environment credential: %v", err) } @@ -102,7 +105,7 @@ func TestChainedTokenCredential_GetTokenFail(t *testing.T) { srv.AppendResponse(mock.WithStatusCode(http.StatusUnauthorized)) options := ClientSecretCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv secCred, err := NewClientSecretCredential(tenantID, clientID, wrongSecret, &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -131,7 +134,7 @@ func TestChainedTokenCredential_GetTokenWithUnavailableCredentialInChain(t *test srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := ClientSecretCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv secCred, err := NewClientSecretCredential(tenantID, clientID, wrongSecret, &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -168,7 +171,7 @@ func TestBearerPolicy_ChainedTokenCredential(t *testing.T) { srv.AppendResponse(mock.WithStatusCode(http.StatusOK)) options := ClientSecretCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewClientSecretCredential(tenantID, clientID, secret, &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) diff --git a/sdk/azidentity/ci.yml b/sdk/azidentity/ci.yml index f145e1fd2d4a..459fbc9e256f 100644 --- a/sdk/azidentity/ci.yml +++ b/sdk/azidentity/ci.yml @@ -22,7 +22,6 @@ pr: - sdk/azidentity/ stages: -- template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml +- template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'azidentity' - RunTests: true diff --git a/sdk/azidentity/client_certificate_credential.go b/sdk/azidentity/client_certificate_credential.go index 2730f88bbf85..4efadb1970b4 100644 --- a/sdk/azidentity/client_certificate_credential.go +++ b/sdk/azidentity/client_certificate_credential.go @@ -19,6 +19,8 @@ import ( // ClientCertificateCredentialOptions contain optional parameters that can be used when configuring a ClientCertificateCredential. // All zero-value fields will be initialized with their default values. type ClientCertificateCredentialOptions struct { + azcore.ClientOptions + // The password required to decrypt the private key. Leave empty if there is no password. Password string // Set to true to include x5c header in client claims when acquiring a token to enable @@ -27,15 +29,6 @@ type ClientCertificateCredentialOptions struct { // The host of the Azure Active Directory authority. The default is AzurePublicCloud. // Leave empty to allow overriding the value from the AZURE_AUTHORITY_HOST environment variable. AuthorityHost AuthorityHost - // HTTPClient sets the transport for making HTTP requests - // Leave this as nil to use the default HTTP transport - HTTPClient policy.Transporter - // Retry configures the built-in retry policy behavior - Retry policy.RetryOptions - // Telemetry configures the built-in telemetry policy behavior - Telemetry policy.TelemetryOptions - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions } // ClientCertificateCredential enables authentication of a service principal to Azure Active Directory using a certificate that is assigned to its App Registration. More information @@ -58,27 +51,28 @@ func NewClientCertificateCredential(tenantID string, clientID string, certData [ if !validTenantID(tenantID) { return nil, &CredentialUnavailableError{credentialType: "Client Certificate Credential", message: tenantIDValidationErr} } - if options == nil { - options = &ClientCertificateCredentialOptions{} + cp := ClientCertificateCredentialOptions{} + if options != nil { + cp = *options } - cert, err := loadPEMCert(certData, options.Password, options.SendCertificateChain) + cert, err := loadPEMCert(certData, cp.Password, cp.SendCertificateChain) if err != nil { - cert, err = loadPKCS12Cert(certData, options.Password, options.SendCertificateChain) + cert, err = loadPKCS12Cert(certData, cp.Password, cp.SendCertificateChain) } if err != nil { credErr := &CredentialUnavailableError{credentialType: "Client Certificate Credential", message: err.Error()} logCredentialError(credErr.credentialType, credErr) return nil, credErr } - authorityHost, err := setAuthorityHost(options.AuthorityHost) + authorityHost, err := setAuthorityHost(cp.AuthorityHost) if err != nil { return nil, err } - c, err := newAADIdentityClient(authorityHost, pipelineOptions{HTTPClient: options.HTTPClient, Retry: options.Retry, Telemetry: options.Telemetry, Logging: options.Logging}) + c, err := newAADIdentityClient(authorityHost, &cp.ClientOptions) if err != nil { return nil, err } - return &ClientCertificateCredential{tenantID: tenantID, clientID: clientID, cert: cert, sendCertificateChain: options.SendCertificateChain, client: c}, nil + return &ClientCertificateCredential{tenantID: tenantID, clientID: clientID, cert: cert, sendCertificateChain: cp.SendCertificateChain, client: c}, nil } // contains decoded cert contents we care about diff --git a/sdk/azidentity/client_certificate_credential_test.go b/sdk/azidentity/client_certificate_credential_test.go index 8cb58f5e2908..ea5327b8786a 100644 --- a/sdk/azidentity/client_certificate_credential_test.go +++ b/sdk/azidentity/client_certificate_credential_test.go @@ -166,7 +166,7 @@ func TestClientCertificateCredential_GetTokenSuccess(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := ClientCertificateCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv options.Password = test.password cred, err := NewClientCertificateCredential(tenantID, clientID, test.certData, &options) if err != nil { @@ -189,7 +189,7 @@ func TestClientCertificateCredential_GetTokenSuccess_withCertificateChain(t *tes options := ClientCertificateCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) options.SendCertificateChain = true - options.HTTPClient = srv + options.Transport = srv options.Password = test.password cred, err := NewClientCertificateCredential(tenantID, clientID, test.certData, &options) if err != nil { @@ -211,7 +211,7 @@ func TestClientCertificateCredential_GetTokenInvalidCredentials(t *testing.T) { srv.SetResponse(mock.WithStatusCode(http.StatusUnauthorized)) options := ClientCertificateCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv options.Password = test.password cred, err := NewClientCertificateCredential(tenantID, clientID, test.certData, &options) if err != nil { @@ -235,7 +235,7 @@ func TestClientCertificateCredential_GetTokenCheckPrivateKeyBlocks(t *testing.T) srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := ClientCertificateCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv certData, err := os.ReadFile("testdata/certificate_formatB.pem") if err != nil { t.Fatalf("Failed to read certificate file: %s", err.Error()) @@ -256,7 +256,7 @@ func TestClientCertificateCredential_NoData(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := ClientCertificateCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv _, err := NewClientCertificateCredential(tenantID, clientID, []byte{}, &options) if err == nil { t.Fatalf("Expected an error but received nil") @@ -269,7 +269,7 @@ func TestClientCertificateCredential_NoCertificate(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := ClientCertificateCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv certData, err := os.ReadFile("testdata/certificate_empty.pem") if err != nil { t.Fatalf("Failed to read certificate file: %s", err.Error()) @@ -286,7 +286,7 @@ func TestClientCertificateCredential_NoPrivateKey(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := ClientCertificateCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv certData, err := os.ReadFile("testdata/certificate_nokey.pem") if err != nil { t.Fatalf("Failed to read certificate file: %s", err.Error()) @@ -304,7 +304,7 @@ func TestBearerPolicy_ClientCertificateCredential(t *testing.T) { srv.AppendResponse(mock.WithStatusCode(http.StatusOK)) options := ClientCertificateCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewClientCertificateCredential(tenantID, clientID, pemCert, &options) if err != nil { t.Fatalf("Did not expect an error but received: %v", err) diff --git a/sdk/azidentity/client_secret_credential.go b/sdk/azidentity/client_secret_credential.go index d6aeb2d5342c..fba9fad57404 100644 --- a/sdk/azidentity/client_secret_credential.go +++ b/sdk/azidentity/client_secret_credential.go @@ -13,18 +13,11 @@ import ( // ClientSecretCredentialOptions configures the ClientSecretCredential with optional parameters. // All zero-value fields will be initialized with their default values. type ClientSecretCredentialOptions struct { + azcore.ClientOptions + // The host of the Azure Active Directory authority. The default is AzurePublicCloud. // Leave empty to allow overriding the value from the AZURE_AUTHORITY_HOST environment variable. AuthorityHost AuthorityHost - // HTTPClient sets the transport for making HTTP requests - // Leave this as nil to use the default HTTP transport - HTTPClient policy.Transporter - // Retry configures the built-in retry policy behavior - Retry policy.RetryOptions - // Telemetry configures the built-in telemetry policy behavior - Telemetry policy.TelemetryOptions - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions } // ClientSecretCredential enables authentication to Azure Active Directory using a client secret that was generated for an App Registration. More information on how @@ -46,14 +39,15 @@ func NewClientSecretCredential(tenantID string, clientID string, clientSecret st if !validTenantID(tenantID) { return nil, &CredentialUnavailableError{credentialType: "Client Secret Credential", message: tenantIDValidationErr} } - if options == nil { - options = &ClientSecretCredentialOptions{} + cp := ClientSecretCredentialOptions{} + if options != nil { + cp = *options } - authorityHost, err := setAuthorityHost(options.AuthorityHost) + authorityHost, err := setAuthorityHost(cp.AuthorityHost) if err != nil { return nil, err } - c, err := newAADIdentityClient(authorityHost, pipelineOptions{HTTPClient: options.HTTPClient, Retry: options.Retry, Telemetry: options.Telemetry, Logging: options.Logging}) + c, err := newAADIdentityClient(authorityHost, &cp.ClientOptions) if err != nil { return nil, err } diff --git a/sdk/azidentity/client_secret_credential_test.go b/sdk/azidentity/client_secret_credential_test.go index 8cae6b6deb67..e449a12eda1a 100644 --- a/sdk/azidentity/client_secret_credential_test.go +++ b/sdk/azidentity/client_secret_credential_test.go @@ -84,7 +84,7 @@ func TestClientSecretCredential_GetTokenSuccess(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := ClientSecretCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewClientSecretCredential(tenantID, clientID, secret, &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -101,7 +101,7 @@ func TestClientSecretCredential_GetTokenInvalidCredentials(t *testing.T) { srv.SetResponse(mock.WithBody([]byte(accessTokenRespError)), mock.WithStatusCode(http.StatusUnauthorized)) options := ClientSecretCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewClientSecretCredential(tenantID, clientID, wrongSecret, &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -125,7 +125,7 @@ func TestClientSecretCredential_GetTokenUnexpectedJSON(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(accessTokenRespMalformed))) options := ClientSecretCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewClientSecretCredential(tenantID, clientID, secret, &options) if err != nil { t.Fatalf("Failed to create the credential") diff --git a/sdk/azidentity/default_azure_credential.go b/sdk/azidentity/default_azure_credential.go index de944c71c2a1..73f266934750 100644 --- a/sdk/azidentity/default_azure_credential.go +++ b/sdk/azidentity/default_azure_credential.go @@ -5,7 +5,6 @@ package azidentity import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/internal/log" ) @@ -17,18 +16,11 @@ const ( // DefaultAzureCredentialOptions contains options for configuring authentication. These options // may not apply to all credentials in the default chain. type DefaultAzureCredentialOptions struct { + azcore.ClientOptions + // The host of the Azure Active Directory authority. The default is AzurePublicCloud. // Leave empty to allow overriding the value from the AZURE_AUTHORITY_HOST environment variable. AuthorityHost AuthorityHost - // HTTPClient sets the transport for making HTTP requests - // Leave this as nil to use the default HTTP transport - HTTPClient policy.Transporter - // Retry configures the built-in retry policy behavior - Retry policy.RetryOptions - // Telemetry configures the built-in telemetry policy behavior - Telemetry policy.TelemetryOptions - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions } // NewDefaultAzureCredential provides a default ChainedTokenCredential configuration for applications that will be deployed to Azure. The following credential @@ -41,15 +33,13 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Chained var creds []azcore.TokenCredential errMsg := "" - if options == nil { - options = &DefaultAzureCredentialOptions{} + cp := DefaultAzureCredentialOptions{} + if options != nil { + cp = *options } - envCred, err := NewEnvironmentCredential(&EnvironmentCredentialOptions{AuthorityHost: options.AuthorityHost, - HTTPClient: options.HTTPClient, - Logging: options.Logging, - Retry: options.Retry, - Telemetry: options.Telemetry, + envCred, err := NewEnvironmentCredential(&EnvironmentCredentialOptions{AuthorityHost: cp.AuthorityHost, + ClientOptions: cp.ClientOptions, }) if err == nil { creds = append(creds, envCred) @@ -57,10 +47,7 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Chained errMsg += err.Error() } - msiCred, err := NewManagedIdentityCredential(&ManagedIdentityCredentialOptions{HTTPClient: options.HTTPClient, - Logging: options.Logging, - Telemetry: options.Telemetry, - }) + msiCred, err := NewManagedIdentityCredential(&ManagedIdentityCredentialOptions{ClientOptions: cp.ClientOptions}) if err == nil { creds = append(creds, msiCred) } else { @@ -80,6 +67,6 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Chained logCredentialError(err.credentialType, err) return nil, err } - log.Write(LogCredential, "Azure Identity => NewDefaultAzureCredential() invoking NewChainedTokenCredential()") + log.Write(EventCredential, "Azure Identity => NewDefaultAzureCredential() invoking NewChainedTokenCredential()") return NewChainedTokenCredential(creds, nil) } diff --git a/sdk/azidentity/device_code_credential.go b/sdk/azidentity/device_code_credential.go index 186ee549df73..1498d459b390 100644 --- a/sdk/azidentity/device_code_credential.go +++ b/sdk/azidentity/device_code_credential.go @@ -22,6 +22,8 @@ const ( // All zero-value fields will be initialized with their default values. Please note, that both the TenantID or ClientID fields should // changed together if default values are not desired. type DeviceCodeCredentialOptions struct { + azcore.ClientOptions + // Gets the Azure Active Directory tenant (directory) ID of the service principal // The default value is "organizations". If this value is changed, then also change ClientID to the corresponding value. TenantID string @@ -34,15 +36,6 @@ type DeviceCodeCredentialOptions struct { // The host of the Azure Active Directory authority. The default is AzurePublicCloud. // Leave empty to allow overriding the value from the AZURE_AUTHORITY_HOST environment variable. AuthorityHost AuthorityHost - // HTTPClient sets the transport for making HTTP requests - // Leave this as nil to use the default HTTP transport - HTTPClient policy.Transporter - // Retry configures the built-in retry policy behavior - Retry policy.RetryOptions - // Telemetry configures the built-in telemetry policy behavior - Telemetry policy.TelemetryOptions - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions } // init provides the default settings for DeviceCodeCredential. @@ -101,7 +94,7 @@ func NewDeviceCodeCredential(options *DeviceCodeCredentialOptions) (*DeviceCodeC if err != nil { return nil, err } - c, err := newAADIdentityClient(authorityHost, pipelineOptions{HTTPClient: cp.HTTPClient, Retry: cp.Retry, Telemetry: cp.Telemetry, Logging: cp.Logging}) + c, err := newAADIdentityClient(authorityHost, &cp.ClientOptions) if err != nil { return nil, err } diff --git a/sdk/azidentity/device_code_credential_test.go b/sdk/azidentity/device_code_credential_test.go index 265a900af389..6296edc4bba4 100644 --- a/sdk/azidentity/device_code_credential_test.go +++ b/sdk/azidentity/device_code_credential_test.go @@ -11,6 +11,7 @@ import ( "net/url" "testing" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/internal/mock" @@ -176,7 +177,7 @@ func TestDeviceCodeCredential_GetTokenSuccess(t *testing.T) { srv.AppendResponse(mock.WithStatusCode(http.StatusOK)) options := DeviceCodeCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewDeviceCodeCredential(&options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -197,7 +198,7 @@ func TestDeviceCodeCredential_GetTokenInvalidCredentials(t *testing.T) { options := DeviceCodeCredentialOptions{} options.ClientID = clientID options.TenantID = tenantID - options.HTTPClient = srv + options.Transport = srv options.AuthorityHost = AuthorityHost(srv.URL()) cred, err := NewDeviceCodeCredential(&options) if err != nil { @@ -219,7 +220,7 @@ func TestDeviceCodeCredential_GetTokenAuthorizationPending(t *testing.T) { options := DeviceCodeCredentialOptions{} options.ClientID = clientID options.TenantID = tenantID - options.HTTPClient = srv + options.Transport = srv options.AuthorityHost = AuthorityHost(srv.URL()) options.UserPrompt = func(context.Context, DeviceCodeMessage) error { return nil } cred, err := NewDeviceCodeCredential(&options) @@ -241,7 +242,7 @@ func TestDeviceCodeCredential_GetTokenExpiredToken(t *testing.T) { options := DeviceCodeCredentialOptions{} options.ClientID = clientID options.TenantID = tenantID - options.HTTPClient = srv + options.Transport = srv options.AuthorityHost = AuthorityHost(srv.URL()) options.UserPrompt = func(context.Context, DeviceCodeMessage) error { return nil } cred, err := NewDeviceCodeCredential(&options) @@ -261,7 +262,7 @@ func TestDeviceCodeCredential_GetTokenWithRefreshTokenFailure(t *testing.T) { options := DeviceCodeCredentialOptions{} options.ClientID = clientID options.TenantID = tenantID - options.HTTPClient = srv + options.Transport = srv options.AuthorityHost = AuthorityHost(srv.URL()) cred, err := NewDeviceCodeCredential(&options) if err != nil { @@ -288,7 +289,7 @@ func TestDeviceCodeCredential_GetTokenWithRefreshTokenSuccess(t *testing.T) { options := DeviceCodeCredentialOptions{} options.ClientID = clientID options.TenantID = tenantID - options.HTTPClient = srv + options.Transport = srv options.AuthorityHost = AuthorityHost(srv.URL()) options.UserPrompt = func(context.Context, DeviceCodeMessage) error { return nil } cred, err := NewDeviceCodeCredential(&options) @@ -314,7 +315,7 @@ func TestBearerPolicy_DeviceCodeCredential(t *testing.T) { options := DeviceCodeCredentialOptions{} options.ClientID = clientID options.TenantID = tenantID - options.HTTPClient = srv + options.Transport = srv options.AuthorityHost = AuthorityHost(srv.URL()) options.UserPrompt = func(context.Context, DeviceCodeMessage) error { return nil } cred, err := NewDeviceCodeCredential(&options) @@ -342,9 +343,9 @@ func TestDeviceCodeCredential_UserPrompt(t *testing.T) { key := "key" val := "value" options := DeviceCodeCredentialOptions{ + ClientOptions: azcore.ClientOptions{Transport: srv}, AuthorityHost: AuthorityHost(srv.URL()), ClientID: clientID, - HTTPClient: srv, TenantID: tenantID, UserPrompt: func(ctx context.Context, m DeviceCodeMessage) error { called = true @@ -377,9 +378,9 @@ func TestDeviceCodeCredential_UserPromptError(t *testing.T) { expectedCtx := context.WithValue(context.Background(), "", "") msg := "it worked" options := DeviceCodeCredentialOptions{ + ClientOptions: azcore.ClientOptions{Transport: srv}, AuthorityHost: AuthorityHost(srv.URL()), ClientID: clientID, - HTTPClient: srv, TenantID: tenantID, UserPrompt: func(ctx context.Context, m DeviceCodeMessage) error { if ctx != expectedCtx { diff --git a/sdk/azidentity/environment_credential.go b/sdk/azidentity/environment_credential.go index d8307686e1da..fcc46641ff54 100644 --- a/sdk/azidentity/environment_credential.go +++ b/sdk/azidentity/environment_credential.go @@ -15,18 +15,11 @@ import ( // EnvironmentCredentialOptions configures the EnvironmentCredential with optional parameters. // All zero-value fields will be initialized with their default values. type EnvironmentCredentialOptions struct { + azcore.ClientOptions + // The host of the Azure Active Directory authority. The default is AzurePublicCloud. // Leave empty to allow overriding the value from the AZURE_AUTHORITY_HOST environment variable. AuthorityHost AuthorityHost - // HTTPClient sets the transport for making HTTP requests - // Leave this as nil to use the default HTTP transport - HTTPClient policy.Transporter - // Retry configures the built-in retry policy behavior - Retry policy.RetryOptions - // Telemetry configures the built-in telemetry policy behavior - Telemetry policy.TelemetryOptions - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions } // EnvironmentCredential enables authentication to Azure Active Directory using either ClientSecretCredential, ClientCertificateCredential or UsernamePasswordCredential. @@ -47,8 +40,9 @@ type EnvironmentCredential struct { // If the expected environment variables are not found at this time, then a CredentialUnavailableError will be returned. // options: The options used to configure the management of the requests sent to Azure Active Directory. func NewEnvironmentCredential(options *EnvironmentCredentialOptions) (*EnvironmentCredential, error) { - if options == nil { - options = &EnvironmentCredentialOptions{} + cp := EnvironmentCredentialOptions{} + if options != nil { + cp = *options } tenantID := os.Getenv("AZURE_TENANT_ID") if tenantID == "" { @@ -63,20 +57,20 @@ func NewEnvironmentCredential(options *EnvironmentCredentialOptions) (*Environme return nil, err } if clientSecret := os.Getenv("AZURE_CLIENT_SECRET"); clientSecret != "" { - log.Write(LogCredential, "Azure Identity => NewEnvironmentCredential() invoking ClientSecretCredential") - cred, err := NewClientSecretCredential(tenantID, clientID, clientSecret, &ClientSecretCredentialOptions{AuthorityHost: options.AuthorityHost, HTTPClient: options.HTTPClient, Retry: options.Retry, Telemetry: options.Telemetry, Logging: options.Logging}) + log.Write(EventCredential, "Azure Identity => NewEnvironmentCredential() invoking ClientSecretCredential") + cred, err := NewClientSecretCredential(tenantID, clientID, clientSecret, &ClientSecretCredentialOptions{AuthorityHost: cp.AuthorityHost, ClientOptions: cp.ClientOptions}) if err != nil { return nil, err } return &EnvironmentCredential{cred: cred}, nil } if certPath := os.Getenv("AZURE_CLIENT_CERTIFICATE_PATH"); certPath != "" { - log.Write(LogCredential, "Azure Identity => NewEnvironmentCredential() invoking ClientCertificateCredential") + log.Write(EventCredential, "Azure Identity => NewEnvironmentCredential() invoking ClientCertificateCredential") certData, err := os.ReadFile(certPath) if err != nil { return nil, &CredentialUnavailableError{credentialType: "Environment Credential", message: "Failed to read certificate file: " + err.Error()} } - cred, err := NewClientCertificateCredential(tenantID, clientID, certData, &ClientCertificateCredentialOptions{AuthorityHost: options.AuthorityHost, HTTPClient: options.HTTPClient, Retry: options.Retry, Telemetry: options.Telemetry, Logging: options.Logging}) + cred, err := NewClientCertificateCredential(tenantID, clientID, certData, &ClientCertificateCredentialOptions{AuthorityHost: cp.AuthorityHost, ClientOptions: cp.ClientOptions}) if err != nil { return nil, err } @@ -84,8 +78,8 @@ func NewEnvironmentCredential(options *EnvironmentCredentialOptions) (*Environme } if username := os.Getenv("AZURE_USERNAME"); username != "" { if password := os.Getenv("AZURE_PASSWORD"); password != "" { - log.Write(LogCredential, "Azure Identity => NewEnvironmentCredential() invoking UsernamePasswordCredential") - cred, err := NewUsernamePasswordCredential(tenantID, clientID, username, password, &UsernamePasswordCredentialOptions{AuthorityHost: options.AuthorityHost, HTTPClient: options.HTTPClient, Retry: options.Retry, Telemetry: options.Telemetry, Logging: options.Logging}) + log.Write(EventCredential, "Azure Identity => NewEnvironmentCredential() invoking UsernamePasswordCredential") + cred, err := NewUsernamePasswordCredential(tenantID, clientID, username, password, &UsernamePasswordCredentialOptions{AuthorityHost: cp.AuthorityHost, ClientOptions: cp.ClientOptions}) if err != nil { return nil, err } diff --git a/sdk/azidentity/go.mod b/sdk/azidentity/go.mod index e1e88f7dbb5f..82ded8237f73 100644 --- a/sdk/azidentity/go.mod +++ b/sdk/azidentity/go.mod @@ -1,12 +1,10 @@ module github.com/Azure/azure-sdk-for-go/sdk/azidentity -go 1.14 - -replace github.com/Azure/azure-sdk-for-go/sdk/azcore => ../azcore +go 1.16 require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0 - github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.1 + github.com/Azure/azure-sdk-for-go/sdk/azcore v0.20.0 + github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.1 github.com/davecgh/go-spew v1.1.1 // indirect github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 diff --git a/sdk/azidentity/go.sum b/sdk/azidentity/go.sum index 891714da0078..4c0862037317 100644 --- a/sdk/azidentity/go.sum +++ b/sdk/azidentity/go.sum @@ -1,5 +1,7 @@ -github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.1 h1:8XSiy/LSvjtFwpguk7m6yGLgGkWocluo8hLM5vtcpcg= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.1/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.20.0 h1:KQgdWmEOmaJKxaUUZwHAYh12t+b+ZJf8q3friycK1kA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.20.0/go.mod h1:ZPW/Z0kLCTdDZaDbYTetxc9Cxl/2lNqxYHYNOF2bti0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.1 h1:BUYIbDf/mMZ8945v3QkG3OuqGVyS4Iek0AOLwdRAYoc= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.1/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -31,7 +33,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/sdk/azidentity/interactive_browser_credential.go b/sdk/azidentity/interactive_browser_credential.go index c445c3028293..f56c615db2f0 100644 --- a/sdk/azidentity/interactive_browser_credential.go +++ b/sdk/azidentity/interactive_browser_credential.go @@ -24,6 +24,8 @@ import ( // All zero-value fields will be initialized with their default values. Please note, that both the TenantID or ClientID fields should // changed together if default values are not desired. type InteractiveBrowserCredentialOptions struct { + azcore.ClientOptions + // The Azure Active Directory tenant (directory) ID of the application. Defaults to "organizations". TenantID string // The ID of the application the user will sign in to. When not set, users will sign in to an Azure development application. @@ -34,15 +36,6 @@ type InteractiveBrowserCredentialOptions struct { // The host of the Azure Active Directory authority. The default is AzurePublicCloud. // Leave empty to allow overriding the value from the AZURE_AUTHORITY_HOST environment variable. AuthorityHost AuthorityHost - // HTTPClient sets the transport for making HTTP requests - // Leave this as nil to use the default HTTP transport - HTTPClient policy.Transporter - // Retry configures the built-in retry policy behavior - Retry policy.RetryOptions - // Telemetry configures the built-in telemetry policy behavior - Telemetry policy.TelemetryOptions - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions } // init returns an instance of InteractiveBrowserCredentialOptions initialized with default values. @@ -77,7 +70,7 @@ func NewInteractiveBrowserCredential(options *InteractiveBrowserCredentialOption if err != nil { return nil, err } - c, err := newAADIdentityClient(authorityHost, pipelineOptions{HTTPClient: cp.HTTPClient, Retry: cp.Retry, Telemetry: cp.Telemetry, Logging: cp.Logging}) + c, err := newAADIdentityClient(authorityHost, &cp.ClientOptions) if err != nil { return nil, err } diff --git a/sdk/azidentity/interactive_browser_credential_test.go b/sdk/azidentity/interactive_browser_credential_test.go index 8c996cf72d11..c1234f3e1715 100644 --- a/sdk/azidentity/interactive_browser_credential_test.go +++ b/sdk/azidentity/interactive_browser_credential_test.go @@ -58,7 +58,7 @@ func TestInteractiveBrowserCredential_GetTokenSuccess(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := InteractiveBrowserCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = client + options.Transport = client cred, err := NewInteractiveBrowserCredential(&options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -90,7 +90,7 @@ func TestInteractiveBrowserCredential_GetTokenInvalidCredentials(t *testing.T) { srv.SetResponse(mock.WithBody([]byte(accessTokenRespError)), mock.WithStatusCode(http.StatusUnauthorized)) options := InteractiveBrowserCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = client + options.Transport = client cred, err := NewInteractiveBrowserCredential(&options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) diff --git a/sdk/azidentity/logging.go b/sdk/azidentity/logging.go index 97bf1fb1810d..2a2613ac79fd 100644 --- a/sdk/azidentity/logging.go +++ b/sdk/azidentity/logging.go @@ -14,14 +14,14 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/internal/log" ) -// LogCredential entries contain information about authentication. +// EventCredential entries contain information about authentication. // This includes information like the names of environment variables // used when obtaining credentials and the type of credential used. -const LogCredential log.Classification = "Credential" +const EventCredential log.Event = "Credential" // log environment variables that can be used for credential types func logEnvVars() { - if !log.Should(LogCredential) { + if !log.Should(EventCredential) { return } // Log available environment variables @@ -42,25 +42,25 @@ func logEnvVars() { envVars = append(envVars, "AZURE_CLI_PATH") } if len(envVars) > 0 { - log.Writef(LogCredential, "Azure Identity => Found the following environment variables:\n\t%s", strings.Join(envVars, ", ")) + log.Writef(EventCredential, "Azure Identity => Found the following environment variables:\n\t%s", strings.Join(envVars, ", ")) } } func logGetTokenSuccess(cred azcore.TokenCredential, opts policy.TokenRequestOptions) { - if !log.Should(LogCredential) { + if !log.Should(EventCredential) { return } msg := fmt.Sprintf("Azure Identity => GetToken() result for %T: SUCCESS\n", cred) msg += fmt.Sprintf("\tCredential Scopes: [%s]", strings.Join(opts.Scopes, ", ")) - log.Write(LogCredential, msg) + log.Write(EventCredential, msg) } func logCredentialError(credName string, err error) { - log.Writef(LogCredential, "Azure Identity => ERROR in %s: %s", credName, err.Error()) + log.Writef(EventCredential, "Azure Identity => ERROR in %s: %s", credName, err.Error()) } func logMSIEnv(msi msiType) { - if !log.Should(LogCredential) { + if !log.Should(EventCredential) { return } var msg string @@ -74,11 +74,11 @@ func logMSIEnv(msi msiType) { default: msg = "Azure Identity => Managed Identity environment: Unknown" } - log.Write(LogCredential, msg) + log.Write(EventCredential, msg) } func addGetTokenFailureLogs(credName string, err error, includeStack bool) { - if !log.Should(LogCredential) { + if !log.Should(EventCredential) { return } stack := "" @@ -86,5 +86,5 @@ func addGetTokenFailureLogs(credName string, err error, includeStack bool) { // skip the stack trace frames and ourself stack = "\n" + diag.StackTrace(3, 32) } - log.Writef(LogCredential, "Azure Identity => ERROR in GetToken() call for %s: %s%s", credName, err.Error(), stack) + log.Writef(EventCredential, "Azure Identity => ERROR in GetToken() call for %s: %s%s", credName, err.Error(), stack) } diff --git a/sdk/azidentity/managed_identity_client.go b/sdk/azidentity/managed_identity_client.go index 659f94b4bb4c..b5ef1286c394 100644 --- a/sdk/azidentity/managed_identity_client.go +++ b/sdk/azidentity/managed_identity_client.go @@ -73,6 +73,48 @@ func (n *wrappedNumber) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, (*json.Number)(n)) } +// setRetryOptionDefaults sets zero-valued fields to default values appropriate for IMDS +func setRetryOptionDefaults(o *policy.RetryOptions) { + if o.MaxRetries == 0 { + o.MaxRetries = 5 + } + if o.MaxRetryDelay == 0 { + o.MaxRetryDelay = 1 * time.Minute + } + if o.RetryDelay == 0 { + o.RetryDelay = 2 * time.Second + } + if o.StatusCodes == nil { + o.StatusCodes = []int{ + // IMDS docs recommend retrying 404, 429 and all 5xx + // https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#error-handling + http.StatusNotFound, // 404 + http.StatusTooManyRequests, // 429 + http.StatusInternalServerError, // 500 + http.StatusNotImplemented, // 501 + http.StatusBadGateway, // 502 + http.StatusGatewayTimeout, // 504 + http.StatusHTTPVersionNotSupported, // 505 + http.StatusVariantAlsoNegotiates, // 506 + http.StatusInsufficientStorage, // 507 + http.StatusLoopDetected, // 508 + http.StatusNotExtended, // 510 + http.StatusNetworkAuthenticationRequired, // 511 + } + } + if o.TryTimeout == 0 { + o.TryTimeout = 1 * time.Minute + } +} + +// newDefaultMSIPipeline creates a pipeline using the specified pipeline options needed +// for a Managed Identity, such as a MSI specific retry policy. +func newDefaultMSIPipeline(o ManagedIdentityCredentialOptions) runtime.Pipeline { + cp := o.ClientOptions + setRetryOptionDefaults(&cp.Retry) + return runtime.NewPipeline(component, version, nil, nil, &cp) +} + // newManagedIdentityClient creates a new instance of the ManagedIdentityClient with the ManagedIdentityCredentialOptions // that are passed into it along with a default pipeline. // options: ManagedIdentityCredentialOptions configure policies for the pipeline and the authority host that diff --git a/sdk/azidentity/managed_identity_client_test.go b/sdk/azidentity/managed_identity_client_test.go index dd46a9145fa5..2ff84dff8319 100644 --- a/sdk/azidentity/managed_identity_client_test.go +++ b/sdk/azidentity/managed_identity_client_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/internal/mock" ) @@ -25,9 +26,7 @@ func TestMSITelemetryDefaultUserAgent(t *testing.T) { srv, close := mock.NewServer() defer close() srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) - options := ManagedIdentityCredentialOptions{ - HTTPClient: srv, - } + options := ManagedIdentityCredentialOptions{ClientOptions: azcore.ClientOptions{Transport: srv}} pipeline := newDefaultMSIPipeline(options) req, err := runtime.NewRequest(context.Background(), http.MethodGet, srv.URL()) if err != nil { @@ -50,9 +49,7 @@ func TestMSITelemetryCustom(t *testing.T) { srv, close := mock.NewServer() defer close() srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) - options := ManagedIdentityCredentialOptions{ - HTTPClient: srv, - } + options := ManagedIdentityCredentialOptions{ClientOptions: azcore.ClientOptions{Transport: srv}} options.Telemetry.ApplicationID = customTelemetry pipeline := newDefaultMSIPipeline(options) req, err := runtime.NewRequest(context.Background(), http.MethodGet, srv.URL()) diff --git a/sdk/azidentity/managed_identity_credential.go b/sdk/azidentity/managed_identity_credential.go index 2a91e15e5baf..ad4159f616ea 100644 --- a/sdk/azidentity/managed_identity_credential.go +++ b/sdk/azidentity/managed_identity_credential.go @@ -53,20 +53,12 @@ func (r ResourceID) String() string { // ManagedIdentityCredentialOptions contains parameters that can be used to configure the pipeline used with Managed Identity Credential. // All zero-value fields will be initialized with their default values. type ManagedIdentityCredentialOptions struct { + azcore.ClientOptions + // ID is the ID of a managed identity the credential should authenticate. Set this field to use a specific identity // instead of the hosting environment's default. The value may be the identity's client ID or resource ID, but note that // some platforms don't accept resource IDs. ID ManagedIDKind - - // HTTPClient sets the transport for making HTTP requests. - // Leave this as nil to use the default HTTP transport. - HTTPClient policy.Transporter - - // Telemetry configures the built-in telemetry policy behavior. - Telemetry policy.TelemetryOptions - - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions } // ManagedIdentityCredential attempts authentication using a managed identity that has been assigned to the deployment environment. This authentication type works in several @@ -83,10 +75,11 @@ type ManagedIdentityCredential struct { // options: ManagedIdentityCredentialOptions that configure the pipeline for requests sent to Azure Active Directory. func NewManagedIdentityCredential(options *ManagedIdentityCredentialOptions) (*ManagedIdentityCredential, error) { // Create a new Managed Identity Client with default options - if options == nil { - options = &ManagedIdentityCredentialOptions{} + cp := ManagedIdentityCredentialOptions{} + if options != nil { + cp = *options } - client := newManagedIdentityClient(options) + client := newManagedIdentityClient(&cp) msiType, err := client.getMSIType() // If there is an error that means that the code is not running in a Managed Identity environment if err != nil { @@ -97,7 +90,7 @@ func NewManagedIdentityCredential(options *ManagedIdentityCredentialOptions) (*M // Assign the msiType discovered onto the client client.msiType = msiType // check if no clientID is specified then check if it exists in an environment variable - id := options.ID + id := cp.ID if id == nil { cID := os.Getenv("AZURE_CLIENT_ID") if cID != "" { diff --git a/sdk/azidentity/managed_identity_credential_test.go b/sdk/azidentity/managed_identity_credential_test.go index fe3c4dcdb3ce..01a9cbb07bdd 100644 --- a/sdk/azidentity/managed_identity_credential_test.go +++ b/sdk/azidentity/managed_identity_credential_test.go @@ -14,6 +14,7 @@ import ( "strings" "testing" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/internal/mock" @@ -88,7 +89,7 @@ func TestManagedIdentityCredential_GetTokenInCloudShellMock(t *testing.T) { _ = os.Setenv("MSI_ENDPOINT", srv.URL()) defer clearEnvVars("MSI_ENDPOINT") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -107,7 +108,7 @@ func TestManagedIdentityCredential_GetTokenInCloudShellMockFail(t *testing.T) { _ = os.Setenv("MSI_ENDPOINT", srv.URL()) defer clearEnvVars("MSI_ENDPOINT") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -127,7 +128,7 @@ func TestManagedIdentityCredential_GetTokenInAppServiceV20170901Mock_windows(t * _ = os.Setenv("MSI_SECRET", "secret") defer clearEnvVars("MSI_ENDPOINT", "MSI_SECRET") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -153,7 +154,7 @@ func TestManagedIdentityCredential_GetTokenInAppServiceV20170901Mock_linux(t *te _ = os.Setenv("MSI_SECRET", "secret") defer clearEnvVars("MSI_ENDPOINT", "MSI_SECRET") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -179,7 +180,7 @@ func TestManagedIdentityCredential_GetTokenInAppServiceV20190801Mock_windows(t * _ = os.Setenv("IDENTITY_HEADER", "header") defer clearEnvVars("IDENTITY_ENDPOINT", "IDENTITY_HEADER") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -205,7 +206,7 @@ func TestManagedIdentityCredential_GetTokenInAppServiceV20190801Mock_linux(t *te _ = os.Setenv("IDENTITY_HEADER", "header") defer clearEnvVars("IDENTITY_ENDPOINT", "IDENTITY_HEADER") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -235,9 +236,7 @@ func TestManagedIdentityCredential_GetTokenInAzureFunctions_linux(t *testing.T) _ = os.Setenv("IDENTITY_ENDPOINT", srv.URL()) _ = os.Setenv("IDENTITY_HEADER", "header") defer clearEnvVars("IDENTITY_ENDPOINT", "IDENTITY_HEADER") - msiCred, err := NewManagedIdentityCredential(&ManagedIdentityCredentialOptions{ - HTTPClient: srv, - }) + msiCred, err := NewManagedIdentityCredential(&ManagedIdentityCredentialOptions{ClientOptions: azcore.ClientOptions{Transport: srv}}) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -328,7 +327,7 @@ func TestManagedIdentityCredential_CreateAccessTokenExpiresOnStringInt(t *testin _ = os.Setenv("MSI_SECRET", "secret") defer clearEnvVars("MSI_ENDPOINT", "MSI_SECRET") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -348,7 +347,7 @@ func TestManagedIdentityCredential_GetTokenInAppServiceMockFail(t *testing.T) { _ = os.Setenv("MSI_SECRET", "secret") defer clearEnvVars("MSI_ENDPOINT", "MSI_SECRET") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -368,7 +367,7 @@ func TestManagedIdentityCredential_GetTokenIMDS400(t *testing.T) { Body: io.NopCloser(bytes.NewBufferString("")), } res2 := res1 - options.HTTPClient = newMockImds(res1, res2) + options.Transport = newMockImds(res1, res2) cred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -392,7 +391,7 @@ func TestManagedIdentityCredential_NewManagedIdentityCredentialFail(t *testing.T _ = os.Setenv("MSI_ENDPOINT", "https://t .com") defer clearEnvVars("MSI_ENDPOINT") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv cred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatal(err) @@ -411,7 +410,7 @@ func TestBearerPolicy_ManagedIdentityCredential(t *testing.T) { _ = os.Setenv("MSI_ENDPOINT", srv.URL()) defer clearEnvVars("MSI_ENDPOINT") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv cred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -435,7 +434,7 @@ func TestManagedIdentityCredential_GetTokenUnexpectedJSON(t *testing.T) { _ = os.Setenv("MSI_ENDPOINT", srv.URL()) defer clearEnvVars("MSI_ENDPOINT") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -496,7 +495,7 @@ func TestManagedIdentityCredential_GetTokenEnvVar(t *testing.T) { _ = os.Setenv("MSI_ENDPOINT", srv.URL()) defer clearEnvVars("MSI_ENDPOINT") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -518,7 +517,7 @@ func TestManagedIdentityCredential_GetTokenNilResource(t *testing.T) { _ = os.Setenv("MSI_ENDPOINT", srv.URL()) defer clearEnvVars("MSI_ENDPOINT") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -539,9 +538,7 @@ func TestManagedIdentityCredential_ScopesImmutable(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(expiresOnIntResp))) _ = os.Setenv(msiEndpoint, srv.URL()) defer clearEnvVars(msiEndpoint) - options := ManagedIdentityCredentialOptions{ - HTTPClient: srv, - } + options := ManagedIdentityCredentialOptions{ClientOptions: azcore.ClientOptions{Transport: srv}} cred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -565,7 +562,7 @@ func TestManagedIdentityCredential_GetTokenMultipleResources(t *testing.T) { _ = os.Setenv("MSI_ENDPOINT", srv.URL()) defer clearEnvVars("MSI_ENDPOINT") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -588,7 +585,7 @@ func TestManagedIdentityCredential_UseResourceID(t *testing.T) { _ = os.Setenv("MSI_SECRET", "secret") defer clearEnvVars("MSI_ENDPOINT", "MSI_SECRET") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv options.ID = ResourceID("sample/resource/id") cred, err := NewManagedIdentityCredential(&options) if err != nil { @@ -676,7 +673,7 @@ func TestManagedIdentityCredential_CreateAccessTokenExpiresOnInt(t *testing.T) { _ = os.Setenv("MSI_SECRET", "secret") defer clearEnvVars("MSI_ENDPOINT", "MSI_SECRET") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -697,7 +694,7 @@ func TestManagedIdentityCredential_CreateAccessTokenExpiresOnFail(t *testing.T) _ = os.Setenv("MSI_SECRET", "secret") defer clearEnvVars("MSI_ENDPOINT", "MSI_SECRET") options := ManagedIdentityCredentialOptions{} - options.HTTPClient = srv + options.Transport = srv msiCred, err := NewManagedIdentityCredential(&options) if err != nil { t.Fatalf("unexpected error: %v", err) diff --git a/sdk/azidentity/username_password_credential.go b/sdk/azidentity/username_password_credential.go index 0be941e9e21f..60bae9dbb754 100644 --- a/sdk/azidentity/username_password_credential.go +++ b/sdk/azidentity/username_password_credential.go @@ -11,21 +11,14 @@ import ( ) // UsernamePasswordCredentialOptions can be used to provide additional information to configure the UsernamePasswordCredential. -// Use these options to modify the default pipeline behavior through the TokenCredentialOptions. +// Use these options to modify the default pipeline behavior through the TokenCredentialcp. // All zero-value fields will be initialized with their default values. type UsernamePasswordCredentialOptions struct { + azcore.ClientOptions + // The host of the Azure Active Directory authority. The default is AzurePublicCloud. // Leave empty to allow overriding the value from the AZURE_AUTHORITY_HOST environment variable. AuthorityHost AuthorityHost - // HTTPClient sets the transport for making HTTP requests - // Leave this as nil to use the default HTTP transport - HTTPClient policy.Transporter - // Retry configures the built-in retry policy behavior - Retry policy.RetryOptions - // Telemetry configures the built-in telemetry policy behavior - Telemetry policy.TelemetryOptions - // Logging configures the built-in logging policy behavior. - Logging policy.LogOptions } // UsernamePasswordCredential enables authentication to Azure Active Directory using a user's username and password. If the user has MFA enabled this @@ -50,14 +43,15 @@ func NewUsernamePasswordCredential(tenantID string, clientID string, username st if !validTenantID(tenantID) { return nil, &CredentialUnavailableError{credentialType: "Username Password Credential", message: tenantIDValidationErr} } - if options == nil { - options = &UsernamePasswordCredentialOptions{} + cp := UsernamePasswordCredentialOptions{} + if options != nil { + cp = *options } - authorityHost, err := setAuthorityHost(options.AuthorityHost) + authorityHost, err := setAuthorityHost(cp.AuthorityHost) if err != nil { return nil, err } - c, err := newAADIdentityClient(authorityHost, pipelineOptions{HTTPClient: options.HTTPClient, Retry: options.Retry, Telemetry: options.Telemetry, Logging: options.Logging}) + c, err := newAADIdentityClient(authorityHost, &cp.ClientOptions) if err != nil { return nil, err } diff --git a/sdk/azidentity/username_password_credential_test.go b/sdk/azidentity/username_password_credential_test.go index 0c600a9dcd7b..ae92d41df39c 100644 --- a/sdk/azidentity/username_password_credential_test.go +++ b/sdk/azidentity/username_password_credential_test.go @@ -83,7 +83,7 @@ func TestUsernamePasswordCredential_GetTokenSuccess(t *testing.T) { srv.AppendResponse(mock.WithBody([]byte(accessTokenRespSuccess))) options := UsernamePasswordCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewUsernamePasswordCredential(tenantID, clientID, "username", "password", &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -100,7 +100,7 @@ func TestUsernamePasswordCredential_GetTokenInvalidCredentials(t *testing.T) { srv.SetResponse(mock.WithStatusCode(http.StatusUnauthorized)) options := UsernamePasswordCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewUsernamePasswordCredential(tenantID, clientID, "username", "wrong_password", &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err) @@ -118,7 +118,7 @@ func TestBearerPolicy_UsernamePasswordCredential(t *testing.T) { srv.AppendResponse(mock.WithStatusCode(http.StatusOK)) options := UsernamePasswordCredentialOptions{} options.AuthorityHost = AuthorityHost(srv.URL()) - options.HTTPClient = srv + options.Transport = srv cred, err := NewUsernamePasswordCredential(tenantID, clientID, "username", "password", &options) if err != nil { t.Fatalf("Unable to create credential. Received: %v", err)