mirror of
https://github.com/Caraxi/mare.server.git
synced 2026-02-05 07:04:35 +01:00
add oauth or something
This commit is contained in:
parent
fe0ee4ed1e
commit
2554fa6d0e
16 changed files with 560 additions and 193 deletions
|
|
@ -2,47 +2,27 @@
|
|||
using MareSynchronosAuthService.Services;
|
||||
using MareSynchronosShared;
|
||||
using MareSynchronosShared.Data;
|
||||
using MareSynchronosShared.Models;
|
||||
using MareSynchronosShared.Services;
|
||||
using MareSynchronosShared.Utils;
|
||||
using MareSynchronosShared.Utils.Configuration;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using StackExchange.Redis.Extensions.Core.Abstractions;
|
||||
using System.Globalization;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
||||
namespace MareSynchronosAuthService.Controllers;
|
||||
|
||||
[AllowAnonymous]
|
||||
[Route(MareAuth.Auth)]
|
||||
public class JwtController : Controller
|
||||
public class JwtController : AuthControllerBase
|
||||
{
|
||||
private readonly ILogger<JwtController> _logger;
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
private readonly IConfigurationService<AuthServiceConfiguration> _configuration;
|
||||
private readonly MareDbContext _mareDbContext;
|
||||
private readonly IRedisDatabase _redis;
|
||||
private readonly GeoIPService _geoIPProvider;
|
||||
private readonly SecretKeyAuthenticatorService _secretKeyAuthenticatorService;
|
||||
|
||||
public JwtController(ILogger<JwtController> logger,
|
||||
IHttpContextAccessor accessor, MareDbContext mareDbContext,
|
||||
SecretKeyAuthenticatorService secretKeyAuthenticatorService,
|
||||
IConfigurationService<AuthServiceConfiguration> configuration,
|
||||
IRedisDatabase redisDb, GeoIPService geoIPProvider)
|
||||
: base(logger, accessor, mareDbContext, secretKeyAuthenticatorService,
|
||||
configuration, redisDb, geoIPProvider)
|
||||
{
|
||||
_logger = logger;
|
||||
_accessor = accessor;
|
||||
_redis = redisDb;
|
||||
_geoIPProvider = geoIPProvider;
|
||||
_mareDbContext = mareDbContext;
|
||||
_secretKeyAuthenticatorService = secretKeyAuthenticatorService;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
|
|
@ -53,7 +33,7 @@ public class JwtController : Controller
|
|||
}
|
||||
|
||||
[Authorize(Policy = "Authenticated")]
|
||||
[HttpGet("renewToken")]
|
||||
[HttpGet(MareAuth.Auth_RenewToken)]
|
||||
public async Task<IActionResult> RenewToken()
|
||||
{
|
||||
try
|
||||
|
|
@ -62,9 +42,9 @@ public class JwtController : Controller
|
|||
var ident = HttpContext.User.Claims.Single(p => string.Equals(p.Type, MareClaimTypes.CharaIdent, StringComparison.Ordinal))!.Value;
|
||||
var alias = HttpContext.User.Claims.SingleOrDefault(p => string.Equals(p.Type, MareClaimTypes.Alias))?.Value ?? string.Empty;
|
||||
|
||||
if (await _mareDbContext.Auth.Where(u => u.UserUID == uid || u.PrimaryUserUID == uid).AnyAsync(a => a.MarkForBan))
|
||||
if (await MareDbContext.Auth.Where(u => u.UserUID == uid || u.PrimaryUserUID == uid).AnyAsync(a => a.MarkForBan))
|
||||
{
|
||||
var userAuth = await _mareDbContext.Auth.SingleAsync(u => u.UserUID == uid);
|
||||
var userAuth = await MareDbContext.Auth.SingleAsync(u => u.UserUID == uid);
|
||||
await EnsureBan(uid, userAuth.PrimaryUserUID, ident);
|
||||
|
||||
return Unauthorized("Your Mare account is banned.");
|
||||
|
|
@ -75,144 +55,33 @@ public class JwtController : Controller
|
|||
return Unauthorized("Your XIV service account is banned from using the service.");
|
||||
}
|
||||
|
||||
_logger.LogInformation("RenewToken:SUCCESS:{id}:{ident}", uid, ident);
|
||||
Logger.LogInformation("RenewToken:SUCCESS:{id}:{ident}", uid, ident);
|
||||
return await CreateJwtFromId(uid, ident, alias);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "RenewToken:FAILURE");
|
||||
Logger.LogError(ex, "RenewToken:FAILURE");
|
||||
return Unauthorized("Unknown error while renewing authentication token");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IActionResult> AuthenticateInternal(string auth, string charaIdent)
|
||||
protected async Task<IActionResult> AuthenticateInternal(string auth, string charaIdent)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(auth)) return BadRequest("No Authkey");
|
||||
if (string.IsNullOrEmpty(charaIdent)) return BadRequest("No CharaIdent");
|
||||
|
||||
var ip = _accessor.GetIpAddress();
|
||||
var ip = HttpAccessor.GetIpAddress();
|
||||
|
||||
var authResult = await _secretKeyAuthenticatorService.AuthorizeAsync(ip, auth);
|
||||
var authResult = await SecretKeyAuthenticatorService.AuthorizeAsync(ip, auth);
|
||||
|
||||
if (await IsIdentBanned(charaIdent))
|
||||
{
|
||||
_logger.LogWarning("Authenticate:IDENTBAN:{id}:{ident}", authResult.Uid, charaIdent);
|
||||
return Unauthorized("Your XIV service account is banned from using the service.");
|
||||
}
|
||||
|
||||
if (!authResult.Success && !authResult.TempBan)
|
||||
{
|
||||
_logger.LogWarning("Authenticate:INVALID:{id}:{ident}", authResult?.Uid ?? "NOUID", charaIdent);
|
||||
return Unauthorized("The provided secret key is invalid. Verify your Mare accounts existence and/or recover the secret key.");
|
||||
}
|
||||
if (!authResult.Success && authResult.TempBan)
|
||||
{
|
||||
_logger.LogWarning("Authenticate:TEMPBAN:{id}:{ident}", authResult.Uid ?? "NOUID", charaIdent);
|
||||
return Unauthorized("Due to an excessive amount of failed authentication attempts you are temporarily banned. Check your Secret Key configuration and try connecting again in 5 minutes.");
|
||||
}
|
||||
|
||||
if (authResult.Permaban || authResult.MarkedForBan)
|
||||
{
|
||||
if (authResult.MarkedForBan)
|
||||
{
|
||||
_logger.LogWarning("Authenticate:MARKBAN:{id}:{primaryid}:{ident}", authResult.Uid, authResult.PrimaryUid, charaIdent);
|
||||
await EnsureBan(authResult.Uid!, authResult.PrimaryUid, charaIdent);
|
||||
}
|
||||
|
||||
_logger.LogWarning("Authenticate:UIDBAN:{id}:{ident}", authResult.Uid, charaIdent);
|
||||
return Unauthorized("Your Mare account is banned from using the service.");
|
||||
}
|
||||
|
||||
var existingIdent = await _redis.GetAsync<string>("UID:" + authResult.Uid);
|
||||
if (!string.IsNullOrEmpty(existingIdent))
|
||||
{
|
||||
_logger.LogWarning("Authenticate:DUPLICATE:{id}:{ident}", authResult.Uid, charaIdent);
|
||||
return Unauthorized("Already logged in to this Mare account. Reconnect in 60 seconds. If you keep seeing this issue, restart your game.");
|
||||
}
|
||||
|
||||
_logger.LogInformation("Authenticate:SUCCESS:{id}:{ident}", authResult.Uid, charaIdent);
|
||||
return await CreateJwtFromId(authResult.Uid!, charaIdent, authResult.Alias ?? string.Empty);
|
||||
return await GenericAuthResponse(charaIdent, authResult);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Authenticate:UNKNOWN");
|
||||
Logger.LogWarning(ex, "Authenticate:UNKNOWN");
|
||||
return Unauthorized("Unknown internal server error during authentication");
|
||||
}
|
||||
}
|
||||
|
||||
private JwtSecurityToken CreateJwt(IEnumerable<Claim> authClaims)
|
||||
{
|
||||
var authSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_configuration.GetValue<string>(nameof(MareConfigurationBase.Jwt))));
|
||||
|
||||
var token = new SecurityTokenDescriptor()
|
||||
{
|
||||
Subject = new ClaimsIdentity(authClaims),
|
||||
SigningCredentials = new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256Signature),
|
||||
Expires = new(long.Parse(authClaims.First(f => string.Equals(f.Type, MareClaimTypes.Expires, StringComparison.Ordinal)).Value!, CultureInfo.InvariantCulture), DateTimeKind.Utc),
|
||||
};
|
||||
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
return handler.CreateJwtSecurityToken(token);
|
||||
}
|
||||
|
||||
private async Task<IActionResult> CreateJwtFromId(string uid, string charaIdent, string alias)
|
||||
{
|
||||
var token = CreateJwt(new List<Claim>()
|
||||
{
|
||||
new Claim(MareClaimTypes.Uid, uid),
|
||||
new Claim(MareClaimTypes.CharaIdent, charaIdent),
|
||||
new Claim(MareClaimTypes.Alias, alias),
|
||||
new Claim(MareClaimTypes.Expires, DateTime.UtcNow.AddHours(6).Ticks.ToString(CultureInfo.InvariantCulture)),
|
||||
new Claim(MareClaimTypes.Continent, await _geoIPProvider.GetCountryFromIP(_accessor))
|
||||
});
|
||||
|
||||
return Content(token.RawData);
|
||||
}
|
||||
|
||||
private async Task EnsureBan(string uid, string? primaryUid, string charaIdent)
|
||||
{
|
||||
if (!_mareDbContext.BannedUsers.Any(c => c.CharacterIdentification == charaIdent))
|
||||
{
|
||||
_mareDbContext.BannedUsers.Add(new Banned()
|
||||
{
|
||||
CharacterIdentification = charaIdent,
|
||||
Reason = "Autobanned CharacterIdent (" + uid + ")",
|
||||
});
|
||||
}
|
||||
|
||||
var uidToLookFor = primaryUid ?? uid;
|
||||
|
||||
var primaryUserAuth = await _mareDbContext.Auth.FirstAsync(f => f.UserUID == uidToLookFor);
|
||||
primaryUserAuth.MarkForBan = false;
|
||||
primaryUserAuth.IsBanned = true;
|
||||
|
||||
var lodestone = await _mareDbContext.LodeStoneAuth.Include(a => a.User).FirstOrDefaultAsync(c => c.User.UID == uidToLookFor);
|
||||
|
||||
if (lodestone != null)
|
||||
{
|
||||
if (!_mareDbContext.BannedRegistrations.Any(c => c.DiscordIdOrLodestoneAuth == lodestone.HashedLodestoneId))
|
||||
{
|
||||
_mareDbContext.BannedRegistrations.Add(new BannedRegistrations()
|
||||
{
|
||||
DiscordIdOrLodestoneAuth = lodestone.HashedLodestoneId,
|
||||
});
|
||||
}
|
||||
if (!_mareDbContext.BannedRegistrations.Any(c => c.DiscordIdOrLodestoneAuth == lodestone.DiscordId.ToString()))
|
||||
{
|
||||
_mareDbContext.BannedRegistrations.Add(new BannedRegistrations()
|
||||
{
|
||||
DiscordIdOrLodestoneAuth = lodestone.DiscordId.ToString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await _mareDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task<bool> IsIdentBanned(string charaIdent)
|
||||
{
|
||||
return await _mareDbContext.BannedUsers.AsNoTracking().AnyAsync(u => u.CharacterIdentification == charaIdent).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue