From efc32a30438aced76bd256a95df405e2c0d80871 Mon Sep 17 00:00:00 2001 From: PauliusIvaskevicius <13413990+PauliusIvaskevicius@users.noreply.github.com> Date: Wed, 25 Oct 2023 20:26:25 +0300 Subject: [PATCH] Add basic authorization --- Apis/IServerDiscordApi.cs | 5 +- Controllers/DiscordController.cs | 2 + Controllers/FeedsController.cs | 4 +- Controllers/PresenceController.cs | 2 + Middlewares/BasicAuthenticationHandler.cs | 53 +++++++++++++++++++++ Models/Credentials.cs | 8 ++++ Models/ResponsePairDto.cs | 18 +++++++ Program.cs | 38 ++++++++++++++- Services/LoginService.cs | 14 ++++-- app.csproj | 3 +- appsettings.json | 58 ++++++++++++----------- 11 files changed, 167 insertions(+), 38 deletions(-) create mode 100644 Middlewares/BasicAuthenticationHandler.cs create mode 100644 Models/Credentials.cs create mode 100644 Models/ResponsePairDto.cs diff --git a/Apis/IServerDiscordApi.cs b/Apis/IServerDiscordApi.cs index 5ccecc4..b0924f7 100644 --- a/Apis/IServerDiscordApi.cs +++ b/Apis/IServerDiscordApi.cs @@ -1,4 +1,5 @@ -using Refit; +using app.Models; +using Refit; namespace app.Apis; @@ -29,5 +30,5 @@ public interface IServerDiscordApi Task PostBan(string channel, ulong senderId, string senderName, ulong targetId, string targetName, string reason); [Post("/login")] - Task<(bool, string)> PostLogin(string name, ulong id, string username, string discriminator, string avatarurl, string password); + Task PostLogin(string name, ulong id, string username, string discriminator, string avatarurl, string password); } diff --git a/Controllers/DiscordController.cs b/Controllers/DiscordController.cs index f8799a5..cd9aed2 100644 --- a/Controllers/DiscordController.cs +++ b/Controllers/DiscordController.cs @@ -1,11 +1,13 @@ using app.Apis; using app.Models; using app.Services; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace app.Controllers { [ApiController] + [Authorize] [Route("[controller]/[action]")] public class DiscordController : ControllerBase { diff --git a/Controllers/FeedsController.cs b/Controllers/FeedsController.cs index 49a93fc..d5f69fe 100644 --- a/Controllers/FeedsController.cs +++ b/Controllers/FeedsController.cs @@ -1,9 +1,11 @@ using app.Services; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace app.Controllers { [ApiController] + [Authorize] [Route("[controller]/[action]")] public class FeedsController : ControllerBase { @@ -14,7 +16,7 @@ public FeedsController(DiscordService discordService) } [HttpPost(Name = "send")] - public async Task PostSend(string channel, [FromBody] string message) + public async Task PostSend(string channel, string message) { var discordChannel = channel switch { diff --git a/Controllers/PresenceController.cs b/Controllers/PresenceController.cs index 978c794..5eed477 100644 --- a/Controllers/PresenceController.cs +++ b/Controllers/PresenceController.cs @@ -1,10 +1,12 @@ using app.Services; using DSharpPlus.Entities; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace app.Controllers { [ApiController] + [Authorize] [Route("[controller]/[action]")] public class PresenceController : ControllerBase { diff --git a/Middlewares/BasicAuthenticationHandler.cs b/Middlewares/BasicAuthenticationHandler.cs new file mode 100644 index 0000000..378667c --- /dev/null +++ b/Middlewares/BasicAuthenticationHandler.cs @@ -0,0 +1,53 @@ +using app.Models; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Options; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; + +namespace app.Middlewares +{ + public class BasicAuthenticationHandler : AuthenticationHandler + { + private readonly IConfiguration _configuration; + private readonly Credentials _credentials; + + public BasicAuthenticationHandler( + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + ISystemClock clock, + IOptions credentials, + IConfiguration configuration) : base(options, logger, encoder, clock) + { + _configuration = configuration; + _credentials = credentials.Value; + } + + protected override async Task HandleAuthenticateAsync() + { + string authHeader = Request.Headers["Authorization"]; + if (authHeader != null && authHeader.StartsWith("Basic")) + { + + var authHeaderValue = authHeader.Replace("Basic ", ""); + var decodedAuthHeaderValue = Encoding.UTF8.GetString(Convert.FromBase64String(authHeaderValue)); + var userPassArray = decodedAuthHeaderValue.Split(":"); + var extractedUsername = userPassArray[0]; + var extractedPassword = userPassArray[1]; + + if (string.Equals(_credentials.Username, extractedUsername) && string.Equals(extractedPassword, _credentials.Password)) + { + var claims = new[] { new Claim(ClaimTypes.Name, _credentials.Username) }; + var identity = new ClaimsIdentity(claims, Scheme.Name); + var principal = new ClaimsPrincipal(identity); + var ticket = new AuthenticationTicket(principal, Scheme.Name); + + return AuthenticateResult.Success(ticket); + } + } + return AuthenticateResult.Fail("Failed to authenticate"); + } + } + +} diff --git a/Models/Credentials.cs b/Models/Credentials.cs new file mode 100644 index 0000000..c5414ec --- /dev/null +++ b/Models/Credentials.cs @@ -0,0 +1,8 @@ +namespace app.Models +{ + public class Credentials + { + public string Username { get; set; } + public string Password { get; set; } + } +} diff --git a/Models/ResponsePairDto.cs b/Models/ResponsePairDto.cs new file mode 100644 index 0000000..d639eb3 --- /dev/null +++ b/Models/ResponsePairDto.cs @@ -0,0 +1,18 @@ +namespace app.Models +{ + public class ResponsePairDto + { + public ResponsePairDto() + { + } + + public ResponsePairDto(bool status, string message) + { + Status = status; + Message = message; + } + + public bool Status { get; set; } + public string Message { get; set; } + } +} diff --git a/Program.cs b/Program.cs index 1a75206..6307b11 100644 --- a/Program.cs +++ b/Program.cs @@ -1,6 +1,14 @@ using app.Services; using app.Settings; using app; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using System.Text; +using Microsoft.OpenApi.Models; +using app.Models; +using Microsoft.Extensions.Configuration; +using app.Middlewares; +using Microsoft.AspNetCore.Authentication; var builder = WebApplication.CreateBuilder(args); @@ -9,6 +17,7 @@ builder.Services.Configure(options => builder.Configuration.GetSection(nameof(DiscordSettings)).Bind(options)); builder.Services.Configure(options => builder.Configuration.GetSection(nameof(ServerApiSettings)).Bind(options)); +builder.Services.Configure(options => builder.Configuration.GetSection(nameof(Credentials)).Bind(options)); builder.Services.AddRefitServices(serverApiSettings); builder.Services.AddControllers(); @@ -19,6 +28,32 @@ builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddHostedService(provider => provider.GetService()); +builder.Services.AddAuthentication("BasicAuthentication") + .AddScheme("BasicAuthentication", null); + +builder.Services.AddSwaggerGen(c => +{ + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Your API", Version = "v1" }); + c.AddSecurityDefinition("Basic", new OpenApiSecurityScheme + { + Name = "Authorization", + Type = SecuritySchemeType.Http, + Scheme = "basic", + In = ParameterLocation.Header, + Description = "Basic Authorization header." + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Basic" } + }, + new string[] { } + } + }); +}); + var app = builder.Build(); @@ -32,9 +67,8 @@ await app.Services.GetService().Start(); app.UseHttpsRedirection(); - +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); - app.Run(); diff --git a/Services/LoginService.cs b/Services/LoginService.cs index 6a5f97c..026a788 100644 --- a/Services/LoginService.cs +++ b/Services/LoginService.cs @@ -38,14 +38,14 @@ private async Task HandleLoginCommand(MessageCreateEventArgs e, string name, str return; } - var (status, response) = await _serverDiscordApi.PostLogin(name, discordMember.Id, discordMember.Username, discordMember.Discriminator, discordMember.AvatarUrl, password); + var response = await _serverDiscordApi.PostLogin(name, discordMember.Id, discordMember.Username, discordMember.Discriminator, discordMember.AvatarUrl, password); - if(status) + if(response.Status) { await discordMember.GrantRoleAsync(_discordService.MemberRole); } - - await e.Channel.SendMessageAsync(response); + + await e.Message.RespondAsync(response.Message); } private async Task OnPrivateMessage(MessageCreateEventArgs e) @@ -62,7 +62,7 @@ private async Task OnPrivateMessage(MessageCreateEventArgs e) if (index == -1) { - await e.Channel.SendMessageAsync("Incorrect format! Write **!login USERNAME PASSWORD**"); + await e.Message.RespondAsync("Incorrect format! Write **!login USERNAME PASSWORD**"); return; } @@ -71,5 +71,9 @@ private async Task OnPrivateMessage(MessageCreateEventArgs e) await HandleLoginCommand(e, accountName, password); } + else + { + await e.Message.RespondAsync("Incorrect format! Write **!login USERNAME PASSWORD**"); + } } } diff --git a/app.csproj b/app.csproj index da04c78..e3ce82a 100644 --- a/app.csproj +++ b/app.csproj @@ -1,7 +1,7 @@ - net6.0 + net7.0 enable enable de413ddd-1e74-4cb2-80c7-bc2e2469d599 @@ -12,6 +12,7 @@ + diff --git a/appsettings.json b/appsettings.json index f57391a..9ccba03 100644 --- a/appsettings.json +++ b/appsettings.json @@ -6,36 +6,40 @@ } }, "AllowedHosts": "*", + "Credentials": { + "Username": "your_username", + "Password": "your_password" + }, "ServerApiSettings": { "Url": "http://localhost:9696/api/", "Username": "admin", - "Password": "test2" + "Password": "test" }, - "DiscordSettings": { - "Token": "DISCORD_BOT_API", - "Guild": 42069, - "Channels": { - "Commands": 42069, - "General": 42069, - "Surveilance": 42069, - "Cheat": 42069, - "LinkedAccounts": 42069, - "VerifyLogs": 42069, - "DiscordBotLogs": 42069, - "Verification": 42069, - "HelpVerify": 42069, - "LinkedAccountsCompact": 42069, - "WeazelFeed": 42069, - "QuizUpdates": 42069, - "AccountCreation": 42069, - "BanNotifications": 42069 - }, - "Roles": { - "Donator": 42069, - "Member": 42069, - "Banned": 42069, - "ReadOnly": 42069, - "Creator": 42069 - } + "DiscordSettings": { + "Token": "DISCORD_BOT_API", + "Guild": 42069, + "Channels": { + "Commands": 42069, + "General": 42069, + "Surveilance": 42069, + "Cheat": 42069, + "LinkedAccounts": 42069, + "VerifyLogs": 42069, + "DiscordBotLogs": 42069, + "Verification": 42069, + "HelpVerify": 42069, + "LinkedAccountsCompact": 42069, + "WeazelFeed": 42069, + "QuizUpdates": 42069, + "AccountCreation": 42069, + "BanNotifications": 42069 + }, + "Roles": { + "Donator": 42069, + "Member": 42069, + "Banned": 42069, + "ReadOnly": 42069, + "Creator": 42069 } } +}