Moved all UnitTests to a single project. Implemented parts of AspNetCore UnitTests.
This commit is contained in:
@@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Authorization
|
||||
/// <summary>
|
||||
/// A basic authentication as attribute to use for specific actions.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public class BasicAuthenticationAttribute : Attribute, IAsyncAuthorizationFilter
|
||||
{
|
||||
/// <summary>
|
||||
@@ -53,11 +54,14 @@ namespace Microsoft.AspNetCore.Authorization
|
||||
var authHeader = AuthenticationHeaderValue.Parse(context.HttpContext.Request.Headers["Authorization"]);
|
||||
byte[] decoded = Convert.FromBase64String(authHeader.Parameter);
|
||||
string plain = Encoding.UTF8.GetString(decoded);
|
||||
string[] credentials = plain.Split(':', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
// See: https://www.rfc-editor.org/rfc/rfc2617, page 6
|
||||
string username = plain.Split(':').First();
|
||||
string password = plain[(username.Length + 1)..];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password))
|
||||
{
|
||||
if (Username == credentials.First() && Password == credentials.Last())
|
||||
if (Username == username && Password == password)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,7 +86,7 @@ namespace Microsoft.AspNetCore.Authorization
|
||||
|
||||
context.HttpContext.Response.Headers["WWW-Authenticate"] = "Basic";
|
||||
if (!string.IsNullOrWhiteSpace(realm))
|
||||
context.HttpContext.Response.Headers["WWW-Authenticate"] += $" realm=\"{realm.Trim().Replace("\"", "")}\"";
|
||||
context.HttpContext.Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{realm.Trim().Replace("\"", "")}\"";
|
||||
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized);
|
||||
@@ -98,22 +102,29 @@ namespace Microsoft.AspNetCore.Authorization
|
||||
var authHeader = AuthenticationHeaderValue.Parse(context.HttpContext.Request.Headers["Authorization"]);
|
||||
byte[] decoded = Convert.FromBase64String(authHeader.Parameter);
|
||||
string plain = Encoding.UTF8.GetString(decoded);
|
||||
string[] credentials = plain.Split(':', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
// See: https://www.rfc-editor.org/rfc/rfc2617, page 6
|
||||
string username = plain.Split(':').First();
|
||||
string password = plain[(username.Length + 1)..];
|
||||
|
||||
var validator = context.HttpContext.RequestServices.GetService<IBasicAuthenticationValidator>();
|
||||
var result = await validator?.ValidateAsync(credentials.First(), credentials.Last(), context.HttpContext.GetRemoteIpAddress());
|
||||
if (result != null)
|
||||
context.HttpContext.User = result;
|
||||
if (validator == null)
|
||||
return null;
|
||||
|
||||
var result = await validator.ValidateAsync(username, password, context.HttpContext.GetRemoteIpAddress());
|
||||
if (result == null)
|
||||
return null;
|
||||
|
||||
context.HttpContext.User = result;
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex, $"Using validator to get HTTP user failed: {ex.InnerException?.Message ?? ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.Filters
|
||||
/// <br/>
|
||||
/// The score from google can be found on HttpContext.Items[GoogleReCaptchaAttribute.ScoreKey].
|
||||
/// </remarks>
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public class GoogleReCaptchaAttribute : ActionFilterAttribute
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace AMWD.Common.AspNetCore.BasicAuthentication
|
||||
/// <summary>
|
||||
/// Implements the <see cref="AuthenticationHandler{TOptions}"/> for Basic Authentication.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
@@ -51,10 +52,13 @@ namespace AMWD.Common.AspNetCore.BasicAuthentication
|
||||
{
|
||||
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
|
||||
string plain = Encoding.UTF8.GetString(Convert.FromBase64String(authHeader.Parameter));
|
||||
string[] credentials = plain.Split(':', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
// See: https://www.rfc-editor.org/rfc/rfc2617, page 6
|
||||
string username = plain.Split(':').First();
|
||||
string password = plain[(username.Length + 1)..];
|
||||
|
||||
var ipAddress = Context.GetRemoteIpAddress();
|
||||
principal = await validator.ValidateAsync(credentials.First(), credentials.Last(), ipAddress);
|
||||
principal = await validator.ValidateAsync(username, password, ipAddress);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace AMWD.Common.AspNetCore.BasicAuthentication
|
||||
{
|
||||
@@ -45,9 +46,12 @@ namespace AMWD.Common.AspNetCore.BasicAuthentication
|
||||
var authHeader = AuthenticationHeaderValue.Parse(httpContext.Request.Headers["Authorization"]);
|
||||
byte[] decoded = Convert.FromBase64String(authHeader.Parameter);
|
||||
string plain = Encoding.UTF8.GetString(decoded);
|
||||
string[] credentials = plain.Split(':', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var principal = await validator.ValidateAsync(credentials.First(), credentials.Last(), httpContext.GetRemoteIpAddress());
|
||||
// See: https://www.rfc-editor.org/rfc/rfc2617, page 6
|
||||
string username = plain.Split(':').First();
|
||||
string password = plain[(username.Length + 1)..];
|
||||
|
||||
var principal = await validator.ValidateAsync(username, password, httpContext.GetRemoteIpAddress());
|
||||
if (principal == null)
|
||||
{
|
||||
SetAuthenticateRequest(httpContext, validator.Realm);
|
||||
@@ -56,9 +60,11 @@ namespace AMWD.Common.AspNetCore.BasicAuthentication
|
||||
|
||||
await next.Invoke(httpContext);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
SetAuthenticateRequest(httpContext, validator.Realm);
|
||||
var logger = (ILogger<BasicAuthenticationMiddleware>)httpContext.RequestServices.GetService(typeof(ILogger<BasicAuthenticationMiddleware>));
|
||||
logger?.LogError(ex, $"Falied to execute basic authentication middleware: {ex.InnerException?.Message ?? ex.Message}");
|
||||
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +72,7 @@ namespace AMWD.Common.AspNetCore.BasicAuthentication
|
||||
{
|
||||
httpContext.Response.Headers["WWW-Authenticate"] = "Basic";
|
||||
if (!string.IsNullOrWhiteSpace(realm))
|
||||
httpContext.Response.Headers["WWW-Authenticate"] += $" realm=\"{realm.Replace("\"", "")}\"";
|
||||
httpContext.Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{realm.Replace("\"", "")}\"";
|
||||
|
||||
httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Builder
|
||||
/// <summary>
|
||||
/// Extensions for the <see cref="IApplicationBuilder"/>.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public static class ApplicationBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace AMWD.Common.AspNetCore.Extensions
|
||||
/// <summary>
|
||||
/// Extensions for the HTML (e.g. <see cref="IHtmlHelper"/>).
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public static class HtmlExtensions
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -30,13 +30,11 @@ namespace Microsoft.AspNetCore.Http
|
||||
/// <returns>The ip address of the client.</returns>
|
||||
public static IPAddress GetRemoteIpAddress(this HttpContext httpContext, string headerName = "X-Forwarded-For")
|
||||
{
|
||||
var remote = httpContext.Connection.RemoteIpAddress;
|
||||
|
||||
string forwardedHeader = httpContext.Request.Headers[headerName].ToString();
|
||||
if (!string.IsNullOrWhiteSpace(forwardedHeader) && IPAddress.TryParse(forwardedHeader, out var forwarded))
|
||||
return forwarded;
|
||||
|
||||
return remote;
|
||||
return httpContext.Connection.RemoteIpAddress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -58,11 +56,13 @@ namespace Microsoft.AspNetCore.Http
|
||||
/// <returns></returns>
|
||||
public static string GetReturnUrl(this HttpContext httpContext)
|
||||
{
|
||||
string url = httpContext.Items["OriginalRequest"]?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
url = httpContext.Request.Query["ReturnUrl"].ToString();
|
||||
if (httpContext.Items.ContainsKey("OriginalRequest"))
|
||||
return httpContext.Items["OriginalRequest"].ToString();
|
||||
|
||||
return url;
|
||||
if (httpContext.Request.Query.ContainsKey("ReturnUrl"))
|
||||
return httpContext.Request.Query["ReturnUrl"].ToString();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -70,6 +70,6 @@ namespace Microsoft.AspNetCore.Http
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The current <see cref="HttpContext"/>.</param>
|
||||
public static void ClearSession(this HttpContext httpContext)
|
||||
=> httpContext?.Session?.Clear();
|
||||
=> httpContext.Session?.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Microsoft.Extensions.Logging
|
||||
/// <summary>
|
||||
/// Extensions for the <see cref="ILogger"/>.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
internal static class LoggerExtensions
|
||||
{
|
||||
// Found here:
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
/// <summary>
|
||||
/// Extensions for the <see cref="IServiceCollection"/>.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||
/// <summary>
|
||||
/// Custom floating point ModelBinder as the team of Microsoft is not capable of fixing their <see href="https://github.com/dotnet/aspnetcore/issues/6566">issue</see> with other cultures than en-US.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public class InvariantFloatingPointModelBinder : IModelBinder
|
||||
{
|
||||
private readonly NumberStyles supportedNumberStyles;
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||
/// options.ModelBinderProviders.Insert(0, new CustomFloatingPointModelBinderProvider());<br/>
|
||||
/// });</code>
|
||||
/// </remarks>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public class InvariantFloatingPointModelBinderProvider : IModelBinderProvider
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
|
||||
/// <summary>
|
||||
/// A tag helper that adds a CSS class attribute based on a condition.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
[HtmlTargetElement(Attributes = ClassPrefix + "*")]
|
||||
public class ConditionClassTagHelper : TagHelper
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
|
||||
/// <summary>
|
||||
/// A tag helper to create a obfuscated email link.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
[HtmlTargetElement("email", TagStructure = TagStructure.WithoutEndTag)]
|
||||
public class EmailTagHelper : TagHelper
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
|
||||
/// <summary>
|
||||
/// A tag helper to dynamically create integrity checks for linked sources.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
[HtmlTargetElement("link")]
|
||||
[HtmlTargetElement("script")]
|
||||
public class IntegrityHashTagHelper : TagHelper
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
/// <summary>
|
||||
/// Adds additional behavior to the modelbinding for numeric properties.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
[HtmlTargetElement("input", Attributes = "asp-for")]
|
||||
public class NumberInputTagHelper : InputTagHelper
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Microsoft.Extensions.Hosting
|
||||
/// Wrapper class to start a background service.
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">The service type.</typeparam>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public class BackgroundServiceStarter<TService> : IHostedService
|
||||
where TService : class, IHostedService
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace AMWD.Common.AspNetCore.Utilities
|
||||
public static bool IsDarkColor(string color)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(color))
|
||||
return false;
|
||||
throw new ArgumentNullException(nameof(color));
|
||||
|
||||
int r, g, b;
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace AMWD.Common.AspNetCore.Utilities
|
||||
|
||||
if (rgbMatch.Success)
|
||||
{
|
||||
r = Convert.ToInt32(rgbMatch.Groups[1].Value);
|
||||
g = Convert.ToInt32(rgbMatch.Groups[2].Value);
|
||||
b = Convert.ToInt32(rgbMatch.Groups[3].Value);
|
||||
r = Convert.ToInt32(rgbMatch.Groups[1].Value, 10);
|
||||
g = Convert.ToInt32(rgbMatch.Groups[2].Value, 10);
|
||||
b = Convert.ToInt32(rgbMatch.Groups[3].Value, 10);
|
||||
}
|
||||
else if (hexMatchFull.Success)
|
||||
{
|
||||
@@ -45,7 +45,7 @@ namespace AMWD.Common.AspNetCore.Utilities
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
throw new NotSupportedException($"Unknown color value '{color}'");
|
||||
}
|
||||
|
||||
double luminance = (r * 0.299 + g * 0.587 + b * 0.114) / 255;
|
||||
|
||||
Reference in New Issue
Block a user