1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ package com .microsoft .aad .msal4j ;
5
+
6
+ import org .slf4j .Logger ;
7
+ import org .slf4j .LoggerFactory ;
8
+
9
+ import java .net .HttpURLConnection ;
10
+ import java .net .URI ;
11
+ import java .net .URISyntaxException ;
12
+ import java .util .Collections ;
13
+ import java .util .HashMap ;
14
+
15
+ class AzureArcManagedIdentitySource extends AbstractManagedIdentitySource {
16
+
17
+ private final static Logger LOG = LoggerFactory .getLogger (AzureArcManagedIdentitySource .class );
18
+ private static final String ARC_API_VERSION = "2019-11-01" ;
19
+ private static final String AZURE_ARC = "Azure Arc" ;
20
+
21
+ private final URI MSI_ENDPOINT ;
22
+
23
+ static AbstractManagedIdentitySource create (MsalRequest msalRequest , ServiceBundle serviceBundle )
24
+ {
25
+ IEnvironmentVariables environmentVariables = getEnvironmentVariables ((ManagedIdentityParameters ) msalRequest .requestContext ().apiParameters ());
26
+ String identityEndpoint = environmentVariables .getEnvironmentVariable (Constants .IDENTITY_ENDPOINT );
27
+ String imdsEndpoint = environmentVariables .getEnvironmentVariable (Constants .IMDS_ENDPOINT );
28
+
29
+ URI validatedUri = validateAndGetUri (identityEndpoint , imdsEndpoint );
30
+ return validatedUri == null ? null : new AzureArcManagedIdentitySource (validatedUri , msalRequest , serviceBundle );
31
+ }
32
+
33
+ private static URI validateAndGetUri (String identityEndpoint , String imdsEndpoint ) {
34
+
35
+ // if BOTH the env vars IDENTITY_ENDPOINT and IMDS_ENDPOINT are set the MsiType is Azure Arc
36
+ if (StringHelper .isNullOrBlank (identityEndpoint ) || StringHelper .isNullOrBlank (imdsEndpoint ))
37
+ {
38
+ LOG .info ("[Managed Identity] Azure Arc managed identity is unavailable." );
39
+ return null ;
40
+ }
41
+
42
+ URI endpointUri ;
43
+ try {
44
+ endpointUri = new URI (identityEndpoint );
45
+ } catch (URISyntaxException e ) {
46
+ throw new MsalManagedIdentityException (MsalError .INVALID_MANAGED_IDENTITY_ENDPOINT , String .format (
47
+ MsalErrorMessage .MANAGED_IDENTITY_ENDPOINT_INVALID_URI_ERROR , "IDENTITY_ENDPOINT" , identityEndpoint , AZURE_ARC ),
48
+ ManagedIdentitySourceType .AzureArc );
49
+ }
50
+
51
+ LOG .info ("[Managed Identity] Creating Azure Arc managed identity. Endpoint URI: " + endpointUri );
52
+ return endpointUri ;
53
+ }
54
+
55
+ private AzureArcManagedIdentitySource (URI endpoint , MsalRequest msalRequest , ServiceBundle serviceBundle ){
56
+ super (msalRequest , serviceBundle , ManagedIdentitySourceType .AzureArc );
57
+ this .MSI_ENDPOINT = endpoint ;
58
+
59
+ ManagedIdentityIdType idType =
60
+ ((ManagedIdentityApplication ) msalRequest .application ()).getManagedIdentityId ().getIdType ();
61
+ if (idType != ManagedIdentityIdType .SystemAssigned ) {
62
+ throw new MsalManagedIdentityException (MsalError .USER_ASSIGNED_MANAGED_IDENTITY_NOT_SUPPORTED ,
63
+ String .format (MsalErrorMessage .MANAGED_IDENTITY_USER_ASSIGNED_NOT_SUPPORTED , AZURE_ARC ),
64
+ ManagedIdentitySourceType .CloudShell );
65
+ }
66
+ }
67
+
68
+ @ Override
69
+ public void createManagedIdentityRequest (String resource )
70
+ {
71
+ managedIdentityRequest .baseEndpoint = MSI_ENDPOINT ;
72
+ managedIdentityRequest .method = HttpMethod .GET ;
73
+
74
+ managedIdentityRequest .headers = new HashMap <>();
75
+ managedIdentityRequest .headers .put ("Metadata" , "true" );
76
+
77
+ managedIdentityRequest .queryParameters = new HashMap <>();
78
+ managedIdentityRequest .queryParameters .put ("api-version" , Collections .singletonList (ARC_API_VERSION ));
79
+ managedIdentityRequest .queryParameters .put ("resource" , Collections .singletonList (resource ));
80
+ }
81
+
82
+ @ Override
83
+ public ManagedIdentityResponse handleResponse (
84
+ ManagedIdentityParameters parameters ,
85
+ IHttpResponse response )
86
+ {
87
+ LOG .info ("[Managed Identity] Response received. Status code: {response.StatusCode}" );
88
+
89
+ if (response .statusCode () == HttpURLConnection .HTTP_UNAUTHORIZED )
90
+ {
91
+ if (!response .headers ().containsKey ("WWW-Authenticate" )){
92
+ LOG .error ("[Managed Identity] WWW-Authenticate header is expected but not found." );
93
+ throw new MsalManagedIdentityException (MsalError .MANAGED_IDENTITY_REQUEST_FAILED ,
94
+ MsalErrorMessage .MANAGED_IDENTITY_NO_CHALLENGE_ERROR ,
95
+ ManagedIdentitySourceType .AzureArc );
96
+ }
97
+
98
+ String challenge = response .headers ().get ("WWW-Authenticate" ).get (0 );
99
+ String [] splitChallenge = challenge .split ("=" );
100
+
101
+ if (splitChallenge .length != 2 )
102
+ {
103
+ LOG .error ("[Managed Identity] The WWW-Authenticate header for Azure arc managed identity is not an expected format." );
104
+ throw new MsalManagedIdentityException (MsalError .MANAGED_IDENTITY_REQUEST_FAILED ,
105
+ MsalErrorMessage .MANAGED_IDENTITY_INVALID_CHALLENGE ,
106
+ ManagedIdentitySourceType .AzureArc );
107
+ }
108
+
109
+ String authHeaderValue = "Basic " + splitChallenge [1 ];
110
+
111
+ createManagedIdentityRequest (parameters .resource );
112
+
113
+ LOG .info ("[Managed Identity] Adding authorization header to the request." );
114
+
115
+ managedIdentityRequest .headers .put ("Authorization" , authHeaderValue );
116
+
117
+ try {
118
+ response = HttpHelper .executeHttpRequest (
119
+ new HttpRequest (HttpMethod .GET , managedIdentityRequest .computeURI ().toString (),
120
+ managedIdentityRequest .headers ),
121
+ managedIdentityRequest .requestContext (),
122
+ serviceBundle );
123
+ } catch (URISyntaxException e ) {
124
+ throw new MsalManagedIdentityException (MsalError .INVALID_MANAGED_IDENTITY_ENDPOINT ,
125
+ MsalErrorMessage .MANAGED_IDENTITY_ENDPOINT_INVALID_URI_ERROR ,
126
+ managedIdentitySourceType );
127
+ }
128
+
129
+ return super .handleResponse (parameters , response );
130
+ }
131
+
132
+ return super .handleResponse (parameters , response );
133
+ }
134
+ }
0 commit comments