forked from gongxuegit/tiku-backend.net
feat: harden SaaS authentication and authorization
This commit is contained in:
98
Tiku.IntegrationTests/Api/TestJwtKeys.cs
Normal file
98
Tiku.IntegrationTests/Api/TestJwtKeys.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Tiku.Application.Security;
|
||||
using Tiku.Domain.Tenancy;
|
||||
|
||||
namespace Tiku.IntegrationTests.Api;
|
||||
|
||||
internal static class TestJwtKeys
|
||||
{
|
||||
public const string Issuer = "tiku-backend";
|
||||
public const string Audience = "tiku-api";
|
||||
public const string KeyId = "integration-test-rsa-key";
|
||||
|
||||
public static string PrivateKeyPem { get; } = CreatePrivateKeyPem();
|
||||
public static string PublicKeyPem { get; } = CreatePublicKeyPem();
|
||||
|
||||
public static string CreateToken(
|
||||
IEnumerable<Claim> claims,
|
||||
AuthRealm realm = AuthRealm.Tenant,
|
||||
bool includeStandardClaims = true,
|
||||
string? keyId = null)
|
||||
{
|
||||
using var rsa = RSA.Create();
|
||||
rsa.ImportFromPem(PrivateKeyPem);
|
||||
var key = new RsaSecurityKey(rsa)
|
||||
{
|
||||
KeyId = keyId ?? KeyId,
|
||||
CryptoProviderFactory = new CryptoProviderFactory
|
||||
{
|
||||
CacheSignatureProviders = false
|
||||
}
|
||||
};
|
||||
var credentials = new SigningCredentials(key, SecurityAlgorithms.RsaSha256);
|
||||
var tokenClaims = claims.ToList();
|
||||
if (tokenClaims.All(claim => claim.Type != TikuClaimTypes.Realm))
|
||||
{
|
||||
tokenClaims.Add(new Claim(
|
||||
TikuClaimTypes.Realm,
|
||||
realm.ToString().ToLowerInvariant()));
|
||||
}
|
||||
|
||||
if (includeStandardClaims)
|
||||
{
|
||||
tokenClaims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")));
|
||||
tokenClaims.Add(new Claim(
|
||||
JwtRegisteredClaimNames.Iat,
|
||||
DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(),
|
||||
ClaimValueTypes.Integer64));
|
||||
}
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
Issuer,
|
||||
Audience,
|
||||
tokenClaims,
|
||||
expires: DateTime.UtcNow.AddMinutes(5),
|
||||
signingCredentials: credentials);
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
|
||||
private static string CreatePrivateKeyPem()
|
||||
{
|
||||
using var rsa = RSA.Create(2048);
|
||||
return rsa.ExportPkcs8PrivateKeyPem();
|
||||
}
|
||||
|
||||
private static string CreatePublicKeyPem()
|
||||
{
|
||||
using var rsa = RSA.Create();
|
||||
rsa.ImportFromPem(PrivateKeyPem);
|
||||
return rsa.ExportSubjectPublicKeyInfoPem();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TestJwtKeyRing : IJwtKeyRing
|
||||
{
|
||||
private static readonly RsaSecurityKey Key = CreateKey();
|
||||
|
||||
public SigningCredentials SigningCredentials { get; } =
|
||||
new(Key, SecurityAlgorithms.RsaSha256);
|
||||
|
||||
public IReadOnlyCollection<SecurityKey> ValidationKeys { get; } = [Key];
|
||||
|
||||
private static RsaSecurityKey CreateKey()
|
||||
{
|
||||
var rsa = RSA.Create();
|
||||
rsa.ImportFromPem(TestJwtKeys.PrivateKeyPem);
|
||||
return new RsaSecurityKey(rsa)
|
||||
{
|
||||
KeyId = TestJwtKeys.KeyId,
|
||||
CryptoProviderFactory = new CryptoProviderFactory
|
||||
{
|
||||
CacheSignatureProviders = false
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user