Skip to content

Commit

Permalink
A few changes ;)
Browse files Browse the repository at this point in the history
Switched to more DDD style configuration with a builder.
Added Legacy helpers. Simplified Authentication with builders.
  • Loading branch information
Jaben committed Aug 11, 2024
1 parent 74a693b commit 4ea7d70
Show file tree
Hide file tree
Showing 87 changed files with 2,553 additions and 2,020 deletions.
4 changes: 1 addition & 3 deletions samples/Docker.Registry.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
using System.Security.Cryptography;
using System.Threading.Tasks;
using Docker.Registry.DotNet;
using Docker.Registry.DotNet.Authentication;
using Docker.Registry.DotNet.Models;
using Docker.Registry.DotNet.Registry;
using Docker.Registry.DotNet.Domain.Registry;

namespace Docker.Registry.Cli
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,49 +1,51 @@
// Copyright 2017-2022 Rich Quackenbush, Jaben Cargman
// and Docker.Registry.DotNet Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Docker.Registry.DotNet.Authentication;

[PublicAPI]
public class AnonymousOAuthAuthenticationProvider : AuthenticationProvider
{
private readonly OAuthClient _client = new();

private static string Schema { get; } = "Bearer";

public override Task Authenticate(HttpRequestMessage request)
{
return Task.CompletedTask;
}

public override async Task Authenticate(
HttpRequestMessage request,
HttpResponseMessage response,
IRegistryUriBuilder uriBuilder)
{
var header = this.TryGetSchemaHeader(response, Schema);

//Get the bearer bits
var bearerBits = AuthenticateParser.ParseTyped(header.Parameter);

//Get the token
var token = await this._client.GetToken(
bearerBits.Realm,
bearerBits.Service,
bearerBits.Scope);

//Set the header
request.Headers.Authorization = new AuthenticationHeaderValue(Schema, token.Token);
}
// Copyright 2017-2022 Rich Quackenbush, Jaben Cargman
// and Docker.Registry.DotNet Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Docker.Registry.DotNet.Application.OAuth;

namespace Docker.Registry.DotNet.Application.Authentication;

[PublicAPI]
public class AnonymousOAuthAuthenticationProvider : AuthenticationProvider
{
private readonly OAuthClient _client = new();

private static string Schema { get; } = "Bearer";

public override Task Authenticate(HttpRequestMessage request)
{
return Task.CompletedTask;
}

public override async Task Authenticate(
HttpRequestMessage request,
HttpResponseMessage response,
IRegistryUriBuilder uriBuilder)
{
var header = this.TryGetSchemaHeader(response, Schema);

//Get the bearer bits
var bearerBits = AuthenticateParser.ParseTyped(header.Parameter);

//Get the token
var token = await this._client.GetToken(
bearerBits.Realm,
bearerBits.Service,
bearerBits.Scope);

//Set the header
request.Headers.Authorization = new AuthenticationHeaderValue(Schema, token.Token);
}
}
Original file line number Diff line number Diff line change
@@ -1,109 +1,109 @@
// Copyright 2017-2022 Rich Quackenbush, Jaben Cargman
// and Docker.Registry.DotNet Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Docker.Registry.DotNet.Authentication;

internal static class AuthenticateParser
{
public static IDictionary<string, string> Parse(string value)
{
//https://stackoverflow.com/questions/45516717/extracting-and-parsing-the-www-authenticate-header-from-httpresponsemessage-in/45516809#45516809
return SplitWWWAuthenticateHeader(value).ToDictionary(GetKey, GetValue);
}

private static IEnumerable<string> SplitWWWAuthenticateHeader(string value)
{
var builder = new StringBuilder();
var inQuotes = false;
for (var i = 0; i < value.Length; i++)
{
var charI = value[i];
switch (charI)
{
case '\"':
if (inQuotes)
{
yield return builder.ToString();
builder.Clear();
inQuotes = false;
}
else
{
inQuotes = true;
}

break;

case ',':
if (inQuotes)
{
builder.Append(charI);
}
else
{
if (builder.Length > 0)
{
yield return builder.ToString();
builder.Clear();
}
}

break;

default:
builder.Append(charI);
break;
}
}

if (builder.Length > 0) yield return builder.ToString();
}

public static ParsedAuthentication ParseTyped(string value)
{
var parsed = Parse(value);

return new ParsedAuthentication(
parsed.GetValueOrDefault("realm"),
parsed.GetValueOrDefault("service"),
parsed.GetValueOrDefault("scope"));
}

private static string GetKey(string pair)
{
var equalPos = pair.IndexOf("=", StringComparison.Ordinal);

if (equalPos < 1)
throw new FormatException("No '=' found.");

return pair.Substring(0, equalPos);
}

private static string GetValue(string pair)
{
var equalPos = pair.IndexOf("=", StringComparison.Ordinal);

if (equalPos < 1)
throw new FormatException("No '=' found.");

var value = pair.Substring(equalPos + 1).Trim();

//Trim quotes
if (value.StartsWith("\"") && value.EndsWith("\""))
value = value.Substring(1, value.Length - 2);

return value;
}
// Copyright 2017-2022 Rich Quackenbush, Jaben Cargman
// and Docker.Registry.DotNet Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Docker.Registry.DotNet.Application.Authentication;

internal static class AuthenticateParser
{
public static IDictionary<string, string> Parse(string value)
{
//https://stackoverflow.com/questions/45516717/extracting-and-parsing-the-www-authenticate-header-from-httpresponsemessage-in/45516809#45516809
return SplitWWWAuthenticateHeader(value).ToDictionary(GetKey, GetValue);
}

private static IEnumerable<string> SplitWWWAuthenticateHeader(string value)
{
var builder = new StringBuilder();
var inQuotes = false;
for (var i = 0; i < value.Length; i++)
{
var charI = value[i];
switch (charI)
{
case '\"':
if (inQuotes)
{
yield return builder.ToString();
builder.Clear();
inQuotes = false;
}
else
{
inQuotes = true;
}

break;

case ',':
if (inQuotes)
{
builder.Append(charI);
}
else
{
if (builder.Length > 0)
{
yield return builder.ToString();
builder.Clear();
}
}

break;

default:
builder.Append(charI);
break;
}
}

if (builder.Length > 0) yield return builder.ToString();
}

public static ParsedAuthentication ParseTyped(string value)
{
var parsed = Parse(value);

return new ParsedAuthentication(
parsed.GetValueOrDefault("realm"),
parsed.GetValueOrDefault("service"),
parsed.GetValueOrDefault("scope"));
}

private static string GetKey(string pair)
{
var equalPos = pair.IndexOf("=", StringComparison.Ordinal);

if (equalPos < 1)
throw new FormatException("No '=' found.");

return pair.Substring(0, equalPos);
}

private static string GetValue(string pair)
{
var equalPos = pair.IndexOf("=", StringComparison.Ordinal);

if (equalPos < 1)
throw new FormatException("No '=' found.");

var value = pair.Substring(equalPos + 1).Trim();

//Trim quotes
if (value.StartsWith("\"") && value.EndsWith("\""))
value = value.Substring(1, value.Length - 2);

return value;
}
}
Loading

0 comments on commit 4ea7d70

Please sign in to comment.