Merged PR 78: Added roles and groups in authorization result
Added roles and groups in authorization resultmaster
parent
ebb0f4de62
commit
fdb08acd21
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
<Import Project="dependencies.props" />
|
<Import Project="dependencies.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>2.4.1</Version>
|
<Version>2.4.2</Version>
|
||||||
<Authors>Tudor Stanciu</Authors>
|
<Authors>Tudor Stanciu</Authors>
|
||||||
<Company>STA</Company>
|
<Company>STA</Company>
|
||||||
<PackageTags>Tuitio</PackageTags>
|
<PackageTags>Tuitio</PackageTags>
|
||||||
|
|
|
@ -103,4 +103,15 @@
|
||||||
◾ The authentication handler has been updated to skip the token validation if the method from controller is marked with [AllowAnonymous] attribute.
|
◾ The authentication handler has been updated to skip the token validation if the method from controller is marked with [AllowAnonymous] attribute.
|
||||||
</Content>
|
</Content>
|
||||||
</Note>
|
</Note>
|
||||||
|
<Note>
|
||||||
|
<Version>2.4.2</Version>
|
||||||
|
<Date>2023-04-08 01:48</Date>
|
||||||
|
<Content>
|
||||||
|
Added user roles and groups in authorization result
|
||||||
|
◾ The authorization result will contain the user role and group codes. They are very useful for an application because after the token is authorized, the application can directly validate its internal permissions based on roles or groups, without calling another method to obtain this information.
|
||||||
|
◾ In addition to these changes, some refactorings were also made.
|
||||||
|
◾ The token "expires in" information measuring unit was changed from milliseconds to seconds.
|
||||||
|
◾ New versions of nuget packages have been released.
|
||||||
|
</Content>
|
||||||
|
</Note>
|
||||||
</ReleaseNotes>
|
</ReleaseNotes>
|
|
@ -8,7 +8,7 @@ namespace Tuitio.Application.Extensions
|
||||||
{
|
{
|
||||||
internal static class EntityExtensions
|
internal static class EntityExtensions
|
||||||
{
|
{
|
||||||
public static UserRole[] GetUserRoles(this AppUser user)
|
public static IEnumerable<UserRole> GetUserRoles(this AppUser user)
|
||||||
{
|
{
|
||||||
var roles = new List<UserRole>();
|
var roles = new List<UserRole>();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Tuitio.Application.Extensions;
|
|
||||||
using Tuitio.Domain.Entities;
|
|
||||||
using dto = Tuitio.PublishedLanguage.Dto;
|
using dto = Tuitio.PublishedLanguage.Dto;
|
||||||
using models = Tuitio.Domain.Models;
|
using models = Tuitio.Domain.Models;
|
||||||
|
|
||||||
|
@ -13,9 +11,6 @@ namespace Tuitio.Application.Mappings
|
||||||
public MappingProfile()
|
public MappingProfile()
|
||||||
{
|
{
|
||||||
CreateMap<models.Token, dto.AuthorizationResult>();
|
CreateMap<models.Token, dto.AuthorizationResult>();
|
||||||
CreateMap<AppUser, models.Token>()
|
|
||||||
.ForMember(z => z.Claims, src => src.MapFrom(z => z.Claims.ToDictionary()));
|
|
||||||
|
|
||||||
CreateMap<models.Account.LogoutResult, dto.AccountLogoutResult>();
|
CreateMap<models.Account.LogoutResult, dto.AccountLogoutResult>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,5 @@ namespace Tuitio.Application.Services.Abstractions
|
||||||
internal interface ITokenService
|
internal interface ITokenService
|
||||||
{
|
{
|
||||||
Token GenerateToken(AppUser user);
|
Token GenerateToken(AppUser user);
|
||||||
string GenerateTokenRaw(Token token);
|
|
||||||
Token ExtractToken(string tokenRaw);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||||
using Tuitio.Application.Services.Abstractions;
|
using Tuitio.Application.Services.Abstractions;
|
||||||
using Tuitio.Application.Stores;
|
using Tuitio.Application.Stores;
|
||||||
using Tuitio.Domain.Entities;
|
using Tuitio.Domain.Entities;
|
||||||
|
using Tuitio.Domain.Models;
|
||||||
using Tuitio.Domain.Repositories;
|
using Tuitio.Domain.Repositories;
|
||||||
|
|
||||||
namespace Tuitio.Application.Services
|
namespace Tuitio.Application.Services
|
||||||
|
@ -15,14 +16,12 @@ namespace Tuitio.Application.Services
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly ILogger<BehaviorService> _logger;
|
private readonly ILogger<BehaviorService> _logger;
|
||||||
private readonly ITokenService _tokenService;
|
|
||||||
private readonly ITokenStore _securityStore;
|
private readonly ITokenStore _securityStore;
|
||||||
|
|
||||||
public BehaviorService(IServiceProvider serviceProvider, ILogger<BehaviorService> logger, ITokenService tokenService, ITokenStore securityStore)
|
public BehaviorService(IServiceProvider serviceProvider, ILogger<BehaviorService> logger, ITokenStore securityStore)
|
||||||
{
|
{
|
||||||
_serviceProvider=serviceProvider;
|
_serviceProvider=serviceProvider;
|
||||||
_logger=logger;
|
_logger=logger;
|
||||||
_tokenService=tokenService;
|
|
||||||
_securityStore=securityStore;
|
_securityStore=securityStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +43,7 @@ namespace Tuitio.Application.Services
|
||||||
_logger.LogInformation($"BehaviorService: {activeTokens.Length} active tokens were found in database.");
|
_logger.LogInformation($"BehaviorService: {activeTokens.Length} active tokens were found in database.");
|
||||||
foreach (var token in activeTokens)
|
foreach (var token in activeTokens)
|
||||||
{
|
{
|
||||||
var storeToken = _tokenService.ExtractToken(token.Token);
|
var storeToken = Token.Import(token.Token);
|
||||||
_securityStore.Set(token.Token, storeToken);
|
_securityStore.Set(token.Token, storeToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
using AutoMapper;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Tuitio.Application.Extensions;
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Tuitio.Application.Services.Abstractions;
|
using Tuitio.Application.Services.Abstractions;
|
||||||
using Tuitio.Domain.Abstractions;
|
using Tuitio.Domain.Abstractions;
|
||||||
using Tuitio.Domain.Entities;
|
using Tuitio.Domain.Entities;
|
||||||
|
@ -14,63 +11,21 @@ namespace Tuitio.Application.Services
|
||||||
{
|
{
|
||||||
internal class TokenService : ITokenService
|
internal class TokenService : ITokenService
|
||||||
{
|
{
|
||||||
private readonly IMapper _mapper;
|
|
||||||
private readonly IConfigProvider _configProvider;
|
private readonly IConfigProvider _configProvider;
|
||||||
|
|
||||||
public TokenService(IMapper mapper, IConfigProvider configProvider)
|
public TokenService(IConfigProvider configProvider)
|
||||||
{
|
{
|
||||||
_mapper=mapper;
|
|
||||||
_configProvider=configProvider;
|
_configProvider=configProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Token GenerateToken(AppUser user)
|
public Token GenerateToken(AppUser user)
|
||||||
{
|
{
|
||||||
var currentDate = DateTime.UtcNow;
|
var token = new Token(_configProvider.Token.ValidityInMinutes);
|
||||||
var validUntil = currentDate.AddMinutes(_configProvider.Token.ValidityInMinutes);
|
var claims = user.Claims?.ToDictionary();
|
||||||
|
var userRoles = user.GetUserRoles().Select(z => z.UserRoleCode);
|
||||||
var token = _mapper.Map<Token>(user);
|
var userGroups = user.UserGroups?.Select(z => z.UserGroup.UserGroupCode);
|
||||||
token.TokenId = Guid.NewGuid();
|
token.SetUserData(user.UserId, user.UserName, user.FirstName, user.LastName, user.Email, user.SecurityStamp, claims, userRoles, userGroups);
|
||||||
token.LockStamp = Regex.Replace(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), "[/+=]", "");
|
|
||||||
token.CreatedAt = currentDate;
|
|
||||||
token.ExpiresIn = (validUntil - currentDate).TotalMilliseconds;
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GenerateTokenRaw(Token token)
|
|
||||||
{
|
|
||||||
var tokenString = JsonConvert.SerializeObject(token);
|
|
||||||
var tokenBytes = Encoding.UTF8.GetBytes(tokenString);
|
|
||||||
var tokenRaw = Convert.ToBase64String(tokenBytes);
|
|
||||||
return tokenRaw;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Token ExtractToken(string tokenRaw)
|
|
||||||
{
|
|
||||||
var valid = ValidateTokenRaw(tokenRaw);
|
|
||||||
if (!valid)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var tokenBytes = Convert.FromBase64String(tokenRaw);
|
|
||||||
var tokenString = Encoding.UTF8.GetString(tokenBytes);
|
|
||||||
var token = JsonConvert.DeserializeObject<Token>(tokenString);
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ValidateTokenRaw(string tokenRaw)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(tokenRaw))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!StringIsBase64(tokenRaw))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool StringIsBase64(string str)
|
|
||||||
{
|
|
||||||
str = str.Trim();
|
|
||||||
return (str.Length % 4 == 0) && Regex.IsMatch(str, @"^[a-zA-Z0-9+/]*={0,3}$", RegexOptions.None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace Tuitio.Application.Services
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var token = _tokenService.GenerateToken(user);
|
var token = _tokenService.GenerateToken(user);
|
||||||
var raw = _tokenService.GenerateTokenRaw(token);
|
var raw = token.Export();
|
||||||
_securityStore.Set(raw, token);
|
_securityStore.Set(raw, token);
|
||||||
|
|
||||||
await _userRepository.UpdateUserAfterLogin(user, token, raw);
|
await _userRepository.UpdateUserAfterLogin(user, token, raw);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
@ -11,7 +11,6 @@
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(MicrosoftExtensionsPackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -25,6 +25,8 @@ namespace Tuitio.Domain.Data.Repositories
|
||||||
return _dbContext.Users
|
return _dbContext.Users
|
||||||
.Include(z => z.Status)
|
.Include(z => z.Status)
|
||||||
.Include(z => z.Claims)
|
.Include(z => z.Claims)
|
||||||
|
.Include(z => z.UserRoles).ThenInclude(z => z.UserRole)
|
||||||
|
.Include(z => z.UserGroups).ThenInclude(z => z.UserGroup).ThenInclude(z => z.GroupRoles).ThenInclude(z => z.UserRole)
|
||||||
.FirstOrDefaultAsync(z => z.UserName == userName && z.Password == password);
|
.FirstOrDefaultAsync(z => z.UserName == userName && z.Password == password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Tuitio.Domain.Helpers
|
||||||
|
{
|
||||||
|
internal static class DataValidationHelper
|
||||||
|
{
|
||||||
|
public static bool StringIsBase64(string str)
|
||||||
|
{
|
||||||
|
str = str.Trim();
|
||||||
|
return (str.Length % 4 == 0) && Regex.IsMatch(str, @"^[a-zA-Z0-9+/]*={0,3}$", RegexOptions.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,11 @@
|
||||||
// Copyright (c) 2020 Tudor Stanciu
|
// Copyright (c) 2020 Tudor Stanciu
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Tuitio.Domain.Helpers;
|
||||||
|
|
||||||
namespace Tuitio.Domain.Models
|
namespace Tuitio.Domain.Models
|
||||||
{
|
{
|
||||||
|
@ -16,7 +20,68 @@ namespace Tuitio.Domain.Models
|
||||||
public string SecurityStamp { get; set; }
|
public string SecurityStamp { get; set; }
|
||||||
public string LockStamp { get; set; }
|
public string LockStamp { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public double ExpiresIn { get; set; }
|
public long ExpiresIn { get; set; }
|
||||||
public Dictionary<string, string> Claims { get; set; }
|
public Dictionary<string, string> Claims { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public IEnumerable<string> UserRoles { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public IEnumerable<string> UserGroups { get; set; }
|
||||||
|
|
||||||
|
[Obsolete("This constructor is only used for deserialization and should not be used for any other purpose.")]
|
||||||
|
public Token() { }
|
||||||
|
|
||||||
|
public Token(int validityInMinutes)
|
||||||
|
{
|
||||||
|
TokenId = Guid.NewGuid();
|
||||||
|
CreatedAt = DateTime.UtcNow;
|
||||||
|
LockStamp = Regex.Replace(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), "[/+=]", "");
|
||||||
|
ExpiresIn = validityInMinutes * 60; // seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUserData(int userId, string userName, string firstName, string lastName, string email, string securityStamp, Dictionary<string, string> claims, IEnumerable<string> userRoles, IEnumerable<string> userGroups)
|
||||||
|
{
|
||||||
|
UserId = userId;
|
||||||
|
UserName = userName;
|
||||||
|
FirstName = firstName;
|
||||||
|
LastName = lastName;
|
||||||
|
Email = email;
|
||||||
|
SecurityStamp = securityStamp;
|
||||||
|
Claims = claims;
|
||||||
|
UserRoles = userRoles;
|
||||||
|
UserGroups = userGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Export()
|
||||||
|
{
|
||||||
|
var tokenString = JsonConvert.SerializeObject(this);
|
||||||
|
var tokenBytes = Encoding.UTF8.GetBytes(tokenString);
|
||||||
|
var tokenRaw = Convert.ToBase64String(tokenBytes);
|
||||||
|
return tokenRaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Token Import(string tokenRaw)
|
||||||
|
{
|
||||||
|
var valid = ValidateTokenRaw(tokenRaw);
|
||||||
|
if (!valid)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var tokenBytes = Convert.FromBase64String(tokenRaw);
|
||||||
|
var tokenString = Encoding.UTF8.GetString(tokenBytes);
|
||||||
|
var token = JsonConvert.DeserializeObject<Token>(tokenString);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ValidateTokenRaw(string tokenRaw)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(tokenRaw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!DataValidationHelper.StringIsBase64(tokenRaw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -18,7 +18,9 @@ namespace Tuitio.PublishedLanguage.Dto
|
||||||
public string SecurityStamp { get; init; }
|
public string SecurityStamp { get; init; }
|
||||||
public string LockStamp { get; init; }
|
public string LockStamp { get; init; }
|
||||||
public DateTime CreatedAt { get; init; }
|
public DateTime CreatedAt { get; init; }
|
||||||
public double ExpiresIn { get; init; }
|
public long ExpiresIn { get; init; }
|
||||||
public Dictionary<string, string> Claims { get; init; }
|
public Dictionary<string, string> Claims { get; init; }
|
||||||
|
public string[] UserRoles { get; init; }
|
||||||
|
public string[] UserGroups { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
2.2.0 release [2023-03-27 19:20]
|
2.2.1 release [2023-04-08 01:48]
|
||||||
|
◾ Added user roles and groups in authorization result
|
||||||
|
|
||||||
|
2.2.0 release [2023-03-27 19:20]
|
||||||
◾ Added "user-info" method in API
|
◾ Added "user-info" method in API
|
||||||
|
|
||||||
2.1.0 release [2023-03-07 22:17]
|
2.1.0 release [2023-03-07 22:17]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<RepositoryUrl>https://lab.code-rove.com/gitea/tudor.stanciu/tuitio</RepositoryUrl>
|
<RepositoryUrl>https://lab.code-rove.com/gitea/tudor.stanciu/tuitio</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/ReleaseNotes.txt"))</PackageReleaseNotes>
|
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/ReleaseNotes.txt"))</PackageReleaseNotes>
|
||||||
<Version>2.2.0</Version>
|
<Version>2.2.1</Version>
|
||||||
<PackageIcon>logo.png</PackageIcon>
|
<PackageIcon>logo.png</PackageIcon>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Company>Toodle HomeLab</Company>
|
<Company>Toodle HomeLab</Company>
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
2.2.0 release [2023-03-27 19:20]
|
2.2.1 release [2023-04-08 01:48]
|
||||||
|
◾ Added user roles and groups in authorization result
|
||||||
|
|
||||||
|
2.2.0 release [2023-03-27 19:20]
|
||||||
◾ Added "user-info" method in API
|
◾ Added "user-info" method in API
|
||||||
|
|
||||||
2.1.0 release [2023-03-07 22:17]
|
2.1.0 release [2023-03-07 22:17]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<RepositoryUrl>https://lab.code-rove.com/gitea/tudor.stanciu/tuitio</RepositoryUrl>
|
<RepositoryUrl>https://lab.code-rove.com/gitea/tudor.stanciu/tuitio</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/ReleaseNotes.txt"))</PackageReleaseNotes>
|
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/ReleaseNotes.txt"))</PackageReleaseNotes>
|
||||||
<Version>2.2.0</Version>
|
<Version>2.2.1</Version>
|
||||||
<PackageIcon>logo.png</PackageIcon>
|
<PackageIcon>logo.png</PackageIcon>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Company>Toodle HomeLab</Company>
|
<Company>Toodle HomeLab</Company>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Tuitio.Application.CommandHandlers;
|
using Tuitio.Application.CommandHandlers;
|
||||||
using Tuitio.Application.Tests.Fixtures;
|
using Tuitio.Application.Tests.Fixtures;
|
||||||
|
@ -132,6 +133,7 @@ namespace Tuitio.Application.Tests
|
||||||
Assert.NotNull(authorizationResult.Result.LockStamp);
|
Assert.NotNull(authorizationResult.Result.LockStamp);
|
||||||
Assert.True(authorizationResult.Result.TokenId != Guid.Empty, "Token id cannot be an empty guid.");
|
Assert.True(authorizationResult.Result.TokenId != Guid.Empty, "Token id cannot be an empty guid.");
|
||||||
Assert.True(authorizationResult.Result.ExpiresIn > 0, "Token expiration must be a positive number.");
|
Assert.True(authorizationResult.Result.ExpiresIn > 0, "Token expiration must be a positive number.");
|
||||||
|
Assert.True(authorizationResult.Result.UserRoles.Any(), "User must have at least one role.");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
@ -14,6 +14,7 @@ using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Tuitio.Domain.Data;
|
using Tuitio.Domain.Data;
|
||||||
using Tuitio.Domain.Data.DbContexts;
|
using Tuitio.Domain.Data.DbContexts;
|
||||||
|
using Tuitio.Domain.Entities;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Tuitio.Application.Tests.Fixtures
|
namespace Tuitio.Application.Tests.Fixtures
|
||||||
|
@ -136,7 +137,21 @@ namespace Tuitio.Application.Tests.Fixtures
|
||||||
SecurityStamp = "A93650FF-1FC4-4999-BAB6-3EEB174F6892",
|
SecurityStamp = "A93650FF-1FC4-4999-BAB6-3EEB174F6892",
|
||||||
StatusId = 1,
|
StatusId = 1,
|
||||||
CreationDate = DateTime.Now,
|
CreationDate = DateTime.Now,
|
||||||
FailedLoginAttempts = 0
|
FailedLoginAttempts = 0,
|
||||||
|
UserRoles = new UserXUserRole[]
|
||||||
|
{
|
||||||
|
new UserXUserRole()
|
||||||
|
{
|
||||||
|
UserId = 1,
|
||||||
|
UserRoleId = 1,
|
||||||
|
UserRole = new UserRole()
|
||||||
|
{
|
||||||
|
UserRoleId = 1,
|
||||||
|
UserRoleCode = "MOCK_ROLE",
|
||||||
|
UserRoleName = "Mock role"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Text;
|
||||||
using Tuitio.Application.Services.Abstractions;
|
using Tuitio.Application.Services.Abstractions;
|
||||||
using Tuitio.Application.Tests.Fixtures;
|
using Tuitio.Application.Tests.Fixtures;
|
||||||
using Tuitio.Domain.Entities;
|
using Tuitio.Domain.Entities;
|
||||||
|
using Tuitio.Domain.Models;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Tuitio.Application.Tests
|
namespace Tuitio.Application.Tests
|
||||||
|
@ -24,7 +26,7 @@ namespace Tuitio.Application.Tests
|
||||||
{
|
{
|
||||||
var user = new AppUser()
|
var user = new AppUser()
|
||||||
{
|
{
|
||||||
UserId = 0,
|
UserId = 1,
|
||||||
UserName = "tuitio.test",
|
UserName = "tuitio.test",
|
||||||
Password = "9B8769A4A742959A2D0298C36FB70623F2DFACDA8436237DF08D8DFD5B37374C", //pass123
|
Password = "9B8769A4A742959A2D0298C36FB70623F2DFACDA8436237DF08D8DFD5B37374C", //pass123
|
||||||
Email = "tuitio.test@test.test",
|
Email = "tuitio.test@test.test",
|
||||||
|
@ -33,7 +35,21 @@ namespace Tuitio.Application.Tests
|
||||||
StatusId = 1,
|
StatusId = 1,
|
||||||
FailedLoginAttempts = 0,
|
FailedLoginAttempts = 0,
|
||||||
SecurityStamp = "A93650FF-1FC4-4999-BAB6-3EEB174F6892",
|
SecurityStamp = "A93650FF-1FC4-4999-BAB6-3EEB174F6892",
|
||||||
CreationDate = DateTime.Now
|
CreationDate = DateTime.Now,
|
||||||
|
UserRoles = new UserXUserRole[]
|
||||||
|
{
|
||||||
|
new UserXUserRole()
|
||||||
|
{
|
||||||
|
UserId = 1,
|
||||||
|
UserRoleId = 1,
|
||||||
|
UserRole = new UserRole()
|
||||||
|
{
|
||||||
|
UserRoleId = 1,
|
||||||
|
UserRoleCode = "MOCK_ROLE",
|
||||||
|
UserRoleName = "Mock role"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
@ -52,16 +68,22 @@ namespace Tuitio.Application.Tests
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var token = _tokenService.GenerateToken(_userMock);
|
var token = _tokenService.GenerateToken(_userMock);
|
||||||
var raw = _tokenService.GenerateTokenRaw(token);
|
var raw = token.Export();
|
||||||
var extracted = _tokenService.ExtractToken(raw);
|
var extracted = Token.Import(raw);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(token);
|
Assert.NotNull(token);
|
||||||
Assert.NotNull(raw);
|
Assert.NotNull(raw);
|
||||||
Assert.NotNull(extracted);
|
Assert.NotNull(extracted);
|
||||||
|
|
||||||
Assert.True(_userMock.UserName == extracted.UserName);
|
Assert.Equal(_userMock.UserName, extracted.UserName);
|
||||||
Assert.True(_userMock.SecurityStamp == extracted.SecurityStamp);
|
Assert.Equal(_userMock.FirstName, extracted.FirstName);
|
||||||
|
Assert.Equal(_userMock.LastName, extracted.LastName);
|
||||||
|
Assert.Equal(_userMock.Email, extracted.Email);
|
||||||
|
Assert.Equal(_userMock.SecurityStamp, extracted.SecurityStamp);
|
||||||
|
|
||||||
|
var decodedTokenString = Encoding.UTF8.GetString(Convert.FromBase64String(raw));
|
||||||
|
Assert.DoesNotContain("UserRoles", decodedTokenString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,20 @@ namespace Tuitio.Application.Tests
|
||||||
{
|
{
|
||||||
public class TokenStoreTests
|
public class TokenStoreTests
|
||||||
{
|
{
|
||||||
|
private Token GetMockedToken()
|
||||||
|
{
|
||||||
|
var token = new Token(1);
|
||||||
|
token.SetUserData(0, "test.tuitio", "tuitio", "user", "user.tuitio@lab.com", Guid.NewGuid().ToString(), null, null, null);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Set_ShouldSetTokenInStore()
|
public void Set_ShouldSetTokenInStore()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var key = "user001";
|
var key = "user001";
|
||||||
var expected = new Token() { TokenId = Guid.NewGuid(), UserId = 0, UserName = "test.tuitio", CreatedAt = DateTime.Now };
|
var expected = GetMockedToken();
|
||||||
|
|
||||||
var store = new TokenStore();
|
var store = new TokenStore();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
@ -30,7 +38,7 @@ namespace Tuitio.Application.Tests
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var key = "user001";
|
var key = "user001";
|
||||||
var mock = new Token() { TokenId = Guid.NewGuid(), UserId = 0, UserName = "test.tuitio", CreatedAt = DateTime.Now };
|
var mock = GetMockedToken();
|
||||||
var store = new TokenStore();
|
var store = new TokenStore();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
Loading…
Reference in New Issue