Skip to content

Commit 449251d

Browse files
committed
Required feature update
1 parent 5c6f22f commit 449251d

File tree

3 files changed

+88
-15
lines changed

3 files changed

+88
-15
lines changed

src/client/Microsoft.Identity.Client/ManagedIdentity/AzureArcManagedIdentitySource.cs

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.Identity.Client.Extensibility;
1313
using Microsoft.Identity.Client.Http;
1414
using Microsoft.Identity.Client.Internal;
15+
using Microsoft.Identity.Client.PlatformsCommon.Shared;
1516
using Microsoft.Identity.Client.Utils;
1617

1718
namespace Microsoft.Identity.Client.ManagedIdentity
@@ -110,19 +111,7 @@ protected override async Task<ManagedIdentityResponse> HandleResponseAsync(
110111

111112
var splitChallenge = challenge.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
112113

113-
if (splitChallenge.Length != 2)
114-
{
115-
_requestContext.Logger.Error("[Managed Identity] The WWW-Authenticate header for Azure arc managed identity is not an expected format.");
116-
117-
var exception = MsalServiceExceptionFactory.CreateManagedIdentityException(
118-
MsalError.ManagedIdentityRequestFailed,
119-
MsalErrorMessage.ManagedIdentityInvalidChallenge,
120-
null,
121-
ManagedIdentitySource.AzureArc,
122-
null);
123-
124-
throw exception;
125-
}
114+
ValidateSplitChallenge(splitChallenge);
126115

127116
var authHeaderValue = "Basic " + File.ReadAllText(splitChallenge[1]);
128117

@@ -138,5 +127,84 @@ protected override async Task<ManagedIdentityResponse> HandleResponseAsync(
138127

139128
return await base.HandleResponseAsync(parameters, response, cancellationToken).ConfigureAwait(false);
140129
}
130+
131+
private void ValidateSplitChallenge(string[] splitChallenge)
132+
{
133+
if (splitChallenge.Length != 2)
134+
{
135+
throw CreateManagedIdentityException(
136+
MsalError.ManagedIdentityRequestFailed,
137+
MsalErrorMessage.ManagedIdentityInvalidChallenge);
138+
}
139+
140+
_requestContext.Logger.Verbose(() => $"[Managed Identity] Challenge is valid. FilePath: {splitChallenge[1]}");
141+
142+
if (DesktopOsHelper.IsWindows())
143+
{
144+
if (!IsValidWindowsPath(splitChallenge[1]))
145+
{
146+
throw CreateManagedIdentityException(
147+
MsalError.ManagedIdentityRequestFailed,
148+
MsalErrorMessage.ManagedIdentityInvalidFile);
149+
}
150+
151+
_requestContext.Logger.Verbose(() => "[Managed Identity] Windows path is valid.");
152+
}
153+
else if (DesktopOsHelper.IsLinux())
154+
{
155+
if (!IsValidLinuxPath(splitChallenge[1]))
156+
{
157+
throw CreateManagedIdentityException(
158+
MsalError.ManagedIdentityRequestFailed,
159+
MsalErrorMessage.ManagedIdentityInvalidFile);
160+
}
161+
162+
_requestContext.Logger.Verbose(() => "[Managed Identity] Linux path is valid.");
163+
}
164+
else
165+
{
166+
throw CreateManagedIdentityException(
167+
MsalError.ManagedIdentityRequestFailed,
168+
MsalErrorMessage.ManagedIdentityPlatformNotSupported);
169+
}
170+
171+
var length = new FileInfo(splitChallenge[1]).Length;
172+
173+
if ((!File.Exists(splitChallenge[1]) || (length) > 4096))
174+
{
175+
_requestContext.Logger.Error($"[Managed Identity] File does not exist or is greater than 4096 bytes. File exists: {File.Exists(splitChallenge[1])}. Length of file: {length}");
176+
throw CreateManagedIdentityException(
177+
MsalError.ManagedIdentityRequestFailed,
178+
MsalErrorMessage.ManagedIdentityInvalidFile);
179+
}
180+
181+
_requestContext.Logger.Verbose(() => "[Managed Identity] File exists and is less than 4096 bytes.");
182+
}
183+
184+
private MsalException CreateManagedIdentityException(string errorCode, string errorMessage)
185+
{
186+
return MsalServiceExceptionFactory.CreateManagedIdentityException(
187+
errorCode,
188+
errorMessage,
189+
null,
190+
ManagedIdentitySource.AzureArc,
191+
null);
192+
}
193+
194+
private bool IsValidLinuxPath(string path)
195+
{
196+
string linuxPath = "/var/opt/azcmagent/tokens/";
197+
198+
return path.StartsWith(linuxPath, StringComparison.OrdinalIgnoreCase) &&
199+
path.EndsWith(".key", StringComparison.OrdinalIgnoreCase);
200+
}
201+
202+
private bool IsValidWindowsPath(string path)
203+
{
204+
string expandedExpectedPath = Environment.ExpandEnvironmentVariables("%ProgramData%\\AzureConnectedMachineAgent\\Tokens\\");
205+
206+
return path.StartsWith(expandedExpectedPath, StringComparison.OrdinalIgnoreCase) &&
207+
path.EndsWith(".key", StringComparison.OrdinalIgnoreCase);
208+
}
141209
}
142210
}

src/client/Microsoft.Identity.Client/MsalErrorMessage.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,8 @@ public static string InvalidTokenProviderResponseValue(string invalidValueName)
419419
public const string ManagedIdentityEndpointInvalidUriError = "[Managed Identity] The environment variable {0} contains an invalid Uri {1} in {2} managed identity source.";
420420
public const string ManagedIdentityNoChallengeError = "[Managed Identity] Did not receive expected WWW-Authenticate header in the response from Azure Arc Managed Identity Endpoint.";
421421
public const string ManagedIdentityInvalidChallenge = "[Managed Identity] The WWW-Authenticate header in the response from Azure Arc Managed Identity Endpoint did not match the expected format.";
422+
public const string ManagedIdentityInvalidFile = "[Managed Identity] The file on the file path in the WWW-Authenticate header is not secure.";
423+
public const string ManagedIdentityPlatformNotSupported = "[Managed Identity] The platform is not supported by Azure Arc. Azure Arc only supports Windows and Linux.";
422424
public const string ManagedIdentityUserAssignedNotSupported = "[Managed Identity] User assigned identity is not supported by the {0} Managed Identity. To authenticate with the system assigned identity omit the client id in ManagedIdentityApplicationBuilder.Create().";
423425
public const string ManagedIdentityUserAssignedNotConfigurableAtRuntime = "[Managed Identity] Service Fabric user assigned managed identity ClientId or ResourceId is not configurable at runtime.";
424426
public const string CombinedUserAppCacheNotSupported = "Using a combined flat storage, like a file, to store both app and user tokens is not supported. Use a partitioned token cache (for ex. distributed cache like Redis) or separate files for app and user token caches. See https://aka.ms/msal-net-token-cache-serialization .";

tests/Microsoft.Identity.Test.Unit/ManagedIdentityTests/AzureArcTests.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.Identity.Test.Common.Core.Helpers;
1313
using Microsoft.Identity.Test.Common.Core.Mocks;
1414
using Microsoft.VisualStudio.TestTools.UnitTesting;
15+
using NSubstitute.Core;
1516
using static Microsoft.Identity.Test.Common.Core.Helpers.ManagedIdentityTestUtil;
1617

1718
namespace Microsoft.Identity.Test.Unit.ManagedIdentityTests
@@ -78,8 +79,10 @@ await mi.AcquireTokenForManagedIdentity("scope")
7879
}
7980
}
8081

81-
[TestMethod]
82-
public async Task AzureArcAuthHeaderInvalidAsync()
82+
[DataTestMethod]
83+
[DataRow("somefile=filename", MsalErrorMessage.ManagedIdentityInvalidChallenge)]
84+
[DataRow("path/filename", MsalErrorMessage.ManagedIdentityInvalidFile)]
85+
public async Task AzureArcAuthHeaderInvalidAsync(string filename, string errorMessage)
8386
{
8487
using (new EnvVariableContext())
8588
using (var httpManager = new MockHttpManager(isManagedIdentity: true))

0 commit comments

Comments
 (0)