diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/BrowserCustomizationOptions.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/BrowserCustomizationOptions.java new file mode 100644 index 0000000000000..f5ed623eac7bb --- /dev/null +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/BrowserCustomizationOptions.java @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity; + +/** + * Represent Options to customize browser view. + */ +public class BrowserCustomizationOptions { + private String htmlMessageSuccess; + private String htmlMessageError; + + /** + * Configures the property to set HtmlMessageSuccess which the browser will show to the user when the user + * finishes authenticating successfully. + * + * @param htmlMessageSuccess the message to display when user finishes authenticating. + * @return the updated options. + */ + public BrowserCustomizationOptions setHtmlMessageSuccess(String htmlMessageSuccess) { + this.htmlMessageSuccess = htmlMessageSuccess; + return this; + } + + /** + * Configure the property to set HtmlMessageError which the browser will show to the user when the user + * finishes authenticating, but an error occurred. You can use a string format e.g. + * "An error has occurred: {0} details: {1}.", the details will be populated by the library. + * + * @param htmlMessageError the message to display when user finishes authenticating, but an error occurred. + * @return the updated options. + */ + public BrowserCustomizationOptions setHtmlMessageError(String htmlMessageError) { + this.htmlMessageError = htmlMessageError; + return this; + } + + /** + * Get the configured message which the browser will show to the user when the user + * finishes authenticating successfully. + * + * @return the string message. + */ + public String getHtmlMessageSuccess() { + return this.htmlMessageSuccess; + } + + /** + * Get the configured message which the browser will show to the user when the user + * finishes authenticating, but an error occurred. + * + * @return the string message. + */ + public String getHtmlMessageError() { + return this.htmlMessageError; + } +} diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/InteractiveBrowserCredentialBuilder.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/InteractiveBrowserCredentialBuilder.java index 520a1b9953413..6010c94e21de0 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/InteractiveBrowserCredentialBuilder.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/InteractiveBrowserCredentialBuilder.java @@ -197,6 +197,16 @@ public InteractiveBrowserCredentialBuilder additionallyAllowedTenants(List authenticateWithBrowserInteraction(TokenRequestContext re } catch (URISyntaxException e) { return Mono.error(LOGGER.logExceptionAsError(new RuntimeException(e))); } - InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = buildInteractiveRequestParameters(request, loginHint, redirectUri); + InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = + buildInteractiveRequestParameters(request, loginHint, redirectUri); SynchronizedAccessor publicClient = getPublicClientInstance(request); diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientBase.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientBase.java index 7146fb5e6f5e9..47650ff736724 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientBase.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientBase.java @@ -27,6 +27,7 @@ import com.azure.core.util.serializer.JacksonAdapter; import com.azure.core.util.serializer.SerializerAdapter; import com.azure.core.util.serializer.SerializerEncoding; +import com.azure.identity.BrowserCustomizationOptions; import com.azure.identity.CredentialUnavailableException; import com.azure.identity.DeviceCodeInfo; import com.azure.identity.TokenCachePersistenceOptions; @@ -43,6 +44,7 @@ import com.microsoft.aad.msal4j.OnBehalfOfParameters; import com.microsoft.aad.msal4j.Prompt; import com.microsoft.aad.msal4j.PublicClientApplication; +import com.microsoft.aad.msal4j.SystemBrowserOptions; import com.microsoft.aad.msal4j.TokenProviderResult; import com.microsoft.aad.msal4j.UserNamePasswordParameters; import reactor.core.publisher.Mono; @@ -479,6 +481,20 @@ InteractiveRequestParameters.InteractiveRequestParametersBuilder buildInteractiv builder.claims(customClaimRequest); } + BrowserCustomizationOptions browserCustomizationOptions = options.getBrowserCustomizationOptions(); + + if (IdentityUtil.browserCustomizationOptionsPresent(browserCustomizationOptions)) { + SystemBrowserOptions.SystemBrowserOptionsBuilder browserOptionsBuilder = SystemBrowserOptions.builder(); + if (!CoreUtils.isNullOrEmpty(browserCustomizationOptions.getHtmlMessageSuccess())) { + browserOptionsBuilder.htmlMessageSuccess(browserCustomizationOptions.getHtmlMessageSuccess()); + } + + if (!CoreUtils.isNullOrEmpty(browserCustomizationOptions.getHtmlMessageError())) { + browserOptionsBuilder.htmlMessageError(browserCustomizationOptions.getHtmlMessageError()); + } + builder.systemBrowserOptions(browserOptionsBuilder.build()); + } + if (loginHint != null) { builder.loginHint(loginHint); } 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 7c806b041f560..ad82c0e03bd2a 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 @@ -15,6 +15,7 @@ import com.azure.core.util.logging.ClientLogger; import com.azure.identity.AzureAuthorityHosts; import com.azure.identity.AuthenticationRecord; +import com.azure.identity.BrowserCustomizationOptions; import com.azure.identity.ChainedTokenCredential; import com.azure.identity.TokenCachePersistenceOptions; import com.azure.identity.implementation.util.IdentityConstants; @@ -40,6 +41,7 @@ public final class IdentityClientOptions implements Cloneable { public static final String AZURE_POD_IDENTITY_AUTHORITY_HOST = "AZURE_POD_IDENTITY_AUTHORITY_HOST"; private String authorityHost; + private BrowserCustomizationOptions browserCustomizationOptions; private String imdsAuthorityHost; private int maxRetry; private Function retryTimeout; @@ -82,6 +84,7 @@ public IdentityClientOptions() { Configuration configuration = Configuration.getGlobalConfiguration().clone(); loadFromConfiguration(configuration); identityLogOptionsImpl = new IdentityLogOptionsImpl(); + browserCustomizationOptions = new BrowserCustomizationOptions(); maxRetry = MAX_RETRY_DEFAULT_LIMIT; retryTimeout = i -> Duration.ofSeconds((long) Math.pow(2, i.getSeconds() - 1)); perCallPolicies = new ArrayList<>(); @@ -659,6 +662,15 @@ public IdentityClientOptions disableInstanceDiscovery() { return this; } + public IdentityClientOptions setBrowserCustomizationOptions(BrowserCustomizationOptions browserCustomizationOptions) { + this.browserCustomizationOptions = browserCustomizationOptions; + return this; + } + + public BrowserCustomizationOptions getBrowserCustomizationOptions() { + return this.browserCustomizationOptions; + } + /** * Gets the instance discovery policy. * @return boolean indicating if instance discovery is enabled. @@ -759,6 +771,7 @@ public IdentityClientOptions clone() { .setRetryPolicy(this.retryPolicy) .setPerCallPolicies(this.perCallPolicies) .setPerRetryPolicies(this.perRetryPolicies) + .setBrowserCustomizationOptions(this.browserCustomizationOptions) .setChained(this.isChained); if (!isInstanceDiscoveryEnabled()) { clone.disableInstanceDiscovery(); 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 5c7d8615d0bff..51df80d3c76be 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 @@ -327,7 +327,8 @@ public MsalToken authenticateWithBrowserInteraction(TokenRequestContext request, throw LOGGER.logExceptionAsError(new RuntimeException(e)); } - InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = buildInteractiveRequestParameters(request, loginHint, redirectUri); + InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = + buildInteractiveRequestParameters(request, loginHint, redirectUri); PublicClientApplication pc = getPublicClientInstance(request).getValue(); try { return new MsalToken(pc.acquireToken(builder.build()).get()); diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/util/IdentityUtil.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/util/IdentityUtil.java index bc9d311f77e3c..57a278358983a 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/util/IdentityUtil.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/util/IdentityUtil.java @@ -8,6 +8,7 @@ import com.azure.core.util.Configuration; import com.azure.core.util.CoreUtils; import com.azure.core.util.logging.ClientLogger; +import com.azure.identity.BrowserCustomizationOptions; import com.azure.identity.implementation.IdentityClientOptions; import java.util.Arrays; @@ -83,4 +84,9 @@ public static List getAdditionalTenantsFromEnvironment(Configuration con return Collections.emptyList(); } } + + public static boolean browserCustomizationOptionsPresent(BrowserCustomizationOptions browserCustomizationOptions) { + return !CoreUtils.isNullOrEmpty(browserCustomizationOptions.getHtmlMessageError()) + || !CoreUtils.isNullOrEmpty(browserCustomizationOptions.getHtmlMessageSuccess()); + } }