first commit
This commit is contained in:
@@ -0,0 +1,391 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Cryptography;
|
||||
using Kafka.Lib.Auth;
|
||||
using MassTransit;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using OpenWarehouse.auth.api.Common.CustomIdentifyManager;
|
||||
using OpenWarehouse.auth.api.Common.Exemptions;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.AuthTokenRepo;
|
||||
|
||||
public class AuthTokenRepo(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
ApplicationDbContext context,
|
||||
ILogger<AuthTokenRepo> logger,
|
||||
ITopicProducer<LogOutMessageType> logOutTopic,
|
||||
ITopicProducer<TokenValidationMessageType> tokenValidationTopic,
|
||||
IConfiguration configuration
|
||||
) : IAuthTokenRepo
|
||||
{
|
||||
public async Task<bool> IsTokenLockAsync(string? token)
|
||||
{
|
||||
if (token.Contains("Bearer")) token = token.Split(" ")[1];
|
||||
|
||||
|
||||
if (token == null) return true;
|
||||
|
||||
var tokenObj = ParseToken(token);
|
||||
|
||||
logger.LogInformation("Checking if token with GUID: {guid}, and user id {id} is locked", tokenObj?.Id, tokenObj?.Subject);
|
||||
|
||||
ApplicationUserTokenRepository? tokenM = await context.ApplicationUserTokenRepositories
|
||||
.Include(q => q.Creator)
|
||||
.Where(q => tokenObj != null && q.GuidToken != null && q.GuidToken.Equals(tokenObj.Id)).FirstOrDefaultAsync();
|
||||
|
||||
if (tokenM?.IsLocked ?? true)
|
||||
{
|
||||
var tokenTopic = new TokenValidationMessageType()
|
||||
{
|
||||
Id = tokenM?.Id.ToString(),
|
||||
Mess = "Token is lock",
|
||||
Token = token
|
||||
};
|
||||
|
||||
_ = tokenValidationTopic.Produce(tokenTopic);
|
||||
|
||||
logger.LogDebug(tokenTopic.Text);
|
||||
logger.LogWarning("Token is locked: {Token}", token);
|
||||
return true;
|
||||
}
|
||||
|
||||
logger.LogInformation("Token with GUID: {guid}, and user id {id} is unlocked", tokenObj?.Id, tokenObj?.Subject);
|
||||
|
||||
return tokenM?.IsLocked ?? true;
|
||||
}
|
||||
|
||||
public bool IsTokenLock(string? token)
|
||||
{
|
||||
var tokenObj = ParseToken(token);
|
||||
|
||||
logger.LogInformation("Checking if token with GUID: {guid}, and user id {id} is locked", tokenObj?.Id, tokenObj?.Subject);
|
||||
|
||||
|
||||
ApplicationUserTokenRepository? tokenM = context.ApplicationUserTokenRepositories
|
||||
.Include(q=>q.Creator)
|
||||
.FirstOrDefault(q => q.GuidToken != null && q.GuidToken.Equals(token));
|
||||
|
||||
|
||||
if (tokenM?.IsLocked ?? true)
|
||||
{
|
||||
var tokenTopic = new TokenValidationMessageType()
|
||||
{
|
||||
Id = tokenM?.Id.ToString(),
|
||||
Mess = "Token is lock",
|
||||
Token = token
|
||||
};
|
||||
|
||||
tokenValidationTopic.Produce(tokenTopic);
|
||||
logger.LogDebug(tokenTopic.Text);
|
||||
logger.LogWarning("Token is locked: {Token}", token);
|
||||
return true;
|
||||
}
|
||||
logger.LogInformation("Token with GUID: {guid}, and user id {id} is unlocked", tokenObj?.Id, tokenObj?.Subject);
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<int> LockTokenAsync(string? token)
|
||||
{
|
||||
var tokenObj = ParseToken(token);
|
||||
|
||||
logger.LogInformation("Running LockTokenAsync function for GUID: {Guid}, User ID: {UserId}", tokenObj?.Id, tokenObj?.Subject);
|
||||
|
||||
ApplicationUserTokenRepository? tokenM = await context.ApplicationUserTokenRepositories
|
||||
.Where(q => tokenObj != null && q.GuidToken != null && q.GuidToken.Equals(tokenObj.Id))
|
||||
.Include(q => q.Creator).FirstOrDefaultAsync();
|
||||
|
||||
if (tokenM != null)
|
||||
{
|
||||
if (tokenM.IsLocked)
|
||||
{
|
||||
logger.LogWarning("Token is already locked for GUID: {Guid}, User ID: {UserId}", tokenObj?.Id, tokenObj?.Subject);
|
||||
return 0;
|
||||
}
|
||||
tokenM.IsLocked = true;
|
||||
if (tokenM.Creator == null) throw new AccountExemptions(false, "Account not found!");
|
||||
|
||||
var topic = new LogOutMessageType()
|
||||
{
|
||||
Id = tokenM.Id.ToString(),
|
||||
Tokens = [token],
|
||||
UserName = tokenM.Creator.UserName
|
||||
};
|
||||
|
||||
_ = logOutTopic.Produce(topic);
|
||||
logger.LogDebug("Produced logout topic for token: {Token}", topic.Text);
|
||||
logger.LogDebug("Token locked and logout topic produced for GUID: {Guid}, User ID: {UserId}", tokenObj?.Id, tokenObj?.Subject);
|
||||
|
||||
|
||||
return await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> LockAllUserTokenAsync(ApplicationUser user)
|
||||
{
|
||||
logger.LogInformation("Locking all tokens for user: {UserId}", user.Id);
|
||||
|
||||
var topic = new LogOutMessageType()
|
||||
{
|
||||
Id = user.Id,
|
||||
UserName = user.UserName
|
||||
};
|
||||
int count = 0;
|
||||
foreach (var tokenRepository in context.ApplicationUserTokenRepositories.Where(repository =>
|
||||
repository.Creator == user && !repository.IsLocked))
|
||||
{
|
||||
if (tokenRepository.GuidToken != null) topic.Tokens?.Add(tokenRepository.GuidToken);
|
||||
tokenRepository.IsLocked = true;
|
||||
count++;
|
||||
|
||||
}
|
||||
logger.LogDebug("Produced logout topic for user: {UserId}, Tokens: {Tokens}", user.Id, topic.Tokens);
|
||||
_ = logOutTopic.Produce(topic);
|
||||
await context.SaveChangesAsync();
|
||||
logger.LogInformation("Locked {Count} tokens for user: {UserId}", count, user.Id);
|
||||
return count;
|
||||
}
|
||||
|
||||
public int LockToken(string token)
|
||||
{
|
||||
logger.LogInformation("Locking token: {Token}", token);
|
||||
ApplicationUserTokenRepository? tokenM =
|
||||
context.ApplicationUserTokenRepositories.FirstOrDefault(q => q.GuidToken != null && q.GuidToken.Equals(token));
|
||||
if (tokenM != null)
|
||||
{
|
||||
tokenM.IsLocked = true;
|
||||
logger.LogInformation("Token locked successfully: {Token}", token);
|
||||
return context.SaveChanges();
|
||||
}
|
||||
|
||||
logger.LogWarning("Token not found for locking: {Token}", token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> AddTokenToRepAsync(string guid, string creator, DateTime exp, DateTime? created = null)
|
||||
{
|
||||
ApplicationUser? user = await userManager.FindByEmailAsync(creator) ??
|
||||
await userManager.FindByNameAsync(creator);
|
||||
|
||||
logger.LogInformation("Adding token to repository for creator: {Creator}", creator);
|
||||
if (user != null)
|
||||
{
|
||||
return await AddTokenToRepAsync(guid, user, exp,created);
|
||||
}
|
||||
|
||||
logger.LogWarning("User not found for token creation: {Creator}", creator);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<int> AddTokenToRepAsync(string guid, ApplicationUser? creator, DateTime? exp, DateTime? created = null)
|
||||
{
|
||||
created ??= DateTime.UtcNow;
|
||||
if (creator == null) return 0;
|
||||
ApplicationUserTokenRepository newToken = new ApplicationUserTokenRepository(guid, creator, created, exp);
|
||||
context.ApplicationUserTokenRepositories.Add(newToken);
|
||||
|
||||
return await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<int> DeleteAllUserTokenAsync(ApplicationUser user)
|
||||
{
|
||||
logger.LogInformation("Deleting all tokens for user: {UserId}", user.Id);
|
||||
var tokens = await context.ApplicationUserTokenRepositories
|
||||
.Where(q => q.Creator == user)
|
||||
.Select(q => q.GuidToken)
|
||||
.ToListAsync();
|
||||
|
||||
var tokensInt = await context.ApplicationUserTokenRepositories
|
||||
.Where(q => q.Creator == user).ExecuteDeleteAsync();
|
||||
|
||||
var topic = new LogOutMessageType()
|
||||
{
|
||||
UserName = user.UserName ?? "User not found",
|
||||
Id = user.Id,
|
||||
Tokens = tokens
|
||||
};
|
||||
await logOutTopic.Produce(topic);
|
||||
logger.LogInformation("Deleted {Count} tokens for user: {UserId}", tokensInt, user.Id);
|
||||
return tokensInt;
|
||||
}
|
||||
|
||||
public async Task<string?> GetLastUserToken(ApplicationUser? user)
|
||||
{
|
||||
logger.LogInformation("Retrieving last token for user: {UserId}", user?.Id);
|
||||
return await context.ApplicationUserTokenRepositories.Where(repository =>
|
||||
repository.Creator == user && repository.ExpireTime < DateTime.UtcNow).Select(repository => repository.GuidToken).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<int> DeleteInactiveToken()
|
||||
{
|
||||
logger.LogInformation("Deleting inactive tokens");
|
||||
var deletedToken =
|
||||
await context.ApplicationUserTokenRepositories.Where(repository =>
|
||||
repository.ExpireTime < DateTime.UtcNow.AddHours(-2)).ExecuteDeleteAsync();
|
||||
logger.LogInformation("Deleted {Count} inactive tokens", deletedToken);
|
||||
return deletedToken;
|
||||
}
|
||||
|
||||
public async Task<string?> CreateJwtToken(ApplicationUser user, DateTime? expires, List<Claim>? claims)
|
||||
{
|
||||
logger.LogInformation("Generating JWT token for user: {UserId}", user.Id);
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
|
||||
var rsaSecurityKey = await GetSigningCredentials();
|
||||
|
||||
var audience = configuration["Jwt:Audience"] ?? string.Empty;
|
||||
var issuer = configuration["Jwt:Issuer"] ?? string.Empty;
|
||||
|
||||
if (user is { UserName: not null, Email: not null })
|
||||
{
|
||||
var claimList = await userManager.GetClaimsAsync(user);
|
||||
var claim = claimList.FirstOrDefault(claim1 => claim1.Type == AccountTypeFunction.AccountTypeType);
|
||||
var guid = Guid.NewGuid().ToString();
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = new ClaimsIdentity(new[]
|
||||
{
|
||||
new Claim(JwtRegisteredClaimNames.Jti, guid),
|
||||
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
|
||||
new Claim(ClaimTypes.NameIdentifier, user.Id),
|
||||
new Claim(ClaimTypes.Name, user.UserName),
|
||||
new Claim(ClaimTypes.Email, user.Email),
|
||||
claim ?? AccountType.Uknow.Claim(),
|
||||
}),
|
||||
|
||||
Expires = expires,
|
||||
Audience = audience,
|
||||
Issuer = issuer,
|
||||
SigningCredentials = rsaSecurityKey,
|
||||
};
|
||||
|
||||
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||
|
||||
string? tokenString = tokenHandler.WriteToken(token);
|
||||
await AddTokenToRepAsync(guid, user, DateTime.UtcNow, tokenDescriptor.Expires);
|
||||
logger.LogInformation("JWT token generated successfully for user: {UserId}", user.Id);
|
||||
return tokenString;
|
||||
}
|
||||
|
||||
logger.LogWarning("Failed to generate JWT token due to missing user information.");
|
||||
return "";
|
||||
}
|
||||
|
||||
public async Task<string?> RegenerateJwtToken(string? token, DateTime? expires)
|
||||
{
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var tokenObj = tokenHandler.ReadJwtToken(token);
|
||||
|
||||
var claims = tokenObj.Claims.ToList();
|
||||
|
||||
claims.RemoveAll(c => c.Type == JwtRegisteredClaimNames.Jti ||
|
||||
c.Type == JwtRegisteredClaimNames.Iat ||
|
||||
c.Type == JwtRegisteredClaimNames.Nbf ||
|
||||
c.Type == "unique_name" ||
|
||||
c.Type == "email");
|
||||
|
||||
var newJti = Guid.NewGuid().ToString();
|
||||
|
||||
claims.Add(new Claim(JwtRegisteredClaimNames.Jti, newJti));
|
||||
|
||||
var rsaSecurityKey = await GetSigningCredentials();
|
||||
|
||||
var userId = claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Sub)?.Value;
|
||||
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
logger.LogWarning("Cannot regenerate token: user ID not found in token claims.");
|
||||
return "";
|
||||
}
|
||||
|
||||
var user = await userManager.FindByIdAsync(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
logger.LogWarning("Cannot regenerate token: user not found.");
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(user.UserName) && !string.IsNullOrEmpty(user.Email))
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.Name, user.UserName));
|
||||
claims.Add(new Claim(ClaimTypes.Email, user.Email));
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
await LockTokenAsync(token);
|
||||
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = new ClaimsIdentity(claims),
|
||||
Expires = expires,
|
||||
SigningCredentials = rsaSecurityKey,
|
||||
};
|
||||
|
||||
var newToken = tokenHandler.CreateToken(tokenDescriptor);
|
||||
|
||||
string? tokenString = tokenHandler.WriteToken(newToken);
|
||||
await AddTokenToRepAsync(newJti, user, DateTime.UtcNow, tokenDescriptor.Expires);
|
||||
|
||||
return tokenString;
|
||||
|
||||
}
|
||||
|
||||
public async Task<bool> TokenIsLock(string? token = null, string? guid = null)
|
||||
{
|
||||
|
||||
if (guid == null && token != null)
|
||||
{
|
||||
guid = ParseToken(token).Id;
|
||||
}
|
||||
|
||||
|
||||
if (guid == null)
|
||||
{
|
||||
logger.LogWarning("Token fot GUID: {guid} is invalid.", guid);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
var result = await context.ApplicationUserTokenRepositories
|
||||
.Where(repository => repository.GuidToken != null && repository.GuidToken.Equals(guid))
|
||||
.Select(repository => repository.IsLocked).FirstOrDefaultAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private JwtSecurityToken ParseToken(string? token)
|
||||
{
|
||||
logger.LogTrace("Parse token");
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var tokenObj = tokenHandler.ReadJwtToken(token);
|
||||
|
||||
logger.LogDebug("Parsed token with GUID: {guid} and userID: {id}", tokenObj.Id, tokenObj.Subject);
|
||||
|
||||
return tokenObj;
|
||||
}
|
||||
|
||||
private async Task<SigningCredentials> GetSigningCredentials()
|
||||
{
|
||||
var contentRoot = configuration["contentRoot"] ?? throw new NullReferenceException();
|
||||
|
||||
var privateKeyPath = Path.Combine(contentRoot, "private_key_pkcs8.pem");
|
||||
|
||||
var rsa = RSA.Create();
|
||||
|
||||
rsa.ImportFromPem(await File.ReadAllTextAsync(privateKeyPath));
|
||||
|
||||
var key = new RsaSecurityKey(rsa)
|
||||
{
|
||||
KeyId = "1"
|
||||
};
|
||||
|
||||
return new SigningCredentials(key , SecurityAlgorithms.RsaSha256);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace OpenWarehouse.auth.api.Common.AuthTokenRepo;
|
||||
|
||||
public interface IAuthTokenRepo
|
||||
{
|
||||
public Task<bool> IsTokenLockAsync(string? token);
|
||||
public bool IsTokenLock(string? token);
|
||||
|
||||
public Task<int> LockTokenAsync(string? token);
|
||||
public Task<int> LockAllUserTokenAsync(ApplicationUser user);
|
||||
public int LockToken(string token);
|
||||
|
||||
public Task<int> AddTokenToRepAsync(string token, string creator, DateTime exp, DateTime? created);
|
||||
|
||||
public Task<int> AddTokenToRepAsync(string token, ApplicationUser? creator, DateTime? exp, DateTime? created);
|
||||
|
||||
public Task<int> DeleteAllUserTokenAsync(ApplicationUser user);
|
||||
|
||||
public Task<string?> GetLastUserToken(ApplicationUser? user);
|
||||
|
||||
public Task<int> DeleteInactiveToken();
|
||||
|
||||
public Task<string?> CreateJwtToken(ApplicationUser user, DateTime? expires, List<Claim> claims);
|
||||
|
||||
public Task<string?> RegenerateJwtToken(string? token, DateTime? expires);
|
||||
|
||||
public Task<bool> TokenIsLock(string? token, string? guid);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OpenWarehouse.auth.api.Common.AuthTokenRepo;
|
||||
|
||||
public class UserTokenInformation
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Net;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.CustomIdentifyManager;
|
||||
|
||||
public enum AccountClaims
|
||||
{
|
||||
ServiceAdress, IfUserCanChangeRole, ServiceName,
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.CustomIdentifyManager;
|
||||
|
||||
public static class AccountClaimsClass
|
||||
{
|
||||
private static readonly Dictionary<AccountClaims, string> AccountTypeDict = new()
|
||||
{
|
||||
{ AccountClaims.ServiceAdress, "Service_Adress" },
|
||||
{ AccountClaims.ServiceName, "ServiceName" },
|
||||
{ AccountClaims.IfUserCanChangeRole, "PrivilageFunct" }
|
||||
};
|
||||
|
||||
public static Claim GetClaim(this AccountClaims claims, string val)
|
||||
{
|
||||
var isSuccess = AccountTypeDict.TryGetValue(claims,out var res);
|
||||
|
||||
if (isSuccess && res != null)
|
||||
{
|
||||
return new Claim(res, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Claim not implemented!");
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetName(AccountClaims claims)
|
||||
{
|
||||
var isSuccess = AccountTypeDict.TryGetValue(claims,out var res);
|
||||
|
||||
|
||||
if (isSuccess && res != null)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Claim not implemented!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OpenWarehouse.auth.api.Common.CustomIdentifyManager;
|
||||
|
||||
public enum AccountType
|
||||
{
|
||||
User, Admin, Service, Uknow
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace OpenWarehouse.auth.api.Common.CustomIdentifyManager;
|
||||
|
||||
public static class AccountTypeFunction
|
||||
{
|
||||
public static string AccountTypeType { get; } = "AccountType";
|
||||
|
||||
private static readonly Dictionary<AccountType, string> AccountTypeMap = new()
|
||||
{
|
||||
{ AccountType.User, "User" },
|
||||
{ AccountType.Admin, "Admin" },
|
||||
{ AccountType.Service, "Service" },
|
||||
{ AccountType.Uknow, "Uknow" },
|
||||
};
|
||||
|
||||
public static string GetValue(this AccountType accountType)
|
||||
{
|
||||
var isSuccess = AccountTypeMap.TryGetValue(accountType, out var acountString);
|
||||
|
||||
if (isSuccess && acountString != null)
|
||||
{
|
||||
return acountString;
|
||||
}
|
||||
|
||||
throw new Exception("Account type not in AccountTypeMap.");
|
||||
}
|
||||
|
||||
public static Claim Claim(this AccountType accountType)
|
||||
{
|
||||
return new Claim(AccountTypeType, accountType.GetValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using OpenWarehouse.auth.api.Common.CustomIdentifyManager;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.DefaultUserAndRole;
|
||||
|
||||
public class DefaultIdentify(
|
||||
ILogger<DefaultIdentify> logger,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
RoleManager<ApplicationRole> roleManager,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
ApplicationDbContext applicationDbContext,
|
||||
PrivilageManager.PrivilegeManager privilegeManager,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
public async Task SeedAsync()
|
||||
{
|
||||
if (!await applicationDbContext.RolePrivilages.AnyAsync(x => true))
|
||||
{
|
||||
var listOfRoles = GlobalPrivilage.GatherPrivilegeStrings();
|
||||
foreach (var privilage in listOfRoles)
|
||||
{
|
||||
var rolePrivilage = new RolePrivilage() { Privilage = privilage };
|
||||
applicationDbContext.RolePrivilages.Add(rolePrivilage);
|
||||
logger.LogDebug($"Created privilage: {privilage}");
|
||||
}
|
||||
|
||||
await applicationDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
||||
if (!roleManager.Roles.Any())
|
||||
{
|
||||
ApplicationRole admin = new ApplicationRole()
|
||||
{
|
||||
Name = "Admin",
|
||||
IsGlobalAdmin = true,
|
||||
};
|
||||
ApplicationRole user = new ApplicationRole()
|
||||
{
|
||||
Name = "User",
|
||||
IsGlobalAdmin = false
|
||||
};
|
||||
ApplicationRole service = new ApplicationRole()
|
||||
{
|
||||
Name = "Service",
|
||||
IsGlobalAdmin = true
|
||||
};
|
||||
if ((await roleManager.CreateAsync(admin)).Succeeded)
|
||||
{
|
||||
logger.LogDebug($"Created role {admin}");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning($"Unable create role {admin}");
|
||||
}
|
||||
if ((await roleManager.CreateAsync(user)).Succeeded)
|
||||
{
|
||||
logger.LogDebug($"Created role {user.Name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning($"Unable create role {user.Name}");
|
||||
}
|
||||
if ((await roleManager.CreateAsync(service)).Succeeded)
|
||||
{
|
||||
logger.LogDebug($"Created role {service.Name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning($"Unable create role {service.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
if (!userManager.Users.Any())
|
||||
{
|
||||
var username = configuration["SuperUser:Name"] ?? "Admin";
|
||||
var email = configuration["SuperUser:Email"] ?? "Admin@admin.local";
|
||||
|
||||
var password = configuration["SuperUser:Password"] ?? GenerateRandomPass(10);
|
||||
|
||||
|
||||
var user = new ApplicationUser() { UserName = username, Email = email, EmailConfirmed = true};
|
||||
var userResult = (await userManager.CreateAsync(user, password));
|
||||
if (userResult.Succeeded)
|
||||
{
|
||||
var claimResult = await userManager.AddClaimAsync(user, AccountType.Admin.Claim());
|
||||
|
||||
if (claimResult.Succeeded)
|
||||
{
|
||||
logger.LogInformation($"Sucess added claim {AccountType.Admin.Claim()} to user {user.UserName}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning($"Unable added claim {AccountType.Admin.Claim()} to user {user.UserName}.");
|
||||
}
|
||||
|
||||
logger.LogInformation($"Created user, Name: {user.UserName} Email: {user.Email}, Password: {password}");
|
||||
var roleResult = (await userManager.AddToRoleAsync(user, "Admin"));
|
||||
if (roleResult.Succeeded)
|
||||
{
|
||||
logger.LogInformation($"Added role Admin to {user.UserName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning($"Unable added role Admin to user {user.UserName}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning($"Unable create user {user.UserToken}. Messs: {string.Join(";",userResult.Errors)}");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateRandomPass(int length)
|
||||
{
|
||||
const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const string lower = "abcdefghijklmnopqrstuvwxyz";
|
||||
const string digits = "0123456789";
|
||||
const string specialChars = "!@#$%^&*()_+{}\":'<>?[];,./";
|
||||
|
||||
var allChars = upper + lower + digits + specialChars;
|
||||
var random = new Random();
|
||||
var passwordChars = new char[length];
|
||||
|
||||
passwordChars[0] = upper[random.Next(upper.Length)];
|
||||
passwordChars[1] = lower[random.Next(lower.Length)];
|
||||
passwordChars[2] = digits[random.Next(digits.Length)];
|
||||
passwordChars[3] = specialChars[random.Next(specialChars.Length)];
|
||||
|
||||
for (int i = 4; i < length; i++)
|
||||
{
|
||||
passwordChars[i] = allChars[random.Next(allChars.Length)];
|
||||
}
|
||||
|
||||
return new string(passwordChars.OrderBy(c => random.Next()).ToArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace OpenWarehouse.auth.api.Common.Exemptions;
|
||||
|
||||
public class AccountExemptions : Exception
|
||||
{
|
||||
private Dictionary<string, string> _otherProblem;
|
||||
private string _message;
|
||||
private bool _accountExist;
|
||||
|
||||
|
||||
public bool AccountExist
|
||||
{
|
||||
get => _accountExist;
|
||||
set => _accountExist = value;
|
||||
}
|
||||
|
||||
public string Message
|
||||
{
|
||||
get => _message;
|
||||
set => _message = value;
|
||||
}
|
||||
|
||||
public Dictionary<string, string> OtherProblem
|
||||
{
|
||||
get => _otherProblem;
|
||||
set => _otherProblem = value;
|
||||
}
|
||||
|
||||
public AccountExemptions(bool accountExist, string message, Dictionary<string, string>? otherProblem = null)
|
||||
{
|
||||
_otherProblem = otherProblem ?? new Dictionary<string, string>();
|
||||
_accountExist = accountExist;
|
||||
_message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace OpenWarehouse.auth.api.Common.Exemptions;
|
||||
|
||||
public class RoleExemptions : Exception
|
||||
{
|
||||
private Dictionary<string, string> _otherProblem;
|
||||
private string? _message;
|
||||
private bool _roleExist;
|
||||
|
||||
|
||||
public bool RoleExist
|
||||
{
|
||||
get => _roleExist;
|
||||
set => _roleExist = value;
|
||||
}
|
||||
|
||||
public override string Message => _message ?? "";
|
||||
|
||||
public Dictionary<string, string> OtherProblem
|
||||
{
|
||||
get => _otherProblem;
|
||||
set => _otherProblem = value;
|
||||
}
|
||||
|
||||
public RoleExemptions(bool accountExist = true, string? message = null, Dictionary<string, string>? otherProblem = null)
|
||||
{
|
||||
_otherProblem = otherProblem ?? new Dictionary<string, string>();
|
||||
_roleExist = accountExist;
|
||||
_message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Kafka.Lib;
|
||||
using MassTransit;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.Kafka;
|
||||
|
||||
public class Consumer : IConsumer<IMessageType>
|
||||
{
|
||||
public Task Consume(ConsumeContext<IMessageType> context)
|
||||
{
|
||||
Console.Out.WriteLine($"{context.Message.Text}");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
namespace OpenWarehouse.auth.api.Common.PrivilageManager;
|
||||
|
||||
public static class GlobalPrivilage
|
||||
{
|
||||
public enum Privilege
|
||||
{
|
||||
GlobalAdmin,
|
||||
GlobalManageUser,
|
||||
GlobalCreateUser,
|
||||
GlobalDeleteUser,
|
||||
GlobalEditUser,
|
||||
GlobalManageRole,
|
||||
GlobalCreateRole,
|
||||
GlobalDeleteRole,
|
||||
GlobalEditRole,
|
||||
GlobalDeleteExpiredToken,
|
||||
GlobalDeactivateUserToken,
|
||||
GlobalUser
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Privilege, string> PrivilegeToStringMap = new()
|
||||
{
|
||||
{ Privilege.GlobalAdmin, "Auth-Admin" },
|
||||
{ Privilege.GlobalManageUser, "Auth-User-Manage" },
|
||||
{ Privilege.GlobalCreateUser, "Auth-User-Create" },
|
||||
{ Privilege.GlobalDeleteUser, "Auth-User-Delete" },
|
||||
{ Privilege.GlobalEditUser, "Auth-User-Edit" },
|
||||
{ Privilege.GlobalManageRole, "Auth-Role-Manage" },
|
||||
{ Privilege.GlobalCreateRole, "Auth-Role-Create-" },
|
||||
{ Privilege.GlobalDeleteRole, "Auth-Role-Delete" },
|
||||
{ Privilege.GlobalEditRole, "Auth-Role-Edit" },
|
||||
{ Privilege.GlobalDeleteExpiredToken, "Auth-Delete-Expired-Token" },
|
||||
{ Privilege.GlobalDeactivateUserToken, "Auth-Deactivate-User-Token" },
|
||||
{ Privilege.GlobalUser, "Auth-User" }
|
||||
};
|
||||
|
||||
|
||||
private static readonly Dictionary<Privilege, List<Privilege>> PrivilegeMap = new()
|
||||
{
|
||||
{ Privilege.GlobalAdmin, new List<Privilege> { Privilege.GlobalAdmin } },
|
||||
{ Privilege.GlobalManageUser, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageUser } },
|
||||
{ Privilege.GlobalCreateUser, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageUser, Privilege.GlobalCreateUser } },
|
||||
{ Privilege.GlobalDeleteUser, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageUser, Privilege.GlobalDeleteUser } },
|
||||
{ Privilege.GlobalEditUser, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageUser, Privilege.GlobalEditUser } },
|
||||
{ Privilege.GlobalManageRole, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageRole } },
|
||||
{ Privilege.GlobalCreateRole, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageRole, Privilege.GlobalCreateRole } },
|
||||
{ Privilege.GlobalDeleteRole, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageRole, Privilege.GlobalDeleteRole } },
|
||||
{ Privilege.GlobalEditRole, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageRole, Privilege.GlobalEditRole } },
|
||||
{ Privilege.GlobalDeactivateUserToken, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalDeactivateUserToken } },
|
||||
{ Privilege.GlobalDeleteExpiredToken, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalDeleteExpiredToken } },
|
||||
{ Privilege.GlobalUser , GetAllPrivilages()}
|
||||
};
|
||||
|
||||
|
||||
public static List<string> GetPrivilegesFor(this Privilege privilegeKey)
|
||||
{
|
||||
var privilegeStrings = new List<string>();
|
||||
|
||||
if (PrivilegeMap.TryGetValue(privilegeKey, out var privileges))
|
||||
{
|
||||
foreach (var privilege in privileges)
|
||||
{
|
||||
if (PrivilegeToStringMap.TryGetValue(privilege, out var privilegeString))
|
||||
{
|
||||
privilegeStrings.Add(privilegeString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return privilegeStrings;
|
||||
}
|
||||
|
||||
public static string? GetStringForPrivilege(this Privilege privilege)
|
||||
{
|
||||
|
||||
bool isSuccess = PrivilegeToStringMap.TryGetValue(privilege, out var privilegeString);
|
||||
|
||||
if (isSuccess)
|
||||
{
|
||||
return privilegeString;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<string> GatherPrivilegeStrings()
|
||||
{
|
||||
var privilegeStrings = new List<string>();
|
||||
|
||||
foreach (var privilege in GetAllPrivilages())
|
||||
{
|
||||
var privilegeString = privilege.GetStringForPrivilege();
|
||||
if (privilegeString != null)
|
||||
{
|
||||
privilegeStrings.Add(privilegeString);
|
||||
}
|
||||
}
|
||||
|
||||
return privilegeStrings;
|
||||
}
|
||||
|
||||
public static List<Privilege> GetAllPrivilages()
|
||||
{
|
||||
var allPrivileges = new List<Privilege>();
|
||||
foreach (var privilege in Enum.GetValues(typeof(Privilege)))
|
||||
{
|
||||
allPrivileges.Add((Privilege)privilege);
|
||||
}
|
||||
|
||||
return allPrivileges;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.PrivilageManager;
|
||||
|
||||
/// <summary>
|
||||
/// Attribute to enforce privilege-based authorization.
|
||||
/// </summary>
|
||||
public class HasPrivilegeAttribute : Attribute, IAsyncAuthorizationFilter
|
||||
{
|
||||
private GlobalPrivilage.Privilege[] Privileges { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HasPrivilegeAttribute"/> class with one or more required privileges.
|
||||
/// </summary>
|
||||
/// <param name="privileges">The privileges required to access the resource.</param>
|
||||
public HasPrivilegeAttribute(params GlobalPrivilage.Privilege[] privileges)
|
||||
{
|
||||
Privileges = privileges;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the privilege check during authorization.
|
||||
/// </summary>
|
||||
/// <param name="context">The authorization filter context.</param>
|
||||
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||
{
|
||||
var userActionId = context.HttpContext.User.FindFirstValue(JwtRegisteredClaimNames.Sub);
|
||||
|
||||
var userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var privilegeManager = context.HttpContext.RequestServices.GetRequiredService<PrivilegeManager>();
|
||||
|
||||
if (userActionId != null)
|
||||
{
|
||||
var userAction = await userManager.FindByIdAsync(userActionId);
|
||||
if (userAction == null ||
|
||||
!await UserHasAnyRequiredPrivilege(privilegeManager, userAction))
|
||||
{
|
||||
context.Result = new ContentResult
|
||||
{
|
||||
StatusCode = StatusCodes.Status403Forbidden,
|
||||
Content = "Access Denied: You do not have the required privileges to perform this action.",
|
||||
ContentType = "text/plain"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the user has at least one of the required privileges.
|
||||
/// </summary>
|
||||
/// <param name="privilegeManager">The privilege manager service.</param>
|
||||
/// <param name="user">The user to check privileges for.</param>
|
||||
/// <returns>True if the user has any required privilege; otherwise, false.</returns>
|
||||
private async Task<bool> UserHasAnyRequiredPrivilege(PrivilegeManager privilegeManager, ApplicationUser user)
|
||||
{
|
||||
foreach (var privilege in Privileges)
|
||||
{
|
||||
if (await privilegeManager.UserHasGlobalPrivilage(user, privilege))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using OpenWarehouse.auth.lib.Model.Service;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.PrivilageManager;
|
||||
|
||||
public interface IPrivilageManager
|
||||
{
|
||||
|
||||
public Task<List<string?>> GetUserPrivilage(ApplicationUser user);
|
||||
public Task<List<string>?> GetRolePrivilage(ApplicationRole role);
|
||||
|
||||
public Task AddRolePrivilage(ApplicationRole role, string privilage);
|
||||
public Task DeleteRolePrivilage(ApplicationRole role, string privilage);
|
||||
|
||||
public Task<bool> RoleHasPrivilage(ApplicationRole role, string privilage);
|
||||
public Task<bool> UserHasPrivilage(ApplicationUser user, string privilage);
|
||||
public Task<bool> UserHasGlobalPrivilage(ApplicationUser user, GlobalPrivilage.Privilege privilege);
|
||||
|
||||
public Task<RolePrivilage?> GetPrivilageByNameIfDontExistCreateAsync(string privilage);
|
||||
|
||||
public Task<RolePrivilage?> GetPrivilageByName(string privilage);
|
||||
|
||||
public Task<CreateServiceRoleResult> CreatePrivageAsync(string privilage);
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using OpenWarehouse.auth.lib.Model.Service;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.PrivilageManager;
|
||||
|
||||
public class PrivilegeManager(ApplicationDbContext context,
|
||||
RoleManager<ApplicationRole> roleManager,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
ILogger<PrivilegeManager> logger) : IPrivilageManager
|
||||
{
|
||||
public async Task<List<string?>> GetUserPrivilage(ApplicationUser user)
|
||||
{
|
||||
var roles = await userManager.GetRolesAsync(user);
|
||||
List<string?> privilages = [];
|
||||
|
||||
foreach (var role in roles)
|
||||
{
|
||||
var roleObj = await context.Roles.Include(applicationRole => applicationRole.Privilege).FirstOrDefaultAsync(applicationRole =>
|
||||
applicationRole.NormalizedName.Equals(roleManager.NormalizeKey(role)));
|
||||
|
||||
if (roleObj != null && roleObj.IsGlobalAdmin)
|
||||
privilages.Add("Admin");
|
||||
|
||||
if (roleObj is { Privilege: not null })
|
||||
privilages.AddRange(roleObj.Privilege.Select(privilage => privilage?.Privilage).ToList());
|
||||
}
|
||||
|
||||
return privilages.Distinct().ToList();
|
||||
}
|
||||
|
||||
public async Task<List<string>?> GetRolePrivilage(ApplicationRole role)
|
||||
{
|
||||
|
||||
List<string>? privilageList = [];
|
||||
if (role.IsGlobalAdmin)
|
||||
{
|
||||
privilageList.Add("Admin");
|
||||
return privilageList;
|
||||
}
|
||||
|
||||
var privilage = await context.RolePrivilages
|
||||
.Where(rolePrivilage => rolePrivilage.Roles.Any(applicationRole => applicationRole == role)).ToListAsync();
|
||||
|
||||
if (privilage != null)
|
||||
privilageList = privilage.Select(privilage => privilage.Privilage).Distinct().ToList();
|
||||
|
||||
return privilageList;
|
||||
}
|
||||
|
||||
public async Task AddRolePrivilage(ApplicationRole role, string privilage)
|
||||
{
|
||||
var privilageObj = await context.RolePrivilages.Include(rolePrivilage => rolePrivilage.Roles)
|
||||
.FirstOrDefaultAsync(rolePrivilage => rolePrivilage.Privilage.Equals(privilage));
|
||||
|
||||
if(privilageObj is { Roles: not null }
|
||||
&& !privilageObj.Roles.Any(applicationRole => applicationRole.Id == role.Id))
|
||||
privilageObj.Roles.Add(role);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteRolePrivilage(ApplicationRole role, string privilage)
|
||||
{
|
||||
var privilageToDelete = await context.RolePrivilages
|
||||
.Where(rolePrivilage => rolePrivilage.Privilage == privilage &&
|
||||
rolePrivilage.Roles.Any(applicationRole => applicationRole.Id == role.Id))
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (privilageToDelete != null)
|
||||
{
|
||||
context.RolePrivilages.Remove(privilageToDelete);
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> RoleHasPrivilage(ApplicationRole role, string privilage)
|
||||
{
|
||||
if (role.IsGlobalAdmin) return true;
|
||||
|
||||
if (role.Privilege == null) return false;
|
||||
|
||||
|
||||
|
||||
return role.Privilege.Any(rolePrivilage => rolePrivilage.Privilage == privilage);
|
||||
}
|
||||
|
||||
public async Task<bool> UserHasPrivilage(ApplicationUser user, string privilage)
|
||||
{
|
||||
var rolesName = await userManager.GetRolesAsync(user);
|
||||
foreach (var roleName in rolesName)
|
||||
{
|
||||
var role = await roleManager.FindByNameAsync(roleName);
|
||||
if (role == null) return false;
|
||||
return await RoleHasPrivilage(role, privilage);
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> UserHasGlobalPrivilage(ApplicationUser user, GlobalPrivilage.Privilege privilage)
|
||||
{
|
||||
var have = false;
|
||||
|
||||
foreach (var priv in privilage.GetPrivilegesFor())
|
||||
{
|
||||
have = await UserHasPrivilage(user, priv);
|
||||
if (have) break;
|
||||
}
|
||||
|
||||
return have;
|
||||
}
|
||||
|
||||
public async Task<RolePrivilage?> GetPrivilageByNameIfDontExistCreateAsync(string privilageName)
|
||||
{
|
||||
var privilage = await GetPrivilageByName(privilageName);
|
||||
|
||||
if (privilage == null)
|
||||
{
|
||||
privilage = new RolePrivilage(privilage: privilageName);
|
||||
context.RolePrivilages.Add(privilage);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return privilage;
|
||||
}
|
||||
|
||||
public async Task<RolePrivilage?> GetPrivilageByName(string privilage)
|
||||
{
|
||||
return await context.RolePrivilages.FirstOrDefaultAsync(q => q.Privilage == privilage);
|
||||
}
|
||||
|
||||
public async Task<CreateServiceRoleResult> CreatePrivageAsync(string privilage)
|
||||
{
|
||||
try
|
||||
{
|
||||
var privilageObj = new RolePrivilage() { Privilage = privilage };
|
||||
|
||||
var entityEntry = context.RolePrivilages.Add(privilageObj);
|
||||
|
||||
if (await context.SaveChangesAsync() > 0) return new CreateServiceRoleResult(isSuccessed: true, null) { };
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dictionary<string, string> errors = new Dictionary<string, string>();
|
||||
|
||||
errors[e.Source ?? "Uknow"] = e.Message;
|
||||
return new CreateServiceRoleResult(false, errors);
|
||||
|
||||
}
|
||||
|
||||
return new CreateServiceRoleResult(false, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace OpenWarehouse.auth.api.Common.RegisterTokenManager;
|
||||
|
||||
public interface IRegisterTokenManager
|
||||
{
|
||||
public Task<RegisterToken> AddNewToken(string token, ApplicationUser creator, List<string> avaliableRole);
|
||||
public Task<RegisterToken> AddNewTolken(string token, ApplicationUser creator, List<ApplicationRole> avaliableRole);
|
||||
public Task<RegisterToken?> GetToken(string token);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Data;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.RegisterTokenManager;
|
||||
|
||||
public class RegisterTokenManager(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
RoleManager<ApplicationRole> roleManager,
|
||||
ApplicationDbContext context
|
||||
) : IRegisterTokenManager
|
||||
{
|
||||
public async Task<RegisterToken> AddNewToken(string token, ApplicationUser creator, List<string> avaliableRole)
|
||||
{
|
||||
var listRole = new List<ApplicationRole>();
|
||||
foreach (var role in avaliableRole)
|
||||
{
|
||||
var roleObj = await roleManager.FindByNameAsync(role);
|
||||
|
||||
if (roleObj != null) listRole.Add(roleObj);
|
||||
}
|
||||
|
||||
return await AddNewTolken(token, creator, listRole);
|
||||
}
|
||||
|
||||
public async Task<RegisterToken> AddNewTolken(string token, ApplicationUser creator, List<ApplicationRole> avaliableRole)
|
||||
{
|
||||
var tokenObj = new RegisterToken()
|
||||
{
|
||||
Creator = creator,
|
||||
AvaliableRole = avaliableRole,
|
||||
Token = token
|
||||
};
|
||||
context.RegisterTokens.Add(tokenObj);
|
||||
|
||||
if (await context.SaveChangesAsync() > 0)
|
||||
{
|
||||
return tokenObj;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DataException();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<RegisterToken?> GetToken(string token)
|
||||
{
|
||||
return await context.RegisterTokens.FirstOrDefaultAsync(registerToken => registerToken.Token.Equals(token));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using OpenWarehouse.auth.lib.Model.Role;
|
||||
using OpenWarehouse.auth.lib.Model.Service;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.ServiceManager;
|
||||
|
||||
|
||||
|
||||
public interface IServiceManager
|
||||
{
|
||||
public Task<bool> CheckIfServiceUserExist(string serviceName);
|
||||
public Task<bool> CreateServiceUserResult(string serviceName, bool serviceIsAdmin = false);
|
||||
public Task<bool> AddAdminToServiceUser(string serviceName);
|
||||
public Task<List<CreateServiceRoleResult>> CreateServiceRoles(List<RoleModel> serviceRoles, bool forcePrivilages = false);
|
||||
public Task<List<CreateServicePrivilageResult>> CreateServicesPrivilage(List<string> servicePrivilages);
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
using Kafka.Lib.Auth;
|
||||
using MassTransit;
|
||||
using OpenWarehouse.auth.api.Common.CustomIdentifyManager;
|
||||
using OpenWarehouse.auth.api.Common.Exemptions;
|
||||
using OpenWarehouse.auth.lib.Model.Role;
|
||||
using OpenWarehouse.auth.lib.Model.Service;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.ServiceManager;
|
||||
|
||||
public class ServiceManager(
|
||||
UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager,
|
||||
PrivilageManager.PrivilegeManager privilegeManager, ILogger<ServiceManager> logger,
|
||||
ITopicProducer<UserChangeMessageType> userTopic) : IServiceManager
|
||||
{
|
||||
|
||||
public async Task<bool> CheckIfServiceUserExist(string serviceName)
|
||||
{
|
||||
return await userManager.FindByNameAsync($"Service-{serviceName}") != null;
|
||||
}
|
||||
|
||||
public async Task<bool> CreateServiceUserResult(string serviceName, bool serviceIsAdmin = false)
|
||||
{
|
||||
var serviceUser = new ApplicationUser()
|
||||
{
|
||||
UserName = $"Service-{serviceName}",
|
||||
Email = $"service-{serviceName}@service.local", LockoutEnabled = true,
|
||||
};
|
||||
|
||||
var result = await userManager.CreateAsync(serviceUser);
|
||||
if (!result.Succeeded) throw new Exception(result.ToString());
|
||||
if (serviceIsAdmin) await AddAdminToServiceUser(serviceName);
|
||||
|
||||
var addClaim = await userManager.AddClaimAsync(serviceUser, AccountType.Service.Claim());
|
||||
|
||||
var topic = new UserChangeMessageType()
|
||||
{
|
||||
UserId = serviceUser.Id,
|
||||
Changes = new Dictionary<string, string>()
|
||||
{
|
||||
{"Username", $"Service-{serviceName}"},
|
||||
{"AccountType", AccountType.Service.GetValue()},
|
||||
{"IsGlobalAdmin", serviceIsAdmin.ToString()}
|
||||
}
|
||||
};
|
||||
|
||||
_ = userTopic.Produce(topic);
|
||||
|
||||
return result.Succeeded && addClaim.Succeeded;
|
||||
}
|
||||
|
||||
public async Task<bool> AddAdminToServiceUser(string serviceName)
|
||||
{
|
||||
var roleName = $"Service-{serviceName}";
|
||||
var user = await userManager.FindByNameAsync(roleName) ?? throw new AccountExemptions(false, "Account not found");
|
||||
var isAllready = await privilegeManager.UserHasGlobalPrivilage(user, GlobalPrivilage.Privilege.GlobalAdmin);
|
||||
|
||||
if (isAllready) return true;
|
||||
|
||||
isAllready = await roleManager.FindByNameAsync(roleName) != null;
|
||||
|
||||
if (!isAllready)
|
||||
{
|
||||
var serviceRole = new ApplicationRole()
|
||||
{
|
||||
IsGlobalAdmin = true,
|
||||
Name = roleName
|
||||
};
|
||||
var serviceRoleResult = await roleManager.CreateAsync(serviceRole);
|
||||
if (!serviceRoleResult.Succeeded)
|
||||
{
|
||||
throw new RoleExemptions(false, serviceRoleResult.ToString(), serviceRoleResult
|
||||
.Errors.Select(error => new KeyValuePair<string, string>(error.Code, error.Description))
|
||||
.ToDictionary());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
var addRes = await userManager.AddToRoleAsync(user, roleName);
|
||||
|
||||
var topic = new UserChangeMessageType()
|
||||
{
|
||||
UserId = user.Id,
|
||||
Changes = new Dictionary<string, string>()
|
||||
{
|
||||
{"Role", isAllready ? "Allready exist" : "Created"},
|
||||
{"Operation", "Added admin to user"},
|
||||
{"Sucess", addRes.Succeeded.ToString()}
|
||||
}
|
||||
};
|
||||
|
||||
_ = userTopic.Produce(topic);
|
||||
|
||||
return addRes.Succeeded;
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<CreateServiceRoleResult>> CreateServiceRoles(List<RoleModel> serviceRoles,
|
||||
bool forcePrivilages = false)
|
||||
{
|
||||
logger.LogDebug($"Create roles: {serviceRoles.Select(q => q.RoleName).ToList()}");
|
||||
var result = new List<CreateServiceRoleResult>();
|
||||
foreach (var role in serviceRoles)
|
||||
{
|
||||
Dictionary<string, string> errors = new();
|
||||
var roleApp = new ApplicationRole()
|
||||
{
|
||||
IsGlobalAdmin = role.IsGlobalAdmin,
|
||||
Name = role.RoleName
|
||||
};
|
||||
|
||||
foreach (var privilage in role.Privilage ?? throw new Exception("Role is null"))
|
||||
{
|
||||
RolePrivilage? privilageObj;
|
||||
if (forcePrivilages)
|
||||
{
|
||||
privilageObj = await privilegeManager.GetPrivilageByName(privilage);
|
||||
}
|
||||
else
|
||||
{
|
||||
privilageObj = await privilegeManager.GetPrivilageByNameIfDontExistCreateAsync(privilage);
|
||||
}
|
||||
|
||||
if (privilageObj != null)
|
||||
{
|
||||
roleApp.Privilege.Add(privilageObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
errors[privilage] = "Not found";
|
||||
logger.LogWarning($"Privilage {privilage} not found");
|
||||
}
|
||||
}
|
||||
|
||||
var resultRole = await roleManager.CreateAsync(roleApp);
|
||||
if (!resultRole.Succeeded)
|
||||
{
|
||||
_ = resultRole.Errors.Select(errorL => errors[errorL.Code] = errorL.Description);
|
||||
}
|
||||
|
||||
result.Add(new CreateServiceRoleResult(resultRole.Succeeded, errors));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<CreateServicePrivilageResult>> CreateServicesPrivilage(List<string> servicePrivilages)
|
||||
{
|
||||
List<CreateServicePrivilageResult> results = new();
|
||||
foreach (var privilage in servicePrivilages)
|
||||
{
|
||||
var resultsLocal = await privilegeManager.CreatePrivageAsync(privilage);
|
||||
|
||||
logger.LogDebug($"Create new role {privilage} is sucess {resultsLocal.IsSuccessed} with errors {resultsLocal.Errors}");
|
||||
|
||||
results.Add(new CreateServicePrivilageResult(privilage, resultsLocal.IsSuccessed));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user