diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props
index 364166cc98678..507c2c2c8f6fa 100644
--- a/eng/Packages.Data.props
+++ b/eng/Packages.Data.props
@@ -152,13 +152,13 @@
-
-
+
+
-
+
@@ -379,7 +379,7 @@
-
+
1.0.0-dev.20240410.2
diff --git a/sdk/identity/Azure.Identity/CHANGELOG.md b/sdk/identity/Azure.Identity/CHANGELOG.md
index 49f853c35971b..800e85ea630bc 100644
--- a/sdk/identity/Azure.Identity/CHANGELOG.md
+++ b/sdk/identity/Azure.Identity/CHANGELOG.md
@@ -1,5 +1,10 @@
# Release History
+## 1.11.4 (2024-06-11)
+
+### Bugs Fixed
+- Managed identity bug fixes
+
## 1.11.3 (2024-05-07)
### Bugs Fixed
diff --git a/sdk/identity/Azure.Identity/src/Azure.Identity.csproj b/sdk/identity/Azure.Identity/src/Azure.Identity.csproj
index 858379b84b2b9..ed8e56cc41f43 100644
--- a/sdk/identity/Azure.Identity/src/Azure.Identity.csproj
+++ b/sdk/identity/Azure.Identity/src/Azure.Identity.csproj
@@ -2,9 +2,9 @@
This is the implementation of the Azure SDK Client Library for Azure Identity
Microsoft Azure.Identity Component
- 1.11.3
+ 1.11.4
- 1.11.2
+ 1.11.3
Microsoft Azure Identity;$(PackageCommonTags)
$(RequiredTargetFrameworks)
$(NoWarn);3021;AZC0011
diff --git a/sdk/identity/Azure.Identity/src/AzureArcManagedIdentitySource.cs b/sdk/identity/Azure.Identity/src/AzureArcManagedIdentitySource.cs
index 42f1f06a36794..fcd1654e51c40 100644
--- a/sdk/identity/Azure.Identity/src/AzureArcManagedIdentitySource.cs
+++ b/sdk/identity/Azure.Identity/src/AzureArcManagedIdentitySource.cs
@@ -88,7 +88,9 @@ protected override async ValueTask HandleResponseAsync(bool async,
{
throw new AuthenticationFailedException(InvalidChallangeErrorMessage);
}
+ string filePath = splitChallenge[1];
+ ValidatePath(filePath);
var authHeaderValue = "Basic " + File.ReadAllText(splitChallenge[1]);
using Request request = CreateRequest(context.Scopes);
@@ -112,5 +114,40 @@ protected override async ValueTask HandleResponseAsync(bool async,
return await base.HandleResponseAsync(async, context, message, cancellationToken).ConfigureAwait(false);
}
+
+ private void ValidatePath(string filePath)
+ {
+ // check that the file ends with '.key'
+ if (!filePath.EndsWith(".key"))
+ {
+ throw new AuthenticationFailedException("The secret key file failed validation. File name is invalid.");
+ }
+ // if the current platform is windows check that the file is in the path %ProgramData%\AzureConnectedMachineAgent\Tokens
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+ {
+ var programData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
+ var expectedPath = Path.Combine(programData, "AzureConnectedMachineAgent", "Tokens");
+ if (!filePath.StartsWith(expectedPath))
+ {
+ throw new AuthenticationFailedException("The secret key file failed validation. File path is invalid.");
+ }
+ }
+
+ // if the current platform is linux check that the file is in the path /var/opt/azcmagent/tokens
+ if (Environment.OSVersion.Platform == PlatformID.Unix)
+ {
+ var expectedPath = Path.Combine("/", "var", "opt", "azcmagent", "tokens");
+ if (!filePath.StartsWith(expectedPath))
+ {
+ throw new AuthenticationFailedException("The secret key file failed validation. File path is invalid.");
+ }
+ }
+
+ // Check that the file length is no larger than 4096 bytes
+ if (new FileInfo(filePath).Length > 4096)
+ {
+ throw new AuthenticationFailedException("The secret key file failed validation. File is too large.");
+ }
+ }
}
}
diff --git a/sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialArcLiveTests.cs b/sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialArcLiveTests.cs
index 73b0dacb68e56..a9d32df6b972b 100644
--- a/sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialArcLiveTests.cs
+++ b/sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialArcLiveTests.cs
@@ -18,6 +18,7 @@ public ManagedIdentityCredentialArcLiveTests(bool isAsync) : base(isAsync)
[NonParallelizable]
[Test]
+ [LiveOnly(Reason = "path validation fails in playback mode")]
public async Task ValidateSystemAssignedIdentity()
{
if (string.IsNullOrEmpty(TestEnvironment.ArcEnable))
diff --git a/sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialTests.cs b/sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialTests.cs
index 5253768da832f..f2a8995e6c2de 100644
--- a/sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialTests.cs
+++ b/sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialTests.cs
@@ -853,6 +853,80 @@ public async Task VerifyAuthenticationFailedExceptionsAreDeferredToGetToken(Dict
await Task.CompletedTask;
}
+ [Test]
+ public void VerifyArcIdentitySourceFilePathValidation_DoesNotEndInDotKey()
+ {
+ using var environment = new TestEnvVar(
+ new()
+ {
+ { "MSI_ENDPOINT", null },
+ { "MSI_SECRET", null },
+ { "IDENTITY_ENDPOINT", "https://identity.constoso.com" },
+ { "IMDS_ENDPOINT", "https://imds.constoso.com" },
+ { "IDENTITY_HEADER", null },
+ { "AZURE_POD_IDENTITY_AUTHORITY_HOST", null }
+ });
+
+ var mockTransport = new MockTransport(request =>
+ {
+ var response = new MockResponse(401);
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+ {
+ response.AddHeader("WWW-Authenticate", "file=c:\\ProgramData\\AzureConnectedMachineAgent\\Tokens\\secret.foo");
+ }
+ else
+ {
+ response.AddHeader("WWW-Authenticate", "file=/var/opt/azcmagent/tokens/secret.foo");
+ }
+ return response;
+ });
+ var options = new TokenCredentialOptions() { Transport = mockTransport };
+ options.Retry.MaxDelay = TimeSpan.Zero;
+ var pipeline = CredentialPipeline.GetInstance(options);
+
+ ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential(null, pipeline));
+
+ var ex = Assert.ThrowsAsync(async () => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));
+ Assert.That(ex.Message, Does.Contain("File name is invalid."));
+ }
+
+ [Test]
+ public void VerifyArcIdentitySourceFilePathValidation_FilePathInvalid()
+ {
+ using var environment = new TestEnvVar(
+ new()
+ {
+ { "MSI_ENDPOINT", null },
+ { "MSI_SECRET", null },
+ { "IDENTITY_ENDPOINT", "https://identity.constoso.com" },
+ { "IMDS_ENDPOINT", "https://imds.constoso.com" },
+ { "IDENTITY_HEADER", null },
+ { "AZURE_POD_IDENTITY_AUTHORITY_HOST", null }
+ });
+
+ var mockTransport = new MockTransport(request =>
+ {
+ var response = new MockResponse(401);
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+ {
+ response.AddHeader("WWW-Authenticate", "file=c:\\ProgramData\\bugus\\AzureConnectedMachineAgent\\Tokens\\secret.key");
+ }
+ else
+ {
+ response.AddHeader("WWW-Authenticate", "file=/var/opt/bogus/azcmagent/tokens/secret.key");
+ }
+ return response;
+ });
+ var options = new TokenCredentialOptions() { Transport = mockTransport };
+ options.Retry.MaxDelay = TimeSpan.Zero;
+ var pipeline = CredentialPipeline.GetInstance(options);
+
+ ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential(null, pipeline));
+
+ var ex = Assert.ThrowsAsync(async () => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));
+ Assert.That(ex.Message, Does.Contain("File path is invalid."));
+ }
+
private static IEnumerable ResourceAndClientIds()
{
yield return new TestCaseData(new object[] { null, false });