144 lines
4.5 KiB
C#
144 lines
4.5 KiB
C#
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Net.Http.Json;
|
|
using System.Security.Claims;
|
|
|
|
namespace ColaFlow.Modules.Identity.IntegrationTests.Infrastructure;
|
|
|
|
/// <summary>
|
|
/// Helper class for authentication-related test operations
|
|
/// Provides utilities for registration, login, token parsing, and common test scenarios
|
|
/// </summary>
|
|
public static class TestAuthHelper
|
|
{
|
|
/// <summary>
|
|
/// Register a new tenant and return the access token and refresh token
|
|
/// </summary>
|
|
public static async Task<(string accessToken, string refreshToken)> RegisterAndGetTokensAsync(
|
|
HttpClient client,
|
|
string? tenantSlug = null,
|
|
string? email = null,
|
|
string? password = null)
|
|
{
|
|
var slug = tenantSlug ?? $"test-{Guid.NewGuid():N}";
|
|
var adminEmail = email ?? $"admin-{Guid.NewGuid():N}@test.com";
|
|
var adminPassword = password ?? "Admin@1234";
|
|
|
|
var request = new
|
|
{
|
|
tenantName = "Test Corp",
|
|
tenantSlug = slug,
|
|
subscriptionPlan = "Professional",
|
|
adminEmail,
|
|
adminPassword,
|
|
adminFullName = "Test Admin"
|
|
};
|
|
|
|
var response = await client.PostAsJsonAsync("/api/tenants/register", request);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<RegisterResponse>();
|
|
|
|
return (result!.AccessToken, result.RefreshToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Login with credentials and return tokens
|
|
/// </summary>
|
|
public static async Task<(string accessToken, string refreshToken)> LoginAndGetTokensAsync(
|
|
HttpClient client,
|
|
string tenantSlug,
|
|
string email,
|
|
string password)
|
|
{
|
|
var request = new
|
|
{
|
|
tenantSlug,
|
|
email,
|
|
password
|
|
};
|
|
|
|
var response = await client.PostAsJsonAsync("/api/auth/login", request);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<LoginResponse>();
|
|
|
|
return (result!.AccessToken, result.RefreshToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse JWT token and extract claims
|
|
/// </summary>
|
|
public static IEnumerable<Claim> ParseJwtToken(string token)
|
|
{
|
|
var handler = new JwtSecurityTokenHandler();
|
|
var jwtToken = handler.ReadJwtToken(token);
|
|
return jwtToken.Claims;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get specific claim value from token
|
|
/// </summary>
|
|
public static string? GetClaimValue(string token, string claimType)
|
|
{
|
|
var claims = ParseJwtToken(token);
|
|
return claims.FirstOrDefault(c => c.Type == claimType)?.Value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify token contains expected role
|
|
/// </summary>
|
|
public static bool HasRole(string token, string role)
|
|
{
|
|
var claims = ParseJwtToken(token);
|
|
return claims.Any(c => c.Type == "role" && c.Value == role) ||
|
|
claims.Any(c => c.Type == "tenant_role" && c.Value == role);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extract invitation token from email HTML body
|
|
/// </summary>
|
|
public static string? ExtractInvitationTokenFromEmail(string htmlBody)
|
|
{
|
|
return ExtractTokenFromEmailBody(htmlBody, "token");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extract verification token from email HTML body
|
|
/// </summary>
|
|
public static string? ExtractVerificationTokenFromEmail(string htmlBody)
|
|
{
|
|
return ExtractTokenFromEmailBody(htmlBody, "token");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extract password reset token from email HTML body
|
|
/// </summary>
|
|
public static string? ExtractPasswordResetTokenFromEmail(string htmlBody)
|
|
{
|
|
return ExtractTokenFromEmailBody(htmlBody, "token");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extract token from email HTML body by parameter name
|
|
/// </summary>
|
|
private static string? ExtractTokenFromEmailBody(string htmlBody, string tokenParam)
|
|
{
|
|
// Pattern to match: token=VALUE or ?token=VALUE or &token=VALUE
|
|
var pattern = $@"[?&]{tokenParam}=([A-Za-z0-9_-]+)";
|
|
var match = System.Text.RegularExpressions.Regex.Match(htmlBody, pattern);
|
|
return match.Success ? match.Groups[1].Value : null;
|
|
}
|
|
}
|
|
|
|
// Response DTOs
|
|
public record RegisterResponse(string AccessToken, string RefreshToken);
|
|
public record LoginResponse(string AccessToken, string RefreshToken);
|
|
public record RefreshResponse(string AccessToken, string RefreshToken);
|
|
public record UserInfoResponse(
|
|
string UserId,
|
|
string TenantId,
|
|
string Email,
|
|
string FullName,
|
|
string TenantSlug,
|
|
string TenantRole);
|