Merge branch 'master' of https://github.com/microsoft/artifacts-credprovider into crmann1-users/crmann1/addMSAL
This commit is contained in:
Коммит
1901798682
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<CredentialProviderVersion>0.1.23</CredentialProviderVersion>
|
||||
<CredentialProviderVersion>0.1.25</CredentialProviderVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<PackageReference Include="Moq" Version="4.13.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.0.0" />
|
||||
<PackageReference Include="NuGet.Protocol" Version="5.3.0" />
|
||||
<PackageReference Include="NuGet.Protocol" Version="5.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace CredentialProvider.Microsoft.Tests.CredentialProviders.Vsts
|
|||
{
|
||||
Environment.SetEnvironmentVariable(EnvUtil.AuthorityEnvVar, string.Empty);
|
||||
Environment.SetEnvironmentVariable(EnvUtil.MsalEnabledEnvVar, string.Empty);
|
||||
Environment.SetEnvironmentVariable(EnvUtil.PpeHostsEnvVar, string.Empty);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -110,46 +111,69 @@ namespace CredentialProvider.Microsoft.Tests.CredentialProviders.Vsts
|
|||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task IsVstsUri_TenantHeaderNotPresent_ReturnsFalse()
|
||||
public async Task GetFeedUriSource_TenantHeaderNotPresent_ReturnsExternal()
|
||||
{
|
||||
var requestUri = new Uri("https://example.pkgs.visualstudio.com/_packaging/feed/nuget/v3/index.json");
|
||||
|
||||
var isVstsUri = await authUtil.IsVstsUriAsync(requestUri);
|
||||
isVstsUri.Should().BeFalse();
|
||||
var feedSource = await authUtil.GetAzDevDeploymentType(requestUri);
|
||||
feedSource.Should().Be(AzDevDeploymentType.External);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task IsVstsUri_TenantHeaderPresent_ReturnsFalse()
|
||||
public async Task GetFeedUriSource_TenantHeaderPresent_VssAuthorizationEndpointNotPresent_ReturnsExternal()
|
||||
{
|
||||
var requestUri = new Uri("https://example.pkgs.visualstudio.com/_packaging/feed/nuget/v3/index.json");
|
||||
|
||||
MockVssResourceTenantHeader();
|
||||
|
||||
var isVstsUri = await authUtil.IsVstsUriAsync(requestUri);
|
||||
isVstsUri.Should().BeFalse();
|
||||
var feedSource = await authUtil.GetAzDevDeploymentType(requestUri);
|
||||
feedSource.Should().Be(AzDevDeploymentType.External);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task IsVstsUri_AuthorizationEndpointHeaderPresent_ReturnsFalse()
|
||||
public async Task GetFeedUriSource_AuthorizationEndpointHeaderPresent_TenantHeaderNotPresent_ReturnsExternal()
|
||||
{
|
||||
var requestUri = new Uri("https://example.pkgs.visualstudio.com/_packaging/feed/nuget/v3/index.json");
|
||||
|
||||
MockVssAuthorizationEndpointHeader();
|
||||
|
||||
var isVstsUri = await authUtil.IsVstsUriAsync(requestUri);
|
||||
isVstsUri.Should().BeFalse();
|
||||
var feedSource = await authUtil.GetAzDevDeploymentType(requestUri);
|
||||
feedSource.Should().Be(AzDevDeploymentType.External);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task IsVstsUri_BothHeadersPresent_ReturnsTrue()
|
||||
public async Task GetFeedUriSource_BothHeadersPresent_ReturnsHosted()
|
||||
{
|
||||
var requestUri = new Uri("https://example.pkgs.visualstudio.com/_packaging/feed/nuget/v3/index.json");
|
||||
|
||||
MockVssResourceTenantHeader();
|
||||
MockVssAuthorizationEndpointHeader();
|
||||
|
||||
var isVstsUri = await authUtil.IsVstsUriAsync(requestUri);
|
||||
isVstsUri.Should().BeTrue();
|
||||
var feedSource = await authUtil.GetAzDevDeploymentType(requestUri);
|
||||
feedSource.Should().Be(AzDevDeploymentType.Hosted);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetFeedUriSource_NoHttps_ReturnsExternal()
|
||||
{
|
||||
var requestUri = new Uri("http://example.pkgs.visualstudio.com/_packaging/feed/nuget/v3/index.json");
|
||||
|
||||
MockVssResourceTenantHeader();
|
||||
MockVssAuthorizationEndpointHeader();
|
||||
|
||||
var feedSource = await authUtil.GetAzDevDeploymentType(requestUri);
|
||||
feedSource.Should().Be(AzDevDeploymentType.External);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetFeedUriSource_OnPremHeaderPresent_ReturnsOnPrem()
|
||||
{
|
||||
var requestUri = new Uri("https://example.pkgs.visualstudio.com/_packaging/feed/nuget/v3/index.json");
|
||||
|
||||
MockResponseHeaders(AuthUtil.VssE2EID, "id");
|
||||
|
||||
var feedSource = await authUtil.GetAzDevDeploymentType(requestUri);
|
||||
feedSource.Should().Be(AzDevDeploymentType.OnPrem);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace CredentialProvider.Microsoft.Tests.CredentialProviders.Vsts
|
|||
}
|
||||
|
||||
mockAuthUtil
|
||||
.Verify(x => x.IsVstsUriAsync(It.IsAny<Uri>()), Times.Never, "because we shouldn't probe for known sources");
|
||||
.Verify(x => x.GetAzDevDeploymentType(It.IsAny<Uri>()), Times.Never, "because we shouldn't probe for known sources");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -103,7 +103,29 @@ namespace CredentialProvider.Microsoft.Tests.CredentialProviders.Vsts
|
|||
}
|
||||
|
||||
mockAuthUtil
|
||||
.Verify(x => x.IsVstsUriAsync(It.IsAny<Uri>()), Times.Never, "because we shouldn't probe for known sources");
|
||||
.Verify(x => x.GetAzDevDeploymentType(It.IsAny<Uri>()), Times.Never, "because we shouldn't probe for known sources");
|
||||
|
||||
Environment.SetEnvironmentVariable(EnvUtil.SupportedHostsEnvVar, string.Empty);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task CanProvideCredentials_CallsGetFeedUriSourceWhenSourcesAreInvalid()
|
||||
{
|
||||
var sources = new[]
|
||||
{
|
||||
new Uri(@"http://example.overrideOne.com/_packaging/TestFeed/nuget/v3/index.json"),
|
||||
new Uri(@"https://example.overrideTwo.com/_packaging/TestFeed/nuget/v3/index.json"),
|
||||
new Uri(@"https://example.overrideThre.com/_packaging/TestFeed/nuget/v3/index.json"),
|
||||
};
|
||||
|
||||
foreach (var source in sources)
|
||||
{
|
||||
var canProvideCredentials = await vstsCredentialProvider.CanProvideCredentialsAsync(source);
|
||||
canProvideCredentials.Should().BeFalse($"because {source} is not a valid host");
|
||||
}
|
||||
|
||||
mockAuthUtil
|
||||
.Verify(x => x.GetAzDevDeploymentType(It.IsAny<Uri>()), Times.Exactly(3), "because sources were unknown");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<PackageReference Include="Microsoft.Identity.Client" Version="4.11.0" />
|
||||
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" Version="2.8.0-preview" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="5.2.3" />
|
||||
<PackageReference Include="NuGet.Protocol" Version="5.3.0" />
|
||||
<PackageReference Include="NuGet.Protocol" Version="5.6.0" />
|
||||
<PackageReference Include="PowerArgs" Version="3.6.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19554-01" PrivateAssets="All"/>
|
||||
</ItemGroup>
|
||||
|
|
|
@ -70,10 +70,12 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
public class UserInterfaceBearerTokenProvider : IBearerTokenProvider
|
||||
{
|
||||
private readonly IAdalTokenProvider adalTokenProvider;
|
||||
private readonly ILogger logger;
|
||||
|
||||
public UserInterfaceBearerTokenProvider(IAdalTokenProvider adalTokenProvider)
|
||||
public UserInterfaceBearerTokenProvider(IAdalTokenProvider adalTokenProvider, ILogger logger)
|
||||
{
|
||||
this.adalTokenProvider = adalTokenProvider;
|
||||
this.adalTokenProvider = adalTokenProvider;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public bool Interactive { get; } = true;
|
||||
|
@ -81,6 +83,7 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
|
||||
public async Task<string> GetTokenAsync(Uri uri, CancellationToken cancellationToken)
|
||||
{
|
||||
logger.Minimal(string.Format(Resources.UIFlowStarted, this.Name, uri.AbsoluteUri));
|
||||
return (await adalTokenProvider.AcquireTokenWithUI(cancellationToken))?.AccessToken;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
// Order here is important - providers (potentially) run in this order.
|
||||
new AdalCacheBearerTokenProvider(adalTokenProvider),
|
||||
new WindowsIntegratedAuthBearerTokenProvider(adalTokenProvider),
|
||||
new UserInterfaceBearerTokenProvider(adalTokenProvider),
|
||||
new UserInterfaceBearerTokenProvider(adalTokenProvider, logger),
|
||||
new DeviceCodeFlowBearerTokenProvider(adalTokenProvider, logger)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,18 +17,26 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
{
|
||||
Task<Uri> GetAadAuthorityUriAsync(Uri uri, CancellationToken cancellationToken);
|
||||
|
||||
Task<bool> IsVstsUriAsync(Uri uri);
|
||||
Task<AzDevDeploymentType> GetAzDevDeploymentType(Uri uri);
|
||||
|
||||
Task<Uri> GetAuthorizationEndpoint(Uri uri, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public enum AzDevDeploymentType
|
||||
{
|
||||
External,
|
||||
Hosted,
|
||||
OnPrem
|
||||
}
|
||||
|
||||
public class AuthUtil : IAuthUtil
|
||||
{
|
||||
public const string VssResourceTenant = "X-VSS-ResourceTenant";
|
||||
public const string VssAuthorizationEndpoint = "X-VSS-AuthorizationEndpoint";
|
||||
private const string OrganizationsTenant = "organizations";
|
||||
private const string CommonTenant = "common";
|
||||
|
||||
public const string VssE2EID = "X-VSS-E2EID";
|
||||
|
||||
private readonly ILogger logger;
|
||||
|
||||
public AuthUtil(ILogger logger)
|
||||
|
@ -46,7 +54,7 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
|
||||
var headers = await GetResponseHeadersAsync(uri, cancellationToken);
|
||||
var bearerHeaders = headers.WwwAuthenticate.Where(x => x.Scheme.Equals("Bearer", StringComparison.Ordinal));
|
||||
|
||||
|
||||
foreach (var param in bearerHeaders)
|
||||
{
|
||||
if (param.Parameter == null)
|
||||
|
@ -77,17 +85,25 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
return new Uri($"{aadBase}/{tenant}");
|
||||
}
|
||||
|
||||
public async Task<bool> IsVstsUriAsync(Uri uri)
|
||||
public async Task<AzDevDeploymentType> GetAzDevDeploymentType(Uri uri)
|
||||
{
|
||||
if (!IsValidScheme(uri))
|
||||
{
|
||||
// We are not talking to a https endpoint so it cannot be a VSTS endpoint
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ping the url to see from headers whether it's an Azure Artifacts feed or external
|
||||
var responseHeaders = await GetResponseHeadersAsync(uri, cancellationToken: default);
|
||||
|
||||
return responseHeaders.Contains(VssResourceTenant) && responseHeaders.Contains(VssAuthorizationEndpoint);
|
||||
// Hosted only allows https
|
||||
if (IsHttpsScheme(uri) && responseHeaders.Contains(VssResourceTenant) && responseHeaders.Contains(VssAuthorizationEndpoint))
|
||||
{
|
||||
return AzDevDeploymentType.Hosted;
|
||||
}
|
||||
|
||||
// If not hosted and has E2EID, assume on prem.
|
||||
if (responseHeaders.Contains(VssE2EID))
|
||||
{
|
||||
return AzDevDeploymentType.OnPrem;
|
||||
}
|
||||
|
||||
// Assume uri is from an external source if expected headers aren't present.
|
||||
return AzDevDeploymentType.External;
|
||||
}
|
||||
|
||||
public async Task<Uri> GetAuthorizationEndpoint(Uri uri, CancellationToken cancellationToken)
|
||||
|
@ -145,7 +161,7 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
return ppeHosts.Any(host => uri.Host.EndsWith(host, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private bool IsValidScheme(Uri uri)
|
||||
private bool IsHttpsScheme(Uri uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -49,16 +49,37 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
return false;
|
||||
}
|
||||
|
||||
var validHosts = EnvUtil.GetHostsFromEnvironment(Logger, EnvUtil.SupportedHostsEnvVar, new[]
|
||||
{
|
||||
".pkgs.vsts.me", // DevFabric
|
||||
".pkgs.codedev.ms", // DevFabric
|
||||
".pkgs.codeapp.ms", // AppFabric
|
||||
".pkgs.visualstudio.com", // Prod
|
||||
".pkgs.dev.azure.com" // Prod
|
||||
});
|
||||
var validHosts = EnvUtil.GetHostsFromEnvironment(Logger, EnvUtil.SupportedHostsEnvVar, new[]
|
||||
{
|
||||
".pkgs.vsts.me", // DevFabric
|
||||
".pkgs.codedev.ms", // DevFabric
|
||||
".pkgs.codeapp.ms", // AppFabric
|
||||
".pkgs.visualstudio.com", // Prod
|
||||
".pkgs.dev.azure.com" // Prod
|
||||
});
|
||||
|
||||
return validHosts.Any(host => uri.Host.EndsWith(host, StringComparison.OrdinalIgnoreCase)) || await authUtil.IsVstsUriAsync(uri);
|
||||
bool isValidHost = validHosts.Any(host => uri.Host.EndsWith(host, StringComparison.OrdinalIgnoreCase));
|
||||
if (isValidHost)
|
||||
{
|
||||
Verbose(string.Format(Resources.HostAccepted, uri.Host));
|
||||
return true;
|
||||
}
|
||||
|
||||
var azDevOpsType = await authUtil.GetAzDevDeploymentType(uri);
|
||||
if (azDevOpsType == AzDevDeploymentType.Hosted)
|
||||
{
|
||||
Verbose(Resources.ValidHeaders);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (azDevOpsType == AzDevDeploymentType.OnPrem)
|
||||
{
|
||||
Verbose(Resources.OnPremDetected);
|
||||
return false;
|
||||
}
|
||||
|
||||
Verbose(string.Format(Resources.ExternalUri, uri));
|
||||
return false;
|
||||
}
|
||||
|
||||
public override async Task<GetAuthenticationCredentialsResponse> HandleRequestAsync(GetAuthenticationCredentialsRequest request, CancellationToken cancellationToken)
|
||||
|
@ -115,7 +136,7 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
|
||||
if (!string.IsNullOrWhiteSpace(sessionToken))
|
||||
{
|
||||
Verbose(string.Format(Resources.VSTSSessionTokenCreated, request.Uri.ToString()));
|
||||
Verbose(string.Format(Resources.VSTSSessionTokenCreated, request.Uri.AbsoluteUri));
|
||||
return new GetAuthenticationCredentialsResponse(
|
||||
Username,
|
||||
sessionToken,
|
||||
|
@ -126,11 +147,11 @@ namespace NuGetCredentialProvider.CredentialProviders.Vsts
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Verbose(string.Format(Resources.VSTSCreateSessionException, request.Uri, e.Message, e.StackTrace));
|
||||
Verbose(string.Format(Resources.VSTSCreateSessionException, request.Uri.AbsoluteUri, e.Message, e.StackTrace));
|
||||
}
|
||||
}
|
||||
|
||||
Verbose(string.Format(Resources.VSTSCredentialsNotFound, request.Uri.ToString()));
|
||||
Verbose(string.Format(Resources.VSTSCredentialsNotFound, request.Uri.AbsoluteUri));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace NuGetCredentialProvider.CredentialProviders.VstsBuildTask
|
|||
Verbose($"{uriPrefix}");
|
||||
}
|
||||
|
||||
string uriString = request.Uri.ToString();
|
||||
string uriString = request.Uri.AbsoluteUri;
|
||||
string matchedPrefix = uriPrefixes.FirstOrDefault(prefix => uriString.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));
|
||||
Verbose(string.Format(Resources.BuildTaskMatchedPrefix, matchedPrefix != null ? matchedPrefix : Resources.BuildTaskNoMatchingPrefixes));
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace NuGetCredentialProvider.CredentialProviders.VstsBuildTaskServiceEndpoi
|
|||
|
||||
Verbose(string.Format(Resources.IsRetry, request.IsRetry));
|
||||
|
||||
string uriString = request.Uri.ToString();
|
||||
string uriString = request.Uri.AbsoluteUri;
|
||||
bool endpointFound = Credentials.TryGetValue(uriString, out EndpointCredentials matchingEndpoint);
|
||||
if (endpointFound)
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace NuGetCredentialProvider.RequestHandlers
|
|||
|
||||
public override async Task<GetAuthenticationCredentialsResponse> HandleRequestAsync(GetAuthenticationCredentialsRequest request)
|
||||
{
|
||||
Logger.Verbose(string.Format(Resources.HandlingAuthRequest, request.Uri, request.IsRetry, request.IsNonInteractive, request.CanShowDialog));
|
||||
Logger.Verbose(string.Format(Resources.HandlingAuthRequest, request.Uri.AbsoluteUri, request.IsRetry, request.IsNonInteractive, request.CanShowDialog));
|
||||
|
||||
if (request?.Uri == null)
|
||||
{
|
||||
|
@ -57,15 +57,16 @@ namespace NuGetCredentialProvider.RequestHandlers
|
|||
responseCode: MessageResponseCode.Error);
|
||||
}
|
||||
|
||||
Logger.Verbose(string.Format(Resources.Uri, request.Uri));
|
||||
Logger.Verbose(string.Format(Resources.Uri, request.Uri.AbsoluteUri));
|
||||
|
||||
foreach (ICredentialProvider credentialProvider in credentialProviders)
|
||||
{
|
||||
if (await credentialProvider.CanProvideCredentialsAsync(request.Uri) == false)
|
||||
{
|
||||
Logger.Verbose(string.Format(Resources.SkippingCredentialProvider, credentialProvider, request.Uri.ToString()));
|
||||
Logger.Verbose(string.Format(Resources.SkippingCredentialProvider, credentialProvider, request.Uri.AbsoluteUri));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Logger.Verbose(string.Format(Resources.UsingCredentialProvider, credentialProvider, request.Uri.AbsoluteUri));
|
||||
|
||||
if (credentialProvider.IsCachable && TryCache(request, out string cachedToken))
|
||||
{
|
||||
|
@ -84,7 +85,7 @@ namespace NuGetCredentialProvider.RequestHandlers
|
|||
{
|
||||
if (cache != null && credentialProvider.IsCachable)
|
||||
{
|
||||
Logger.Verbose(string.Format(Resources.CachingSessionToken, request.Uri.ToString()));
|
||||
Logger.Verbose(string.Format(Resources.CachingSessionToken, request.Uri.AbsoluteUri));
|
||||
cache[request.Uri] = response.Password;
|
||||
}
|
||||
|
||||
|
@ -142,18 +143,18 @@ namespace NuGetCredentialProvider.RequestHandlers
|
|||
Logger.Verbose(string.Format(Resources.IsRetry, request.IsRetry));
|
||||
if (request.IsRetry)
|
||||
{
|
||||
Logger.Verbose(string.Format(Resources.InvalidatingCachedSessionToken, request.Uri.ToString()));
|
||||
Logger.Verbose(string.Format(Resources.InvalidatingCachedSessionToken, request.Uri.AbsoluteUri));
|
||||
cache?.Remove(request.Uri);
|
||||
return false;
|
||||
}
|
||||
else if (cache.TryGetValue(request.Uri, out string password))
|
||||
{
|
||||
Logger.Verbose(string.Format(Resources.FoundCachedSessionToken, request.Uri.ToString()));
|
||||
Logger.Verbose(string.Format(Resources.FoundCachedSessionToken, request.Uri.AbsoluteUri));
|
||||
cachedToken = password;
|
||||
return true;
|
||||
}
|
||||
|
||||
Logger.Verbose(string.Format(Resources.CachedSessionTokenNotFound, request.Uri.ToString()));
|
||||
Logger.Verbose(string.Format(Resources.CachedSessionTokenNotFound, request.Uri.AbsoluteUri));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -442,6 +442,15 @@ namespace NuGetCredentialProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} is not an Azure Artifacts feed..
|
||||
/// </summary>
|
||||
internal static string ExternalUri {
|
||||
get {
|
||||
return ResourceManager.GetString("ExternalUri", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Faulted on message: {0}.
|
||||
/// </summary>
|
||||
|
@ -505,6 +514,15 @@ namespace NuGetCredentialProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Matched well-known Azure DevOps Service hostname: {0}.
|
||||
/// </summary>
|
||||
internal static string HostAccepted {
|
||||
get {
|
||||
return ResourceManager.GetString("HostAccepted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalidating SessionToken cache for {0}.
|
||||
/// </summary>
|
||||
|
@ -559,6 +577,15 @@ namespace NuGetCredentialProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Detected an on premise Azure DevOps Server..
|
||||
/// </summary>
|
||||
internal static string OnPremDetected {
|
||||
get {
|
||||
return ResourceManager.GetString("OnPremDetected", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Parsing json.
|
||||
/// </summary>
|
||||
|
@ -739,6 +766,15 @@ namespace NuGetCredentialProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Using the {0} flow for uri {1}. User sign-in required in a pop-up authentication window..
|
||||
/// </summary>
|
||||
internal static string UIFlowStarted {
|
||||
get {
|
||||
return ResourceManager.GetString("UIFlowStarted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to URI: {0}.
|
||||
/// </summary>
|
||||
|
@ -757,6 +793,24 @@ namespace NuGetCredentialProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Using {0} to try to get credentials for {1}..
|
||||
/// </summary>
|
||||
internal static string UsingCredentialProvider {
|
||||
get {
|
||||
return ResourceManager.GetString("UsingCredentialProvider", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Detected a hosted Azure DevOps Service..
|
||||
/// </summary>
|
||||
internal static string ValidHeaders {
|
||||
get {
|
||||
return ResourceManager.GetString("ValidHeaders", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error happened while parsing json: {0}.
|
||||
/// </summary>
|
||||
|
|
|
@ -476,4 +476,23 @@ Provide MSAL Cache Location
|
|||
<data name="ForcingCanShowDialogFromTo" xml:space="preserve">
|
||||
<value>Forcing canShowDialog from {0} to {1} due to setting from environment variable</value>
|
||||
</data>
|
||||
<data name="UIFlowStarted" xml:space="preserve">
|
||||
<value>Using the {0} flow for uri {1}. User sign-in required in a pop-up authentication window.</value>
|
||||
</data>
|
||||
<data name="HostAccepted" xml:space="preserve">
|
||||
<value>Matched well-known Azure DevOps Service hostname: {0}</value>
|
||||
</data>
|
||||
<data name="OnPremDetected" xml:space="preserve">
|
||||
<value>Detected an on premise Azure DevOps Server.</value>
|
||||
</data>
|
||||
<data name="UsingCredentialProvider" xml:space="preserve">
|
||||
<value>Using {0} to try to get credentials for {1}.</value>
|
||||
<comment>{0} - credential provider name, {1} - Uri</comment>
|
||||
</data>
|
||||
<data name="ValidHeaders" xml:space="preserve">
|
||||
<value>Detected a hosted Azure DevOps Service.</value>
|
||||
</data>
|
||||
<data name="ExternalUri" xml:space="preserve">
|
||||
<value>{0} is not an Azure Artifacts feed.</value>
|
||||
</data>
|
||||
</root>
|
16
README.md
16
README.md
|
@ -38,7 +38,9 @@ Dotnet needs the `netcore` version to be installed. NuGet and MSBuild need the `
|
|||
|
||||
[PowerShell helper script](helpers/installcredprovider.ps1)
|
||||
- To install netcore, run `installcredprovider.ps1`
|
||||
- e.g. `iex "& { $(irm https://aka.ms/install-artifacts-credprovider.ps1) }"`
|
||||
- To install both netfx and netcore, run `installcredprovider.ps1 -AddNetfx`. The netfx version is needed for nuget.exe.
|
||||
- e.g. `iex "& { $(irm https://aka.ms/install-artifacts-credprovider.ps1) } -AddNetfx"`
|
||||
|
||||
#### Manual installation on Windows
|
||||
|
||||
|
@ -53,12 +55,13 @@ Using the above is recommended, but as per [NuGet's plugin discovery rules](http
|
|||
#### Automatic bash script
|
||||
|
||||
[Linux or Mac helper script](helpers/installcredprovider.sh)
|
||||
- e.g. `wget -qO- https://aka.ms/install-artifacts-credprovider.sh | bash`
|
||||
|
||||
#### Manual installation on Linux and Mac
|
||||
|
||||
1. Download the latest release of [Microsoft.NuGet.CredentialProvider.tar.gz](https://github.com/Microsoft/artifacts-credprovider/releases)
|
||||
2. Untar the file
|
||||
3. Copy the `netcore` directory from the extracted archive to `$HOME\.nuget\plugins`
|
||||
3. Copy the `netcore` directory from the extracted archive to `$HOME/.nuget/plugins`
|
||||
|
||||
Using the above is recommended, but as per [NuGet's plugin discovery rules](https://github.com/NuGet/Home/wiki/NuGet-cross-plat-authentication-plugin#plugin-installation-and-discovery), alternatively you can install the credential provider to a location you prefer, and then set the environment variable NUGET_PLUGIN_PATHS to the .dll of the credential provider found in plugins\netcore\CredentialProvider.Microsoft\CredentialProvider.Microsoft.dll. For example, $env:NUGET_PLUGIN_PATHS="my-alternative-location\CredentialProvider.Microsoft.dll".
|
||||
|
||||
|
@ -105,12 +108,19 @@ Once you've successfully acquired a token, you can run authenticated commands wi
|
|||
|
||||
### Unattended build agents
|
||||
|
||||
With Azure DevOps Pipelines, please use the [NuGet Authenticate](https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/package/nuget-authenticate?view=azure-devops) task before running NuGet, dotnet or MSBuild commands that need authentication.
|
||||
#### Azure DevOps Pipelines
|
||||
Use the [NuGet Authenticate](https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/package/nuget-authenticate?view=azure-devops) task before running NuGet, dotnet or MSBuild commands that need authentication.
|
||||
|
||||
#### Other automated build scenarios
|
||||
If you're running the command as part of an automated build on an unattended build agent outside of Azure DevOps Pipelines, you can supply an access token directly using the `VSS_NUGET_EXTERNAL_FEED_ENDPOINTS` [environment variable](#environment-variables). The use of [Personal Access Tokens](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops) is recommended. You may need to restart the agent service or the computer before the environment variables are available to the agent.
|
||||
|
||||
### Docker containers
|
||||
[Sample Dockerfile](https://github.com/microsoft/artifacts-credprovider/blob/master/samples/dockerfile.sample.txt)
|
||||
[Managing NuGet credentials in Docker scenarios](https://github.com/dotnet/dotnet-docker/blob/master/documentation/scenarios/nuget-credentials.md#using-the-azure-artifact-credential-provider)
|
||||
|
||||
### Azure DevOps Server
|
||||
The Azure Artifacts Credential Provider may not be necessary for an on-premises Azure DevOps Server on Windows. If the credential provider is needed, it cannot acquire credentials interactively, therefore, the VSS_NUGET_EXTERNAL_FEED_ENDPOINTS environment variable must be used as an alternative. Supply a [Personal Access Token](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops) directly using the `VSS_NUGET_EXTERNAL_FEED_ENDPOINTS` [environment variable](#environment-variables).
|
||||
|
||||
From Azure DevOps Server 2020 RC1 forward, the NuGet Authenticate task can be used in Pipelines.
|
||||
|
||||
## Session Token Cache Locations
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@ ARG FEED_URL
|
|||
ARG PAT
|
||||
|
||||
# download and install latest credential provider. Not required after https://github.com/dotnet/dotnet-docker/issues/878
|
||||
RUN wget -qO- https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh | bash
|
||||
RUN wget -qO- https://aka.ms/install-artifacts-credprovider.sh | bash
|
||||
|
||||
# Optional
|
||||
WORKDIR /workdir
|
||||
COPY ./ .
|
||||
|
||||
# Optional: Sometimes the http client hangs because of a .NEt issue. Setting this in dockerfile helps
|
||||
# Optional: Sometimes the http client hangs because of a .NET issue. Setting this in dockerfile helps
|
||||
ENV DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0
|
||||
|
||||
# Environment variable to enable seesion token cache. More on this here: https://github.com/Microsoft/artifacts-credprovider#help
|
||||
|
@ -25,4 +25,4 @@ ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS {\"endpointCredentials\": [{\"endpoint\":\
|
|||
RUN dotnet restore
|
||||
|
||||
# Optional: Extended step to build the app using dotnet msbuild.
|
||||
RUN dotnet build dirs.proj
|
||||
RUN dotnet build dirs.proj
|
||||
|
|
Загрузка…
Ссылка в новой задаче