Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion eng/Packages.Data.props
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
<PackageReference Update="Azure.Communication.Common" Version="1.2.1" />
<PackageReference Update="Azure.Core" Version="1.37.0" />
<PackageReference Update="Azure.Core.Amqp" Version="1.3.0" />
<PackageReference Update="Azure.Core.Experimental" Version="0.1.0-preview.31" />
<PackageReference Update="Azure.Core.Experimental" Version="0.1.0-preview.32" />
<PackageReference Update="Azure.Core.Expressions.DataFactory" Version="1.0.0-beta.6" />
<PackageReference Update="Azure.Data.SchemaRegistry" Version="1.2.0" />
<PackageReference Update="Azure.Data.Tables" Version="12.8.0" />
Expand Down
1 change: 1 addition & 0 deletions sdk/identity/Azure.Identity.Broker/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features Added

- `InteractiveBrowserCredentialBrokerOptions` and `SharedTokenCacheCredentialBrokerOptions` now support a `UseOperatingSystemAccount` property to enable the use of the currently logged in operating system account for authentication rather than prompting for a credential.
- Preview support for Proof of Possession (PoP) tokens for `InteractiveBrowserCredential`. This feature is enabled via the `IsProofOfPossessionRequired` property on `InteractiveBrowserCredentialBrokerOptions`.

### Breaking Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ public partial class InteractiveBrowserCredentialBrokerOptions : Azure.Identity.
public InteractiveBrowserCredentialBrokerOptions(System.IntPtr parentWindowHandle) { }
public bool? IsLegacyMsaPassthroughEnabled { get { throw null; } set { } }
public bool IsProofOfPossessionRequired { get { throw null; } set { } }
public bool UseOperatingSystemAccount { get { throw null; } set { } }
}
public partial class SharedTokenCacheCredentialBrokerOptions : Azure.Identity.SharedTokenCacheCredentialOptions
{
public SharedTokenCacheCredentialBrokerOptions() { }
public SharedTokenCacheCredentialBrokerOptions(Azure.Identity.TokenCachePersistenceOptions tokenCacheOptions) { }
public bool? IsLegacyMsaPassthroughEnabled { get { throw null; } set { } }
public bool IsProofOfPossessionRequired { get { throw null; } set { } }
public bool UseOperatingSystemAccount { get { throw null; } set { } }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ public partial class InteractiveBrowserCredentialBrokerOptions : Azure.Identity.
public InteractiveBrowserCredentialBrokerOptions(System.IntPtr parentWindowHandle) { }
public bool? IsLegacyMsaPassthroughEnabled { get { throw null; } set { } }
public bool IsProofOfPossessionRequired { get { throw null; } set { } }
public bool UseOperatingSystemAccount { get { throw null; } set { } }
}
public partial class SharedTokenCacheCredentialBrokerOptions : Azure.Identity.SharedTokenCacheCredentialOptions
{
public SharedTokenCacheCredentialBrokerOptions() { }
public SharedTokenCacheCredentialBrokerOptions(Azure.Identity.TokenCachePersistenceOptions tokenCacheOptions) { }
public bool? IsLegacyMsaPassthroughEnabled { get { throw null; } set { } }
public bool IsProofOfPossessionRequired { get { throw null; } set { } }
public bool UseOperatingSystemAccount { get { throw null; } set { } }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ public partial class InteractiveBrowserCredentialBrokerOptions : Azure.Identity.
public InteractiveBrowserCredentialBrokerOptions(System.IntPtr parentWindowHandle) { }
public bool? IsLegacyMsaPassthroughEnabled { get { throw null; } set { } }
public bool IsProofOfPossessionRequired { get { throw null; } set { } }
public bool UseOperatingSystemAccount { get { throw null; } set { } }
}
public partial class SharedTokenCacheCredentialBrokerOptions : Azure.Identity.SharedTokenCacheCredentialOptions
{
public SharedTokenCacheCredentialBrokerOptions() { }
public SharedTokenCacheCredentialBrokerOptions(Azure.Identity.TokenCachePersistenceOptions tokenCacheOptions) { }
public bool? IsLegacyMsaPassthroughEnabled { get { throw null; } set { } }
public bool IsProofOfPossessionRequired { get { throw null; } set { } }
public bool UseOperatingSystemAccount { get { throw null; } set { } }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public class InteractiveBrowserCredentialBrokerOptions : InteractiveBrowserCrede
/// </summary>
public bool IsProofOfPossessionRequired { get; set; }

/// <summary>
/// Authenticate with the currently signed in user instead of prompting the user with a login dialog.
/// </summary>
public bool UseOperatingSystemAccount { get; set; }

/// <summary>
/// Creates a new instance of <see cref="InteractiveBrowserCredentialBrokerOptions"/> to configure a <see cref="InteractiveBrowserCredential"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public class SharedTokenCacheCredentialBrokerOptions : SharedTokenCacheCredentia
/// </summary>
public bool IsProofOfPossessionRequired { get; set; }

/// <summary>
/// Authenticate with the currently signed in user instead of prompting the user with a login dialog.
/// </summary>
public bool UseOperatingSystemAccount { get; set; }

/// <summary>
/// Initializes a new instance of <see cref="SharedTokenCacheCredentialBrokerOptions"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ public void RespectsMsaPassthrough(
IMsalPublicClientInitializerOptions credentialOptions;
if (enableMsaPassthrough.HasValue)
{
credentialOptions = new InteractiveBrowserCredentialBrokerOptions(parentWindowHandle) { IsLegacyMsaPassthroughEnabled = enableMsaPassthrough.Value } as IMsalPublicClientInitializerOptions;
credentialOptions = new InteractiveBrowserCredentialBrokerOptions(parentWindowHandle) { IsLegacyMsaPassthroughEnabled = enableMsaPassthrough.Value };
}
else
{
credentialOptions = new InteractiveBrowserCredentialBrokerOptions(parentWindowHandle) as IMsalPublicClientInitializerOptions;
credentialOptions = new InteractiveBrowserCredentialBrokerOptions(parentWindowHandle);
}
PublicClientApplicationBuilder builder = PublicClientApplicationBuilder
.Create(Guid.NewGuid().ToString());
Expand All @@ -34,6 +34,20 @@ public void RespectsMsaPassthrough(
Assert.AreEqual(parentWindowHandle, Parent());
}

[Test]
public void RespectsUseOperatingSystemAccount(
[Values(true, false)] bool enableUseOperatingSystemAccount)
{
IntPtr parentWindowHandle = new(1234);
IMsalPublicClientInitializerOptions credentialOptions;
credentialOptions = new InteractiveBrowserCredentialBrokerOptions(parentWindowHandle) { UseOperatingSystemAccount = enableUseOperatingSystemAccount };
PublicClientApplicationBuilder builder = PublicClientApplicationBuilder
.Create(Guid.NewGuid().ToString());

var credential = new InteractiveBrowserCredential((InteractiveBrowserCredentialBrokerOptions)credentialOptions);
Assert.AreEqual(enableUseOperatingSystemAccount, credential.UseOperatingSystemAccount);
}

private static (BrokerOptions Options, Func<object> Parent) GetBrokerOptions(PublicClientApplicationBuilder builder)
{
var config = builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ public async Task AuthenticateWithBrokerAsync()
Assert.NotNull(token.Token);
}

[Test]
[Ignore("This test is an integration test which can only be run with user interaction")]
public async Task AuthenticateWithBrokerWithUseOperatingSystemAccount_DoesNotPrompt()
{
IntPtr parentWindowHandle = GetForegroundWindow();

var cred = new InteractiveBrowserCredential(new InteractiveBrowserCredentialBrokerOptions(parentWindowHandle) { UseOperatingSystemAccount = true });

AccessToken token = await cred.GetTokenAsync(new TokenRequestContext(new string[] { "https://vault.azure.net/.default" })).ConfigureAwait(false);

Assert.NotNull(token.Token);
}

[Test]
[TestCase(true)]
[TestCase(false)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,16 @@ public async Task SilentAuthenticateWithBrokerAsync()

Assert.NotNull(token.Token);
}

[Test]
[Ignore("This test is an integration test which can only be run with user interaction")]
public async Task AuthenticateWithBrokerWithUseOperatingSystemAccount_DoesNotPrompt()
{
var cred = new SharedTokenCacheCredential(new SharedTokenCacheCredentialBrokerOptions() { UseOperatingSystemAccount = true });

AccessToken token = await cred.GetTokenAsync(new TokenRequestContext(new string[] { "https://vault.azure.net/.default" })).ConfigureAwait(false);

Assert.NotNull(token.Token);
}
}
}
2 changes: 1 addition & 1 deletion sdk/identity/Azure.Identity/src/Azure.Identity.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<DefineConstants>PREVIEW_FEATURE_FLAG</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\core\Azure.Core.Experimental\src\Azure.Core.Experimental.csproj" />
<PackageReference Include="Azure.Core.Experimental" />
</ItemGroup>
</When>
</Choose>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class InteractiveBrowserCredential : TokenCredential
internal AuthenticationRecord Record { get; private set; }
internal string DefaultScope { get; }
internal TenantIdResolverBase TenantIdResolver { get; }
internal bool UseOperatingSystemAccount { get; }

private const string AuthenticationRequiredMessage = "Interactive authentication is needed to acquire token. Call Authenticate to interactively authenticate.";
private const string NoDefaultScopeMessage = "Authenticating in this environment requires specifying a TokenRequestContext.";
Expand Down Expand Up @@ -95,6 +96,7 @@ internal InteractiveBrowserCredential(string tenantId, string clientId, TokenCre
AdditionallyAllowedTenantIds = TenantIdResolver.ResolveAddionallyAllowedTenantIds((options as ISupportsAdditionallyAllowedTenants)?.AdditionallyAllowedTenants);
Record = (options as InteractiveBrowserCredentialOptions)?.AuthenticationRecord;
BrowserCustomization = (options as InteractiveBrowserCredentialOptions)?.BrowserCustomization;
UseOperatingSystemAccount = (options as IMsalPublicClientInitializerOptions)?.UseOperatingSystemAccount ?? false;
}

/// <summary>
Expand Down Expand Up @@ -228,13 +230,23 @@ private async ValueTask<AccessToken> GetTokenImplAsync(bool async, PopTokenReque
Exception inner = null;

var tenantId = TenantIdResolver.Resolve(TenantId ?? Record?.TenantId, requestContext, AdditionallyAllowedTenantIds);
if (Record is not null)
if (Record is not null || UseOperatingSystemAccount)
{
try
{
AuthenticationResult result = await Client
.AcquireTokenSilentAsync(requestContext.Scopes, requestContext.Claims, Record, tenantId, requestContext.IsCaeEnabled, async, cancellationToken)
AuthenticationResult result;
if (Record is null)
{
result = await Client
.AcquireTokenSilentAsync(requestContext.Scopes, requestContext.Claims, PublicClientApplication.OperatingSystemAccount, tenantId, requestContext.IsCaeEnabled, async, cancellationToken)
.ConfigureAwait(false);
}
else
{
result = await Client
.AcquireTokenSilentAsync(requestContext.Scopes, requestContext.Claims, Record, tenantId, requestContext.IsCaeEnabled, async, cancellationToken)
.ConfigureAwait(false);
}

return scope.Succeeded(new AccessToken(result.AccessToken, result.ExpiresOn));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class SharedTokenCacheCredential : TokenCredential
internal string Username { get; }
internal MsalPublicClient Client { get; }
internal TenantIdResolverBase TenantIdResolver { get; }
internal bool UseOperatingSystemAccount { get; }

/// <summary>
/// Creates a new <see cref="SharedTokenCacheCredential"/> which will authenticate users signed in through developer tools supporting Azure single sign on.
Expand Down Expand Up @@ -83,6 +84,7 @@ internal SharedTokenCacheCredential(string tenantId, string username, TokenCrede
options ?? s_DefaultCacheOptions);
_accountAsyncLock = new AsyncLockWithValue<IAccount>();
TenantIdResolver = options?.TenantIdResolver ?? TenantIdResolverBase.Default;
UseOperatingSystemAccount = (options as IMsalPublicClientInitializerOptions)?.UseOperatingSystemAccount ?? false;
}

/// <summary>
Expand Down Expand Up @@ -118,8 +120,20 @@ private async ValueTask<AccessToken> GetTokenImplAsync(bool async, TokenRequestC
try
{
var tenantId = TenantIdResolver.Resolve(TenantId, requestContext, TenantIdResolverBase.AllTenants);
IAccount account = await GetAccountAsync(tenantId, requestContext.IsCaeEnabled, async, cancellationToken).ConfigureAwait(false);
AuthenticationResult result = await Client.AcquireTokenSilentAsync(requestContext.Scopes, requestContext.Claims, account, tenantId, requestContext.IsCaeEnabled, async, cancellationToken).ConfigureAwait(false);

IAccount account = UseOperatingSystemAccount ?
PublicClientApplication.OperatingSystemAccount :
await GetAccountAsync(tenantId, requestContext.IsCaeEnabled, async, cancellationToken).ConfigureAwait(false);

AuthenticationResult result = await Client.AcquireTokenSilentAsync(
requestContext.Scopes,
requestContext.Claims,
account,
tenantId,
requestContext.IsCaeEnabled,
async,
cancellationToken).ConfigureAwait(false);

return scope.Succeeded(new AccessToken(result.AccessToken, result.ExpiresOn));
}
catch (MsalUiRequiredException ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ internal interface IMsalPublicClientInitializerOptions
{
Action<PublicClientApplicationBuilder> BeforeBuildClient { get; }
bool IsProofOfPossessionRequired { get; set; }

bool UseOperatingSystemAccount { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ public ExtendedInteractiveBrowserCredentialOptions(Action<PublicClientApplicatio

public bool IsProofOfPossessionRequired { get; set; }

public bool UseOperatingSystemAccount { get; set; }

Action<PublicClientApplicationBuilder> IMsalPublicClientInitializerOptions.BeforeBuildClient { get { return _beforeBuildClient; } }
}

Expand Down