From ab3a0f58f1bb4dd76af0d60f834cf6d380ba3619 Mon Sep 17 00:00:00 2001 From: Thomas Suckow Date: Wed, 3 May 2023 21:54:11 -0700 Subject: [PATCH] Implement AuthHandler in Kestrel --- .../WebServer/AuthenticationHandler.cs | 2 +- Duplicati/WebserverCore/AuthMiddleware.cs | 38 +++++++++++++++++++ Duplicati/WebserverCore/DuplicatiWebserver.cs | 5 +-- .../WebserverCore/LegacyHttpRequestShim.cs | 7 ++-- .../WebserverCore/LegacyHttpResponseShim.cs | 7 +++- Duplicati/WebserverCore/TestMiddleware.cs | 37 ------------------ 6 files changed, 50 insertions(+), 46 deletions(-) create mode 100644 Duplicati/WebserverCore/AuthMiddleware.cs delete mode 100644 Duplicati/WebserverCore/TestMiddleware.cs diff --git a/Duplicati.Library.RestAPI/WebServer/AuthenticationHandler.cs b/Duplicati.Library.RestAPI/WebServer/AuthenticationHandler.cs index 3dd26011d..ba6fd921b 100644 --- a/Duplicati.Library.RestAPI/WebServer/AuthenticationHandler.cs +++ b/Duplicati.Library.RestAPI/WebServer/AuthenticationHandler.cs @@ -25,7 +25,7 @@ using Duplicati.Library.RestAPI; namespace Duplicati.Server.WebServer { - internal class AuthenticationHandler : HttpModule + public class AuthenticationHandler : HttpModule { private const string AUTH_COOKIE_NAME = "session-auth"; private const string NONCE_COOKIE_NAME = "session-nonce"; diff --git a/Duplicati/WebserverCore/AuthMiddleware.cs b/Duplicati/WebserverCore/AuthMiddleware.cs new file mode 100644 index 000000000..9aaae10e6 --- /dev/null +++ b/Duplicati/WebserverCore/AuthMiddleware.cs @@ -0,0 +1,38 @@ + +namespace Duplicati.WebserverCore +{ + public class AuthMiddleware + { + private readonly RequestDelegate _next; + private readonly Server.WebServer.AuthenticationHandler _authHandler = new(); + + public AuthMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(HttpContext context) + { + var info = new Server.WebServer.RESTMethods.RequestInfo(new LegacyHttpRequestShim(context.Request), new LegacyHttpResponseShim(context.Response), new LegacyHttpSessionShim()); + + if (!_authHandler.Process(info.Request, info.Response, info.Session)) + { + // Call the next delegate/middleware in the pipeline. + await _next(context); + } + else + { + info.Response.Send(); + } + } + } + + public static class AuthMiddlewareExtensions + { + public static IApplicationBuilder UseAuthMiddleware( + this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/Duplicati/WebserverCore/DuplicatiWebserver.cs b/Duplicati/WebserverCore/DuplicatiWebserver.cs index 431bc085a..ca227d420 100644 --- a/Duplicati/WebserverCore/DuplicatiWebserver.cs +++ b/Duplicati/WebserverCore/DuplicatiWebserver.cs @@ -15,10 +15,7 @@ namespace Duplicati.WebserverCore .AddApplicationPart(this.GetType().Assembly); builder.Services.AddHostedService(); var app = builder.Build(); - - //app.UseTestMiddleware(); - //app.UseRESTHandlerEndpoints(); - + app.UseAuthMiddleware(); string webroot = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); diff --git a/Duplicati/WebserverCore/LegacyHttpRequestShim.cs b/Duplicati/WebserverCore/LegacyHttpRequestShim.cs index db74be3c6..381e1be3f 100644 --- a/Duplicati/WebserverCore/LegacyHttpRequestShim.cs +++ b/Duplicati/WebserverCore/LegacyHttpRequestShim.cs @@ -2,6 +2,7 @@ using Duplicati.Library.Utility; using HttpServer; using HttpServer.FormDecoders; +using Microsoft.AspNetCore.Http.Extensions; using System; using System.Collections.Specialized; using System.Globalization; @@ -23,7 +24,7 @@ class LegacyHttpRequestShim : HttpServer.IHttpRequest public ConnectionType Connection { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public int ContentLength { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public RequestCookies Cookies => throw new NotImplementedException(); + public RequestCookies Cookies => new RequestCookies(request.Headers.Cookie); public HttpForm Form { @@ -31,7 +32,7 @@ class LegacyHttpRequestShim : HttpServer.IHttpRequest { var form = new HttpForm(); - if (request.ContentType.StartsWith("multipart/form-data", true, CultureInfo.InvariantCulture) || request.ContentType.StartsWith("application/x-www-form-urlencoded", true, CultureInfo.InvariantCulture) ) + if (request.ContentType != null && (request.ContentType.StartsWith("multipart/form-data", true, CultureInfo.InvariantCulture) || request.ContentType.StartsWith("application/x-www-form-urlencoded", true, CultureInfo.InvariantCulture) )) { foreach (var kvp in request.Form) @@ -103,7 +104,7 @@ class LegacyHttpRequestShim : HttpServer.IHttpRequest public IPEndPoint RemoteEndPoint => throw new NotImplementedException(); - public System.Uri Uri { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public System.Uri Uri { get => new System.Uri(request.GetEncodedUrl()); set => throw new NotImplementedException(); } public string[] UriParts => throw new NotImplementedException(); diff --git a/Duplicati/WebserverCore/LegacyHttpResponseShim.cs b/Duplicati/WebserverCore/LegacyHttpResponseShim.cs index 6e5064d5e..873c7ccb9 100644 --- a/Duplicati/WebserverCore/LegacyHttpResponseShim.cs +++ b/Duplicati/WebserverCore/LegacyHttpResponseShim.cs @@ -9,6 +9,7 @@ using HttpResponse = Microsoft.AspNetCore.Http.HttpResponse; class LegacyHttpResponseShim : HttpServer.IHttpResponse { HttpResponse response; + ResponseCookies cookies = new(); public LegacyHttpResponseShim(HttpResponse response) { this.response = response; } public Stream Body { get => response.Body; set => throw new NotImplementedException(); } public string ProtocolVersion { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } @@ -25,7 +26,7 @@ class LegacyHttpResponseShim : HttpServer.IHttpResponse public bool Sent => throw new NotImplementedException(); - public ResponseCookies Cookies => throw new NotImplementedException(); + public ResponseCookies Cookies => cookies; public void AddHeader(string name, string value) { @@ -48,6 +49,10 @@ class LegacyHttpResponseShim : HttpServer.IHttpResponse public void Send() { + foreach(ResponseCookie cookie in cookies) + { + response.Cookies.Append(cookie.Name, cookie.Value, new CookieOptions() { Expires = cookie.Expires, Path = cookie.Path, IsEssential=true }) ; + } response.StartAsync(); } diff --git a/Duplicati/WebserverCore/TestMiddleware.cs b/Duplicati/WebserverCore/TestMiddleware.cs deleted file mode 100644 index 04c8a9246..000000000 --- a/Duplicati/WebserverCore/TestMiddleware.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Globalization; -namespace Duplicati.WebserverCore -{ - public class TestMiddleware - { - private readonly RequestDelegate _next; - - public TestMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task InvokeAsync(HttpContext context) - { - var cultureQuery = context.Request.Query["culture"]; - if (!string.IsNullOrWhiteSpace(cultureQuery)) - { - var culture = new CultureInfo(cultureQuery); - - CultureInfo.CurrentCulture = culture; - CultureInfo.CurrentUICulture = culture; - } - - // Call the next delegate/middleware in the pipeline. - await _next(context); - } - } - - public static class TestMiddlewareExtensions - { - public static IApplicationBuilder UseTestMiddleware( - this IApplicationBuilder builder) - { - return builder.UseMiddleware(); - } - } -} \ No newline at end of file