diff --git a/sdk/identity/azure-identity/pom.xml b/sdk/identity/azure-identity/pom.xml index 0708c9a5983a4..0563543b6aed2 100644 --- a/sdk/identity/azure-identity/pom.xml +++ b/sdk/identity/azure-identity/pom.xml @@ -17,6 +17,7 @@ --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED + --add-exports com.azure.core/com.azure.core.implementation.util=ALL-UNNAMED true diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/AuthenticationUtil.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/AuthenticationUtil.java new file mode 100644 index 0000000000000..4e5982aa19892 --- /dev/null +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/AuthenticationUtil.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity; + +import com.azure.core.credential.TokenCredential; +import com.azure.core.http.HttpHeaderName; +import com.azure.core.http.HttpMethod; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.util.Context; + +import java.util.function.Supplier; + +/** + * Utility methods for working with authentication. + */ +public final class AuthenticationUtil { + + private AuthenticationUtil() { + } + + /** + * Creates a {@link Supplier} that provides a Bearer token from the specified credential. + * The token is cached and will refresh when it expires. + *

Using the supplier:

+ * + *
+     * DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
+     * String scope = "https://cognitiveservices.azure.com/.default";
+     * Supplier<String> supplier = AuthenticationUtil.getBearerTokenSupplier(credential, scope);
+     *
+     * // This example simply uses the Azure SDK HTTP library to demonstrate setting the header.
+     * // Use the token as is appropriate for your circumstances.
+     * HttpRequest request = new HttpRequest(HttpMethod.GET, "https://www.example.com");
+     * request.setHeader(HttpHeaderName.AUTHORIZATION, "Bearer " + supplier.get());
+     * HttpClient client = HttpClient.createDefault();
+     * client.sendSync(request, Context.NONE);
+     * 
+ * + * + * @param credential The {@link TokenCredential} from which to retrieve a token. + * @param scopes The scopes as appropriate for the token you are retrieving. + * @return A {@link Supplier} which returns the bearer token as a {@link String}. + */ + public static Supplier getBearerTokenSupplier(TokenCredential credential, String... scopes) { + HttpPipeline pipeline = new HttpPipelineBuilder().policies(new BearerTokenAuthenticationPolicy(credential, scopes)).build(); + return () -> { + // This request will never need to go anywhere; it is simply to cause the policy to interact with + // the user's credential + HttpRequest req = new HttpRequest(HttpMethod.GET, "https://www.example.com"); + try (HttpResponse res = pipeline.sendSync(req, Context.NONE)) { + return res.getRequest().getHeaders().get(HttpHeaderName.AUTHORIZATION).getValue().split(" ")[1]; + } + }; + } +} diff --git a/sdk/identity/azure-identity/src/samples/java/com/azure/identity/credential/JavaDocCodeSnippets.java b/sdk/identity/azure-identity/src/samples/java/com/azure/identity/credential/JavaDocCodeSnippets.java index 0b054ddecb570..ea19730493958 100644 --- a/sdk/identity/azure-identity/src/samples/java/com/azure/identity/credential/JavaDocCodeSnippets.java +++ b/sdk/identity/azure-identity/src/samples/java/com/azure/identity/credential/JavaDocCodeSnippets.java @@ -6,9 +6,15 @@ import com.azure.core.credential.AccessToken; import com.azure.core.credential.TokenCredential; import com.azure.core.credential.TokenRequestContext; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpHeaderName; +import com.azure.core.http.HttpMethod; +import com.azure.core.http.HttpRequest; import com.azure.core.http.ProxyOptions; import com.azure.core.http.ProxyOptions.Type; +import com.azure.core.util.Context; import com.azure.identity.AuthenticationRecord; +import com.azure.identity.AuthenticationUtil; import com.azure.identity.AuthorizationCodeCredential; import com.azure.identity.AuthorizationCodeCredentialBuilder; import com.azure.identity.AzureCliCredential; @@ -54,6 +60,7 @@ import java.io.FileOutputStream; import java.net.InetSocketAddress; import java.nio.file.Files; +import java.util.function.Supplier; /** * This class contains code samples for generating javadocs through doclets for azure-identity. @@ -349,4 +356,20 @@ public void silentAuthenticationSnippets() { // END: com.azure.identity.silentauthentication } + + public void bearerTokenProviderSampleSync() { + // BEGIN: com.azure.identity.util.getBearerTokenSupplier + DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build(); + String scope = "https://cognitiveservices.azure.com/.default"; + Supplier supplier = AuthenticationUtil.getBearerTokenSupplier(credential, scope); + + // This example simply uses the Azure SDK HTTP library to demonstrate setting the header. + // Use the token as is appropriate for your circumstances. + HttpRequest request = new HttpRequest(HttpMethod.GET, "https://www.example.com"); + request.setHeader(HttpHeaderName.AUTHORIZATION, "Bearer " + supplier.get()); + HttpClient client = HttpClient.createDefault(); + client.sendSync(request, Context.NONE); + // END: com.azure.identity.util.getBearerTokenSupplier + } + } diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/AuthenticationUtilTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/AuthenticationUtilTest.java new file mode 100644 index 0000000000000..c6cca4884eb4b --- /dev/null +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/AuthenticationUtilTest.java @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity; + +import com.azure.core.test.utils.MockTokenCredential; +import org.junit.jupiter.api.Test; + +import java.util.function.Supplier; + +import static com.azure.identity.AuthenticationUtil.getBearerTokenSupplier; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AuthenticationUtilTest { + + @Test + public void testGetBearerTokenSupplier() { + MockTokenCredential credential = new MockTokenCredential(); + Supplier supplier = getBearerTokenSupplier(credential, "scope"); + assertEquals("mockToken", supplier.get()); + } +}