(feature): test updates, jwt secret generation method
This commit is contained in:
parent
4a6e89c350
commit
f80aa1dd95
@ -14,7 +14,7 @@ public class JwtGeneratorTests {
|
||||
[Fact]
|
||||
public void GenerateToken_ShouldReturnValidToken() {
|
||||
// Act
|
||||
var token = JwtGenerator.GenerateToken(Secret, Issuer, Audience, Expiration, Username, Roles);
|
||||
var (token, jwtTokenClaims) = JwtGenerator.GenerateToken(Secret, Issuer, Audience, Expiration, Username, Roles);
|
||||
|
||||
// Assert
|
||||
Assert.False(string.IsNullOrEmpty(token));
|
||||
@ -23,7 +23,7 @@ public class JwtGeneratorTests {
|
||||
[Fact]
|
||||
public void ValidateToken_ShouldReturnClaimsPrincipal_WhenTokenIsValid() {
|
||||
// Arrange
|
||||
var token = JwtGenerator.GenerateToken(Secret, Issuer, Audience, Expiration, Username, Roles);
|
||||
var (token, _) = JwtGenerator.GenerateToken(Secret, Issuer, Audience, Expiration, Username, Roles);
|
||||
|
||||
// Act
|
||||
var jwtTokenClaims = JwtGenerator.ValidateToken(Secret, Issuer, Audience, token);
|
||||
@ -55,4 +55,16 @@ public class JwtGeneratorTests {
|
||||
// Assert
|
||||
Assert.False(string.IsNullOrEmpty(refreshToken));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenerateSecret_ShouldReturnDifferentValuesOnSubsequentCalls() {
|
||||
// Act
|
||||
string secret1 = JwtGenerator.GenerateSecret();
|
||||
string secret2 = JwtGenerator.GenerateSecret();
|
||||
|
||||
// Assert
|
||||
Assert.False(string.IsNullOrEmpty(secret1));
|
||||
Assert.False(string.IsNullOrEmpty(secret2));
|
||||
Assert.NotEqual(secret1, secret2); // Ensure the secrets are unique
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
<!-- NuGet package metadata -->
|
||||
<PackageId>MaksIT.Core</PackageId>
|
||||
<Version>1.0.4</Version>
|
||||
<Version>1.0.5</Version>
|
||||
<Authors>Maksym Sadovnychyy</Authors>
|
||||
<Company>MAKS-IT</Company>
|
||||
<Product>MaksIT.Core</Product>
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
|
||||
namespace MaksIT.Core.Security;
|
||||
|
||||
public class JWTTokenClaims {
|
||||
@ -15,10 +15,9 @@ public class JWTTokenClaims {
|
||||
public DateTime? ExpiresAt { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public static class JwtGenerator {
|
||||
public static (string, JWTTokenClaims) GenerateToken(string secret, string issuer, string audience, double expiration, string username, List<string> roles) {
|
||||
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
|
||||
var secretKey = GetSymmetricSecurityKey(secret);
|
||||
var credentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
var issuedAt = DateTime.UtcNow;
|
||||
@ -34,18 +33,16 @@ public static class JwtGenerator {
|
||||
|
||||
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
var tokenDescriptor = new JwtSecurityToken(
|
||||
issuer: issuer,
|
||||
audience: audience,
|
||||
claims: claims,
|
||||
expires: DateTime.Now.AddMinutes(Convert.ToDouble(expiration)),
|
||||
expires: expiresAt,
|
||||
signingCredentials: credentials
|
||||
);
|
||||
|
||||
var jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
|
||||
var jwtToken = new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
|
||||
|
||||
|
||||
// Create the JWTTokenClaims object
|
||||
var tokenClaims = new JWTTokenClaims {
|
||||
Username = username,
|
||||
Roles = roles,
|
||||
@ -56,13 +53,13 @@ public static class JwtGenerator {
|
||||
return (jwtToken, tokenClaims);
|
||||
}
|
||||
|
||||
|
||||
public static string GenerateSecret(int keySize = 32) => Convert.ToBase64String(GetRandomBytes(keySize));
|
||||
|
||||
public static JWTTokenClaims? ValidateToken(string secret, string issuer, string audience, string token) {
|
||||
try {
|
||||
var key = Encoding.UTF8.GetBytes(secret);
|
||||
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
|
||||
var validationParameters = new TokenValidationParameters {
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(key),
|
||||
@ -76,17 +73,30 @@ public static class JwtGenerator {
|
||||
|
||||
var principal = tokenHandler.ValidateToken(token, validationParameters, out var validatedToken);
|
||||
|
||||
var username = principal?.Identity?.Name;
|
||||
var roles = principal?.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value).ToList();
|
||||
// Validate the algorithm used
|
||||
if (validatedToken is JwtSecurityToken jwtToken && jwtToken.Header.Alg != SecurityAlgorithms.HmacSha256)
|
||||
throw new SecurityTokenException("Invalid token algorithm");
|
||||
|
||||
return ExtractClaims(principal);
|
||||
}
|
||||
catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var issuedAtClaim = principal?.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Iat)?.Value;
|
||||
var expiresAtClaim = principal?.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Exp)?.Value;
|
||||
public static string GenerateRefreshToken() => Convert.ToBase64String(GetRandomBytes(32));
|
||||
|
||||
// Private helper method to extract claims
|
||||
private static JWTTokenClaims? ExtractClaims(ClaimsPrincipal principal) {
|
||||
var username = principal.Identity?.Name;
|
||||
var roles = principal.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value).ToList();
|
||||
|
||||
var issuedAtClaim = principal.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Iat)?.Value;
|
||||
var expiresAtClaim = principal.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Exp)?.Value;
|
||||
|
||||
DateTime? issuedAt = issuedAtClaim != null ? DateTimeOffset.FromUnixTimeSeconds(long.Parse(issuedAtClaim)).UtcDateTime : (DateTime?)null;
|
||||
DateTime? expiresAt = expiresAtClaim != null ? DateTimeOffset.FromUnixTimeSeconds(long.Parse(expiresAtClaim)).UtcDateTime : (DateTime?)null;
|
||||
|
||||
|
||||
return new JWTTokenClaims {
|
||||
Username = username,
|
||||
Roles = roles,
|
||||
@ -94,16 +104,14 @@ public static class JwtGenerator {
|
||||
ExpiresAt = expiresAt
|
||||
};
|
||||
}
|
||||
catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GenerateRefreshToken() {
|
||||
var randomNumber = new byte[32];
|
||||
using (var rng = RandomNumberGenerator.Create()) {
|
||||
rng.GetBytes(randomNumber);
|
||||
return Convert.ToBase64String(randomNumber);
|
||||
}
|
||||
// Private helper method to get a symmetric security key
|
||||
private static SymmetricSecurityKey GetSymmetricSecurityKey(string secret) => new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
|
||||
|
||||
// Private helper method for generating random bytes
|
||||
private static byte[] GetRandomBytes(int size) {
|
||||
var bytes = new byte[size];
|
||||
RandomNumberGenerator.Fill(bytes);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user