Skip to content

Commit 2db9a0f

Browse files
committed
AzureArcManagedIdentitySource fix
1 parent 06dd672 commit 2db9a0f

File tree

6 files changed

+123
-6
lines changed

6 files changed

+123
-6
lines changed

eng/Packages.Data.props

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,13 @@
152152
<!-- Other approved packages -->
153153
<PackageReference Update="Microsoft.Azure.Amqp" Version="2.6.5" />
154154
<PackageReference Update="Microsoft.Azure.WebPubSub.Common" Version="1.2.0" />
155-
<PackageReference Update="Microsoft.Identity.Client" Version="4.60.3" />
156-
<PackageReference Update="Microsoft.Identity.Client.Extensions.Msal" Version="4.60.3" />
155+
<PackageReference Update="Microsoft.Identity.Client" Version="4.61.3" />
156+
<PackageReference Update="Microsoft.Identity.Client.Extensions.Msal" Version="4.61.3" />
157157
<!--
158158
TODO: This package needs to be released as GA and arch-board approved before taking a dependency in any stable SDK library.
159159
Currently, it is referencd by Azure.Identity.Broker which is still in beta
160160
-->
161-
<PackageReference Update="Microsoft.Identity.Client.Broker" Version="4.60.3" />
161+
<PackageReference Update="Microsoft.Identity.Client.Broker" Version="4.61.3" />
162162

163163
<!-- TODO: Make sure this package is arch-board approved -->
164164
<PackageReference Update="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="6.35.0" />
@@ -379,7 +379,7 @@
379379
<PackageReference Update="Microsoft.Extensions.Http" Version="2.1.1" />
380380
<PackageReference Update="Microsoft.Extensions.Logging.Configuration" Version="2.1.1" />
381381
</ItemGroup>
382-
382+
383383
<PropertyGroup>
384384
<TestProxyVersion>1.0.0-dev.20240410.2</TestProxyVersion>
385385
</PropertyGroup>

sdk/identity/Azure.Identity/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Release History
22

3+
## 1.11.4 (2024-06-11)
4+
5+
### Bugs Fixed
6+
- Managed identity bug fixes
7+
38
## 1.11.3 (2024-05-07)
49

510
### Bugs Fixed

sdk/identity/Azure.Identity/src/Azure.Identity.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
<PropertyGroup>
33
<Description>This is the implementation of the Azure SDK Client Library for Azure Identity</Description>
44
<AssemblyTitle>Microsoft Azure.Identity Component</AssemblyTitle>
5-
<Version>1.11.3</Version>
5+
<Version>1.11.4</Version>
66
<!--The ApiCompatVersion is managed automatically and should not generally be modified manually.-->
7-
<ApiCompatVersion>1.11.2</ApiCompatVersion>
7+
<ApiCompatVersion>1.11.3</ApiCompatVersion>
88
<PackageTags>Microsoft Azure Identity;$(PackageCommonTags)</PackageTags>
99
<TargetFrameworks>$(RequiredTargetFrameworks)</TargetFrameworks>
1010
<NoWarn>$(NoWarn);3021;AZC0011</NoWarn>

sdk/identity/Azure.Identity/src/AzureArcManagedIdentitySource.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ protected override async ValueTask<AccessToken> HandleResponseAsync(bool async,
8888
{
8989
throw new AuthenticationFailedException(InvalidChallangeErrorMessage);
9090
}
91+
string filePath = splitChallenge[1];
9192

93+
ValidatePath(filePath);
9294
var authHeaderValue = "Basic " + File.ReadAllText(splitChallenge[1]);
9395

9496
using Request request = CreateRequest(context.Scopes);
@@ -112,5 +114,40 @@ protected override async ValueTask<AccessToken> HandleResponseAsync(bool async,
112114

113115
return await base.HandleResponseAsync(async, context, message, cancellationToken).ConfigureAwait(false);
114116
}
117+
118+
private void ValidatePath(string filePath)
119+
{
120+
// check that the file ends with '.key'
121+
if (!filePath.EndsWith(".key"))
122+
{
123+
throw new AuthenticationFailedException("The secret key file failed validation. File name is invalid.");
124+
}
125+
// if the current platform is windows check that the file is in the path %ProgramData%\AzureConnectedMachineAgent\Tokens
126+
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
127+
{
128+
var programData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
129+
var expectedPath = Path.Combine(programData, "AzureConnectedMachineAgent", "Tokens");
130+
if (!filePath.StartsWith(expectedPath))
131+
{
132+
throw new AuthenticationFailedException("The secret key file failed validation. File path is invalid.");
133+
}
134+
}
135+
136+
// if the current platform is linux check that the file is in the path /var/opt/azcmagent/tokens
137+
if (Environment.OSVersion.Platform == PlatformID.Unix)
138+
{
139+
var expectedPath = Path.Combine("/", "var", "opt", "azcmagent", "tokens");
140+
if (!filePath.StartsWith(expectedPath))
141+
{
142+
throw new AuthenticationFailedException("The secret key file failed validation. File path is invalid.");
143+
}
144+
}
145+
146+
// Check that the file length is no larger than 4096 bytes
147+
if (new FileInfo(filePath).Length > 4096)
148+
{
149+
throw new AuthenticationFailedException("The secret key file failed validation. File is too large.");
150+
}
151+
}
115152
}
116153
}

sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialArcLiveTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public ManagedIdentityCredentialArcLiveTests(bool isAsync) : base(isAsync)
1818

1919
[NonParallelizable]
2020
[Test]
21+
[LiveOnly(Reason = "path validation fails in playback mode")]
2122
public async Task ValidateSystemAssignedIdentity()
2223
{
2324
if (string.IsNullOrEmpty(TestEnvironment.ArcEnable))

sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialTests.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,80 @@ public async Task VerifyAuthenticationFailedExceptionsAreDeferredToGetToken(Dict
853853
await Task.CompletedTask;
854854
}
855855

856+
[Test]
857+
public void VerifyArcIdentitySourceFilePathValidation_DoesNotEndInDotKey()
858+
{
859+
using var environment = new TestEnvVar(
860+
new()
861+
{
862+
{ "MSI_ENDPOINT", null },
863+
{ "MSI_SECRET", null },
864+
{ "IDENTITY_ENDPOINT", "https://identity.constoso.com" },
865+
{ "IMDS_ENDPOINT", "https://imds.constoso.com" },
866+
{ "IDENTITY_HEADER", null },
867+
{ "AZURE_POD_IDENTITY_AUTHORITY_HOST", null }
868+
});
869+
870+
var mockTransport = new MockTransport(request =>
871+
{
872+
var response = new MockResponse(401);
873+
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
874+
{
875+
response.AddHeader("WWW-Authenticate", "file=c:\\ProgramData\\AzureConnectedMachineAgent\\Tokens\\secret.foo");
876+
}
877+
else
878+
{
879+
response.AddHeader("WWW-Authenticate", "file=/var/opt/azcmagent/tokens/secret.foo");
880+
}
881+
return response;
882+
});
883+
var options = new TokenCredentialOptions() { Transport = mockTransport };
884+
options.Retry.MaxDelay = TimeSpan.Zero;
885+
var pipeline = CredentialPipeline.GetInstance(options);
886+
887+
ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential(null, pipeline));
888+
889+
var ex = Assert.ThrowsAsync<AuthenticationFailedException>(async () => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));
890+
Assert.That(ex.Message, Does.Contain("File name is invalid."));
891+
}
892+
893+
[Test]
894+
public void VerifyArcIdentitySourceFilePathValidation_FilePathInvalid()
895+
{
896+
using var environment = new TestEnvVar(
897+
new()
898+
{
899+
{ "MSI_ENDPOINT", null },
900+
{ "MSI_SECRET", null },
901+
{ "IDENTITY_ENDPOINT", "https://identity.constoso.com" },
902+
{ "IMDS_ENDPOINT", "https://imds.constoso.com" },
903+
{ "IDENTITY_HEADER", null },
904+
{ "AZURE_POD_IDENTITY_AUTHORITY_HOST", null }
905+
});
906+
907+
var mockTransport = new MockTransport(request =>
908+
{
909+
var response = new MockResponse(401);
910+
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
911+
{
912+
response.AddHeader("WWW-Authenticate", "file=c:\\ProgramData\\bugus\\AzureConnectedMachineAgent\\Tokens\\secret.key");
913+
}
914+
else
915+
{
916+
response.AddHeader("WWW-Authenticate", "file=/var/opt/bogus/azcmagent/tokens/secret.key");
917+
}
918+
return response;
919+
});
920+
var options = new TokenCredentialOptions() { Transport = mockTransport };
921+
options.Retry.MaxDelay = TimeSpan.Zero;
922+
var pipeline = CredentialPipeline.GetInstance(options);
923+
924+
ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential(null, pipeline));
925+
926+
var ex = Assert.ThrowsAsync<AuthenticationFailedException>(async () => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));
927+
Assert.That(ex.Message, Does.Contain("File path is invalid."));
928+
}
929+
856930
private static IEnumerable<TestCaseData> ResourceAndClientIds()
857931
{
858932
yield return new TestCaseData(new object[] { null, false });

0 commit comments

Comments
 (0)