Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Integrate AzArtifacts Credential Provider #1765

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"sdk": {
"version": "8.0.403"
"version": "8.0.404"
}
}
301 changes: 301 additions & 0 deletions src/code/CredentialProvider.cs

Large diffs are not rendered by default.

35 changes: 32 additions & 3 deletions src/code/FindHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,16 @@ public IEnumerable<PSResourceInfo> FindByResourceName(
}

repositoryNamesToSearch.Add(currentRepository.Name);
_networkCredential = Utils.SetNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);

// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (currentRepository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}
else {
_networkCredential = Utils.SetSecretManagementNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}

ServerApiCall currentServer = ServerFactory.GetServer(currentRepository, _cmdletPassedIn, _networkCredential);
if (currentServer == null)
{
Expand Down Expand Up @@ -386,7 +395,17 @@ public IEnumerable<PSCommandResourceInfo> FindByCommandOrDscResource(
}

repositoryNamesToSearch.Add(currentRepository.Name);
_networkCredential = Utils.SetNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);

// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (currentRepository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}
else
{
_networkCredential = Utils.SetSecretManagementNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}

ServerApiCall currentServer = ServerFactory.GetServer(currentRepository, _cmdletPassedIn, _networkCredential);
if (currentServer == null)
{
Expand Down Expand Up @@ -590,7 +609,17 @@ public IEnumerable<PSResourceInfo> FindByTag(
}

repositoryNamesToSearch.Add(currentRepository.Name);
_networkCredential = Utils.SetNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);

// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (currentRepository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}
else
{
_networkCredential = Utils.SetSecretManagementNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}

ServerApiCall currentServer = ServerFactory.GetServer(currentRepository, _cmdletPassedIn, _networkCredential);
if (currentServer == null)
{
Expand Down
64 changes: 10 additions & 54 deletions src/code/InstallHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,16 @@ private List<PSResourceInfo> ProcessRepositories(
string repoName = currentRepository.Name;
sourceTrusted = currentRepository.Trusted || trustRepository;

_networkCredential = Utils.SetNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (currentRepository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}
else
{
_networkCredential = Utils.SetSecretManagementNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}

ServerApiCall currentServer = ServerFactory.GetServer(currentRepository, _cmdletPassedIn, _networkCredential);

if (currentServer == null)
Expand Down Expand Up @@ -357,59 +366,6 @@ private List<PSResourceInfo> ProcessRepositories(
return allPkgsInstalled;
}

/// <summary>
/// Checks if any of the package versions are already installed and if they are removes them from the list of packages to install.
/// </summary>
private List<PSResourceInfo> FilterByInstalledPkgs(List<PSResourceInfo> packages)
{
// Package install paths.
// _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable).
// _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations.
// e.g.:
// ./InstallPackagePath1/PackageA
// ./InstallPackagePath1/PackageB
// ./InstallPackagePath2/PackageC
// ./InstallPackagePath3/PackageD

_cmdletPassedIn.WriteDebug("In InstallHelper::FilterByInstalledPkgs()");
// Get currently installed packages.
var getHelper = new GetHelper(_cmdletPassedIn);
var installedPackageNames = new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);
foreach (var installedPkg in getHelper.GetInstalledPackages(
pkgs: packages,
pathsToSearch: _pathsToSearch))
{
installedPackageNames.Add(installedPkg.Name);
}

if (installedPackageNames.Count is 0)
{
return packages;
}

// Return only packages that are not already installed.
var filteredPackages = new List<PSResourceInfo>();
foreach (var pkg in packages)
{
if (!installedPackageNames.Contains(pkg.Name))
{
// Add packages that still need to be installed.
filteredPackages.Add(pkg);
}
else
{
// Remove from tracking list of packages to install.
pkg.AdditionalMetadata.TryGetValue("NormalizedVersion", out string normalizedVersion);
_cmdletPassedIn.WriteWarning($"Resource '{pkg.Name}' with version '{normalizedVersion}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter");

// Remove from tracking list of packages to install.
_pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase));
}
}

return filteredPackages;
}

/// <summary>
/// Deletes temp directory and is called at end of install process.
/// </summary>
Expand Down
40 changes: 18 additions & 22 deletions src/code/PSRepositoryInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,74 +27,70 @@ public enum APIVersion
ContainerRegistry
}

public enum CredentialProviderType
{
None,
AzArtifacts
}

#endregion

#region Constructor

public PSRepositoryInfo(string name, Uri uri, int priority, bool trusted, PSCredentialInfo credentialInfo, APIVersion apiVersion, bool allowed)
public PSRepositoryInfo(string name, Uri uri, int priority, bool trusted, PSCredentialInfo credentialInfo, CredentialProviderType credentialProvider, APIVersion apiVersion, bool allowed)
{
Name = name;
Uri = uri;
Priority = priority;
Trusted = trusted;
CredentialInfo = credentialInfo;
CredentialProvider = credentialProvider;
ApiVersion = apiVersion;
IsAllowedByPolicy = allowed;
}

#endregion

#region Enum

public enum RepositoryProviderType
{
None,
ACR,
AzureDevOps
}

#endregion

#region Properties

/// <summary>
/// the Name of the repository
/// The Name of the repository.
/// </summary>
public string Name { get; }

/// <summary>
/// the Uri for the repository
/// The Uri for the repository.
/// </summary>
public Uri Uri { get; }

/// <summary>
/// whether the repository is trusted
/// Whether the repository is trusted.
/// </summary>
public bool Trusted { get; }

/// <summary>
/// the priority of the repository
/// The priority of the repository.
/// </summary>
[ValidateRange(0, 100)]
public int Priority { get; }

/// <summary>
/// the type of repository provider (eg, AzureDevOps, ContainerRegistry, etc.)
/// The credential information for repository authentication.
/// </summary>
public RepositoryProviderType RepositoryProvider { get; }
public PSCredentialInfo CredentialInfo { get; set; }

/// <summary>
/// the credential information for repository authentication
/// Specifies which credential provider to use.
/// </summary>
public PSCredentialInfo CredentialInfo { get; }
public CredentialProviderType CredentialProvider { get; set; }

/// <summary>
/// the API protocol version for the repository
/// The API protocol version for the repository.
/// </summary>
public APIVersion ApiVersion { get; }

// <summary>
/// is it allowed by policy
/// Specifies whether the repository is allowed by policy.
/// </summary>
public bool IsAllowedByPolicy { get; set; }

Expand Down
10 changes: 9 additions & 1 deletion src/code/PublishHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,15 @@ internal void PushResource(string Repository, string modulePrefix, bool SkipDepe
return;
}

_networkCredential = Utils.SetNetworkCredential(repository, _networkCredential, _cmdletPassedIn);
// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (repository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(repository, _networkCredential, _cmdletPassedIn);
}
else
{
_networkCredential = Utils.SetSecretManagementNetworkCredential(repository, _networkCredential, _cmdletPassedIn);
}

// Check if dependencies already exist within the repo if:
// 1) the resource to publish has dependencies and
Expand Down
67 changes: 64 additions & 3 deletions src/code/RegisterPSResourceRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;

using Dbg = System.Diagnostics.Debug;
Expand All @@ -23,7 +24,7 @@ namespace Microsoft.PowerShell.PSResourceGet.Cmdlets
SupportsShouldProcess = true,
ConfirmImpact = ConfirmImpact.Low)]
public sealed
class RegisterPSResourceRepository : PSCmdlet
class RegisterPSResourceRepository : PSCmdlet, IDynamicParameters
{
#region Members

Expand All @@ -35,6 +36,7 @@ class RegisterPSResourceRepository : PSCmdlet
private const string PSGalleryParameterSet = "PSGalleryParameterSet";
private const string RepositoriesParameterSet = "RepositoriesParameterSet";
private Uri _uri;
private CredentialProviderDynamicParameters _credentialProvider;

#endregion

Expand Down Expand Up @@ -111,6 +113,25 @@ class RegisterPSResourceRepository : PSCmdlet

#endregion

#region DynamicParameters

public object GetDynamicParameters()
{
// Dynamic parameter '-CredentialProvider' should not appear for PSGallery, or any container registry repository.
// It should also not appear when using the 'Repositories' parameter set.
if (ParameterSetName.Equals(PSGalleryParameterSet) ||
ParameterSetName.Equals(RepositoriesParameterSet) ||
Uri.EndsWith(".azurecr.io") || Uri.EndsWith(".azurecr.io/") || Uri.Contains("mcr.microsoft.com"))
{
return null;
}

_credentialProvider = new CredentialProviderDynamicParameters();
return _credentialProvider;
}

#endregion

#region Methods

protected override void BeginProcessing()
Expand All @@ -127,6 +148,8 @@ protected override void ProcessRecord()
repoApiVersion = ApiVersion;
}

PSRepositoryInfo.CredentialProviderType? credentialProvider = _credentialProvider?.CredentialProvider;

switch (ParameterSetName)
{
case NameParameterSet:
Expand All @@ -140,7 +163,7 @@ protected override void ProcessRecord()

try
{
items.Add(RepositorySettings.AddRepository(Name, _uri, Priority, Trusted, repoApiVersion, CredentialInfo, Force, this, out string errorMsg));
items.Add(RepositorySettings.AddRepository(Name, _uri, Priority, Trusted, repoApiVersion, CredentialInfo, credentialProvider, Force, this, out string errorMsg));

if (!string.IsNullOrEmpty(errorMsg))
{
Expand Down Expand Up @@ -217,7 +240,8 @@ private PSRepositoryInfo PSGalleryParameterSetHelper(int repoPriority, bool repo
repoPriority,
repoTrusted,
apiVersion: null,
repoCredentialInfo: null,
repoCredentialInfo: null,
credentialProvider: null,
Force,
this,
out string errorMsg);
Expand Down Expand Up @@ -352,6 +376,21 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo)
return null;
}

if (repo.ContainsKey("CredentialProvider") &&
(String.IsNullOrEmpty(repo["CredentialProvider"].ToString()) ||
!(repo["CredentialProvider"].ToString().Equals("None", StringComparison.OrdinalIgnoreCase) ||
repo["CredentialProvider"].ToString().Equals("AzArtifacts", StringComparison.OrdinalIgnoreCase))))
{
WriteError(new ErrorRecord(
new PSInvalidOperationException("Repository 'CredentialProvider' must be set to either 'None' or 'AzArtifacts'"),
"InvalidCredentialProviderForRepositoriesParameterSetRegistration",
ErrorCategory.InvalidArgument,
this));

return null;
}


try
{
WriteDebug($"Registering repository '{repo["Name"]}' with uri '{repoUri}'");
Expand All @@ -361,6 +400,7 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo)
repo.ContainsKey("Trusted") ? Convert.ToBoolean(repo["Trusted"].ToString()) : DefaultTrusted,
apiVersion: repo.ContainsKey("Trusted") ? (PSRepositoryInfo.APIVersion?) repo["ApiVersion"] : null,
repoCredentialInfo,
repo.ContainsKey("CredentialProvider") ? (PSRepositoryInfo.CredentialProviderType?)repo["CredentialProvider"] : null,
Force,
this,
out string errorMsg);
Expand Down Expand Up @@ -399,4 +439,25 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo)

#endregion
}

public class CredentialProviderDynamicParameters
{
PSRepositoryInfo.CredentialProviderType? _credProvider = null;

/// <summary>
/// Specifies which credential provider to use.
/// </summary>
[Parameter]
public PSRepositoryInfo.CredentialProviderType? CredentialProvider {
get
{
return _credProvider;
}

set
{
_credProvider = value;
}
}
}
}
Loading
Loading