Skip to content

Commit 3f3050c

Browse files
authored
Credential creation validation (Azure#27918)
* in progress * make `managedIdentityServiceCredential` package private for testing * In the case `IDENTITY_ENDPOINT` and `IDENTITY_HEADER` are set we should use `AppServiceMsiCredential` * Unit tests validating correct credentials are created based on environment variables. * add hamcrest for testing * use hamcrest for type checking * update CHANGELOG.md * add x-version-update * add hamcrest to external_dependencies.txt * remove uninteresting CHANGELOG.md entry
1 parent 39c8a3d commit 3f3050c

File tree

5 files changed

+106
-2
lines changed

5 files changed

+106
-2
lines changed

eng/versioning/external_dependencies.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ org.eclipse.jetty:jetty-http;9.4.44.v20210927
203203
org.eclipse.jetty:jetty-server;9.4.44.v20210927
204204
org.eclipse.jgit:org.eclipse.jgit;4.5.7.201904151645-r
205205
org.glassfish:javax.json;1.1.4
206+
org.hamcrest:hamcrest;2.2
206207
org.hamcrest:hamcrest-all;1.3
207208
org.hamcrest:hamcrest-library;2.2
208209
org.junit.jupiter:junit-jupiter;5.8.2

sdk/identity/azure-identity/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
Removed `disableAuthoriyValidaionSafetyCheck` for GA, will reintroduce in next beta.
99

1010
### Bugs Fixed
11+
Correctly use an `AppServiceMsiCredential` in the case both `IDENTITY_ENDPOINT` and `IDENTITY_HEADER` are set.
1112

1213
### Other Changes
1314

sdk/identity/azure-identity/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@
9292
<artifactId>json-smart</artifactId>
9393
<version>2.4.7</version> <!-- {x-version-update;net.minidev:json-smart;external_dependency} -->
9494
</dependency>
95+
<dependency>
96+
<groupId>org.hamcrest</groupId>
97+
<artifactId>hamcrest</artifactId>
98+
<version>2.2</version> <!-- {x-version-update;org.hamcrest:hamcrest;external_dependency} -->
99+
<scope>test</scope>
100+
</dependency>
95101
</dependencies>
96102

97103
<build>

sdk/identity/azure-identity/src/main/java/com/azure/identity/ManagedIdentityCredential.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
public final class ManagedIdentityCredential implements TokenCredential {
2424
private static final ClientLogger LOGGER = new ClientLogger(ManagedIdentityCredential.class);
2525

26-
private final ManagedIdentityServiceCredential managedIdentityServiceCredential;
26+
final ManagedIdentityServiceCredential managedIdentityServiceCredential;
2727
private final IdentityClientOptions identityClientOptions;
2828

2929
static final String PROPERTY_IMDS_ENDPOINT = "IMDS_ENDPOINT";
@@ -48,14 +48,27 @@ public final class ManagedIdentityCredential implements TokenCredential {
4848
Configuration configuration = identityClientOptions.getConfiguration() == null
4949
? Configuration.getGlobalConfiguration().clone() : identityClientOptions.getConfiguration();
5050

51+
52+
/*
53+
* Choose credential based on available environment variables in this order:
54+
*
55+
* Azure Arc: IDENTITY_ENDPOINT, IMDS_ENDPOINT
56+
* Service Fabric: IDENTITY_ENDPOINT, IDENTITY_HEADER, IDENTITY_SERVER_THUMBPRINT
57+
* App Service 2019-08-01: IDENTITY_ENDPOINT, IDENTITY_HEADER (MSI_ENDPOINT and MSI_SECRET will also be set.)
58+
* App Service 2017-09-01: MSI_ENDPOINT, MSI_SECRET
59+
* Cloud Shell: MSI_ENDPOINT
60+
* Pod Identity V2 (AksExchangeToken): AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_FEDERATED_TOKEN_FILE
61+
* IMDS/Pod Identity V1: No variables set.
62+
*/
63+
5164
if (configuration.contains(Configuration.PROPERTY_MSI_ENDPOINT)) {
5265
managedIdentityServiceCredential = new AppServiceMsiCredential(clientId, clientBuilder.build());
5366
} else if (configuration.contains(Configuration.PROPERTY_IDENTITY_ENDPOINT)) {
5467
if (configuration.contains(Configuration.PROPERTY_IDENTITY_HEADER)) {
5568
if (configuration.get(PROPERTY_IDENTITY_SERVER_THUMBPRINT) != null) {
5669
managedIdentityServiceCredential = new ServiceFabricMsiCredential(clientId, clientBuilder.build());
5770
} else {
58-
managedIdentityServiceCredential = new VirtualMachineMsiCredential(clientId, clientBuilder.build());
71+
managedIdentityServiceCredential = new AppServiceMsiCredential(clientId, clientBuilder.build());
5972
}
6073
} else if (configuration.get(PROPERTY_IMDS_ENDPOINT) != null) {
6174
managedIdentityServiceCredential = new ArcIdentityCredential(clientId, clientBuilder.build());

sdk/identity/azure-identity/src/test/java/com/azure/identity/ManagedIdentityCredentialTest.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.time.ZoneOffset;
2222
import java.util.UUID;
2323

24+
import static org.hamcrest.MatcherAssert.assertThat;
25+
import static org.hamcrest.core.IsInstanceOf.instanceOf;
2426
import static org.mockito.Mockito.when;
2527

2628
@RunWith(PowerMockRunner.class)
@@ -121,5 +123,86 @@ public void testInvalidIdCombination() {
121123
new ManagedIdentityCredentialBuilder().clientId(CLIENT_ID).resourceId(resourceId).build();
122124
}
123125

126+
@Test
127+
public void testArcIdentityCredentialCreated() {
128+
Configuration configuration = Configuration.getGlobalConfiguration().clone();
129+
130+
configuration.put("IDENTITY_ENDPOINT", "http://localhost");
131+
configuration.put("IMDS_ENDPOINT", "http://localhost");
132+
133+
ManagedIdentityCredential cred = new ManagedIdentityCredentialBuilder().configuration(configuration).build();
134+
assertThat("Received class " + cred.managedIdentityServiceCredential.getClass().toString(),
135+
cred.managedIdentityServiceCredential, instanceOf(ArcIdentityCredential.class));
136+
}
137+
138+
@Test
139+
public void testServiceFabricMsiCredentialCreated() {
140+
Configuration configuration = Configuration.getGlobalConfiguration().clone();
141+
142+
configuration.put("IDENTITY_ENDPOINT", "http://localhost");
143+
configuration.put("IDENTITY_SERVER_THUMBPRINT", "thumbprint");
144+
configuration.put("IDENTITY_HEADER", "header");
145+
146+
ManagedIdentityCredential cred = new ManagedIdentityCredentialBuilder().configuration(configuration).build();
147+
assertThat("Received class " + cred.managedIdentityServiceCredential.getClass().toString(),
148+
cred.managedIdentityServiceCredential, instanceOf(ServiceFabricMsiCredential.class));
149+
}
150+
151+
@Test
152+
public void testAppServiceMsi2019CredentialCreated() {
153+
Configuration configuration = Configuration.getGlobalConfiguration().clone();
154+
155+
configuration.put("IDENTITY_ENDPOINT", "http://localhost");
156+
configuration.put("IDENTITY_HEADER", "header");
157+
158+
ManagedIdentityCredential cred = new ManagedIdentityCredentialBuilder().configuration(configuration).build();
159+
assertThat("Received class " + cred.managedIdentityServiceCredential.getClass().toString(),
160+
cred.managedIdentityServiceCredential, instanceOf(AppServiceMsiCredential.class));
161+
}
162+
163+
@Test
164+
public void testAppServiceMsi2017CredentialCreated() {
165+
Configuration configuration = Configuration.getGlobalConfiguration().clone();
166+
167+
configuration.put("MSI_ENDPOINT", "http://localhost");
168+
configuration.put("MSI_SECRET", "secret");
169+
170+
ManagedIdentityCredential cred = new ManagedIdentityCredentialBuilder().configuration(configuration).build();
171+
assertThat("Received class " + cred.managedIdentityServiceCredential.getClass().toString(),
172+
cred.managedIdentityServiceCredential, instanceOf(AppServiceMsiCredential.class));
173+
}
174+
175+
@Test
176+
public void testCloudShellCredentialCreated() {
177+
Configuration configuration = Configuration.getGlobalConfiguration().clone();
178+
179+
configuration.put("MSI_ENDPOINT", "http://localhost");
180+
181+
ManagedIdentityCredential cred = new ManagedIdentityCredentialBuilder().configuration(configuration).build();
182+
assertThat("Received class " + cred.managedIdentityServiceCredential.getClass().toString(),
183+
cred.managedIdentityServiceCredential, instanceOf(AppServiceMsiCredential.class));
184+
}
185+
186+
@Test
187+
public void testAksExchangeTokenCredentialCreated() {
188+
Configuration configuration = Configuration.getGlobalConfiguration().clone();
189+
190+
configuration.put("AZURE_TENANT_ID", "tenantId");
191+
configuration.put("AZURE_CLIENT_ID", "clientId");
192+
configuration.put("AZURE_FEDERATED_TOKEN_FILE", "tokenFile");
193+
194+
ManagedIdentityCredential cred = new ManagedIdentityCredentialBuilder().configuration(configuration).build();
195+
assertThat("Received class " + cred.managedIdentityServiceCredential.getClass().toString(),
196+
cred.managedIdentityServiceCredential, instanceOf(AksExchangeTokenCredential.class));
197+
}
198+
199+
@Test
200+
public void testIMDSPodIdentityV1Credential() {
201+
Configuration configuration = Configuration.getGlobalConfiguration().clone();
202+
203+
ManagedIdentityCredential cred = new ManagedIdentityCredentialBuilder().configuration(configuration).build();
204+
assertThat("Received class " + cred.managedIdentityServiceCredential.getClass().toString(),
205+
cred.managedIdentityServiceCredential, instanceOf(VirtualMachineMsiCredential.class));
206+
}
124207
}
125208

0 commit comments

Comments
 (0)