Skip to content
This repository was archived by the owner on Jun 13, 2024. It is now read-only.

Commit da4becb

Browse files
authored
Bug fixes for registering repositories with credentil provider (#506)
1 parent a57df3c commit da4becb

File tree

3 files changed

+207
-2
lines changed

3 files changed

+207
-2
lines changed

src/PowerShellGet/PSGet.Resource.psd1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ ConvertFrom-StringData @'
110110
UseDefaultParameterSetOnRegisterPSRepository=Use 'Register-PSRepository -Default' to register the PSGallery repository.
111111
RepositoryNameContainsWildCards=The repository name '{0}' should not have wildcards, correct it and try again.
112112
InvalidRepository=The specified repository '{0}' is not a valid registered repository name. Please ensure that '{1}' is a registered repository.
113+
RepositoryCannotBeRegistered=The specified repository '{0}' is unauthorized and cannot be registered. Try running with -Credential.
113114
RepositoryRegistered=Successfully registered the repository '{0}' with source location '{1}'.
114115
RepositoryUnregistered=Successfully unregistered the repository '{0}'.
115116
PSGalleryPublishLocationIsMissing=The specified repository '{0}' does not have a valid PublishLocation. Retry after setting the PublishLocation for repository '{1}' to a valid NuGet publishing endpoint using the Set-PSRepository cmdlet.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
2+
function Get-CredsFromCredentialProvider {
3+
[CmdletBinding()]
4+
Param
5+
(
6+
[Parameter()]
7+
[ValidateNotNullOrEmpty()]
8+
[Uri]
9+
$SourceLocation,
10+
11+
[Parameter()]
12+
[bool]
13+
$isRetry = $false
14+
)
15+
16+
17+
Write-Verbose "PowerShellGet Calling 'CallCredProvider' on $SourceLocation"
18+
# Example query: https://pkgs.dev.azure.com/onegettest/_packaging/onegettest/nuget/v2
19+
$regex = [regex] '^(\S*pkgs.dev.azure.com\S*/v2)$|^(\S*pkgs.visualstudio.com\S*/v2)$'
20+
21+
if (!($SourceLocation -match $regex)) {
22+
return $null;
23+
}
24+
25+
# Find credential provider
26+
# Option 1. Use env var 'NUGET_PLUGIN_PATHS' to find credential provider
27+
# See: https://docs.microsoft.com/en-us/nuget/reference/extensibility/nuget-cross-platform-plugins#plugin-installation-and-discovery
28+
# Note: OSX and Linux can only use option 1
29+
# Nuget prioritizes credential providers stored in the NUGET_PLUGIN_PATHS env var
30+
$credProviderPath = $null
31+
$defaultEnvPath = "NUGET_PLUGIN_PATHS"
32+
$nugetPluginPath = Get-Childitem env:$defaultEnvPath -ErrorAction SilentlyContinue
33+
$callDotnet = $true;
34+
35+
if ($nugetPluginPath -and $nugetPluginPath.value) {
36+
# Obtion 1a) The environment variable NUGET_PLUGIN_PATHS should contain a full path to the executable,
37+
# .exe in the .NET Framework case and .dll in the .NET Core case
38+
$credProviderPath = $nugetPluginPath.value
39+
$extension = $credProviderPath.Substring($credProviderPath.get_Length() - 4)
40+
if ($extension -eq ".exe") {
41+
$callDotnet = $false
42+
}
43+
}
44+
else {
45+
# Option 1b) Find User-location - The NuGet Home location - %UserProfile%/.nuget/plugins/
46+
$path = "$env:UserProfile/.nuget/plugins/netcore/CredentialProvider.Microsoft/CredentialProvider.Microsoft.dll";
47+
48+
if ($script:IsLinux -or $script:IsMacOS) {
49+
$path = "$HOME/.nuget/plugins/netcore/CredentialProvider.Microsoft/CredentialProvider.Microsoft.dll";
50+
}
51+
if (Test-Path $path -PathType Leaf) {
52+
$credProviderPath = $path
53+
}
54+
}
55+
56+
# Option 2. Use Visual Studio path to find credential provider
57+
# Visual Studio comes pre-installed with the Azure Artifacts credential provider, so we'll search for that file using vswhere.exe
58+
# If Windows (ie not unix), we'll use vswhere.exe to find installation path of VsWhere
59+
# If credProviderPath is already set we can skip option 2
60+
if (!$credProviderPath -and $script:IsWindows) {
61+
if (${Env:ProgramFiles(x86)}) {
62+
$programFiles = ${Env:ProgramFiles(x86)}
63+
}
64+
elseif ($Env:Programfiles) {
65+
$programFiles = $Env:Programfiles
66+
}
67+
else {
68+
return $null
69+
}
70+
71+
$vswhereExePath = $programFiles + "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
72+
if (!(Test-Path $vswhereExePath -PathType Leaf)) {
73+
return $null
74+
}
75+
76+
$RedirectedOutput = Join-Path ([System.IO.Path]::GetTempPath()) 'RedirectedOutput.txt'
77+
Start-Process $vswhereExePath `
78+
-Wait `
79+
-WorkingDirectory $PSHOME `
80+
-RedirectStandardOutput $RedirectedOutput `
81+
-NoNewWindow
82+
83+
$content = Get-Content $RedirectedOutput
84+
Remove-Item $RedirectedOutput -Force -Recurse -ErrorAction SilentlyContinue
85+
86+
$vsInstallationPath = ""
87+
if ([System.Text.RegularExpressions.Regex]::IsMatch($content, "installationPath")) {
88+
$vsInstallationPath = [System.Text.RegularExpressions.Regex]::Match($content, "(?<=installationPath: ).*(?= installationVersion:)");
89+
$vsInstallationPath = $vsInstallationPath.ToString()
90+
}
91+
92+
# Then use the installation path discovered by vswhere.exe to create the path to search for credential provider
93+
# ex: "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise" + "\Common7\IDE\CommonExtensions\Microsoft\NuGet\Plugins\CredentialProvider.Microsoft\CredentialProvider.Microsoft.exe"
94+
if ($vsInstallationPath) {
95+
$credProviderPath = ($vsInstallationPath + '\Common7\IDE\CommonExtensions\Microsoft\NuGet\Plugins\CredentialProvider.Microsoft\CredentialProvider.Microsoft.exe')
96+
if (!(Test-Path $credProviderPath -PathType Leaf)) {
97+
return $null
98+
}
99+
$callDotnet = $false;
100+
}
101+
}
102+
103+
if (!(Test-Path $credProviderPath -PathType Leaf)) {
104+
return $null
105+
}
106+
107+
$filename = $credProviderPath
108+
$arguments = "-U $SourceLocation"
109+
if ($callDotnet) {
110+
$filename = "dotnet"
111+
$arguments = "$credProviderPath $arguments"
112+
}
113+
$argumentsNoRetry = $arguments
114+
if ($isRetry) {
115+
$arguments = "$arguments -I";
116+
Write-Debug "Credential provider is re-running with -IsRetry"
117+
}
118+
119+
Write-Debug "Credential provider path is: $credProviderPath"
120+
# Using a process to run CredentialProvider.Microsoft.exe with arguments -V verbose -U query (and -IsRetry when appropriate)
121+
# See: https://github.com/Microsoft/artifacts-credprovider
122+
Start-Process $filename -ArgumentList "$arguments -V minimal" `
123+
-Wait `
124+
-WorkingDirectory $PSHOME `
125+
-NoNewWindow
126+
127+
# This should never run IsRetry
128+
$RedirectedOutput = Join-Path ([System.IO.Path]::GetTempPath()) 'RedirectedOutput.txt'
129+
Start-Process $filename -ArgumentList "$argumentsNoRetry -V verbose" `
130+
-Wait `
131+
-WorkingDirectory $PSHOME `
132+
-RedirectStandardOutput $RedirectedOutput `
133+
-NoNewWindow
134+
135+
$content = Get-Content $RedirectedOutput
136+
Remove-Item $RedirectedOutput -Force -Recurse -ErrorAction SilentlyContinue
137+
138+
$username = [System.Text.RegularExpressions.Regex]::Match($content, '(?<=Username: )\S*')
139+
$password = [System.Text.RegularExpressions.Regex]::Match($content, '(?<=Password: ).*')
140+
141+
if ($username -and $password) {
142+
$secstr = ConvertTo-SecureString $password -AsPlainText -Force
143+
$credential = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
144+
145+
return $credential
146+
}
147+
148+
return $null
149+
}

src/PowerShellGet/public/psgetfunctions/Register-PSRepository.ps1

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,61 @@ function Register-PSRepository {
139139
return
140140
}
141141

142+
$pingResult = Ping-Endpoint -Endpoint (Get-LocationString -LocationUri $SourceLocation) -Credential $Credential -Proxy $Proxy -ProxyCredential $ProxyCredential
143+
144+
$retrievedCredential = $null
145+
if (!$Credential -and $pingResult -and $pingResult.ContainsKey($Script:StatusCode) `
146+
-and ($pingResult[$Script:StatusCode] -eq 401)) {
147+
148+
# Try pulling credentials from credential provider
149+
$retrievedCredential = Get-CredsFromCredentialProvider -SourceLocation $SourceLocation
150+
151+
# Ping and resolve the specified location
152+
$SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) `
153+
-LocationParameterName 'SourceLocation' `
154+
-Credential $retrievedCredential `
155+
-Proxy $Proxy `
156+
-ProxyCredential $ProxyCredential `
157+
-CallerPSCmdlet $PSCmdlet
158+
if (-not $SourceLocation) {
159+
# Above Resolve-Location function throws an error when it is not able to resolve a location
160+
return
161+
}
162+
163+
$pingResult = Ping-Endpoint -Endpoint (Get-LocationString -LocationUri $SourceLocation) -Credential $retrievedCredential -Proxy $Proxy -ProxyCredential $ProxyCredential
164+
165+
if (!$retrievedCredential -or ($pingResult -and $pingResult.ContainsKey($Script:StatusCode) `
166+
-and ($pingResult[$Script:StatusCode] -eq 401))) {
167+
168+
# Try again
169+
$retriedRetrievedCredential = Get-CredsFromCredentialProvider -SourceLocation $SourceLocation -IsRetry $true
170+
171+
# Ping and resolve the specified location
172+
$SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) `
173+
-LocationParameterName 'SourceLocation' `
174+
-Credential $retriedRetrievedCredential `
175+
-Proxy $Proxy `
176+
-ProxyCredential $ProxyCredential `
177+
-CallerPSCmdlet $PSCmdlet
178+
179+
if (-not $SourceLocation) {
180+
# Above Resolve-Location function throws an error when it is not able to resolve a location
181+
return
182+
}
183+
184+
$pingResult = Ping-Endpoint -Endpoint (Get-LocationString -LocationUri $SourceLocation) -Credential $retrievedCredential -Proxy $Proxy -ProxyCredential $ProxyCredential
185+
186+
if (!$retriedRetrievedCredential -or ($pingResult -and $pingResult.ContainsKey($Script:StatusCode) `
187+
-and ($pingResult[$Script:StatusCode] -eq 401))) {
188+
189+
$message = $LocalizedData.RepositoryCannotBeRegistered -f ($Name)
190+
Write-Error -Message $message -ErrorId "RepositoryCannotBeRegistered" -Category InvalidOperation
191+
192+
return
193+
}
194+
}
195+
}
196+
142197
$providerName = $null
143198

144199
if ($PackageManagementProvider) {
@@ -183,9 +238,9 @@ function Register-PSRepository {
183238

184239
# add nuget based repo as a nuget source
185240
$nugetCmd = Microsoft.PowerShell.Core\Get-Command -Name $script:NuGetExeName `
186-
-ErrorAction SilentlyContinue -WarningAction SilentlyContinue
241+
-ErrorAction SilentlyContinue -WarningAction SilentlyContinue
187242

188-
if ($nugetCmd){
243+
if ($nugetCmd) {
189244
$nugetSourceExists = nuget sources list | where-object { $_.Trim() -in $SourceLocation }
190245
if (!$nugetSourceExists) {
191246
nuget sources add -name $Name -source $SourceLocation

0 commit comments

Comments
 (0)