@@ -2,10 +2,10 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Tiku.Application.Auth;
|
||||
using Tiku.Application.Content;
|
||||
using Tiku.Api.Contracts;
|
||||
using Tiku.Api.Options;
|
||||
using Tiku.Application.Auth;
|
||||
using Tiku.Application.Content;
|
||||
using Tiku.Application.Security;
|
||||
using Tiku.Application.Tenancy;
|
||||
using Tiku.Domain.Tenancy;
|
||||
@@ -59,12 +59,10 @@ public sealed class AuthController(
|
||||
{
|
||||
var realm = request.Realm!.Value;
|
||||
if (realm != AuthRealm.Tenant)
|
||||
{
|
||||
throw new RequiredFieldException("SMS authentication is only available in the tenant realm.");
|
||||
}
|
||||
|
||||
var tenantId = await ResolveRealmTenantIdAsync(realm, request.TenantCode, cancellationToken)
|
||||
?? throw new RequiredFieldException("tenantCode is required for SMS authentication.");
|
||||
?? throw new RequiredFieldException("tenantCode is required for SMS authentication.");
|
||||
var result = await smsVerificationService.CreateCodeAsync(
|
||||
new SendSmsCodeRequest(
|
||||
tenantId,
|
||||
@@ -90,10 +88,7 @@ public sealed class AuthController(
|
||||
{
|
||||
var realm = request.Realm!.Value;
|
||||
var identifier = request.Identifier ?? request.Phone;
|
||||
if (string.IsNullOrWhiteSpace(identifier))
|
||||
{
|
||||
throw new RequiredFieldException("identifier is required.");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(identifier)) throw new RequiredFieldException("identifier is required.");
|
||||
var result = await authService.LoginWithPasswordAsync(
|
||||
new PasswordLoginRequest(
|
||||
realm,
|
||||
@@ -223,10 +218,7 @@ public sealed class AuthController(
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> LogoutAll(CancellationToken cancellationToken)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
if (currentUser.UserId is not { } userId) return Unauthorized();
|
||||
|
||||
await authService.LogoutAllAsync(userId, cancellationToken);
|
||||
return NoContent();
|
||||
@@ -260,7 +252,7 @@ public sealed class AuthController(
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = await ResolveRealmTenantIdAsync(AuthRealm.Tenant, request.TenantCode, cancellationToken)
|
||||
?? throw new RequiredFieldException("tenantCode is required for password reset.");
|
||||
?? throw new RequiredFieldException("tenantCode is required for password reset.");
|
||||
var result = await authService.RequestPasswordResetAsync(
|
||||
new PasswordResetCodeRequest(
|
||||
tenantId,
|
||||
@@ -282,7 +274,7 @@ public sealed class AuthController(
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = await ResolveRealmTenantIdAsync(AuthRealm.Tenant, request.TenantCode, cancellationToken)
|
||||
?? throw new RequiredFieldException("tenantCode is required for password reset.");
|
||||
?? throw new RequiredFieldException("tenantCode is required for password reset.");
|
||||
await authService.ResetPasswordAsync(
|
||||
new PasswordResetRequest(
|
||||
tenantId,
|
||||
@@ -304,10 +296,7 @@ public sealed class AuthController(
|
||||
AuthenticatedPasswordChangeDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId || currentUser.SessionId is not { } sessionId)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
if (currentUser.UserId is not { } userId || currentUser.SessionId is not { } sessionId) return Unauthorized();
|
||||
|
||||
var result = await authService.ChangePasswordAsync(
|
||||
new AuthenticatedPasswordChangeRequest(
|
||||
@@ -323,53 +312,39 @@ public sealed class AuthController(
|
||||
|
||||
private void ResolveRefreshTokenTenant(string refreshToken)
|
||||
{
|
||||
if (!sessionStore.TryParseRefreshToken(refreshToken, out var locator))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!sessionStore.TryParseRefreshToken(refreshToken, out var locator)) return;
|
||||
|
||||
if (locator.Realm == AuthRealm.Platform)
|
||||
{
|
||||
EnsurePlatformHost();
|
||||
if (tenantContext.IsResolved)
|
||||
{
|
||||
throw new TenantContextConflictException(tenantContext.TenantId!.Value, Guid.Empty);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tenantContext.IsResolved)
|
||||
{
|
||||
throw new RequiredFieldException(
|
||||
"tenant refresh/logout requires a tenant host or x-tenant-code matching the refresh token.");
|
||||
}
|
||||
|
||||
tenantContextInitializer.Initialize(locator.TenantId!.Value, null, TenantResolutionSource.RefreshToken);
|
||||
}
|
||||
|
||||
private void ResolveAuthChallengeTenant(string challengeToken)
|
||||
{
|
||||
var parts = challengeToken.Split('.', 4, StringSplitOptions.None);
|
||||
if (parts.Length != 4 || parts[0] != "c1")
|
||||
{
|
||||
return;
|
||||
}
|
||||
var parts = challengeToken.Split('.', 4);
|
||||
if (parts.Length != 4 || parts[0] != "c1") return;
|
||||
|
||||
if (parts[1] == "p" && parts[2] == "-")
|
||||
{
|
||||
EnsurePlatformHost();
|
||||
if (tenantContext.IsResolved)
|
||||
{
|
||||
throw new TenantContextConflictException(tenantContext.TenantId!.Value, Guid.Empty);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (parts[1] != "t" || !Guid.TryParseExact(parts[2], "N", out var tenantId) || !tenantContext.IsResolved)
|
||||
{
|
||||
throw new RequiredFieldException(
|
||||
"tenant authentication challenge requires a tenant host or x-tenant-code.");
|
||||
}
|
||||
|
||||
tenantContextInitializer.Initialize(tenantId, null, TenantResolutionSource.RefreshToken);
|
||||
}
|
||||
@@ -388,9 +363,8 @@ public sealed class AuthController(
|
||||
{
|
||||
EnsurePlatformHost();
|
||||
if (tenantContext.IsResolved || !string.IsNullOrWhiteSpace(tenantCode))
|
||||
{
|
||||
throw new RequiredFieldException("platform realm does not accept tenantCode and must use a platform host.");
|
||||
}
|
||||
throw new RequiredFieldException(
|
||||
"platform realm does not accept tenantCode and must use a platform host.");
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -402,23 +376,19 @@ public sealed class AuthController(
|
||||
{
|
||||
var supplied = await tenantDirectory.FindByCodeAsync(tenantCode.Trim(), cancellationToken);
|
||||
if (supplied?.TenantId != tenantContext.TenantId.Value)
|
||||
{
|
||||
throw new TenantContextConflictException(
|
||||
tenantContext.TenantId.Value,
|
||||
supplied?.TenantId ?? Guid.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
return tenantContext.TenantId.Value;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(tenantCode))
|
||||
{
|
||||
throw new RequiredFieldException("tenantCode is required when the request host does not resolve a tenant.");
|
||||
}
|
||||
|
||||
var tenant = await tenantDirectory.FindByCodeAsync(tenantCode.Trim(), cancellationToken)
|
||||
?? throw new TenantNotFoundException();
|
||||
?? throw new TenantNotFoundException();
|
||||
tenantContextInitializer.Initialize(
|
||||
tenant.TenantId,
|
||||
tenant.TenantCode,
|
||||
@@ -434,8 +404,6 @@ public sealed class AuthController(
|
||||
host.Trim().TrimEnd('.'),
|
||||
requestHost,
|
||||
StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
throw new RequiredFieldException("platform realm is only available on a configured platform host.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user