diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/Configuration.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/Configuration.java
index bf7b8cbd4a8e9..677ca5ec70d24 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/util/Configuration.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/Configuration.java
@@ -75,6 +75,11 @@ public class Configuration implements Cloneable {
*/
public static final String PROPERTY_AZURE_TENANT_ID = "AZURE_TENANT_ID";
+ /**
+ * Path of a PEM certificate file to use when performing service principal authentication with Azure.
+ */
+ public static final String PROPERTY_AZURE_CLIENT_CERTIFICATE_PATH = "AZURE_CLIENT_CERTIFICATE_PATH";
+
/**
* Name of the Azure resource group.
*/
@@ -83,7 +88,7 @@ public class Configuration implements Cloneable {
/**
* Name of the Azure cloud to connect to.
*/
- public static final String PROPERTY_AZURE_CLOUD = "AZURE_CLOUD";
+ public static final String PROPERTY_AZURE_AUTHORITY_HOST = "AZURE_AUTHORITY_HOST";
/**
* Disables telemetry collection.
@@ -115,8 +120,9 @@ public class Configuration implements Cloneable {
PROPERTY_AZURE_CLIENT_ID,
PROPERTY_AZURE_CLIENT_SECRET,
PROPERTY_AZURE_TENANT_ID,
+ PROPERTY_AZURE_CLIENT_CERTIFICATE_PATH,
PROPERTY_AZURE_RESOURCE_GROUP,
- PROPERTY_AZURE_CLOUD,
+ PROPERTY_AZURE_AUTHORITY_HOST,
PROPERTY_AZURE_TELEMETRY_DISABLED,
PROPERTY_AZURE_LOG_LEVEL,
PROPERTY_AZURE_TRACING_DISABLED,
diff --git a/sdk/eventhubs/microsoft-azure-eventhubs-eph/Readme.md b/sdk/eventhubs/microsoft-azure-eventhubs-eph/README.md
similarity index 100%
rename from sdk/eventhubs/microsoft-azure-eventhubs-eph/Readme.md
rename to sdk/eventhubs/microsoft-azure-eventhubs-eph/README.md
diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/EnvironmentCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/EnvironmentCredential.java
index 1c1f3ef6d1756..bbc795f5f3687 100644
--- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/EnvironmentCredential.java
+++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/EnvironmentCredential.java
@@ -14,7 +14,7 @@
import reactor.core.publisher.Mono;
/**
- * A credential provider that provides token credentials based on environment variables. The environment variables
+ * A credential provider that provides token credentials based on environment variables. The sets of environment variables
* expected are:
*
*
@@ -22,6 +22,20 @@
* - {@link Configuration#PROPERTY_AZURE_CLIENT_SECRET AZURE_CLIENT_SECRET}
* - {@link Configuration#PROPERTY_AZURE_TENANT_ID AZURE_TENANT_ID}
*
+ * or:
+ *
+ *
+ * - {@link Configuration#PROPERTY_AZURE_CLIENT_ID AZURE_CLIENT_ID}
+ * - {@link Configuration#PROPERTY_AZURE_CLIENT_CERTIFICATE_PATH AZURE_CLIENT_CERTIFICATE_PATH}
+ * - {@link Configuration#PROPERTY_AZURE_TENANT_ID AZURE_TENANT_ID}
+ *
+ * or:
+ *
+ *
+ * - {@link Configuration#PROPERTY_AZURE_CLIENT_ID AZURE_CLIENT_ID}
+ * - {@link Configuration#PROPERTY_AZURE_USERNAME AZURE_USERNAME}
+ * - {@link Configuration#PROPERTY_AZURE_PASSWORD AZURE_PASSWORD}
+ *
*/
@Immutable
public class EnvironmentCredential implements TokenCredential {
@@ -41,15 +55,22 @@ public class EnvironmentCredential implements TokenCredential {
@Override
public Mono getToken(TokenRequestContext request) {
+ String clientId = configuration.get(Configuration.PROPERTY_AZURE_CLIENT_ID);
+ String tenantId = configuration.get(Configuration.PROPERTY_AZURE_TENANT_ID);
+ String clientSecret = configuration.get(Configuration.PROPERTY_AZURE_CLIENT_SECRET);
+ String certPath = configuration.get(Configuration.PROPERTY_AZURE_CLIENT_CERTIFICATE_PATH);
+ String username = configuration.get(Configuration.PROPERTY_AZURE_USERNAME);
+ String password = configuration.get(Configuration.PROPERTY_AZURE_PASSWORD);
return Mono.fromSupplier(() -> {
- if (configuration.contains(Configuration.PROPERTY_AZURE_CLIENT_ID)
- && configuration.contains(Configuration.PROPERTY_AZURE_CLIENT_SECRET)
- && configuration.contains(Configuration.PROPERTY_AZURE_TENANT_ID)) {
- // TODO: support other clouds
- return new ClientSecretCredential(configuration.get(Configuration.PROPERTY_AZURE_TENANT_ID),
- configuration.get(Configuration.PROPERTY_AZURE_CLIENT_ID),
- configuration.get(Configuration.PROPERTY_AZURE_CLIENT_SECRET),
- identityClientOptions);
+ if (verifyNotNull(clientId)) {
+ if (verifyNotNull(tenantId, clientSecret)) {
+ // TODO: support other clouds
+ return new ClientSecretCredential(tenantId, clientId, clientSecret, identityClientOptions);
+ } else if (verifyNotNull(tenantId, certPath)) {
+ return new ClientCertificateCredential(tenantId, clientId, certPath, null, identityClientOptions);
+ } else if (verifyNotNull(username, password)) {
+ return new UsernamePasswordCredential(clientId, tenantId, username, password, identityClientOptions);
+ }
}
// Other environment variables
@@ -58,4 +79,13 @@ public Mono getToken(TokenRequestContext request) {
null));
}).flatMap(cred -> cred.getToken(request));
}
+
+ private boolean verifyNotNull(String... configs){
+ for(String config: configs){
+ if(config == null){
+ return false;
+ }
+ }
+ return true;
+ }
}
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 33cad876b36b3..454e3bef413b6 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
@@ -5,6 +5,7 @@
import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenRequestContext;
+import com.azure.core.exception.ClientAuthenticationException;
import com.azure.core.http.ProxyOptions;
import com.azure.core.util.serializer.SerializerAdapter;
import com.azure.core.util.serializer.SerializerEncoding;
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 4fb5c1372ab10..5205bd2f13563 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
@@ -24,7 +24,9 @@ public final class IdentityClientOptions {
* Creates an instance of IdentityClientOptions with default settings.
*/
public IdentityClientOptions() {
- authorityHost = DEFAULT_AUTHORITY_HOST;
+ Configuration configuration = Configuration.getGlobalConfiguration();
+ authorityHost = configuration.contains(configuration.PROPERTY_AZURE_AUTHORITY_HOST)
+ ? configuration.get(configuration.PROPERTY_AZURE_AUTHORITY_HOST) : DEFAULT_AUTHORITY_HOST;
maxRetry = MAX_RETRY_DEFAULT_LIMIT;
retryTimeout = i -> Duration.ofSeconds((long) Math.pow(2, i.getSeconds() - 1));
}
diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/EnvironmentCredentialTests.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/EnvironmentCredentialTests.java
index 7c3e54c1a7eab..5483db061fe04 100644
--- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/EnvironmentCredentialTests.java
+++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/EnvironmentCredentialTests.java
@@ -17,11 +17,11 @@
public class EnvironmentCredentialTests {
@Test
- public void testCreateEnvironmentCredential() {
- Configuration configuration = Configuration.getGlobalConfiguration();
- configuration.put(Configuration.PROPERTY_AZURE_CLIENT_ID, "foo");
- configuration.put(Configuration.PROPERTY_AZURE_CLIENT_SECRET, "bar");
- configuration.put(Configuration.PROPERTY_AZURE_TENANT_ID, "baz");
+ public void testCreateEnvironmentClientSecretCredential() {
+ Configuration.getGlobalConfiguration()
+ .put(Configuration.PROPERTY_AZURE_CLIENT_ID, "foo")
+ .put(Configuration.PROPERTY_AZURE_USERNAME, "bar")
+ .put(Configuration.PROPERTY_AZURE_PASSWORD, "baz");
EnvironmentCredential credential = new EnvironmentCredentialBuilder().build();
@@ -36,4 +36,46 @@ public void testCreateEnvironmentCredential() {
.expectNextMatches(token -> "token".equals(token.getToken()))
.verifyComplete();
}
+
+ @Test
+ public void testCreateEnvironmentClientCertificateCredential() {
+ Configuration.getGlobalConfiguration()
+ .put(Configuration.PROPERTY_AZURE_CLIENT_ID, "foo")
+ .put(Configuration.PROPERTY_AZURE_USERNAME, "bar")
+ .put(Configuration.PROPERTY_AZURE_PASSWORD, "baz");
+
+ EnvironmentCredential credential = new EnvironmentCredentialBuilder().build();
+
+ // authentication will fail client-id=foo, but should be able to create ClientCertificateCredential
+ StepVerifier.create(credential.getToken(new TokenRequestContext().addScopes("qux/.default"))
+ .doOnSuccess(s -> fail())
+ .onErrorResume(t -> {
+ String message = t.getMessage();
+ Assert.assertFalse(message != null && message.contains("Cannot create any credentials with the current environment variables"));
+ return Mono.just(new AccessToken("token", OffsetDateTime.MAX));
+ }))
+ .expectNextMatches(token -> "token".equals(token.getToken()))
+ .verifyComplete();
+ }
+
+ @Test
+ public void testCreateEnvironmentUserPasswordCredential() {
+ Configuration.getGlobalConfiguration()
+ .put(Configuration.PROPERTY_AZURE_CLIENT_ID, "foo")
+ .put(Configuration.PROPERTY_AZURE_USERNAME, "bar")
+ .put(Configuration.PROPERTY_AZURE_PASSWORD, "baz");
+
+ EnvironmentCredential credential = new EnvironmentCredentialBuilder().build();
+
+ // authentication will fail client-id=foo, but should be able to create UsernamePasswordCredential
+ StepVerifier.create(credential.getToken(new TokenRequestContext().addScopes("qux/.default"))
+ .doOnSuccess(s -> fail())
+ .onErrorResume(t -> {
+ String message = t.getMessage();
+ Assert.assertFalse(message != null && message.contains("Cannot create any credentials with the current environment variables"));
+ return Mono.just(new AccessToken("token", OffsetDateTime.MAX));
+ }))
+ .expectNextMatches(token -> "token".equals(token.getToken()))
+ .verifyComplete();
+ }
}