♻️ Extract the Storage service to DysonNetwork.Drive microservice
This commit is contained in:
@ -218,7 +218,7 @@ public class AuthController(
|
||||
if (session is not null)
|
||||
return BadRequest("Session already exists for this challenge.");
|
||||
|
||||
session = new Session
|
||||
var session = new AuthSession
|
||||
{
|
||||
LastGrantedAt = Instant.FromDateTimeUtc(DateTime.UtcNow),
|
||||
ExpiredAt = Instant.FromDateTimeUtc(DateTime.UtcNow.AddDays(30)),
|
||||
|
@ -3,11 +3,14 @@ using System.Security.Cryptography;
|
||||
using System.Text.Encodings.Web;
|
||||
using DysonNetwork.Pass.Features.Account;
|
||||
using DysonNetwork.Pass.Features.Auth.OidcProvider.Services;
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using DysonNetwork.Pass.Storage.Handlers;
|
||||
using DysonNetwork.Common.Services;
|
||||
using DysonNetwork.Drive.Handlers;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SystemClock = NodaTime.SystemClock;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Drive;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.Services;
|
||||
|
||||
@ -57,14 +60,14 @@ public class DysonTokenAuthHandler(
|
||||
|
||||
try
|
||||
{
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var now = NodaTime.SystemClock.Instance.GetCurrentInstant();
|
||||
|
||||
// Validate token and extract session ID
|
||||
if (!ValidateToken(tokenInfo.Token, out var sessionId))
|
||||
return AuthenticateResult.Fail("Invalid token.");
|
||||
|
||||
// Try to get session from cache first
|
||||
var session = await cache.GetAsync<Session>($"{AuthCachePrefix}{sessionId}");
|
||||
var session = await cache.GetAsync<AuthSession>($"{AuthCachePrefix}{sessionId}");
|
||||
|
||||
// If not in cache, load from database
|
||||
if (session is null)
|
||||
@ -126,7 +129,7 @@ public class DysonTokenAuthHandler(
|
||||
{
|
||||
Account = session.Account,
|
||||
Session = session,
|
||||
SeenAt = SystemClock.Instance.GetCurrentInstant(),
|
||||
SeenAt = NodaTime.SystemClock.Instance.GetCurrentInstant(),
|
||||
};
|
||||
fbs.Enqueue(lastInfo);
|
||||
|
||||
|
@ -5,6 +5,7 @@ using DysonNetwork.Pass.Storage;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Common.Models;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Security.Cryptography;
|
||||
using DysonNetwork.Common.Models;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth;
|
||||
|
||||
@ -7,7 +8,7 @@ public class CompactTokenService(IConfiguration config)
|
||||
private readonly string _privateKeyPath = config["AuthToken:PrivateKeyPath"]
|
||||
?? throw new InvalidOperationException("AuthToken:PrivateKeyPath configuration is missing");
|
||||
|
||||
public string CreateToken(Session session)
|
||||
public string CreateToken(AuthSession session)
|
||||
{
|
||||
// Load the private key for signing
|
||||
var privateKeyPem = File.ReadAllText(_privateKeyPath);
|
||||
|
@ -5,6 +5,8 @@ using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using DysonNetwork.Common.Services;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
@ -14,11 +16,12 @@ namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
public class AppleOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
private readonly IConfiguration _configuration = configuration;
|
||||
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
|
||||
|
@ -1,17 +1,20 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using DysonNetwork.Common.Services;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
public class DiscordOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
public override string ProviderName => "Discord";
|
||||
protected override string DiscoveryEndpoint => ""; // Discord doesn't have a standard OIDC discovery endpoint
|
||||
|
@ -1,17 +1,20 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using DysonNetwork.Common.Services;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
public class GitHubOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
public override string ProviderName => "GitHub";
|
||||
protected override string DiscoveryEndpoint => ""; // GitHub doesn't have a standard OIDC discovery endpoint
|
||||
@ -77,7 +80,7 @@ public class GitHubOidcService(
|
||||
var client = HttpClientFactory.CreateClient();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/user");
|
||||
request.Headers.Add("Authorization", $"Bearer {accessToken}");
|
||||
request.Headers.Add("User-Agent", "DysonNetwork.Sphere");
|
||||
request.Headers.Add("User-Agent", "DysonNetwork.Drive");
|
||||
|
||||
var response = await client.SendAsync(request);
|
||||
response.EnsureSuccessStatusCode();
|
||||
@ -109,7 +112,7 @@ public class GitHubOidcService(
|
||||
var client = HttpClientFactory.CreateClient();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/user/emails");
|
||||
request.Headers.Add("Authorization", $"Bearer {accessToken}");
|
||||
request.Headers.Add("User-Agent", "DysonNetwork.Sphere");
|
||||
request.Headers.Add("User-Agent", "DysonNetwork.Drive");
|
||||
|
||||
var response = await client.SendAsync(request);
|
||||
if (!response.IsSuccessStatusCode) return null;
|
||||
|
@ -4,17 +4,20 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using DysonNetwork.Common.Services;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
public class GoogleOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
|
||||
|
||||
|
@ -1,17 +1,20 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using DysonNetwork.Common.Services;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
public class MicrosoftOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
public override string ProviderName => "Microsoft";
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
using DysonNetwork.Common.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
@ -10,7 +12,8 @@ namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
[Route("/auth/login")]
|
||||
public class OidcController(
|
||||
IServiceProvider serviceProvider,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AccountService accounts,
|
||||
ICacheService cache
|
||||
)
|
||||
@ -31,7 +34,7 @@ public class OidcController(
|
||||
var oidcService = GetOidcService(provider);
|
||||
|
||||
// If the user is already authenticated, treat as an account connection request
|
||||
if (HttpContext.Items["CurrentUser"] is Models.Account currentUser)
|
||||
if (HttpContext.Items["CurrentUser"] is Account currentUser)
|
||||
{
|
||||
var state = Guid.NewGuid().ToString();
|
||||
var nonce = Guid.NewGuid().ToString();
|
||||
@ -67,7 +70,7 @@ public class OidcController(
|
||||
/// Handles Apple authentication directly from mobile apps
|
||||
/// </summary>
|
||||
[HttpPost("apple/mobile")]
|
||||
public async Task<ActionResult<Challenge>> AppleMobileLogin(
|
||||
public async Task<ActionResult<AuthChallenge>> AppleMobileSignIn(
|
||||
[FromBody] AppleMobileSignInRequest request)
|
||||
{
|
||||
try
|
||||
@ -124,7 +127,7 @@ public class OidcController(
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<Models.Account> FindOrCreateAccount(OidcUserInfo userInfo, string provider)
|
||||
private async Task<Account> FindOrCreateAccount(OidcUserInfo userInfo, string provider)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userInfo.Email))
|
||||
throw new ArgumentException("Email is required for account creation");
|
||||
@ -134,15 +137,16 @@ public class OidcController(
|
||||
if (existingAccount != null)
|
||||
{
|
||||
// Check if this provider connection already exists
|
||||
var existingConnection = await db.AccountConnections
|
||||
.FirstOrDefaultAsync(c => c.AccountId == existingAccount.Id &&
|
||||
c.Provider == provider &&
|
||||
c.ProvidedIdentifier == userInfo.UserId);
|
||||
var existingConnection = await passDb.AccountConnections
|
||||
.FirstOrDefaultAsync(c => c.Provider == provider &&
|
||||
c.ProvidedIdentifier == userInfo.UserId &&
|
||||
c.AccountId == existingAccount.Id
|
||||
);
|
||||
|
||||
// If no connection exists, create one
|
||||
if (existingConnection != null)
|
||||
{
|
||||
await db.AccountConnections
|
||||
await passDb.AccountConnections
|
||||
.Where(c => c.AccountId == existingAccount.Id &&
|
||||
c.Provider == provider &&
|
||||
c.ProvidedIdentifier == userInfo.UserId)
|
||||
@ -164,8 +168,8 @@ public class OidcController(
|
||||
Meta = userInfo.ToMetadata()
|
||||
};
|
||||
|
||||
await db.AccountConnections.AddAsync(connection);
|
||||
await db.SaveChangesAsync();
|
||||
await passDb.AccountConnections.AddAsync(connection);
|
||||
await passDb.SaveChangesAsync();
|
||||
|
||||
return existingAccount;
|
||||
}
|
||||
@ -185,8 +189,8 @@ public class OidcController(
|
||||
Meta = userInfo.ToMetadata()
|
||||
};
|
||||
|
||||
db.AccountConnections.Add(newConnection);
|
||||
await db.SaveChangesAsync();
|
||||
await passDb.AccountConnections.Add(newConnection);
|
||||
await passDb.SaveChangesAsync();
|
||||
|
||||
return newAccount;
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ using DysonNetwork.Common.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Pass.Data;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
@ -21,7 +23,7 @@ public abstract class OidcService(
|
||||
{
|
||||
protected readonly IConfiguration Configuration = configuration;
|
||||
protected readonly IHttpClientFactory HttpClientFactory = httpClientFactory;
|
||||
protected readonly AppDatabase Db = db;
|
||||
protected readonly PassDatabase Db = db;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique identifier for this provider
|
||||
|
Reference in New Issue
Block a user