Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix azidentity CI #15886

Merged
merged 14 commits into from
Oct 22, 2021
4 changes: 4 additions & 0 deletions sdk/azidentity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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`
Expand Down
11 changes: 5 additions & 6 deletions sdk/azidentity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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).

Expand All @@ -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)

Expand Down Expand Up @@ -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:
Expand All @@ -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.
Expand Down Expand Up @@ -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)
10 changes: 4 additions & 6 deletions sdk/azidentity/aad_identity_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 5 additions & 8 deletions sdk/azidentity/aad_identity_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
}
Expand Down
22 changes: 8 additions & 14 deletions sdk/azidentity/authorization_code_credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions sdk/azidentity/authorization_code_credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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")
Expand Down
67 changes: 0 additions & 67 deletions sdk/azidentity/azidentity.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
7 changes: 2 additions & 5 deletions sdk/azidentity/azidentity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 8 additions & 5 deletions sdk/azidentity/chained_token_credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions sdk/azidentity/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading