cli: add GCM_OVERRIDE_URL support.
Provide a mechanism for setting `TargetUri.ActualUri` via environment variables. - [x] Add `UrlOverride` property to `OperationArguments`. - [x] Add `UrlOverride` to the `KeyType` enumeration. - [x] Modify `OperationArguments` to use `UrlOverride` in its calculation of `TargetUri`. - [x] Add feature validation test.
This commit is contained in:
Родитель
8f4673bad6
Коммит
a8d87f349c
|
@ -123,7 +123,7 @@ namespace Microsoft.Alm.Cli
|
|||
{
|
||||
_context.Trace.WriteLine($"converted '{url}' to '{uri.AbsoluteUri}'.");
|
||||
|
||||
OperationArguments operationArguments = new OperationArguments(_context);
|
||||
var operationArguments = new OperationArguments(_context);
|
||||
|
||||
operationArguments.SetTargetUri(uri);
|
||||
|
||||
|
@ -357,8 +357,12 @@ namespace Microsoft.Alm.Cli
|
|||
await LoadOperationArguments(operationArguments);
|
||||
EnableTraceLogging(operationArguments);
|
||||
|
||||
// Read the details of any git-remote-http(s).exe parent process.
|
||||
ReadGitRemoteDetails(operationArguments);
|
||||
// Read the details of any git-remote-http(s).exe parent process, but only if
|
||||
// an override hasn't been set which would override the git-remote details.
|
||||
if (string.IsNullOrEmpty(operationArguments.UrlOverride))
|
||||
{
|
||||
ReadGitRemoteDetails(operationArguments);
|
||||
}
|
||||
|
||||
// Set the parent window handle.
|
||||
ParentHwnd = operationArguments.ParentHwnd;
|
||||
|
@ -381,7 +385,7 @@ namespace Microsoft.Alm.Cli
|
|||
// see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
|
||||
using (var stdin = InStream)
|
||||
{
|
||||
OperationArguments operationArguments = new OperationArguments(_context);
|
||||
var operationArguments = new OperationArguments(_context);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
|
@ -397,8 +401,12 @@ namespace Microsoft.Alm.Cli
|
|||
await LoadOperationArguments(operationArguments);
|
||||
EnableTraceLogging(operationArguments);
|
||||
|
||||
// Read the details of any git-remote-http(s).exe parent process.
|
||||
ReadGitRemoteDetails(operationArguments);
|
||||
// Read the details of any git-remote-http(s).exe parent process, but only if
|
||||
// an override hasn't been set which would override the git-remote details.
|
||||
if (string.IsNullOrEmpty(operationArguments.UrlOverride))
|
||||
{
|
||||
ReadGitRemoteDetails(operationArguments);
|
||||
}
|
||||
|
||||
// Set the parent window handle.
|
||||
ParentHwnd = operationArguments.ParentHwnd;
|
||||
|
@ -433,7 +441,7 @@ namespace Microsoft.Alm.Cli
|
|||
{
|
||||
string doc = Path.Combine(installation.Doc, HelpFileName);
|
||||
|
||||
// if the help file exists, send it to the operating system to display to the user
|
||||
// If the help file exists, send it to the operating system to display to the user.
|
||||
if (Storage.FileExists(doc))
|
||||
{
|
||||
Trace.WriteLine($"opening help documentation '{doc}'.");
|
||||
|
@ -467,7 +475,7 @@ namespace Microsoft.Alm.Cli
|
|||
// see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
|
||||
using (var stdin = InStream)
|
||||
{
|
||||
OperationArguments operationArguments = new OperationArguments(_context);
|
||||
var operationArguments = new OperationArguments(_context);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
|
@ -488,8 +496,12 @@ namespace Microsoft.Alm.Cli
|
|||
await LoadOperationArguments(operationArguments);
|
||||
EnableTraceLogging(operationArguments);
|
||||
|
||||
// Read the details of any git-remote-http(s).exe parent process.
|
||||
ReadGitRemoteDetails(operationArguments);
|
||||
// Read the details of any git-remote-http(s).exe parent process, but only if
|
||||
// an override hasn't been set which would override the git-remote details.
|
||||
if (string.IsNullOrEmpty(operationArguments.UrlOverride))
|
||||
{
|
||||
ReadGitRemoteDetails(operationArguments);
|
||||
}
|
||||
|
||||
// Set the parent window handle.
|
||||
ParentHwnd = operationArguments.ParentHwnd;
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Alm.Authentication;
|
||||
using Xunit;
|
||||
using static System.StringComparer;
|
||||
|
||||
namespace Microsoft.Alm.Cli.Test
|
||||
{
|
||||
public class BasicLogonTests : Authentication.Test.UnitTestBase
|
||||
{
|
||||
private static readonly Encoding Utf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
|
||||
|
||||
public BasicLogonTests(Xunit.Abstractions.ITestOutputHelper output)
|
||||
: base(XunitHelper.Convert(output))
|
||||
{ }
|
||||
|
||||
[Fact]
|
||||
public void EnvironmentUrlOverride()
|
||||
{
|
||||
const string protocol = "https";
|
||||
const string host = "microsoft-git-tools.visualstudio.com";
|
||||
const string urlOverride = protocol + "://github.com";
|
||||
|
||||
Environment.SetEnvironmentVariable("GCM_URL_OVERRIDE", urlOverride, EnvironmentVariableTarget.Process);
|
||||
|
||||
InitializeTest();
|
||||
|
||||
var errorBuffer = new byte[4096];
|
||||
var outputBuffer = new byte[4096];
|
||||
var program = new Program(Context);
|
||||
|
||||
using (var inputStream = new MemoryStream())
|
||||
using (var outputStream = new MemoryStream(outputBuffer))
|
||||
using (var errorStream = new MemoryStream(errorBuffer))
|
||||
using (var writer = new StreamWriter(inputStream, Utf8))
|
||||
{
|
||||
SetupProgramStandardPipes(program, inputStream, outputStream, errorStream);
|
||||
|
||||
MimicGitCredential(writer, protocol, host);
|
||||
|
||||
inputStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
program._exit = (Program p, int exitcode, string message, string path, int line, string name) =>
|
||||
{
|
||||
Assert.Same(program, p);
|
||||
Assert.Equal(-1, exitcode);
|
||||
Assert.Equal(Program.LogonFailedMessage, message, Ordinal);
|
||||
};
|
||||
program._queryCredentials = (Program p, OperationArguments opArgs) =>
|
||||
{
|
||||
Assert.Same(program, p);
|
||||
Assert.NotNull(opArgs);
|
||||
Assert.NotNull(opArgs.UrlOverride);
|
||||
Assert.NotNull(opArgs.TargetUri);
|
||||
|
||||
Assert.Equal(urlOverride, opArgs.UrlOverride, OrdinalIgnoreCase);
|
||||
|
||||
var actualUrl = opArgs.TargetUri.ActualUri?.ToString()?.TrimEnd('/');
|
||||
var queryUrl = opArgs.TargetUri.QueryUri.ToString().TrimEnd('/');
|
||||
|
||||
Assert.Equal(urlOverride, actualUrl, OrdinalIgnoreCase);
|
||||
Assert.Equal(protocol + "://" + host, queryUrl, OrdinalIgnoreCase);
|
||||
|
||||
return Task.FromResult<Credential>(null);
|
||||
};
|
||||
|
||||
program.Get();
|
||||
}
|
||||
}
|
||||
|
||||
private static void MimicGitCredential(TextWriter writer, string protocol, string host)
|
||||
{
|
||||
writer.Write("protocol=");
|
||||
writer.Write(protocol);
|
||||
writer.Write("\n");
|
||||
writer.Write("host=");
|
||||
writer.Write(host);
|
||||
writer.Write("\n");
|
||||
writer.Write("\n");
|
||||
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
private static void SetupProgramStandardPipes(Program program, Stream standardInput, Stream standardOutput, Stream standardError)
|
||||
{
|
||||
program._openStandardErrorStream = (Program p) =>
|
||||
{
|
||||
Assert.Same(program, p);
|
||||
|
||||
return standardError;
|
||||
};
|
||||
program._openStandardInputStream = (Program p) =>
|
||||
{
|
||||
Assert.Same(program, p);
|
||||
|
||||
return standardInput;
|
||||
};
|
||||
program._openStandardOutputStream = (Program p) =>
|
||||
{
|
||||
Assert.Same(program, p);
|
||||
|
||||
return standardOutput;
|
||||
};
|
||||
program._write = (Program p, string message) =>
|
||||
{
|
||||
Assert.Same(program, p);
|
||||
|
||||
var buffer = Encoding.Unicode.GetBytes(message);
|
||||
standardError.Write(buffer, 0, buffer.Length);
|
||||
};
|
||||
program._writeLine = (Program p, string message) =>
|
||||
{
|
||||
Assert.Same(program, p);
|
||||
|
||||
var buffer = Encoding.Unicode.GetBytes(message + Environment.NewLine);
|
||||
standardError.Write(buffer, 0, buffer.Length);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -72,6 +72,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BasicAuthenticationTests.cs" />
|
||||
<Compile Include="BasicLogonTests.cs" />
|
||||
<Compile Include="BitbucketLogonTests.cs" />
|
||||
<Compile Include="GlobalSuppressions.cs" />
|
||||
<Compile Include="OperationArgumentsTests.cs" />
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -82,125 +82,125 @@ namespace Microsoft.Alm.Cli
|
|||
switch (operationArguments.Authority)
|
||||
{
|
||||
case AuthorityType.Auto:
|
||||
program.Trace.WriteLine($"detecting authority type for '{operationArguments.TargetUri}'.");
|
||||
program.Trace.WriteLine($"detecting authority type for '{operationArguments.TargetUri}'.");
|
||||
|
||||
// Detect the authority.
|
||||
authority = await Vsts.Authentication.GetAuthentication(program.Context,
|
||||
operationArguments.TargetUri,
|
||||
Program.VstsCredentialScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Vsts.Authentication.UriNameConversion))
|
||||
?? Github.Authentication.GetAuthentication(program.Context,
|
||||
// Detect the authority.
|
||||
authority = await Vsts.Authentication.GetAuthentication(program.Context,
|
||||
operationArguments.TargetUri,
|
||||
Program.GitHubCredentialScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToName),
|
||||
githubCredentialCallback,
|
||||
githubAuthcodeCallback,
|
||||
null)
|
||||
?? Bitbucket.Authentication.GetAuthentication(program.Context,
|
||||
operationArguments.TargetUri,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
|
||||
bitbucketCredentialCallback,
|
||||
bitbucketOauthCallback);
|
||||
Program.VstsCredentialScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Vsts.Authentication.UriNameConversion))
|
||||
?? Github.Authentication.GetAuthentication(program.Context,
|
||||
operationArguments.TargetUri,
|
||||
Program.GitHubCredentialScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToName),
|
||||
githubCredentialCallback,
|
||||
githubAuthcodeCallback,
|
||||
null)
|
||||
?? Bitbucket.Authentication.GetAuthentication(program.Context,
|
||||
operationArguments.TargetUri,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
|
||||
bitbucketCredentialCallback,
|
||||
bitbucketOauthCallback);
|
||||
|
||||
if (authority != null)
|
||||
if (authority != null)
|
||||
{
|
||||
// Set the authority type based on the returned value.
|
||||
if (authority is Vsts.MsaAuthentication)
|
||||
{
|
||||
// Set the authority type based on the returned value.
|
||||
if (authority is Vsts.MsaAuthentication)
|
||||
{
|
||||
operationArguments.Authority = AuthorityType.MicrosoftAccount;
|
||||
goto case AuthorityType.MicrosoftAccount;
|
||||
}
|
||||
else if (authority is Vsts.AadAuthentication)
|
||||
{
|
||||
operationArguments.Authority = AuthorityType.AzureDirectory;
|
||||
goto case AuthorityType.AzureDirectory;
|
||||
}
|
||||
else if (authority is Github.Authentication)
|
||||
{
|
||||
operationArguments.Authority = AuthorityType.GitHub;
|
||||
goto case AuthorityType.GitHub;
|
||||
}
|
||||
else if (authority is Bitbucket.Authentication)
|
||||
{
|
||||
operationArguments.Authority = AuthorityType.Bitbucket;
|
||||
goto case AuthorityType.Bitbucket;
|
||||
}
|
||||
operationArguments.Authority = AuthorityType.MicrosoftAccount;
|
||||
goto case AuthorityType.MicrosoftAccount;
|
||||
}
|
||||
goto default;
|
||||
else if (authority is Vsts.AadAuthentication)
|
||||
{
|
||||
operationArguments.Authority = AuthorityType.AzureDirectory;
|
||||
goto case AuthorityType.AzureDirectory;
|
||||
}
|
||||
else if (authority is Github.Authentication)
|
||||
{
|
||||
operationArguments.Authority = AuthorityType.GitHub;
|
||||
goto case AuthorityType.GitHub;
|
||||
}
|
||||
else if (authority is Bitbucket.Authentication)
|
||||
{
|
||||
operationArguments.Authority = AuthorityType.Bitbucket;
|
||||
goto case AuthorityType.Bitbucket;
|
||||
}
|
||||
}
|
||||
goto default;
|
||||
|
||||
case AuthorityType.AzureDirectory:
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Azure Directory.");
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Azure Directory.");
|
||||
|
||||
if (authority is null)
|
||||
if (authority is null)
|
||||
{
|
||||
Guid tenantId = Guid.Empty;
|
||||
|
||||
// Get the identity of the tenant.
|
||||
var result = await Vsts.Authentication.DetectAuthority(program.Context, operationArguments.TargetUri);
|
||||
|
||||
if (result.HasValue)
|
||||
{
|
||||
Guid tenantId = Guid.Empty;
|
||||
|
||||
// Get the identity of the tenant.
|
||||
var result = await Vsts.Authentication.DetectAuthority(program.Context, operationArguments.TargetUri);
|
||||
|
||||
if (result.HasValue)
|
||||
{
|
||||
tenantId = result.Value;
|
||||
}
|
||||
|
||||
// Create the authority object.
|
||||
authority = new Vsts.AadAuthentication(program.Context,
|
||||
tenantId,
|
||||
operationArguments.VstsTokenScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Vsts.AadAuthentication.UriNameConversion));
|
||||
tenantId = result.Value;
|
||||
}
|
||||
|
||||
// Return the allocated authority or a generic AAD backed VSTS authentication object.
|
||||
return authority;
|
||||
// Create the authority object.
|
||||
authority = new Vsts.AadAuthentication(program.Context,
|
||||
tenantId,
|
||||
operationArguments.VstsTokenScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Vsts.AadAuthentication.UriNameConversion));
|
||||
}
|
||||
|
||||
// Return the allocated authority or a generic AAD backed VSTS authentication object.
|
||||
return authority;
|
||||
|
||||
case AuthorityType.Basic:
|
||||
// Enforce basic authentication only.
|
||||
basicNtlmSupport = NtlmSupport.Never;
|
||||
goto default;
|
||||
// Enforce basic authentication only.
|
||||
basicNtlmSupport = NtlmSupport.Never;
|
||||
goto default;
|
||||
|
||||
case AuthorityType.GitHub:
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is GitHub.");
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is GitHub.");
|
||||
|
||||
// Return a GitHub authentication object.
|
||||
return authority ?? new Github.Authentication(program.Context,
|
||||
operationArguments.TargetUri,
|
||||
Program.GitHubCredentialScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToName),
|
||||
githubCredentialCallback,
|
||||
githubAuthcodeCallback,
|
||||
null);
|
||||
// Return a GitHub authentication object.
|
||||
return authority ?? new Github.Authentication(program.Context,
|
||||
operationArguments.TargetUri,
|
||||
Program.GitHubCredentialScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToName),
|
||||
githubCredentialCallback,
|
||||
githubAuthcodeCallback,
|
||||
null);
|
||||
|
||||
case AuthorityType.Bitbucket:
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Bitbucket.");
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Bitbucket.");
|
||||
|
||||
// Return a Bitbucket authentication object.
|
||||
return authority ?? new Bitbucket.Authentication(program.Context,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
|
||||
bitbucketCredentialCallback,
|
||||
bitbucketOauthCallback);
|
||||
// Return a Bitbucket authentication object.
|
||||
return authority ?? new Bitbucket.Authentication(program.Context,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
|
||||
bitbucketCredentialCallback,
|
||||
bitbucketOauthCallback);
|
||||
|
||||
case AuthorityType.MicrosoftAccount:
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Microsoft Live.");
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Microsoft Live.");
|
||||
|
||||
// Return the allocated authority or a generic MSA backed VSTS authentication object.
|
||||
return authority ?? new Vsts.MsaAuthentication(program.Context,
|
||||
operationArguments.VstsTokenScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Vsts.MsaAuthentication.UriNameConversion));
|
||||
// Return the allocated authority or a generic MSA backed VSTS authentication object.
|
||||
return authority ?? new Vsts.MsaAuthentication(program.Context,
|
||||
operationArguments.VstsTokenScope,
|
||||
new SecretStore(program.Context, secretsNamespace, Vsts.MsaAuthentication.UriNameConversion));
|
||||
|
||||
case AuthorityType.Ntlm:
|
||||
// Enforce NTLM authentication only.
|
||||
basicNtlmSupport = NtlmSupport.Always;
|
||||
goto default;
|
||||
// Enforce NTLM authentication only.
|
||||
basicNtlmSupport = NtlmSupport.Always;
|
||||
goto default;
|
||||
|
||||
default:
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is basic with NTLM={basicNtlmSupport}.");
|
||||
program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is basic with NTLM={basicNtlmSupport}.");
|
||||
|
||||
// Return a generic username + password authentication object.
|
||||
return authority ?? new BasicAuthentication(program.Context,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
|
||||
basicNtlmSupport,
|
||||
basicCredentialCallback,
|
||||
null);
|
||||
// Return a generic username + password authentication object.
|
||||
return authority ?? new BasicAuthentication(program.Context,
|
||||
new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
|
||||
basicNtlmSupport,
|
||||
basicCredentialCallback,
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,24 +217,24 @@ namespace Microsoft.Alm.Cli
|
|||
{
|
||||
default:
|
||||
case AuthorityType.Basic:
|
||||
program.Trace.WriteLine($"deleting basic credentials for '{operationArguments.TargetUri}'.");
|
||||
return await authentication.DeleteCredentials(operationArguments.TargetUri);
|
||||
program.Trace.WriteLine($"deleting basic credentials for '{operationArguments.TargetUri}'.");
|
||||
return await authentication.DeleteCredentials(operationArguments.TargetUri);
|
||||
|
||||
case AuthorityType.AzureDirectory:
|
||||
case AuthorityType.MicrosoftAccount:
|
||||
program.Trace.WriteLine($"deleting VSTS credentials for '{operationArguments.TargetUri}'.");
|
||||
var vstsAuth = authentication as Vsts.Authentication;
|
||||
return await vstsAuth.DeleteCredentials(operationArguments.TargetUri);
|
||||
program.Trace.WriteLine($"deleting VSTS credentials for '{operationArguments.TargetUri}'.");
|
||||
var vstsAuth = authentication as Vsts.Authentication;
|
||||
return await vstsAuth.DeleteCredentials(operationArguments.TargetUri);
|
||||
|
||||
case AuthorityType.GitHub:
|
||||
program.Trace.WriteLine($"deleting GitHub credentials for '{operationArguments.TargetUri}'.");
|
||||
var ghAuth = authentication as Github.Authentication;
|
||||
return await ghAuth.DeleteCredentials(operationArguments.TargetUri);
|
||||
program.Trace.WriteLine($"deleting GitHub credentials for '{operationArguments.TargetUri}'.");
|
||||
var ghAuth = authentication as Github.Authentication;
|
||||
return await ghAuth.DeleteCredentials(operationArguments.TargetUri);
|
||||
|
||||
case AuthorityType.Bitbucket:
|
||||
program.Trace.WriteLine($"deleting Bitbucket credentials for '{operationArguments.TargetUri}'.");
|
||||
var bbAuth = authentication as Bitbucket.Authentication;
|
||||
return await bbAuth.DeleteCredentials(operationArguments.TargetUri, operationArguments.Username);
|
||||
program.Trace.WriteLine($"deleting Bitbucket credentials for '{operationArguments.TargetUri}'.");
|
||||
var bbAuth = authentication as Bitbucket.Authentication;
|
||||
return await bbAuth.DeleteCredentials(operationArguments.TargetUri, operationArguments.Username);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -617,6 +617,17 @@ namespace Microsoft.Alm.Cli
|
|||
Trace.WriteLine($"Failed to parse {program.KeyTypeName(KeyType.ParentHwnd)}.");
|
||||
}
|
||||
}
|
||||
|
||||
// Check for URL overrides provided by the calling process.
|
||||
if (program.TryReadString(operationArguments, KeyType.UrlOverride, out value))
|
||||
{
|
||||
program.Trace.WriteLine($"{program.KeyTypeName(KeyType.UrlOverride)} = '{value}'.");
|
||||
|
||||
if (Uri.TryCreate(value, UriKind.Absolute, out Uri actualUri))
|
||||
{
|
||||
operationArguments.UrlOverride = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogEvent(Program program, string message, EventLogEntryType eventType)
|
||||
|
@ -688,154 +699,154 @@ namespace Microsoft.Alm.Cli
|
|||
{
|
||||
default:
|
||||
case AuthorityType.Basic:
|
||||
{
|
||||
var basicAuth = authentication as BasicAuthentication;
|
||||
{
|
||||
var basicAuth = authentication as BasicAuthentication;
|
||||
|
||||
// Attempt to get cached credentials or acquire credentials if interactivity is allowed.
|
||||
if ((operationArguments.Interactivity != Interactivity.Always
|
||||
&& (credentials = await authentication.GetCredentials(operationArguments.TargetUri)) != null)
|
||||
|| (operationArguments.Interactivity != Interactivity.Never
|
||||
&& (credentials = await basicAuth.AcquireCredentials(operationArguments.TargetUri)) != null))
|
||||
{
|
||||
program.Trace.WriteLine("credentials found.");
|
||||
// No need to save the credentials explicitly, as Git will call back
|
||||
// with a store command if the credentials are valid.
|
||||
}
|
||||
else
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
|
||||
program.LogEvent($"Failed to retrieve credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
}
|
||||
// Attempt to get cached credentials or acquire credentials if interactivity is allowed.
|
||||
if ((operationArguments.Interactivity != Interactivity.Always
|
||||
&& (credentials = await authentication.GetCredentials(operationArguments.TargetUri)) != null)
|
||||
|| (operationArguments.Interactivity != Interactivity.Never
|
||||
&& (credentials = await basicAuth.AcquireCredentials(operationArguments.TargetUri)) != null))
|
||||
{
|
||||
program.Trace.WriteLine("credentials found.");
|
||||
// No need to save the credentials explicitly, as Git will call back
|
||||
// with a store command if the credentials are valid.
|
||||
}
|
||||
break;
|
||||
else
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
|
||||
program.LogEvent($"Failed to retrieve credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AuthorityType.AzureDirectory:
|
||||
{
|
||||
var aadAuth = authentication as Vsts.AadAuthentication;
|
||||
var patOptions = new Vsts.PersonalAccessTokenOptions()
|
||||
{
|
||||
var aadAuth = authentication as Vsts.AadAuthentication;
|
||||
var patOptions = new Vsts.PersonalAccessTokenOptions()
|
||||
{
|
||||
RequireCompactToken = true,
|
||||
TokenDuration = operationArguments.TokenDuration,
|
||||
TokenScope = null,
|
||||
};
|
||||
RequireCompactToken = true,
|
||||
TokenDuration = operationArguments.TokenDuration,
|
||||
TokenScope = null,
|
||||
};
|
||||
|
||||
// Attempt to get cached credentials -> non-interactive logon -> interactive
|
||||
// logon note that AAD "credentials" are always scoped access tokens.
|
||||
if (((operationArguments.Interactivity != Interactivity.Always
|
||||
&& ((credentials = await aadAuth.GetCredentials(operationArguments.TargetUri)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
|| (operationArguments.Interactivity != Interactivity.Always
|
||||
&& ((credentials = await aadAuth.NoninteractiveLogon(operationArguments.TargetUri, patOptions)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))
|
||||
|| (operationArguments.Interactivity != Interactivity.Never
|
||||
&& ((credentials = await aadAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
|
||||
program.LogEvent($"Azure Directory credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
|
||||
}
|
||||
else
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
|
||||
program.LogEvent($"Failed to retrieve Azure Directory credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
}
|
||||
// Attempt to get cached credentials -> non-interactive logon -> interactive
|
||||
// logon note that AAD "credentials" are always scoped access tokens.
|
||||
if (((operationArguments.Interactivity != Interactivity.Always
|
||||
&& ((credentials = await aadAuth.GetCredentials(operationArguments.TargetUri)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
|| (operationArguments.Interactivity != Interactivity.Always
|
||||
&& ((credentials = await aadAuth.NoninteractiveLogon(operationArguments.TargetUri, patOptions)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))
|
||||
|| (operationArguments.Interactivity != Interactivity.Never
|
||||
&& ((credentials = await aadAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
|
||||
program.LogEvent($"Azure Directory credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
|
||||
}
|
||||
break;
|
||||
else
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
|
||||
program.LogEvent($"Failed to retrieve Azure Directory credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AuthorityType.MicrosoftAccount:
|
||||
{
|
||||
var msaAuth = authentication as Vsts.MsaAuthentication;
|
||||
var patOptions = new Vsts.PersonalAccessTokenOptions()
|
||||
{
|
||||
var msaAuth = authentication as Vsts.MsaAuthentication;
|
||||
var patOptions = new Vsts.PersonalAccessTokenOptions()
|
||||
{
|
||||
RequireCompactToken = true,
|
||||
TokenDuration = operationArguments.TokenDuration,
|
||||
TokenScope = null,
|
||||
};
|
||||
RequireCompactToken = true,
|
||||
TokenDuration = operationArguments.TokenDuration,
|
||||
TokenScope = null,
|
||||
};
|
||||
|
||||
// Attempt to get cached credentials -> interactive logon note that MSA
|
||||
// "credentials" are always scoped access tokens.
|
||||
if (((operationArguments.Interactivity != Interactivity.Always
|
||||
&& ((credentials = await msaAuth.GetCredentials(operationArguments.TargetUri)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
|| (operationArguments.Interactivity != Interactivity.Never
|
||||
&& ((credentials = await msaAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
|
||||
program.LogEvent($"Microsoft Live credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
|
||||
}
|
||||
else
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
|
||||
program.LogEvent($"Failed to retrieve Microsoft Live credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
}
|
||||
// Attempt to get cached credentials -> interactive logon note that MSA
|
||||
// "credentials" are always scoped access tokens.
|
||||
if (((operationArguments.Interactivity != Interactivity.Always
|
||||
&& ((credentials = await msaAuth.GetCredentials(operationArguments.TargetUri)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
|| (operationArguments.Interactivity != Interactivity.Never
|
||||
&& ((credentials = await msaAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
|
||||
program.LogEvent($"Microsoft Live credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
|
||||
}
|
||||
break;
|
||||
else
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
|
||||
program.LogEvent($"Failed to retrieve Microsoft Live credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AuthorityType.GitHub:
|
||||
{
|
||||
var ghAuth = authentication as Github.Authentication;
|
||||
{
|
||||
var ghAuth = authentication as Github.Authentication;
|
||||
|
||||
if ((operationArguments.Interactivity != Interactivity.Always
|
||||
&& ((credentials = await ghAuth.GetCredentials(operationArguments.TargetUri)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))
|
||||
|| (operationArguments.Interactivity != Interactivity.Never
|
||||
&& ((credentials = await ghAuth.InteractiveLogon(operationArguments.TargetUri)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
|
||||
program.LogEvent($"GitHub credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
|
||||
}
|
||||
else
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
|
||||
program.LogEvent($"Failed to retrieve GitHub credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
}
|
||||
if ((operationArguments.Interactivity != Interactivity.Always
|
||||
&& ((credentials = await ghAuth.GetCredentials(operationArguments.TargetUri)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))
|
||||
|| (operationArguments.Interactivity != Interactivity.Never
|
||||
&& ((credentials = await ghAuth.InteractiveLogon(operationArguments.TargetUri)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
|
||||
program.LogEvent($"GitHub credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
|
||||
}
|
||||
break;
|
||||
else
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
|
||||
program.LogEvent($"Failed to retrieve GitHub credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AuthorityType.Bitbucket:
|
||||
{
|
||||
var bbcAuth = authentication as Bitbucket.Authentication;
|
||||
{
|
||||
var bbcAuth = authentication as Bitbucket.Authentication;
|
||||
|
||||
if (((operationArguments.Interactivity != Interactivity.Always)
|
||||
&& ((credentials = await bbcAuth.GetCredentials(operationArguments.TargetUri, operationArguments.Username)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.Username, credentials)) != null)))
|
||||
|| ((operationArguments.Interactivity != Interactivity.Never)
|
||||
&& ((credentials = await bbcAuth.InteractiveLogon(operationArguments.TargetUri, operationArguments.Username)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.Username, credentials)) != null))))
|
||||
if (((operationArguments.Interactivity != Interactivity.Always)
|
||||
&& ((credentials = await bbcAuth.GetCredentials(operationArguments.TargetUri, operationArguments.Username)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.Username, credentials)) != null)))
|
||||
|| ((operationArguments.Interactivity != Interactivity.Never)
|
||||
&& ((credentials = await bbcAuth.InteractiveLogon(operationArguments.TargetUri, operationArguments.Username)) != null)
|
||||
&& (!operationArguments.ValidateCredentials
|
||||
|| ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.Username, credentials)) != null))))
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
|
||||
// Bitbucket relies on a username + secret, so make sure there is a
|
||||
// username to return.
|
||||
if (operationArguments.Username != null)
|
||||
{
|
||||
program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
|
||||
// Bitbucket relies on a username + secret, so make sure there is a
|
||||
// username to return.
|
||||
if (operationArguments.Username != null)
|
||||
{
|
||||
credentials = new Credential(operationArguments.Username, credentials.Password);
|
||||
}
|
||||
program.LogEvent($"Bitbucket credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
|
||||
}
|
||||
else
|
||||
{
|
||||
program.LogEvent($"Failed to retrieve Bitbucket credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
credentials = new Credential(operationArguments.Username, credentials.Password);
|
||||
}
|
||||
program.LogEvent($"Bitbucket credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
|
||||
}
|
||||
break;
|
||||
else
|
||||
{
|
||||
program.LogEvent($"Failed to retrieve Bitbucket credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AuthorityType.Ntlm:
|
||||
{
|
||||
program.Trace.WriteLine($"'{operationArguments.TargetUri}' is NTLM.");
|
||||
credentials = BasicAuthentication.NtlmCredentials;
|
||||
}
|
||||
break;
|
||||
{
|
||||
program.Trace.WriteLine($"'{operationArguments.TargetUri}' is NTLM.");
|
||||
credentials = BasicAuthentication.NtlmCredentials;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (credentials != null)
|
||||
|
@ -902,8 +913,8 @@ namespace Microsoft.Alm.Cli
|
|||
goto parse_localval;
|
||||
}
|
||||
|
||||
// Parse the value into a bool.
|
||||
parse_localval:
|
||||
// Parse the value into a bool.
|
||||
parse_localval:
|
||||
|
||||
// An empty value is unset / should not be there, so treat it as if it isn't.
|
||||
if (string.IsNullOrWhiteSpace(localVal))
|
||||
|
|
|
@ -80,6 +80,7 @@ namespace Microsoft.Alm.Cli
|
|||
private string _queryProtocol;
|
||||
private TargetUri _targetUri;
|
||||
private TimeSpan? _tokenDuration;
|
||||
private string _urlOverride;
|
||||
private bool _useHttpPath;
|
||||
private bool _useLocalConfig;
|
||||
private bool _useModalUi;
|
||||
|
@ -163,6 +164,7 @@ namespace Microsoft.Alm.Cli
|
|||
{
|
||||
_gitRemoteHttpCommandLine = value;
|
||||
|
||||
// Re-create the target Uri.
|
||||
CreateTargetUri();
|
||||
}
|
||||
}
|
||||
|
@ -332,6 +334,23 @@ namespace Microsoft.Alm.Cli
|
|||
set { _tokenDuration = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the override value for the `<seealso cref="TargetUri.ActualUri"/>` value.
|
||||
/// <para/>
|
||||
/// Default value is `<see langword="null"/>`.
|
||||
/// </summary>
|
||||
public virtual string UrlOverride
|
||||
{
|
||||
get { return _urlOverride; }
|
||||
set
|
||||
{
|
||||
_urlOverride = value;
|
||||
|
||||
// Re-create the target Uri.
|
||||
CreateTargetUri();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets `<see langword="false"/>` if `<seealso cref="LoadConfiguration"/>` ignores local Git configuration values; otherwise `<see langword="true"/>`.
|
||||
/// <para/>
|
||||
|
@ -435,7 +454,7 @@ namespace Microsoft.Alm.Cli
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Reads git-credential formatted input from `<paramref name="readableStream"/>`, parses the data, and populates `<seealso cref="TargetUri"/>`.
|
||||
/// </summary>
|
||||
/// <param name="readableStream">
|
||||
/// Readable stream with credential protocol formatted information.
|
||||
|
@ -576,9 +595,7 @@ namespace Microsoft.Alm.Cli
|
|||
/// <param name="url">The uniform-resource-locater of the proxy.</param>
|
||||
public virtual void SetProxy(string url)
|
||||
{
|
||||
Uri tmp = null;
|
||||
|
||||
if (Uri.TryCreate(url, UriKind.Absolute, out tmp))
|
||||
if (Uri.TryCreate(url, UriKind.Absolute, out Uri tmp))
|
||||
{
|
||||
Trace.WriteLine($"successfully set proxy to '{tmp.AbsoluteUri}'.");
|
||||
}
|
||||
|
@ -621,7 +638,7 @@ namespace Microsoft.Alm.Cli
|
|||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append("protocol=")
|
||||
.Append(_queryProtocol ?? string.Empty)
|
||||
|
@ -686,7 +703,7 @@ namespace Microsoft.Alm.Cli
|
|||
string proxyUrl = _proxyUri?.OriginalString;
|
||||
string actualUrl = null;
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
var buffer = new StringBuilder();
|
||||
|
||||
// URI format is {protocol}://{username}@{host}/{path] with
|
||||
// everything optional except for {host}.
|
||||
|
@ -721,32 +738,52 @@ namespace Microsoft.Alm.Cli
|
|||
|
||||
queryUrl = buffer.ToString();
|
||||
|
||||
// If the actual-url override has been set, honor it.
|
||||
if (!string.IsNullOrEmpty(_urlOverride))
|
||||
{
|
||||
if (Uri.TryCreate(_urlOverride, UriKind.Absolute, out Uri uri))
|
||||
{
|
||||
actualUrl = uri.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.WriteLine($"failed to parse \"{_urlOverride}\", unable to set URL override.");
|
||||
}
|
||||
}
|
||||
// If the git-remote-http(s) command line has been captured,
|
||||
// try and parse it and provide the command-url .
|
||||
if (!string.IsNullOrEmpty(_gitRemoteHttpCommandLine))
|
||||
else if (!string.IsNullOrEmpty(_gitRemoteHttpCommandLine))
|
||||
{
|
||||
string[] parts = _gitRemoteHttpCommandLine.Split(' ');
|
||||
|
||||
switch(parts.Length)
|
||||
switch (parts.Length)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if (Uri.TryCreate(parts[0], UriKind.Absolute, out Uri uri))
|
||||
{
|
||||
if (Uri.TryCreate(parts[0], UriKind.Absolute, out Uri uri))
|
||||
{
|
||||
actualUrl = uri.ToString();
|
||||
}
|
||||
actualUrl = uri.ToString();
|
||||
}
|
||||
break;
|
||||
else
|
||||
{
|
||||
Trace.WriteLine($"failed to parse \"{parts[0]}\", unable to set URL override.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
if (Uri.TryCreate(parts[2], UriKind.Absolute, out Uri uri))
|
||||
{
|
||||
if (Uri.TryCreate(parts[2], UriKind.Absolute, out Uri uri))
|
||||
{
|
||||
actualUrl = uri.ToString();
|
||||
}
|
||||
actualUrl = uri.ToString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.WriteLine($"failed to parse \"{parts[2]}\", unable to set URL override.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the target URI object.
|
||||
|
@ -778,7 +815,7 @@ namespace Microsoft.Alm.Cli
|
|||
case ',':
|
||||
case ';':
|
||||
case '=':
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace Microsoft.Alm.Cli
|
|||
Namespace,
|
||||
PreserveCredentials,
|
||||
TokenDuration,
|
||||
UrlOverride,
|
||||
Username,
|
||||
Validate,
|
||||
VstsScope,
|
||||
|
@ -117,19 +118,19 @@ namespace Microsoft.Alm.Cli
|
|||
|
||||
internal readonly Dictionary<KeyType, string> _configurationKeys = new Dictionary<KeyType, string>()
|
||||
{
|
||||
{ KeyType.Authority, "authority" },
|
||||
{ KeyType.HttpProxy, "httpProxy" },
|
||||
{ KeyType.HttpsProxy, "httpsProxy" },
|
||||
{ KeyType.Interactive, "interactive" },
|
||||
{ KeyType.ModalPrompt, "modalPrompt" },
|
||||
{ KeyType.Namespace, "namespace" },
|
||||
{ KeyType.PreserveCredentials, "preserve" },
|
||||
{ KeyType.TokenDuration, "tokenDuration" },
|
||||
{ KeyType.HttpPath, "useHttpPath" },
|
||||
{ KeyType.Username, "username" },
|
||||
{ KeyType.Validate, "validate" },
|
||||
{ KeyType.VstsScope, "vstsScope" },
|
||||
{ KeyType.Writelog, "writeLog" },
|
||||
{ KeyType.Authority, "authority" },
|
||||
{ KeyType.HttpProxy, "httpProxy" },
|
||||
{ KeyType.HttpsProxy, "httpsProxy" },
|
||||
{ KeyType.Interactive, "interactive" },
|
||||
{ KeyType.ModalPrompt, "modalPrompt" },
|
||||
{ KeyType.Namespace, "namespace" },
|
||||
{ KeyType.PreserveCredentials, "preserve" },
|
||||
{ KeyType.TokenDuration, "tokenDuration" },
|
||||
{ KeyType.HttpPath, "useHttpPath" },
|
||||
{ KeyType.Username, "username" },
|
||||
{ KeyType.Validate, "validate" },
|
||||
{ KeyType.VstsScope,"vstsScope" },
|
||||
{ KeyType.Writelog, "writeLog" },
|
||||
};
|
||||
internal readonly Dictionary<KeyType, string> _environmentKeys = new Dictionary<KeyType, string>()
|
||||
{
|
||||
|
@ -142,11 +143,12 @@ namespace Microsoft.Alm.Cli
|
|||
{ KeyType.Interactive, "GCM_INTERACTIVE" },
|
||||
{ KeyType.ModalPrompt, "GCM_MODAL_PROMPT" },
|
||||
{ KeyType.Namespace, "GCM_NAMESPACE" },
|
||||
{ KeyType.ParentHwnd, "GCM_MODAL_PARENTHWND" },
|
||||
{ KeyType.PreserveCredentials, "GCM_PRESERVE" },
|
||||
{ KeyType.TokenDuration, "GCM_TOKEN_DURATION" },
|
||||
{ KeyType.UrlOverride, "GCM_URL_OVERRIDE" },
|
||||
{ KeyType.Validate, "GCM_VALIDATE" },
|
||||
{ KeyType.VstsScope, "GCM_VSTS_SCOPE" },
|
||||
{ KeyType.ParentHwnd, "GCM_MODAL_PARENTHWND" },
|
||||
{ KeyType.Writelog, "GCM_WRITELOG" },
|
||||
};
|
||||
|
||||
|
@ -475,7 +477,7 @@ namespace Microsoft.Alm.Cli
|
|||
// If the value is true or a number greater than zero, then trace to standard error.
|
||||
if (Git.Configuration.PaserBoolean(traceValue))
|
||||
{
|
||||
Trace.AddListener(Console.Error);
|
||||
Trace.AddListener(Error);
|
||||
}
|
||||
// If the value is a rooted path, then trace to that file and not to the console.
|
||||
else if (Path.IsPathRooted(traceValue))
|
||||
|
|
Загрузка…
Ссылка в новой задаче