Skip to content
This repository has been archived by the owner on Apr 16, 2020. It is now read-only.

Commit

Permalink
support basic authentication (#266)
Browse files Browse the repository at this point in the history
  • Loading branch information
JonCubed authored and ctaggart committed Sep 27, 2017
1 parent aa58f91 commit 062989d
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 13 deletions.
33 changes: 33 additions & 0 deletions dotnet-sourcelink/AuthenticationHeaderProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Net.Http.Headers;
using System.Text;

namespace SourceLink
{
public interface IAuthenticationHeaderValueProvider
{
AuthenticationHeaderValue GetValue();
}

internal class BasicAuthenticationHeaderValueProvider : IAuthenticationHeaderValueProvider
{
private readonly string _username;
private readonly string _password;
private readonly Encoding _encoding;

public BasicAuthenticationHeaderValueProvider(string username, string password, Encoding encoding = null)
{
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentNullException(nameof(username),"Invalid username value");
if (string.IsNullOrWhiteSpace(password)) throw new ArgumentNullException(nameof(password),"Invalid password value");

_username = username;
_password = password;
_encoding = encoding ?? Encoding.ASCII;
}

public AuthenticationHeaderValue GetValue()
{
return new AuthenticationHeaderValue("Basic", Convert.ToBase64String(_encoding.GetBytes($"{_username}:{_password}")));
}
}
}
65 changes: 52 additions & 13 deletions dotnet-sourcelink/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,20 +167,20 @@ public static void PrintUrls(CommandLineApplication command)
return 0;
});
}

public static int TestFile(string path)
public static int TestFile(string path, IAuthenticationHeaderValueProvider authenticationHeaderValueProvider = null)
{
using (var drp = new DebugReaderProvider(path))
{
return TestFile(drp);
return TestFile(drp, authenticationHeaderValueProvider);
}
}

public static int TestFile(DebugReaderProvider drp)
public static int TestFile(DebugReaderProvider drp, IAuthenticationHeaderValueProvider authenticationHeaderValueProvider = null)
{
var missingDocs = new List<Document>();
var erroredDocs = new List<Document>();
var documents = GetDocumentsWithUrlHashes(drp).GetAwaiter().GetResult();
var documents = GetDocumentsWithUrlHashes(drp, authenticationHeaderValueProvider).GetAwaiter().GetResult();

foreach (var doc in documents)
{
Expand Down Expand Up @@ -234,7 +234,7 @@ public static int TestFile(DebugReaderProvider drp)
return 0;
}

public static int TestNupkg(string path, List<string> files)
public static int TestNupkg(string path, List<string> files, IAuthenticationHeaderValueProvider authenticationHeaderValueProvider = null)
{
var errors = 0;
using (var p = new PackageArchiveReader(File.OpenRead(path)))
Expand Down Expand Up @@ -282,7 +282,7 @@ public static int TestNupkg(string path, List<string> files)
ms.Position = 0;
using (var drp = new DebugReaderProvider(file, ms))
{
if (TestFile(drp) != 0)
if (TestFile(drp, authenticationHeaderValueProvider) != 0)
{
Console.WriteLine("failed for " + file);
errors++;
Expand All @@ -305,6 +305,11 @@ public static void Test(CommandLineApplication command)
command.Description = "test each URL and verify that the checksums match";
var pathArgument = command.Argument("path", "path to pdb, dll or nupkg", false);
var fileOption = command.Option("-f|--file <path>", "the path to a dll or pdb in a nupkg", CommandOptionType.MultipleValue);
var authOption = command.Option("-a|--use-auth <type>", "Use authentication. Defaults to Basic", CommandOptionType.SingleValue);
var authEncodingOption = command.Option("-ae|--auth-encoding <encoding>", "Encoding to use on authentication value. Defaults to ASCII", CommandOptionType.SingleValue);
var authUsernameOption = command.Option("-u|--username <username>", "Username to use to authenticate", CommandOptionType.SingleValue);
var authPasswordOption = command.Option("-p|--password <password>", "Password for the username that is use to authenticate", CommandOptionType.SingleValue);

command.HelpOption("-h|--help");

command.OnExecute(() =>
Expand All @@ -320,13 +325,26 @@ public static void Test(CommandLineApplication command)
Console.WriteLine("file does not exist: " + path);
return 3;
}


// collect all the authentication details from the commandline
var authDetails = (
AuthType: authOption.HasValue() ? authOption.Value() ?? "Basic" : null,
Encoding: authEncodingOption.HasValue() ? Encoding.GetEncoding(authEncodingOption.Value()) : Encoding.ASCII,
Username: authUsernameOption.Value(),
Password: authPasswordOption.Value()
);

// get the authentication header provider based on the commandline inputs
var authenticationHeaderValueProvider = GetAuthenticationHeaderValueProvider(authDetails);

switch (Path.GetExtension(path))
{
case ".dll":
case ".pdb":
return TestFile(path);
return TestFile(path, authenticationHeaderValueProvider);
case ".nupkg":
var errors = TestNupkg(path, fileOption.Values);
var errors = TestNupkg(path, fileOption.Values, authenticationHeaderValueProvider);
if (errors > 0)
{
Console.WriteLine("{0} files did not pass in {1}", errors, path);
Expand All @@ -339,6 +357,23 @@ public static void Test(CommandLineApplication command)
});
}

private static IAuthenticationHeaderValueProvider GetAuthenticationHeaderValueProvider((string AuthType, Encoding Encoding, string Username, string password) authDetails)
{
if (string.IsNullOrWhiteSpace(authDetails.AuthType))
{
return null;
}

switch (authDetails.AuthType.ToLower())
{
case "basic":
return new BasicAuthenticationHeaderValueProvider(authDetails.Username, authDetails.password, authDetails.Encoding);

default:
throw new NotSupportedException($"Authentication type of {authDetails.AuthType} is not supported");
}
}

public static readonly Guid SourceLinkId = new Guid("CC110556-A091-4D38-9FEC-25AB9A351A6A");

public static byte[] GetSourceLinkBytes(DebugReaderProvider drp)
Expand Down Expand Up @@ -428,21 +463,25 @@ public static string GetUrl(string file, SourceLinkJson json)
return null;
}

static async Task<IEnumerable<Document>> GetDocumentsWithUrlHashes(DebugReaderProvider drp)
static async Task<IEnumerable<Document>> GetDocumentsWithUrlHashes(DebugReaderProvider drp, IAuthenticationHeaderValueProvider authenticationHeaderValueProvider)
{
// https://github.com/ctaggart/SourceLink/blob/v1/Exe/Http.fs
// https://github.com/ctaggart/SourceLink/blob/v1/Exe/Checksums.fs

var handler = new HttpClientHandler();
if (handler.SupportsAutomaticDecompression)
handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

using (var hc = new HttpClient(handler))
{
hc.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("SourceLink", "2.0.0"));
// TODO Basic Auth support, ASCII or UTF8
//hc.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue("Basic",
// Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password")));

if (authenticationHeaderValueProvider != null)
{
// if authentication is required get the header value
hc.DefaultRequestHeaders.Authorization = authenticationHeaderValueProvider.GetValue();
}

var tasks = GetDocumentsWithUrls(drp)
.Select(doc => CheckDocumentHash(hc, doc))
.ToArray();
Expand Down
1 change: 1 addition & 0 deletions dotnet-sourcelink/dotnet-sourcelink.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="NuGet.Packaging" Version="4.0.0" />
<PackageReference Include="System.Reflection.Metadata" Version="1.4.2" />
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
</ItemGroup>
<Import Project="..\dotnet-sourcelink-shared\dotnet-sourcelink-shared.projitems" Label="Shared" />
<Import Project="../build/sourcelink.props" />
Expand Down

0 comments on commit 062989d

Please sign in to comment.