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

Add ClientId to DAC Options #23680

Merged
merged 3 commits into from
Sep 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/identity/Azure.Identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features Added

- `DefaultAzureCredentialOptions` now has a `InteractiveBrowserClientId` property which allows passing a ClientId value to the InteractiveBrowserCredential` when constructing a `DefaultAzureCredential`.
- Implement `OnBehalfOfCredential` which enables authentication to Azure Active Directory using an On-Behalf-Of flow.

### Breaking Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ public DefaultAzureCredentialOptions() { }
public bool ExcludeSharedTokenCacheCredential { get { throw null; } set { } }
public bool ExcludeVisualStudioCodeCredential { get { throw null; } set { } }
public bool ExcludeVisualStudioCredential { get { throw null; } set { } }
public string InteractiveBrowserCredentialClientId { get { throw null; } set { } }
public string InteractiveBrowserTenantId { get { throw null; } set { } }
public string ManagedIdentityClientId { get { throw null; } set { } }
public string SharedTokenCacheTenantId { get { throw null; } set { } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ private static TokenCredential[] GetDefaultAzureCredentialChain(DefaultAzureCred

if (!options.ExcludeInteractiveBrowserCredential)
{
chain[i++] = factory.CreateInteractiveBrowserCredential(options.InteractiveBrowserTenantId);
chain[i++] = factory.CreateInteractiveBrowserCredential(options.InteractiveBrowserTenantId, options.InteractiveBrowserCredentialClientId);
}

if (i == 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ public virtual TokenCredential CreateSharedTokenCacheCredential(string tenantId,
return new SharedTokenCacheCredential(tenantId, username, null, Pipeline);
}

public virtual TokenCredential CreateInteractiveBrowserCredential(string tenantId)
public virtual TokenCredential CreateInteractiveBrowserCredential(string tenantId, string clientId)
{
return new InteractiveBrowserCredential(
tenantId,
Constants.DeveloperSignOnClientId,
clientId ?? Constants.DeveloperSignOnClientId,
new InteractiveBrowserCredentialOptions { TokenCachePersistenceOptions = new TokenCachePersistenceOptions() },
Pipeline);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public class DefaultAzureCredentialOptions : TokenCredentialOptions
/// </remarks>
public string SharedTokenCacheUsername { get; set; } = GetNonEmptyStringOrNull(EnvironmentVariables.Username);

/// <summary>
/// Specifies the client id of the selected credential
/// </summary>
public string InteractiveBrowserCredentialClientId { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we default this to Constants.DeveloperSignOnClientId since that is the client id which will be used if the user doesn't set this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do that here:

clientId ?? Constants.DeveloperSignOnClientId,


/// <summary>
/// Specifies the client id of the azure ManagedIdentity in the case of user assigned identity.
/// </summary>
Expand Down
23 changes: 13 additions & 10 deletions sdk/identity/Azure.Identity/tests/DefaultAzureCredentialTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ public void ValidateCtorOptionsPassedToCredentials()
string expBrowserTenantId = Guid.NewGuid().ToString();
string expVsTenantId = Guid.NewGuid().ToString();
string expCodeTenantId = Guid.NewGuid().ToString();
string actClientId = null;
string actClientId_ManagedIdentity = null;
string actClientId_InteractiveBrowser = null;
string actUsername = null;
string actCacheTenantId = null;
string actBrowserTenantId = null;
Expand All @@ -84,15 +85,16 @@ public void ValidateCtorOptionsPassedToCredentials()

var credFactory = new MockDefaultAzureCredentialFactory(CredentialPipeline.GetInstance(null));

credFactory.OnCreateManagedIdentityCredential = (clientId, _) => actClientId = clientId;
credFactory.OnCreateManagedIdentityCredential = (clientId, _) => actClientId_ManagedIdentity = clientId;
credFactory.OnCreateSharedTokenCacheCredential = (tenantId, username, _) => { actCacheTenantId = tenantId; actUsername = username; };
credFactory.OnCreateInteractiveBrowserCredential = (tenantId, _) => { actBrowserTenantId = tenantId; };
credFactory.OnCreateInteractiveBrowserCredential = (tenantId, clientId, _) => { actBrowserTenantId = tenantId; actClientId_InteractiveBrowser = clientId; };
credFactory.OnCreateVisualStudioCredential = (tenantId, _) => { actVsTenantId = tenantId; };
credFactory.OnCreateVisualStudioCodeCredential = (tenantId, _) => { actCodeTenantId = tenantId; };
credFactory.OnCreateAzurePowerShellCredential = _ => {};

var options = new DefaultAzureCredentialOptions
{
InteractiveBrowserCredentialClientId = expClientId,
ManagedIdentityClientId = expClientId,
SharedTokenCacheUsername = expUsername,
ExcludeSharedTokenCacheCredential = false,
Expand All @@ -105,7 +107,8 @@ public void ValidateCtorOptionsPassedToCredentials()

new DefaultAzureCredential(credFactory, options);

Assert.AreEqual(expClientId, actClientId);
Assert.AreEqual(expClientId, actClientId_ManagedIdentity);
Assert.AreEqual(expClientId, actClientId_InteractiveBrowser);
Assert.AreEqual(expUsername, actUsername);
Assert.AreEqual(expCacheTenantId, actCacheTenantId);
Assert.AreEqual(expBrowserTenantId, actBrowserTenantId);
Expand Down Expand Up @@ -148,7 +151,7 @@ public void ValidateEnvironmentBasedOptionsPassedToCredentials([Values] bool cli
Assert.AreEqual(expUsername, username);
};

credFactory.OnCreateInteractiveBrowserCredential = (tenantId, _) =>
credFactory.OnCreateInteractiveBrowserCredential = (tenantId, clientId, _) =>
{
onCreateInteractiveCalled = true;
Assert.AreEqual(expTenantId, tenantId);
Expand Down Expand Up @@ -221,7 +224,7 @@ public void ValidateEmptyEnvironmentBasedOptionsNotPassedToCredentials([Values]
Assert.IsNull(username);
};

credFactory.OnCreateInteractiveBrowserCredential = (tenantId, _) =>
credFactory.OnCreateInteractiveBrowserCredential = (tenantId, _, _) =>
{
onCreateInteractiveCalled = true;
Assert.IsNull(tenantId);
Expand Down Expand Up @@ -282,7 +285,7 @@ public void ValidateCtorWithExcludeOptions([Values(true, false)]bool excludeEnvi

credFactory.OnCreateEnvironmentCredential = _ => environmentCredentialIncluded = true;
credFactory.OnCreateAzureCliCredential = _ => cliCredentialIncluded = true;
credFactory.OnCreateInteractiveBrowserCredential = (tenantId, _) => interactiveBrowserCredentialIncluded = true;
credFactory.OnCreateInteractiveBrowserCredential = (tenantId, _, _) => interactiveBrowserCredentialIncluded = true;
credFactory.OnCreateVisualStudioCredential = (tenantId, _) => visualStudioCredentialIncluded = true;
credFactory.OnCreateVisualStudioCodeCredential = (tenantId, _) => visualStudioCodeCredentialIncluded = true;
credFactory.OnCreateAzurePowerShellCredential = _ => powerShellCredentialsIncluded = true;
Expand Down Expand Up @@ -349,7 +352,7 @@ void SetupMockForException<T>(Mock<T> mock) where T : TokenCredential =>

credFactory.OnCreateEnvironmentCredential = c =>
SetupMockForException(c);
credFactory.OnCreateInteractiveBrowserCredential = (_, c) =>
credFactory.OnCreateInteractiveBrowserCredential = (_, _, c) =>
SetupMockForException(c);
credFactory.OnCreateManagedIdentityCredential = (_, c) =>
SetupMockForException(c);
Expand Down Expand Up @@ -450,7 +453,7 @@ void SetupMockForException<T>(Mock<T> mock) where T : TokenCredential
credFactory.OnCreateAzurePowerShellCredential = c =>
SetupMockForException(c);

credFactory.OnCreateInteractiveBrowserCredential = (_, c) =>
credFactory.OnCreateInteractiveBrowserCredential = (_, _, c) =>
{
c.Setup(m => m.GetTokenAsync(It.IsAny<TokenRequestContext>(), It.IsAny<CancellationToken>()))
.Throws(new MockClientException("InteractiveBrowserCredential unhandled exception"));
Expand Down Expand Up @@ -573,7 +576,7 @@ void SetupMockForException<T>(Mock<T> mock) where T : TokenCredential =>
SetupMockForException(c);
credFactory.OnCreateAzureCliCredential = c =>
SetupMockForException(c);
credFactory.OnCreateInteractiveBrowserCredential = (_, c) =>
credFactory.OnCreateInteractiveBrowserCredential = (_, _, c) =>
SetupMockForException(c);
credFactory.OnCreateVisualStudioCredential = (_, c) =>
SetupMockForException(c);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public MockDefaultAzureCredentialFactory(CredentialPipeline pipeline) : base(pip
private Mock<ManagedIdentityCredential> mockManagedIdentityCredential = new();
public Action<string, string, Mock<SharedTokenCacheCredential>> OnCreateSharedTokenCacheCredential { get; set; }
private Mock<SharedTokenCacheCredential> mockSharedTokenCacheCredential = new();
public Action<string, Mock<InteractiveBrowserCredential>> OnCreateInteractiveBrowserCredential { get; set; }
public Action<string, string, Mock<InteractiveBrowserCredential>> OnCreateInteractiveBrowserCredential { get; set; }
private Mock<InteractiveBrowserCredential> mockInteractiveBrowserCredential = new();
public Action<string, Mock<VisualStudioCredential>> OnCreateVisualStudioCredential { get; set; }
private Mock<VisualStudioCredential> mockVisualStudioCredential = new();
Expand Down Expand Up @@ -58,9 +58,9 @@ public override TokenCredential CreateAzurePowerShellCredential()
return mockAzurePowershellCredential.Object;
}

public override TokenCredential CreateInteractiveBrowserCredential(string tenantId)
public override TokenCredential CreateInteractiveBrowserCredential(string tenantId, string clientId)
{
OnCreateInteractiveBrowserCredential?.Invoke(tenantId, mockInteractiveBrowserCredential);
OnCreateInteractiveBrowserCredential?.Invoke(tenantId, clientId, mockInteractiveBrowserCredential);
return mockInteractiveBrowserCredential.Object;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ public override TokenCredential CreateManagedIdentityCredential(string clientId)
=> new ManagedIdentityCredential(new ManagedIdentityClient(Pipeline, clientId));

public override TokenCredential CreateSharedTokenCacheCredential(string tenantId, string username)
=> new SharedTokenCacheCredential(tenantId, username, default, Pipeline);
=> new SharedTokenCacheCredential(tenantId, username, null, Pipeline);

public override TokenCredential CreateInteractiveBrowserCredential(string tenantId)
=> new InteractiveBrowserCredential(tenantId, Constants.DeveloperSignOnClientId, new InteractiveBrowserCredentialOptions(), Pipeline);
public override TokenCredential CreateInteractiveBrowserCredential(string tenantId, string clientId)
=> new InteractiveBrowserCredential(tenantId, clientId ?? Constants.DeveloperSignOnClientId, new InteractiveBrowserCredentialOptions(), Pipeline);

public override TokenCredential CreateAzureCliCredential()
=> new AzureCliCredential(Pipeline, _processService);
Expand Down