diff --git a/sdk/identity/azure-identity-broker-samples/src/samples/java/com/azure/identity/broker/JavaDocCodeSnippets.java b/sdk/identity/azure-identity-broker-samples/src/samples/java/com/azure/identity/broker/JavaDocCodeSnippets.java index de949729d745..b08c5b654cf4 100644 --- a/sdk/identity/azure-identity-broker-samples/src/samples/java/com/azure/identity/broker/JavaDocCodeSnippets.java +++ b/sdk/identity/azure-identity-broker-samples/src/samples/java/com/azure/identity/broker/JavaDocCodeSnippets.java @@ -40,6 +40,14 @@ public void configureCredentialForWindows() { // END: com.azure.identity.broker.interactivebrowserbrokercredentialbuilder.useinteractivebrowserbroker.windows } + public void configureCredentialForDefaultAccount() { + // BEGIN: com.azure.identity.broker.interactivebrowserbrokercredentialbuilder.useinteractivebrowserbroker.defaultaccount + InteractiveBrowserCredential cred = new InteractiveBrowserBrokerCredentialBuilder() + .useDefaultBrokerAccount() + .build(); + // END: com.azure.identity.broker.interactivebrowserbrokercredentialbuilder.useinteractivebrowserbroker.defaultaccount + } + private long getWindowHandle() { return 0; } diff --git a/sdk/identity/azure-identity-broker/CHANGELOG.md b/sdk/identity/azure-identity-broker/CHANGELOG.md index bd9d79d8c18c..4ad9cba6b8c0 100644 --- a/sdk/identity/azure-identity-broker/CHANGELOG.md +++ b/sdk/identity/azure-identity-broker/CHANGELOG.md @@ -4,6 +4,8 @@ ### Features Added +- Added support for using the default broker account + ### Breaking Changes ### Bugs Fixed diff --git a/sdk/identity/azure-identity-broker/README.md b/sdk/identity/azure-identity-broker/README.md index 11f496207516..f08a3d3c8127 100644 --- a/sdk/identity/azure-identity-broker/README.md +++ b/sdk/identity/azure-identity-broker/README.md @@ -89,6 +89,16 @@ InteractiveBrowserCredential cred = new InteractiveBrowserBrokerCredentialBuilde .build(); ``` +#### Use the default account for sign-in + +When this option is enabled, the credential will attempt to silently use the default broker account. If using the default account fails, the credential will fall back to interactive authentication. + +```java com.azure.identity.broker.interactivebrowserbrokercredentialbuilder.useinteractivebrowserbroker.defaultaccount +InteractiveBrowserCredential cred = new InteractiveBrowserBrokerCredentialBuilder() + .useDefaultBrokerAccount() + .build(); +``` + #### Obtain a window handle ##### JavaFX diff --git a/sdk/identity/azure-identity-broker/src/main/java/com/azure/identity/broker/InteractiveBrowserBrokerCredentialBuilder.java b/sdk/identity/azure-identity-broker/src/main/java/com/azure/identity/broker/InteractiveBrowserBrokerCredentialBuilder.java index a1bc9c1f9f0d..a5c395f444c5 100644 --- a/sdk/identity/azure-identity-broker/src/main/java/com/azure/identity/broker/InteractiveBrowserBrokerCredentialBuilder.java +++ b/sdk/identity/azure-identity-broker/src/main/java/com/azure/identity/broker/InteractiveBrowserBrokerCredentialBuilder.java @@ -62,15 +62,13 @@ public InteractiveBrowserBrokerCredentialBuilder enableLegacyMsaPassthrough() { } /** - * Enables automatically using the signed-in user's account for brokered authentication instead of - * of prompting the user with a login dialog. + * Enables automatically using the default broker account for authentication instead + * of prompting the user with an account picker. * - * @param useOperatingSystemAccount Boolean value to determine if the operating system account should be used. - * @return An updated instance of this builder with useOperatingSystemAccount set. + * @return An updated instance of this builder with useDefaultBrokerAccount set. */ - public InteractiveBrowserCredentialBuilder useOperatingSystemAccount(boolean useOperatingSystemAccount) { - CredentialBuilderBaseHelper.getClientOptions(this). - setUseOperatingSystemAccount(useOperatingSystemAccount); + public InteractiveBrowserCredentialBuilder useDefaultBrokerAccount() { + CredentialBuilderBaseHelper.getClientOptions(this).setUseDefaultBrokerAccount(true); return this; } diff --git a/sdk/identity/azure-identity-broker/src/test/java/com/azure/identity/broker/InteractiveBrowserBrokerCredentialBuilderTest.java b/sdk/identity/azure-identity-broker/src/test/java/com/azure/identity/broker/InteractiveBrowserBrokerCredentialBuilderTest.java index 070622c138d5..d6fd468b3fb3 100644 --- a/sdk/identity/azure-identity-broker/src/test/java/com/azure/identity/broker/InteractiveBrowserBrokerCredentialBuilderTest.java +++ b/sdk/identity/azure-identity-broker/src/test/java/com/azure/identity/broker/InteractiveBrowserBrokerCredentialBuilderTest.java @@ -242,10 +242,10 @@ void proxyOptions() { } @Test - void setUseOperatingSystemAccount() { + void setDefaultBrokerAccount() { assertDoesNotThrow(() -> { InteractiveBrowserBrokerCredentialBuilder builder = new InteractiveBrowserBrokerCredentialBuilder(); - builder.useOperatingSystemAccount(true); + builder.useDefaultBrokerAccount(); builder.build(); }); } diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java index 920c7a4e740e..1557d07d0d81 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java @@ -823,24 +823,36 @@ public Mono authenticateWithBrowserInteraction(TokenRequestContext re return Mono.error(LOGGER.logExceptionAsError(new RuntimeException(e))); } - if (options.isBrokerEnabled() && options.useOperatingSystemAccount()) { - return getPublicClientInstance(request).getValue().flatMap(pc -> - Mono.fromFuture(() -> - acquireTokenFromPublicClientSilently(request, pc, null, false)). - map(MsalToken::new)); - } else { - + // If the broker is enabled, try to get the token for the default account by passing + // a null account to MSAL. If that fails, show the dialog. + + return getPublicClientInstance(request).getValue().flatMap(pc -> { + if (options.isBrokerEnabled() && options.useDefaultBrokerAccount()) { + return Mono.fromFuture(() -> + acquireTokenFromPublicClientSilently(request, pc, null, false)) + // The error case here represents the silent acquisition failing. There's nothing actionable and + // in this case the fallback path of showing the dialog will capture any meaningful error and share it. + .onErrorResume(e -> Mono.empty()); + } else { + return Mono.empty(); + } + }) + .switchIfEmpty(Mono.defer(() -> { InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = buildInteractiveRequestParameters(request, loginHint, redirectUri); SynchronizedAccessor publicClient = getPublicClientInstance(request); - Mono acquireToken = publicClient.getValue() + return publicClient.getValue() .flatMap(pc -> Mono.fromFuture(() -> pc.acquireToken(builder.build()))); - return acquireToken.onErrorMap(t -> new ClientAuthenticationException( - "Failed to acquire token with Interactive Browser Authentication.", null, t)).map(MsalToken::new); - } + })) + // If we're already throwing a ClientAuthenticationException we don't need to wrap it again. + .onErrorMap(t -> !(t instanceof ClientAuthenticationException), + t -> { + throw new ClientAuthenticationException("Failed to acquire token with Interactive Browser Authentication.", null, t); + }) + .map(MsalToken::new); } /** diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientOptions.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientOptions.java index 4350bb5e9ebe..9087bf8e0687 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientOptions.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientOptions.java @@ -79,7 +79,7 @@ public final class IdentityClientOptions implements Cloneable { private long brokerWindowHandle; private boolean brokerEnabled; private boolean enableMsaPassthrough; - private boolean useOperatingSystemAccount; + private boolean useDefaultBrokerAccount; /** * Creates an instance of IdentityClientOptions with default settings. @@ -784,11 +784,11 @@ public IdentityClientOptions setEnableLegacyMsaPassthrough(boolean enableMsaPass /** * Sets whether to use the logged-in user's account for broker authentication. - * @param useOperatingSystemAccount + * @param useDefaultBrokerAccount * @return the updated client options */ - public IdentityClientOptions setUseOperatingSystemAccount(boolean useOperatingSystemAccount) { - this.useOperatingSystemAccount = useOperatingSystemAccount; + public IdentityClientOptions setUseDefaultBrokerAccount(boolean useDefaultBrokerAccount) { + this.useDefaultBrokerAccount = useDefaultBrokerAccount; return this; } @@ -804,8 +804,8 @@ public boolean isMsaPassthroughEnabled() { * Gets the status whether to use the logged-in user's account for broker authentication. * @return the flag indicating if the logged-in user's account should be used for broker authentication. */ - public boolean useOperatingSystemAccount() { - return this.useOperatingSystemAccount; + public boolean useDefaultBrokerAccount() { + return this.useDefaultBrokerAccount; } public IdentityClientOptions clone() { diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentitySyncClient.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentitySyncClient.java index 6402042cc034..37949583c002 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentitySyncClient.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentitySyncClient.java @@ -337,12 +337,21 @@ public MsalToken authenticateWithBrowserInteraction(TokenRequestContext request, } PublicClientApplication pc = getPublicClientInstance(request).getValue(); - if (options.isBrokerEnabled() && options.useOperatingSystemAccount()) { - return acquireTokenFromPublicClientSilently(request, - pc, - null, - false); - } else { + // If the broker is enabled, try to get the token for the default account by passing + // a null account to MSAL. If that fails, show the dialog. + MsalToken token = null; + if (options.isBrokerEnabled() && options.useDefaultBrokerAccount()) { + try { + token = acquireTokenFromPublicClientSilently(request, + pc, + null, + false); + } catch (Exception e) { + // The error case here represents the silent acquisition failing. There's nothing actionable and + // in this case the fallback path of showing the dialog will capture any meaningful error and share it. + } + } + if (token == null) { InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = buildInteractiveRequestParameters(request, loginHint, redirectUri); @@ -353,6 +362,7 @@ public MsalToken authenticateWithBrowserInteraction(TokenRequestContext request, "Failed to acquire token with Interactive Browser Authentication.", null, e)); } } + return token; } /**