Skip to content

Commit

Permalink
Remove v1.6.0-beta API (#22230)
Browse files Browse the repository at this point in the history
  • Loading branch information
chlowell authored Jan 12, 2024
1 parent 58fcfdd commit 375fab3
Show file tree
Hide file tree
Showing 21 changed files with 115 additions and 231 deletions.
11 changes: 5 additions & 6 deletions sdk/azidentity/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
# Release History

## 1.5.0-beta.3 (Unreleased)

### Features Added
* Added `AzureCLICredentialOptions.Subscription`
## 1.5.0 (2024-01-16)

### Breaking Changes
> These changes affect only code written against a beta version such as v1.5.0-beta.1
* Removed persistent token caching. It will return in v1.6.0-beta.1

### Bugs Fixed
* `azidentity.doForClient` method no longer removes headers from the incoming request
* Credentials now preserve MSAL headers e.g. X-Client-Sku

### Other Changes
* Move to latest released versions of net, crypto, core, etc...
* Upgraded dependencies

## 1.5.0-beta.2 (2023-11-07)

Expand Down
18 changes: 9 additions & 9 deletions sdk/azidentity/authentication_record.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import (

var supportedAuthRecordVersions = []string{"1.0"}

// AuthenticationRecord is non-secret account information about an authenticated user that user credentials such as
// authenticationRecord is non-secret account information about an authenticated user that user credentials such as
// [DeviceCodeCredential] and [InteractiveBrowserCredential] can use to access previously cached authentication
// data. Call these credentials' Authenticate method to get an AuthenticationRecord for a user.
type AuthenticationRecord struct {
// data. Call these credentials' Authenticate method to get an authenticationRecord for a user.
type authenticationRecord struct {
// Authority is the URL of the authority that issued the token.
Authority string `json:"authority"`

Expand All @@ -42,11 +42,11 @@ type AuthenticationRecord struct {
}

// UnmarshalJSON implements json.Unmarshaler for AuthenticationRecord
func (a *AuthenticationRecord) UnmarshalJSON(b []byte) error {
func (a *authenticationRecord) UnmarshalJSON(b []byte) error {
// Default unmarshaling is fine but we want to return an error if the record's version isn't supported i.e., we
// want to inspect the unmarshalled values before deciding whether to return an error. Unmarshaling a formally
// different type enables this by assigning all the fields without recursing into this method.
type r AuthenticationRecord
type r authenticationRecord
err := json.Unmarshal(b, (*r)(a))
if err != nil {
return err
Expand All @@ -63,18 +63,18 @@ func (a *AuthenticationRecord) UnmarshalJSON(b []byte) error {
}

// account returns the AuthenticationRecord as an MSAL Account. The account is zero-valued when the AuthenticationRecord is zero-valued.
func (a *AuthenticationRecord) account() public.Account {
func (a *authenticationRecord) account() public.Account {
return public.Account{
Environment: a.Authority,
HomeAccountID: a.HomeAccountID,
PreferredUsername: a.Username,
}
}

func newAuthenticationRecord(ar public.AuthResult) (AuthenticationRecord, error) {
func newAuthenticationRecord(ar public.AuthResult) (authenticationRecord, error) {
u, err := url.Parse(ar.IDToken.Issuer)
if err != nil {
return AuthenticationRecord{}, fmt.Errorf("Authenticate expected a URL issuer but got %q", ar.IDToken.Issuer)
return authenticationRecord{}, fmt.Errorf("Authenticate expected a URL issuer but got %q", ar.IDToken.Issuer)
}
tenant := ar.IDToken.TenantID
if tenant == "" {
Expand All @@ -84,7 +84,7 @@ func newAuthenticationRecord(ar public.AuthResult) (AuthenticationRecord, error)
if username == "" {
username = ar.IDToken.UPN
}
return AuthenticationRecord{
return authenticationRecord{
Authority: fmt.Sprintf("%s://%s", u.Scheme, u.Host),
ClientID: ar.IDToken.Audience,
HomeAccountID: ar.Account.HomeAccountID,
Expand Down
4 changes: 2 additions & 2 deletions sdk/azidentity/authentication_record_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestAuthenticationRecord_MarshalUnmarshal(t *testing.T) {
{desc: "unsupported version", err: true, version: "42"},
} {
t.Run(test.desc, func(t *testing.T) {
record := AuthenticationRecord{
record := authenticationRecord{
Authority: "authority",
ClientID: "client",
HomeAccountID: "oid.tid",
Expand All @@ -35,7 +35,7 @@ func TestAuthenticationRecord_MarshalUnmarshal(t *testing.T) {
if err != nil {
t.Fatal(err)
}
var unmarshaled AuthenticationRecord
var unmarshaled authenticationRecord
err = json.Unmarshal(marshaled, &unmarshaled)
if err != nil {
if !test.err {
Expand Down
4 changes: 2 additions & 2 deletions sdk/azidentity/azidentity.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ var (
errInvalidTenantID = errors.New("invalid tenantID. You can locate your tenantID by following the instructions listed here: https://learn.microsoft.com/partner-center/find-ids-and-domain-names")
)

// TokenCachePersistenceOptions contains options for persistent token caching
type TokenCachePersistenceOptions = internal.TokenCachePersistenceOptions
// tokenCachePersistenceOptions contains options for persistent token caching
type tokenCachePersistenceOptions = internal.TokenCachePersistenceOptions

// setAuthorityHost initializes the authority host for credentials. Precedence is:
// 1. cloud.Configuration.ActiveDirectoryAuthorityHost value set by user
Expand Down
83 changes: 42 additions & 41 deletions sdk/azidentity/azidentity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,33 +103,33 @@ func (t *tokenRequestCountingPolicy) Do(req *policy.Request) (*http.Response, er
func TestUserAuthentication(t *testing.T) {
type authenticater interface {
azcore.TokenCredential
Authenticate(context.Context, *policy.TokenRequestOptions) (AuthenticationRecord, error)
authenticate(context.Context, *policy.TokenRequestOptions) (authenticationRecord, error)
}
for _, credential := range []struct {
name string
interactive, recordable bool
new func(*TokenCachePersistenceOptions, azcore.ClientOptions, AuthenticationRecord, bool) (authenticater, error)
new func(*tokenCachePersistenceOptions, azcore.ClientOptions, authenticationRecord, bool) (authenticater, error)
}{
{
name: credNameBrowser,
new: func(tcpo *TokenCachePersistenceOptions, co azcore.ClientOptions, ar AuthenticationRecord, disableAutoAuth bool) (authenticater, error) {
new: func(tcpo *tokenCachePersistenceOptions, co azcore.ClientOptions, ar authenticationRecord, disableAutoAuth bool) (authenticater, error) {
return NewInteractiveBrowserCredential(&InteractiveBrowserCredentialOptions{
AuthenticationRecord: ar,
authenticationRecord: ar,
ClientOptions: co,
DisableAutomaticAuthentication: disableAutoAuth,
TokenCachePersistenceOptions: tcpo,
disableAutomaticAuthentication: disableAutoAuth,
tokenCachePersistenceOptions: tcpo,
})
},
interactive: true,
},
{
name: credNameDeviceCode,
new: func(tcpo *TokenCachePersistenceOptions, co azcore.ClientOptions, ar AuthenticationRecord, disableAutoAuth bool) (authenticater, error) {
new: func(tcpo *tokenCachePersistenceOptions, co azcore.ClientOptions, ar authenticationRecord, disableAutoAuth bool) (authenticater, error) {
o := DeviceCodeCredentialOptions{
AuthenticationRecord: ar,
authenticationRecord: ar,
ClientOptions: co,
DisableAutomaticAuthentication: disableAutoAuth,
TokenCachePersistenceOptions: tcpo,
disableAutomaticAuthentication: disableAutoAuth,
tokenCachePersistenceOptions: tcpo,
}
if recording.GetRecordMode() == recording.PlaybackMode {
o.UserPrompt = func(context.Context, DeviceCodeMessage) error { return nil }
Expand All @@ -141,11 +141,11 @@ func TestUserAuthentication(t *testing.T) {
},
{
name: credNameUserPassword,
new: func(tcpo *TokenCachePersistenceOptions, co azcore.ClientOptions, ar AuthenticationRecord, disableAutoAuth bool) (authenticater, error) {
new: func(tcpo *tokenCachePersistenceOptions, co azcore.ClientOptions, ar authenticationRecord, disableAutoAuth bool) (authenticater, error) {
opts := UsernamePasswordCredentialOptions{
AuthenticationRecord: ar,
authenticationRecord: ar,
ClientOptions: co,
TokenCachePersistenceOptions: tcpo,
tokenCachePersistenceOptions: tcpo,
}
return NewUsernamePasswordCredential(liveUser.tenantID, developerSignOnClientID, liveUser.username, liveUser.password, &opts)
},
Expand All @@ -170,15 +170,15 @@ func TestUserAuthentication(t *testing.T) {
}}

co := azcore.ClientOptions{Cloud: cc, Transport: &sts}
cred, err := credential.new(nil, co, AuthenticationRecord{}, false)
cred, err := credential.new(nil, co, authenticationRecord{}, false)
require.NoError(t, err)
_, err = cred.Authenticate(context.Background(), nil)
_, err = cred.authenticate(context.Background(), nil)
require.NoError(t, err)

os.Setenv(azureAuthorityHost, cc.ActiveDirectoryAuthorityHost)
cred, err = credential.new(nil, azcore.ClientOptions{Transport: &sts}, AuthenticationRecord{}, false)
cred, err = credential.new(nil, azcore.ClientOptions{Transport: &sts}, authenticationRecord{}, false)
require.NoError(t, err)
_, err = cred.Authenticate(context.Background(), nil)
_, err = cred.authenticate(context.Background(), nil)
if cc.ActiveDirectoryAuthorityHost == customCloud.ActiveDirectoryAuthorityHost {
// Authenticate should return an error because it can't map an unknown host to a default scope
require.ErrorIs(t, err, errScopeRequired)
Expand All @@ -204,12 +204,12 @@ func TestUserAuthentication(t *testing.T) {
counter := tokenRequestCountingPolicy{}
co.PerCallPolicies = append(co.PerCallPolicies, &counter)

cred, err := credential.new(nil, co, AuthenticationRecord{}, false)
cred, err := credential.new(nil, co, authenticationRecord{}, false)
require.NoError(t, err)
ar, err := cred.Authenticate(context.Background(), &testTRO)
ar, err := cred.authenticate(context.Background(), &testTRO)
require.NoError(t, err)

// some fields of the returned AuthenticationRecord should have specific values
// some fields of the returned authenticationRecord should have specific values
require.Equal(t, ar.ClientID, developerSignOnClientID)
require.Equal(t, ar.Version, supportedAuthRecordVersions[0])
// all others should have nonempty values
Expand All @@ -222,6 +222,7 @@ func TestUserAuthentication(t *testing.T) {
})

t.Run("PersistentCache_Live/"+credential.name, func(t *testing.T) {
t.Skip("TODO: fix this test after restoring persistent cache feature")
switch recording.GetRecordMode() {
case recording.LiveMode:
if credential.interactive && !runManualTests {
Expand All @@ -242,11 +243,11 @@ func TestUserAuthentication(t *testing.T) {
defer stop()
counter := tokenRequestCountingPolicy{}
co.PerCallPolicies = append(co.PerCallPolicies, &counter)
tcpo := TokenCachePersistenceOptions{Name: t.Name()}
tcpo := tokenCachePersistenceOptions{Name: t.Name()}

cred, err := credential.new(&tcpo, co, AuthenticationRecord{}, true)
cred, err := credential.new(&tcpo, co, authenticationRecord{}, true)
require.NoError(t, err)
record, err := cred.Authenticate(context.Background(), &testTRO)
record, err := cred.authenticate(context.Background(), &testTRO)
require.NoError(t, err)
defer os.Remove(p)
tk, err := cred.GetToken(context.Background(), testTRO)
Expand All @@ -262,12 +263,12 @@ func TestUserAuthentication(t *testing.T) {

if credential.interactive {
t.Run("DisableAutomaticAuthentication/"+credential.name, func(t *testing.T) {
cred, err := credential.new(nil, policy.ClientOptions{Transport: &mockSTS{}}, AuthenticationRecord{}, true)
cred, err := credential.new(nil, policy.ClientOptions{Transport: &mockSTS{}}, authenticationRecord{}, true)
require.NoError(t, err)
_, err = cred.GetToken(context.Background(), testTRO)
require.ErrorIs(t, err, ErrAuthenticationRequired)
require.ErrorIs(t, err, errAuthenticationRequired)
if credential.name != credNameBrowser || runManualTests {
_, err = cred.Authenticate(context.Background(), &testTRO)
_, err = cred.authenticate(context.Background(), &testTRO)
require.NoError(t, err)
// silent auth should succeed this time
_, err = cred.GetToken(context.Background(), testTRO)
Expand Down Expand Up @@ -842,7 +843,7 @@ func TestCLIArgumentValidation(t *testing.T) {
}
t.Run(credNameAzureCLI+"/subscription", func(t *testing.T) {
for _, r := range invalidRunes {
if _, err := NewAzureCLICredential(&AzureCLICredentialOptions{Subscription: string(r)}); err == nil {
if _, err := NewAzureCLICredential(&AzureCLICredentialOptions{subscription: string(r)}); err == nil {
t.Errorf("expected an error for a subscription containing %q", r)
}
}
Expand Down Expand Up @@ -911,19 +912,19 @@ func TestTokenCachePersistenceOptions(t *testing.T) {
t.Cleanup(func() { internal.NewCache = before })
for _, test := range []struct {
desc string
options *TokenCachePersistenceOptions
options *tokenCachePersistenceOptions
err error
}{
{
desc: "nil options",
},
{
desc: "default options",
options: &TokenCachePersistenceOptions{},
options: &tokenCachePersistenceOptions{},
},
{
desc: "all options set",
options: &TokenCachePersistenceOptions{AllowUnencryptedStorage: true, Name: "name"},
options: &tokenCachePersistenceOptions{AllowUnencryptedStorage: true, Name: "name"},
},
} {
internal.NewCache = func(o *internal.TokenCachePersistenceOptions, _ bool) (cache.ExportReplace, error) {
Expand All @@ -941,46 +942,46 @@ func TestTokenCachePersistenceOptions(t *testing.T) {
return nil, nil
}
for _, subtest := range []struct {
ctor func(azcore.ClientOptions, *TokenCachePersistenceOptions) (azcore.TokenCredential, error)
ctor func(azcore.ClientOptions, *tokenCachePersistenceOptions) (azcore.TokenCredential, error)
env map[string]string
name string
}{
{
name: credNameAssertion,
ctor: func(co azcore.ClientOptions, tco *TokenCachePersistenceOptions) (azcore.TokenCredential, error) {
o := ClientAssertionCredentialOptions{ClientOptions: co, TokenCachePersistenceOptions: tco}
ctor: func(co azcore.ClientOptions, tco *tokenCachePersistenceOptions) (azcore.TokenCredential, error) {
o := ClientAssertionCredentialOptions{ClientOptions: co, tokenCachePersistenceOptions: tco}
return NewClientAssertionCredential(fakeTenantID, fakeClientID, func(context.Context) (string, error) { return "...", nil }, &o)
},
},
{
name: credNameCert,
ctor: func(co azcore.ClientOptions, tco *TokenCachePersistenceOptions) (azcore.TokenCredential, error) {
o := ClientCertificateCredentialOptions{ClientOptions: co, TokenCachePersistenceOptions: tco}
ctor: func(co azcore.ClientOptions, tco *tokenCachePersistenceOptions) (azcore.TokenCredential, error) {
o := ClientCertificateCredentialOptions{ClientOptions: co, tokenCachePersistenceOptions: tco}
return NewClientCertificateCredential(fakeTenantID, fakeClientID, allCertTests[0].certs, allCertTests[0].key, &o)
},
},
{
name: credNameDeviceCode,
ctor: func(co azcore.ClientOptions, tco *TokenCachePersistenceOptions) (azcore.TokenCredential, error) {
ctor: func(co azcore.ClientOptions, tco *tokenCachePersistenceOptions) (azcore.TokenCredential, error) {
o := DeviceCodeCredentialOptions{
ClientOptions: co,
TokenCachePersistenceOptions: tco,
tokenCachePersistenceOptions: tco,
UserPrompt: func(context.Context, DeviceCodeMessage) error { return nil },
}
return NewDeviceCodeCredential(&o)
},
},
{
name: credNameSecret,
ctor: func(co azcore.ClientOptions, tco *TokenCachePersistenceOptions) (azcore.TokenCredential, error) {
o := ClientSecretCredentialOptions{ClientOptions: co, TokenCachePersistenceOptions: tco}
ctor: func(co azcore.ClientOptions, tco *tokenCachePersistenceOptions) (azcore.TokenCredential, error) {
o := ClientSecretCredentialOptions{ClientOptions: co, tokenCachePersistenceOptions: tco}
return NewClientSecretCredential(fakeTenantID, fakeClientID, fakeSecret, &o)
},
},
{
name: credNameUserPassword,
ctor: func(co azcore.ClientOptions, tco *TokenCachePersistenceOptions) (azcore.TokenCredential, error) {
o := UsernamePasswordCredentialOptions{ClientOptions: co, TokenCachePersistenceOptions: tco}
ctor: func(co azcore.ClientOptions, tco *tokenCachePersistenceOptions) (azcore.TokenCredential, error) {
o := UsernamePasswordCredentialOptions{ClientOptions: co, tokenCachePersistenceOptions: tco}
return NewUsernamePasswordCredential(fakeTenantID, fakeClientID, fakeUsername, "password", &o)
},
},
Expand Down
10 changes: 5 additions & 5 deletions sdk/azidentity/azure_cli_credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ type AzureCLICredentialOptions struct {
// logged in account can access.
AdditionallyAllowedTenants []string

// Subscription is the name or ID of a subscription. Set this to acquire tokens for an account other
// subscription is the name or ID of a subscription. Set this to acquire tokens for an account other
// than the Azure CLI's current account.
Subscription string
subscription string

// TenantID identifies the tenant the credential should authenticate in.
// Defaults to the CLI's default tenant, which is typically the home tenant of the logged in user.
Expand Down Expand Up @@ -68,9 +68,9 @@ func NewAzureCLICredential(options *AzureCLICredentialOptions) (*AzureCLICredent
if options != nil {
cp = *options
}
for _, r := range cp.Subscription {
for _, r := range cp.subscription {
if !(alphanumeric(r) || r == '-' || r == '_' || r == ' ' || r == '.') {
return nil, fmt.Errorf("%s: invalid Subscription %q", credNameAzureCLI, cp.Subscription)
return nil, fmt.Errorf("%s: invalid Subscription %q", credNameAzureCLI, cp.subscription)
}
}
if cp.TenantID != "" && !validTenantID(cp.TenantID) {
Expand All @@ -97,7 +97,7 @@ func (c *AzureCLICredential) GetToken(ctx context.Context, opts policy.TokenRequ
}
c.mu.Lock()
defer c.mu.Unlock()
b, err := c.opts.tokenProvider(ctx, opts.Scopes, tenant, c.opts.Subscription)
b, err := c.opts.tokenProvider(ctx, opts.Scopes, tenant, c.opts.subscription)
if err == nil {
at, err = c.createAccessToken(b)
}
Expand Down
2 changes: 1 addition & 1 deletion sdk/azidentity/azure_cli_credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func TestAzureCLICredential_Subscription(t *testing.T) {
for _, want := range []string{"", "expected-subscription"} {
t.Run(fmt.Sprintf("subscription=%q", want), func(t *testing.T) {
options := AzureCLICredentialOptions{
Subscription: want,
subscription: want,
tokenProvider: func(ctx context.Context, scopes []string, tenant, subscription string) ([]byte, error) {
called = true
if subscription != want {
Expand Down
6 changes: 3 additions & 3 deletions sdk/azidentity/client_assertion_credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ type ClientAssertionCredentialOptions struct {
// the application responsible for ensuring the configured authority is valid and trustworthy.
DisableInstanceDiscovery bool

// TokenCachePersistenceOptions enables persistent token caching when not nil.
TokenCachePersistenceOptions *TokenCachePersistenceOptions
// tokenCachePersistenceOptions enables persistent token caching when not nil.
tokenCachePersistenceOptions *tokenCachePersistenceOptions
}

// NewClientAssertionCredential constructs a ClientAssertionCredential. The getAssertion function must be thread safe. Pass nil for options to accept defaults.
Expand All @@ -64,7 +64,7 @@ func NewClientAssertionCredential(tenantID, clientID string, getAssertion func(c
AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
ClientOptions: options.ClientOptions,
DisableInstanceDiscovery: options.DisableInstanceDiscovery,
TokenCachePersistenceOptions: options.TokenCachePersistenceOptions,
tokenCachePersistenceOptions: options.tokenCachePersistenceOptions,
}
c, err := newConfidentialClient(tenantID, clientID, credNameAssertion, cred, msalOpts)
if err != nil {
Expand Down
Loading

0 comments on commit 375fab3

Please sign in to comment.