Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update EnvironmentCredential and azure.core.util.Configuration #7337

Merged
merged 8 commits into from
Jan 28, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,28 @@
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:
* <p>
* <ul>
* <li>{@link Configuration#PROPERTY_AZURE_CLIENT_ID AZURE_CLIENT_ID}</li>
* <li>{@link Configuration#PROPERTY_AZURE_CLIENT_SECRET AZURE_CLIENT_SECRET}</li>
* <li>{@link Configuration#PROPERTY_AZURE_TENANT_ID AZURE_TENANT_ID}</li>
* </ul>
* or:
* <p>
* <ul>
* <li>{@link Configuration#PROPERTY_AZURE_CLIENT_ID AZURE_CLIENT_ID}</li>
* <li>{@link Configuration#PROPERTY_AZURE_CLIENT_CERTIFICATE_PATH AZURE_CLIENT_CERTIFICATE_PATH}</li>
* <li>{@link Configuration#PROPERTY_AZURE_TENANT_ID AZURE_TENANT_ID}</li>
* </ul>
* or:
* <p>
* <ul>
* <li>{@link Configuration#PROPERTY_AZURE_CLIENT_ID AZURE_CLIENT_ID}</li>
* <li>{@link Configuration#PROPERTY_AZURE_USERNAME AZURE_USERNAME}</li>
* <li>{@link Configuration#PROPERTY_AZURE_PASSWORD AZURE_PASSWORD}</li>
* </ul>
*/
@Immutable
public class EnvironmentCredential implements TokenCredential {
Expand All @@ -41,15 +55,22 @@ public class EnvironmentCredential implements TokenCredential {

@Override
public Mono<AccessToken> 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
Expand All @@ -58,4 +79,13 @@ public Mono<AccessToken> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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();
}
}