WIP: Update ContainerRegistry code to use ORAS.NET#1961
WIP: Update ContainerRegistry code to use ORAS.NET#1961adityapatwardhan wants to merge 6 commits intomasterfrom
Conversation
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
| ? string.Format(RefreshTokenRequestBodyNoTenantTemplate, _registryHost, aadAccessToken) | ||
| : string.Format(RefreshTokenRequestBodyTemplate, _registryHost, tenantId, aadAccessToken); | ||
|
|
||
| using var content = new StringContent(requestBody, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded"); |
Check warning
Code scanning / CodeQL
Information exposure through transmitted data Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 2 days ago
In general, the right fix is not to stop sending the access token to the token-exchange service (that’s necessary) but to (1) ensure it is only ever transmitted over a secure channel to the expected host, and (2) make sure it is never reflected back to the user via error messages or logs. This aligns with the guideline “avoid transmitting passwords or exceptions to the user”: we continue to transmit the token to the auth service, but we prevent accidental disclosure elsewhere and explicitly constrain the transmission to HTTPS.
For this specific code, the best minimally invasive fix is:
- Validate
exchangeUrlbefore sending the HTTP request inExchangeForAcrRefreshTokenAsync:- Parse
exchangeUrlas aUri. - Ensure its scheme is
https; if not, throw or return null with a safe warning, without ever sending the sensitiverequestBody. - Optionally, we can also ensure the host matches the expected registry host domain, but we can do that without changing functionality by at least enforcing HTTPS.
- Parse
- Keep the existing behavior of using
aadAccessTokenin the request body; we are only adding a guard to ensure that this sensitive value is not sent over an insecure protocol. - Avoid introducing any logs that include the token value; the current code does not log it, so we leave logging as-is.
All required changes are localized to ExchangeForAcrRefreshTokenAsync in src/code/PSResourceGetCredentialProvider.cs. No changes are needed in Utils.cs, and we can rely on System.Uri, which is already part of the BCL and requires no new imports.
Concretely:
- In
ExchangeForAcrRefreshTokenAsync, right afterstring exchangeUrl = ..., add code to create aUrifromexchangeUrland verifyuri.Scheme == Uri.UriSchemeHttps. If not, throw anInvalidOperationException(or returnnull) before constructingrequestBodyor sending it. - This makes CodeQL recognize that any transmission of the tainted value only happens over HTTPS and mitigates accidental exposure via non-secure channels.
| @@ -145,6 +145,14 @@ | ||
| private async Task<string> ExchangeForAcrRefreshTokenAsync(string aadAccessToken, string tenantId, CancellationToken cancellationToken) | ||
| { | ||
| string exchangeUrl = string.Format(OAuthExchangeUrlTemplate, _registryHost); | ||
|
|
||
| // Ensure that we only transmit the access token over a secure (HTTPS) channel. | ||
| if (!Uri.TryCreate(exchangeUrl, UriKind.Absolute, out Uri exchangeUri) || | ||
| !string.Equals(exchangeUri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| throw new InvalidOperationException($"Exchange URL must use HTTPS. Actual URL: {exchangeUrl}"); | ||
| } | ||
|
|
||
| string requestBody = string.IsNullOrEmpty(tenantId) | ||
| ? string.Format(RefreshTokenRequestBodyNoTenantTemplate, _registryHost, aadAccessToken) | ||
| : string.Format(RefreshTokenRequestBodyTemplate, _registryHost, tenantId, aadAccessToken); |
05a352c to
55340f9
Compare
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
PR Summary
This pull request introduces significant updates to modernize the codebase by migrating from .NET Framework 4.7.2 to .NET 8.0, adds new dependencies for improved functionality, and refines group policy enforcement to be Windows-specific. Additionally, it introduces a new credential provider for ORAS registry integration and makes several code improvements for robustness and maintainability.
Migration to .NET 8.0 and Dependency Updates:
build.ps1,doBuild.ps1,Microsoft.PowerShell.PSResourceGet.csproj) to targetnet8.0instead ofnet472, updated language version to 12.0, and added/updated dependencies includingOrasProject.Oras,Microsoft.Extensions.Caching.Memory, and others. [1] [2] [3] [4] [5]Group Policy Enforcement Improvements:
OperatingSystem.IsWindows()and[SupportedOSPlatform("windows")]attributes, ensuring cross-platform compatibility and avoiding unnecessary checks on non-Windows systems. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]ORAS Registry Integration:
PSResourceGetCredentialProvider.csimplementing theICredentialProviderinterface for ORAS registry authentication, supporting SecretManagement, Azure Identity, and anonymous access, and handling AAD-to-ACR token exchanges.OrasProject.OrasNuGet package as a dependency in the project file.Code Robustness and Maintenance:
GroupPolicyRepositoryEnforcementto check for null or empty values before conversion, preventing potential exceptions.InstallHelper.csto rethrow exceptions without losing stack trace.Minor Improvements:
PSScriptMetadataconstructor to accept an explicit GUID instead of generating a new one when not provided.using NuGet.Protocol.Core.Types;inRepositorySettings.csfor completeness.PR Context
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:or[ WIP ]to the beginning of the title (theWIPbot will keep its status check atPendingwhile the prefix is present) and remove the prefix when the PR is ready.