Selaa lähdekoodia

unit test for authorizationHubFilter completed

feature/mongo-services-with-interfaces
Dzenis Hadzifejzovic 3 vuotta sitten
vanhempi
commit
6042b77ff1

+ 1
- 0
Backend/Diligent.WebAPI.Business/Interfaces/IAuthenticationService.cs Näytä tiedosto

{ {
Task<bool> ValidateCustomer(string username, string password); Task<bool> ValidateCustomer(string username, string password);
Task<string?> GenerateToken(); Task<string?> GenerateToken();
Task<Customer> GetByUserName(string username);
} }
} }

Backend/Diligent.WebAPI.Business/Interfaces/ICustomerService.cs → Backend/Diligent.WebAPI.Business/Interfaces/ICustomerRepository.cs Näytä tiedosto



namespace Diligent.WebAPI.Business.Interfaces namespace Diligent.WebAPI.Business.Interfaces
{ {
public interface ICustomerService
public interface ICustomerRepository
{ {
Task<Customer> GetCustomer(string username); Task<Customer> GetCustomer(string username);



+ 9
- 8
Backend/Diligent.WebAPI.Business/Services/AuthenticationService.cs Näytä tiedosto

using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using System.Threading.Tasks;


namespace Diligent.WebAPI.Business.Services namespace Diligent.WebAPI.Business.Services
{ {
public class AuthenticationService:IAuthenticationService
public class AuthenticationService : IAuthenticationService
{ {
private readonly UserManager<Customer> _customerManager; private readonly UserManager<Customer> _customerManager;
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
private Customer _customer; private Customer _customer;
public AuthenticationService(UserManager<Customer> customerManager,IConfiguration configuration)
public AuthenticationService(UserManager<Customer> customerManager, IConfiguration configuration)
{ {
_customerManager = customerManager; _customerManager = customerManager;
_configuration = configuration; _configuration = configuration;
} }


public async Task<bool> ValidateCustomer(string username,string password)
public async Task<bool> ValidateCustomer(string username, string password)
{ {
_customer = await _customerManager.FindByNameAsync(username); _customer = await _customerManager.FindByNameAsync(username);
return (_customer != null && await _customerManager.CheckPasswordAsync return (_customer != null && await _customerManager.CheckPasswordAsync
private async Task<List<Claim>> GetClaims() private async Task<List<Claim>> GetClaims()
{ {
//method creates a list of claims with the user name inside and all the roles the user belongs to. //method creates a list of claims with the user name inside and all the roles the user belongs to.
Claim claim = new (ClaimTypes.Name, _customer.UserName);
Claim claim = new(ClaimTypes.Name, _customer.UserName);


var claims = new List<Claim> var claims = new List<Claim>
{ {
return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256); return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
} }


public async Task<Customer> GetByUserName(string username)
{
return await _customerManager.FindByNameAsync(username);
}

private JwtSecurityToken GenerateTokenOptions(SigningCredentials private JwtSecurityToken GenerateTokenOptions(SigningCredentials
signingCredentials, List<Claim> claims) signingCredentials, List<Claim> claims)
{ {

+ 0
- 26
Backend/Diligent.WebAPI.Business/Services/AuthorizationService.cs Näytä tiedosto

using Diligent.WebAPI.Business.MongoServices;
using Diligent.WebAPI.Data;
using Diligent.WebAPI.Data.Entities;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Diligent.WebAPI.Business.Services
{
[ExcludeFromCodeCoverage]
public class AuthorizationService : BaseMongo<Customer>
{
public AuthorizationService(IOptions<WebApiDatabaseSettings> webApiDatabaseSettings) :
base(webApiDatabaseSettings, "Customer")
{ }
public async Task<Customer> GetByUserName(string username)
{
return await _mongoCollection.Find(c => c.UserName == username).FirstOrDefaultAsync();
}
}
}

Backend/Diligent.WebAPI.Business/Services/CustomerService.cs → Backend/Diligent.WebAPI.Business/Services/CustomerRepository.cs Näytä tiedosto

using Diligent.WebAPI.Business.Interfaces; using Diligent.WebAPI.Business.Interfaces;
using Diligent.WebAPI.Data.Entities; using Diligent.WebAPI.Data.Entities;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Diligent.WebAPI.Business.Services namespace Diligent.WebAPI.Business.Services
{ {
[ExcludeFromCodeCoverage] [ExcludeFromCodeCoverage]
public class CustomerService : ICustomerService
public class CustomerRepository : ICustomerRepository
{ {
private readonly UserManager<Customer> _customerManager; private readonly UserManager<Customer> _customerManager;


public CustomerService(UserManager<Customer> customerManager)
public CustomerRepository(UserManager<Customer> customerManager)
{ {
_customerManager = customerManager; _customerManager = customerManager;
} }

+ 1
- 3
Backend/Diligent.WebAPI.Host/Extensions/WebAppBuilder.cs Näytä tiedosto

builder.Services.AddScoped<IRoomRepository, RoomRepository>(); builder.Services.AddScoped<IRoomRepository, RoomRepository>();
builder.Services.AddScoped<IMongoDBContext, MongoDBContext>(); builder.Services.AddScoped<IMongoDBContext, MongoDBContext>();
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>(); builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
builder.Services.AddScoped<ICustomerService, CustomerService>();

builder.Services.AddSingleton<AuthorizationService>();
builder.Services.AddScoped<ICustomerRepository, CustomerRepository>();


builder.Services.AddMediatR(Assembly.GetExecutingAssembly()); builder.Services.AddMediatR(Assembly.GetExecutingAssembly());
builder.Services.AddSignalR(options => builder.Services.AddSignalR(options =>

+ 4
- 4
Backend/Diligent.WebAPI.Host/Mediator/Authentication/Handlers/LoginUserHandler.cs Näytä tiedosto

private readonly UserManager<Customer> _customerManager; private readonly UserManager<Customer> _customerManager;
private readonly IAuthenticationService _authenticationService; private readonly IAuthenticationService _authenticationService;
private readonly IMapper _mapper; private readonly IMapper _mapper;
private readonly ICustomerService _customerService;
private readonly ICustomerRepository _customerRepository;


public LoginUserHandler(UserManager<Customer> customerManager, IAuthenticationService authenticationService, public LoginUserHandler(UserManager<Customer> customerManager, IAuthenticationService authenticationService,
IMapper mapper, ICustomerService customerService)
IMapper mapper, ICustomerRepository customerService)
{ {
_customerManager = customerManager; _customerManager = customerManager;
_authenticationService = authenticationService; _authenticationService = authenticationService;
_mapper = mapper; _mapper = mapper;
_customerService = customerService;
_customerRepository = customerService;
} }
public async Task<CustomerReadDTO> Handle(LoginUserQuery request, CancellationToken cancellationToken) public async Task<CustomerReadDTO> Handle(LoginUserQuery request, CancellationToken cancellationToken)
{ {
if (!await _authenticationService.ValidateCustomer(customerLoginDTO.Username, customerLoginDTO.Password)) if (!await _authenticationService.ValidateCustomer(customerLoginDTO.Username, customerLoginDTO.Password))
throw new BadHttpRequestException("Authentication failed.Wrong Username or password"); throw new BadHttpRequestException("Authentication failed.Wrong Username or password");


Customer customer = await _customerService.GetCustomer(customerLoginDTO.Username);
Customer customer = await _customerRepository.GetCustomer(customerLoginDTO.Username);
var customerReadDTO = _mapper.Map<CustomerReadDTO>(customer); var customerReadDTO = _mapper.Map<CustomerReadDTO>(customer);
customerReadDTO.Token = await _authenticationService.GenerateToken() ?? ""; customerReadDTO.Token = await _authenticationService.GenerateToken() ?? "";
customerReadDTO.Roles = (List<string>)await _customerManager.GetRolesAsync(customer); customerReadDTO.Roles = (List<string>)await _customerManager.GetRolesAsync(customer);

+ 3
- 3
Backend/Diligent.WebAPI.Host/Mediator/Notifications/Handlers/AddNotificationHandler.cs Näytä tiedosto

{ {
public class AddNotificationHandler : IRequestHandler<AddNotificationCommand, Unit> public class AddNotificationHandler : IRequestHandler<AddNotificationCommand, Unit>
{ {
private readonly ICustomerService _customerService;
private readonly ICustomerRepository _customerService;


public AddNotificationHandler(ICustomerService customerService)
public AddNotificationHandler(ICustomerRepository customerRepository)
{ {
_customerService = customerService;
_customerService = customerRepository;
} }


public async Task<Unit> Handle(AddNotificationCommand request, CancellationToken cancellationToken) public async Task<Unit> Handle(AddNotificationCommand request, CancellationToken cancellationToken)

+ 5
- 5
Backend/Diligent.WebAPI.Host/Mediator/Notifications/Handlers/DeleteNotificationHandler.cs Näytä tiedosto

{ {
public class DeleteNotificationHandler : IRequestHandler<DeleteNotificationCommand, Unit> public class DeleteNotificationHandler : IRequestHandler<DeleteNotificationCommand, Unit>
{ {
private readonly ICustomerService _customerService;
private readonly ICustomerRepository _customerRepository;


public DeleteNotificationHandler(ICustomerService customerService)
public DeleteNotificationHandler(ICustomerRepository customerRepository)
{ {
_customerService = customerService;
_customerRepository = customerRepository;
} }


public async Task<Unit> Handle(DeleteNotificationCommand request, CancellationToken cancellationToken) public async Task<Unit> Handle(DeleteNotificationCommand request, CancellationToken cancellationToken)
{ {
var user = await _customerService.GetCustomerById(request.NotificationData.UserId);
var user = await _customerRepository.GetCustomerById(request.NotificationData.UserId);


if (user == null) if (user == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
} }


await _customerService.DeleteNotification(user, notification);
await _customerRepository.DeleteNotification(user, notification);


return new Unit(); return new Unit();
} }

+ 4
- 4
Backend/Diligent.WebAPI.Host/Mediator/Notifications/Handlers/GetNotificationsHandler.cs Näytä tiedosto

{ {
public class GetNotificationsHandler : IRequestHandler<GetNotificationsQuery, List<NotificationReadDTO>> public class GetNotificationsHandler : IRequestHandler<GetNotificationsQuery, List<NotificationReadDTO>>
{ {
private readonly ICustomerService _customerService;
private readonly ICustomerRepository _customerRepository;
private readonly IMapper _mapper; private readonly IMapper _mapper;


public GetNotificationsHandler(ICustomerService customerService, IMapper mapper)
public GetNotificationsHandler(ICustomerRepository customerRepository, IMapper mapper)
{ {
_customerService = customerService;
_customerRepository = customerRepository;
_mapper = mapper; _mapper = mapper;
} }


public async Task<List<NotificationReadDTO>> Handle(GetNotificationsQuery request, CancellationToken cancellationToken) public async Task<List<NotificationReadDTO>> Handle(GetNotificationsQuery request, CancellationToken cancellationToken)
{ {
return _mapper.Map<List<NotificationReadDTO>>(await _customerService.ReadNotifications(request.UserId));
return _mapper.Map<List<NotificationReadDTO>>(await _customerRepository.ReadNotifications(request.UserId));
} }
} }
} }

+ 57
- 21
Backend/Diligent.WebAPI.Host/Middlewares/AuthorizationHubFilter.cs Näytä tiedosto

using Diligent.WebAPI.Business.Services;
using Diligent.WebAPI.Business.Interfaces;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using System.Diagnostics.CodeAnalysis;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Net; using System.Net;
using System.Reflection;
using System.Text; using System.Text;
using System.Web.Http; using System.Web.Http;


public class AuthorizationHubFilter : Attribute, IHubFilter public class AuthorizationHubFilter : Attribute, IHubFilter
{ {
public string Roles; public string Roles;
private JwtSecurityToken _token;


public async ValueTask<object> InvokeMethodAsync( public async ValueTask<object> InvokeMethodAsync(
HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next) HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next)
{ {
Type type = typeof(AuthorizationHubFilter); Type type = typeof(AuthorizationHubFilter);
var arguments = Attribute.GetCustomAttributes(invocationContext.HubMethod).Where(k => k.TypeId.ToString() == type.ToString()).ToList();
var arguments = GetCustomAttributes(invocationContext.HubMethod)
.Where(k => k.TypeId.ToString() == type.ToString())
.ToList();


// there is no custom attributes, so the filter does not need to perform authorization // there is no custom attributes, so the filter does not need to perform authorization
if (!arguments.Any()) if (!arguments.Any())
return await next(invocationContext); return await next(invocationContext);


// get filter attribute // get filter attribute
var roles = Attribute.GetCustomAttribute(invocationContext.HubMethod, arguments[0].GetType());
var roles = GetCustomAttribute(invocationContext.HubMethod, arguments[0].GetType());


if (roles is null) if (roles is null)
throw new NullReferenceException(); throw new NullReferenceException();
// get roles from filter attribute and split roles into an array // get roles from filter attribute and split roles into an array
var arrayOfRoles = ((AuthorizationHubFilter)roles).Roles.Split(","); var arrayOfRoles = ((AuthorizationHubFilter)roles).Roles.Split(",");


var context = invocationContext.Context.GetHttpContext();
var context = GetHttpContext(invocationContext);


if (context is null) if (context is null)
throw new NullReferenceException(); throw new NullReferenceException();
return await next(invocationContext); return await next(invocationContext);
} }


private static async Task AttachUserToContext(HttpContext context, string token, string[] roles)
public async Task AttachUserToContext(HttpContext context, string token, string[] roles)
{ {
bool contain = false; bool contain = false;
try try
{ {
var authorizationService = context.RequestServices.GetService(typeof(AuthorizationService));
var authorizationService = context.RequestServices.GetService(typeof(IAuthenticationService));
var configuration = context.RequestServices.GetService(typeof(IConfiguration)); var configuration = context.RequestServices.GetService(typeof(IConfiguration));


if (authorizationService is null || configuration is null) if (authorizationService is null || configuration is null)
var audience = jwtSettings["validAudience"]; var audience = jwtSettings["validAudience"];
var key = Encoding.UTF8.GetBytes(jwtSettings["jwtSecret"]); var key = Encoding.UTF8.GetBytes(jwtSettings["jwtSecret"]);


tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidIssuer = issuer,
ValidAudience = audience,
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
}, out SecurityToken validatedToken);

var jwtToken = (JwtSecurityToken)validatedToken;
var userName = jwtToken.Payload["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"].ToString();
var rl = (jwtToken.Payload["http://schemas.microsoft.com/ws/2008/06/identity/claims/role"]).ToString();
SetToken(tokenHandler, token, audience, issuer, key);
var userName = ReturnTokenPayload(_token, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name");
var rl = ReturnTokenPayload(_token, "http://schemas.microsoft.com/ws/2008/06/identity/claims/role");


if (rl is null) if (rl is null)
throw new Exception(); throw new Exception();


if (!contain) if (!contain)
{ {
contain = true;
throw new Exception(); throw new Exception();
} }


// attach user to context on successful jwt validation // attach user to context on successful jwt validation
if (userName != null) if (userName != null)
{ {
context.Items["User"] = await ((AuthorizationService)authorizationService).GetByUserName(userName);
context.Items["User"] = await ((IAuthenticationService)authorizationService).GetByUserName(userName);
} }


} }
throw new UnauthorizedAccessException(); throw new UnauthorizedAccessException();
} }
} }

[ExcludeFromCodeCoverage]
public new virtual Attribute? GetCustomAttribute(MemberInfo element, Type attributeType)
{
return Attribute.GetCustomAttribute(element, attributeType);
}

[ExcludeFromCodeCoverage]
public new virtual Attribute[] GetCustomAttributes(MemberInfo element)
{
return Attribute.GetCustomAttributes(element);
}

[ExcludeFromCodeCoverage]
public virtual HttpContext? GetHttpContext(HubInvocationContext invocationContext)
{
return invocationContext.Context.GetHttpContext();
}

[ExcludeFromCodeCoverage]
public virtual void SetToken(JwtSecurityTokenHandler tokenHandler, string token, string audience, string issuer, byte[] key)
{
tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidIssuer = issuer,
ValidAudience = audience,
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
}, out SecurityToken validatedToken);

_token = (JwtSecurityToken)validatedToken;
}

[ExcludeFromCodeCoverage]
public virtual string? ReturnTokenPayload(JwtSecurityToken token, string payload)
{
return _token.Payload[payload].ToString();
}
} }
} }

+ 101
- 0
Backend/Tests/AuthenticationHandlerTests.cs Näytä tiedosto

using AutoMapper;
using Diligent.WebAPI.Business.Interfaces;
using Diligent.WebAPI.Data.Entities;
using Diligent.WebAPI.Host.DTOs.Customer;
using Diligent.WebAPI.Host.Mapper;
using Diligent.WebAPI.Host.Mediator.Authentication.Commands;
using Diligent.WebAPI.Host.Mediator.Authentication.Handlers;
using Diligent.WebAPI.Host.Mediator.Authentication.Queries;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Moq;

namespace Tests
{
[TestFixture]
public class AuthenticationHandlerTests
{
private Mock<IAuthenticationService> _authenticationServiceMock;
private IMapper _mapper;
private Mock<ICustomerRepository> _customerServiceMock;
private Mock<UserManager<Customer>> _userManagerMock;
private readonly Customer _customer = new()
{
Id = Guid.NewGuid(),
Email = "user@gmail.com",
FirstName = "User",
LastName = "User",
Notifications = new List<Notification>(),
Roles = new List<Guid> { Guid.NewGuid() },
UserName = "user12"
};
private readonly CustomerCreateDTO _customerCreateDTO = new()
{
Email = "user@gmail.com",
FirstName = "User",
LastName = "User",
Username = "user12"
};

[SetUp]
public void Setup()
{
_authenticationServiceMock = new Mock<IAuthenticationService>();
_customerServiceMock = new Mock<ICustomerRepository>();
_userManagerMock = new Mock<UserManager<Customer>>(Mock.Of<IUserStore<Customer>>(), null, null, null, null, null, null, null, null);
var configuration = new MapperConfiguration(cfg => cfg.AddProfile(new CustomerMappingProfile()));
_mapper = new Mapper(configuration);
}

[Test]
public void LoginUser_UserIsNotAuthenticated_ThrowBadHttpRequestException()
{
_authenticationServiceMock.Setup(a => a.ValidateCustomer(It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(false));
var query = new LoginUserQuery(new CustomerLoginDTO { Username = "user1", Password = "somePassword" });
var handler = new LoginUserHandler(_userManagerMock.Object, _authenticationServiceMock.Object, _mapper, _customerServiceMock.Object);

Assert.That(async () => await handler.Handle(query, new CancellationToken()), Throws.Exception.TypeOf<BadHttpRequestException>());
}
[Test]
public async Task LoginUser_UserIsAuthenticated_ReturnUserObject()
{
var list = new List<string> { "Customer" };
_authenticationServiceMock.Setup(a => a.ValidateCustomer(It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(true));
_authenticationServiceMock.Setup(a => a.GenerateToken()).Returns(Task.FromResult("someToken"));
_customerServiceMock.Setup(c => c.GetCustomer(It.IsAny<string>())).Returns(Task.FromResult(_customer));
_userManagerMock.Setup(u => u.GetRolesAsync(It.IsAny<Customer>())).Returns(Task.FromResult((IList<string>)list));
var query = new LoginUserQuery(new CustomerLoginDTO { Username = "user1", Password = "somePassword" });
var handler = new LoginUserHandler(_userManagerMock.Object, _authenticationServiceMock.Object, _mapper, _customerServiceMock.Object);

var result = await handler.Handle(query, new CancellationToken());

Assert.That(result.Id, Is.EqualTo(_customer.Id.ToString()));
}

[Test]
public void RegisterUser_ErrorWhenCreatingUser_ThrowBadHttpRequestException()
{
_userManagerMock.Setup(u => u.CreateAsync(It.IsAny<Customer>(), It.IsAny<string>())).ReturnsAsync(() => IdentityResult.Failed());
var command = new RegisterUserCommand(_customerCreateDTO);
var handler = new RegisterUserHandler(_userManagerMock.Object, _authenticationServiceMock.Object, _mapper);

Assert.That(() => handler.Handle(command, new CancellationToken()), Throws.Exception.TypeOf<BadHttpRequestException>());
}

[Test]
public async Task RegisterUser_ThereIsNoError_ReturnObject()
{
_userManagerMock.Setup(u => u.CreateAsync(It.IsAny<Customer>(), It.IsAny<string>())).ReturnsAsync(() => IdentityResult.Success);
_userManagerMock.Setup(u => u.AddToRoleAsync(It.IsAny<Customer>(), It.IsAny<string>())).ReturnsAsync(() => IdentityResult.Success);
_authenticationServiceMock.Setup(u => u.ValidateCustomer(It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(true));
_authenticationServiceMock.Setup(u => u.GenerateToken()).Returns(Task.FromResult("dasdada"));
_userManagerMock.Setup(u => u.GetRolesAsync(It.IsAny<Customer>())).Returns(Task.FromResult((IList<string>)new List<string> { "role" }));
var command = new RegisterUserCommand(_customerCreateDTO);
var handler = new RegisterUserHandler(_userManagerMock.Object, _authenticationServiceMock.Object, _mapper);

var result = await handler.Handle(command, new CancellationToken());

Assert.That(result, Is.Not.Null);
}
}
}

+ 105
- 0
Backend/Tests/AuthenticationServiceTests.cs Näytä tiedosto

using AutoMapper;
using Diligent.WebAPI.Business.Interfaces;
using Diligent.WebAPI.Business.Services;
using Diligent.WebAPI.Data.Entities;
using Diligent.WebAPI.Host.Mapper;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Moq;

namespace Tests
{
public class AuthenticationServiceTests
{
private Mock<IAuthenticationService> _authenticationServiceMock;
private IAuthenticationService _authenticationService;
private IConfiguration _configuration;
private Mock<UserManager<Customer>> _userManagerMock;
private readonly Customer _customer = new()
{
Id = Guid.NewGuid(),
Email = "user@gmail.com",
FirstName = "User",
LastName = "User",
Notifications = new List<Notification>(),
Roles = new List<Guid> { Guid.NewGuid() },
UserName = "user12"
};

[SetUp]
public void Setup()
{
var inMemorySettings = new Dictionary<string, string> {
{"JwtSettings:jwtSecret", "Ovo je neka sifra koja treba biti tajna"},
{"JwtSettings:validIssuer", "http://localhost:5116"},
{"JwtSettings:validAudience", "http://localhost:3000"},
};
_configuration = new ConfigurationBuilder()
.AddInMemoryCollection(inMemorySettings)
.Build();
_authenticationServiceMock = new Mock<IAuthenticationService>();
_userManagerMock = new Mock<UserManager<Customer>>(Mock.Of<IUserStore<Customer>>(), null, null, null, null, null, null, null, null);
_authenticationService = new AuthenticationService(_userManagerMock.Object, _configuration);
var configuration = new MapperConfiguration(cfg => cfg.AddProfile(new CustomerMappingProfile()));
}

[Test]
public async Task ValidateCustomer_CustomerIsNull_CustomerIsNotValid()
{
_userManagerMock.Setup(u => u.FindByNameAsync(It.IsAny<string>())).Returns(Task.FromResult<Customer>(null));
await _authenticationServiceMock.Object.ValidateCustomer("dasdas", "dasdasd");

var result = await _authenticationService.ValidateCustomer(It.IsAny<string>(), It.IsAny<string>());

Assert.That(result, Is.False);
}

[Test]
public async Task ValidateCustomer_CustomerIsNotNullAndUserCredentialsAreNotValid_CustomerIsNotValid()
{
_userManagerMock.Setup(u => u.FindByNameAsync(It.IsAny<string>())).Returns(Task.FromResult(_customer));
_userManagerMock.Setup(u => u.CheckPasswordAsync(It.IsAny<Customer>(), It.IsAny<string>())).Returns(Task.FromResult(false));
await _authenticationServiceMock.Object.ValidateCustomer("dasdas", "dasdasd");

var result = await _authenticationService.ValidateCustomer(It.IsAny<string>(), It.IsAny<string>());

Assert.That(result, Is.False);
}

[Test]
public async Task ValidateCustomer_CustomerIsNotNullAndUserCredentialsAreValid_CustomerIsValid()
{
_userManagerMock.Setup(u => u.FindByNameAsync(It.IsAny<string>())).Returns(Task.FromResult(_customer));
_userManagerMock.Setup(u => u.CheckPasswordAsync(It.IsAny<Customer>(), It.IsAny<string>())).Returns(Task.FromResult(true));

var result = await _authenticationService.ValidateCustomer("dasdasd", "dasdasd");

Assert.That(result, Is.True);
}

[Test]
public async Task GenerateToken_UserIsNotValid_ReturnNull()
{
_userManagerMock.Setup(u => u.GetRolesAsync(It.IsAny<Customer>())).ReturnsAsync((IList<string>)new List<string> { "roles" });

var result = await _authenticationService.GenerateToken();

Assert.That(result, Is.Null);
}

[Test]
public async Task GenerateToken_UserIsValid_ReturnToken()
{
_userManagerMock.Setup(u => u.GetRolesAsync(It.IsAny<Customer>())).ReturnsAsync((IList<string>)new List<string> { "roles" });
_userManagerMock.Setup(u => u.FindByNameAsync(It.IsAny<string>())).Returns(Task.FromResult(_customer));
_userManagerMock.Setup(u => u.CheckPasswordAsync(It.IsAny<Customer>(), It.IsAny<string>())).Returns(Task.FromResult(true));
await _authenticationService.ValidateCustomer("dasdas", "dasd"); //user must be first valid and then we generate token for him

var result = await _authenticationService.GenerateToken();

Assert.That(result, Is.Not.Null);
}


}
}

+ 2
- 2
Backend/Tests/AuthenticationTests.cs Näytä tiedosto

private IAuthenticationService _authenticationService; private IAuthenticationService _authenticationService;
private IMapper _mapper; private IMapper _mapper;
private IConfiguration _configuration; private IConfiguration _configuration;
private Mock<ICustomerService> _customerServiceMock;
private Mock<ICustomerRepository> _customerServiceMock;
private Mock<UserManager<Customer>> _userManagerMock; private Mock<UserManager<Customer>> _userManagerMock;
private readonly Customer _customer = new() private readonly Customer _customer = new()
{ {
.AddInMemoryCollection(inMemorySettings) .AddInMemoryCollection(inMemorySettings)
.Build(); .Build();
_authenticationServiceMock = new Mock<IAuthenticationService>(); _authenticationServiceMock = new Mock<IAuthenticationService>();
_customerServiceMock = new Mock<ICustomerService>();
_customerServiceMock = new Mock<ICustomerRepository>();
_userManagerMock = new Mock<UserManager<Customer>>(Mock.Of<IUserStore<Customer>>(), null, null, null, null, null, null, null, null); _userManagerMock = new Mock<UserManager<Customer>>(Mock.Of<IUserStore<Customer>>(), null, null, null, null, null, null, null, null);
_authenticationService = new AuthenticationService(_userManagerMock.Object, _configuration); _authenticationService = new AuthenticationService(_userManagerMock.Object, _configuration);
var configuration = new MapperConfiguration(cfg => cfg.AddProfile(new CustomerMappingProfile())); var configuration = new MapperConfiguration(cfg => cfg.AddProfile(new CustomerMappingProfile()));

+ 181
- 0
Backend/Tests/AuthorizationFilterHubTests.cs Näytä tiedosto

using AutoMapper;
using Diligent.WebAPI.Business.Interfaces;
using Diligent.WebAPI.Business.Services;
using Diligent.WebAPI.Data.Entities;
using Diligent.WebAPI.Host.Mapper;
using Diligent.WebAPI.Host.Middlewares;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Configuration;
using Moq;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Web.Http;

namespace Tests
{
public class AuthorizationHubFilterTests
{
private IAuthenticationService _authenticationService;
private Mock<IAuthenticationService> _authenticationServiceMock;
private IConfiguration _configuration;
private Mock<UserManager<Customer>> _userManagerMock;
private readonly Customer _customer = new()
{
Id = Guid.NewGuid(),
Email = "user@gmail.com",
FirstName = "User",
LastName = "User",
Notifications = new List<Notification>(),
Roles = new List<Guid> { Guid.NewGuid() },
UserName = "user12"
};
private Mock<AuthorizationHubFilter> _authorizationHubFilterMock;
private AuthorizationHubFilter _authorizationHubFilter;
private HubInvocationContext _hubInvocationContext;
private Mock<Func<HubInvocationContext, ValueTask<object>>> _hubInvocationContextFuncMock;
private Mock<HttpContext> _httpContextMock;

[SetUp]
public void Setup()
{
var inMemorySettings = new Dictionary<string, string> {
{"JwtSettings:jwtSecret", "Ovo je neka sifra koja treba biti tajna"},
{"JwtSettings:validIssuer", "http://localhost:5116"},
{"JwtSettings:validAudience", "http://localhost:3000"},
};
_configuration = new ConfigurationBuilder()
.AddInMemoryCollection(inMemorySettings)
.Build();
_userManagerMock = new Mock<UserManager<Customer>>(Mock.Of<IUserStore<Customer>>(), null, null, null, null, null, null, null, null);
_authenticationService = new AuthenticationService(_userManagerMock.Object, _configuration);
_authenticationServiceMock = new Mock<IAuthenticationService>();
var configuration = new MapperConfiguration(cfg => cfg.AddProfile(new CustomerMappingProfile()));

_authorizationHubFilterMock = new Mock<AuthorizationHubFilter>();
_authorizationHubFilter = new AuthorizationHubFilter();
var hubCallerContext = new Mock<HubCallerContext>();
var serviceProvider = new Mock<IServiceProvider>();
var hub = new Mock<Hub>();
var methodInfo = new Mock<MethodInfo>();
_hubInvocationContext = new HubInvocationContext(hubCallerContext.Object, serviceProvider.Object, hub.Object, methodInfo.Object, null);
_hubInvocationContextFuncMock = new Mock<Func<HubInvocationContext, ValueTask<object>>>();
_httpContextMock = new Mock<HttpContext>();
}

[Test]
public async Task InvokeMethodAsync_ThereIsNoCustomAttributes_SkipFurtherExcecutionOfFilter()
{
_authorizationHubFilterMock.Setup(k => k.GetCustomAttributes(It.IsAny<MemberInfo>())).Returns(Array.Empty<Attribute>());

var result = await _authorizationHubFilterMock.Object.InvokeMethodAsync(_hubInvocationContext, _hubInvocationContextFuncMock.Object);

Assert.That(result, Is.Null);
}

[Test]
public void InvokeMethodAsync_ThereIsCustomAttributeButNoRoles_ThrowNullReferenceException()
{
_authorizationHubFilterMock.Setup(k => k.GetCustomAttributes(It.IsAny<MemberInfo>()))
.Returns(new Attribute[1] { new AuthorizationHubFilter() });
_authorizationHubFilterMock.Setup(k => k.GetCustomAttribute(It.IsAny<MemberInfo>(), It.IsAny<Type>())).Returns((Attribute)null);

Assert.That(() => _authorizationHubFilterMock.Object.InvokeMethodAsync(_hubInvocationContext, _hubInvocationContextFuncMock.Object),
Throws.Exception.TypeOf<NullReferenceException>());
}

[Test]
public void InvokeMethodAsync_ThereIsCustomAttributeAndRolesAndHttpContextIsNull_ThrowNullReferenceException()
{
var filter = new AuthorizationHubFilter { Roles = "Customer,Support" };
_authorizationHubFilterMock.Setup(k => k.GetCustomAttributes(It.IsAny<MemberInfo>())).Returns(new Attribute[1] { filter });
_authorizationHubFilterMock.Setup(k => k.GetCustomAttribute(It.IsAny<MemberInfo>(), It.IsAny<Type>())).Returns(filter);
_authorizationHubFilterMock.Setup(k => k.GetHttpContext(It.IsAny<HubInvocationContext>())).Returns((HttpContext)null);

Assert.That(() => _authorizationHubFilterMock.Object.InvokeMethodAsync(_hubInvocationContext, _hubInvocationContextFuncMock.Object),
Throws.Exception.TypeOf<NullReferenceException>());
}

[Test]
public async Task InvokeMethodAsync_ThereIsCustomAttributeAndRolesAndHttpContextIsNotNull_nextIsCalled()
{
var filter = new AuthorizationHubFilter { Roles = "Customer,Support" };
_httpContextMock.Setup(k => k.Request.Query[It.IsAny<string>()]).Returns("someToken");

//Optimization of this tests is to mock AttachToUser function but there is problem because that function is not virtual and if it were a virtual method there would be problems with other tests
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IAuthenticationService))).Returns(_authenticationServiceMock.Object);
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IConfiguration))).Returns(_configuration);
_httpContextMock.Setup(k => k.Items[It.IsAny<string>()]).Returns(Task.CompletedTask);
_authorizationHubFilterMock.Setup(k => k.ReturnTokenPayload(It.IsAny<JwtSecurityToken>(), It.IsAny<string>()))
.Returns("Customer");

_authorizationHubFilterMock.Setup(k => k.GetCustomAttributes(It.IsAny<MemberInfo>())).Returns(new Attribute[1] { filter });
_authorizationHubFilterMock.Setup(k => k.GetCustomAttribute(It.IsAny<MemberInfo>(), It.IsAny<Type>())).Returns(filter);
_authorizationHubFilterMock.Setup(k => k.GetHttpContext(It.IsAny<HubInvocationContext>())).Returns(_httpContextMock.Object);

await _authorizationHubFilterMock.Object.InvokeMethodAsync(_hubInvocationContext, _hubInvocationContextFuncMock.Object);

_hubInvocationContextFuncMock.Verify(k => k.Invoke(It.IsAny<HubInvocationContext>()), Times.Once);
}
[Test]
public void AttachUserToContext_AuthorizationServiceIsNull_ThrowHttpResponseException()
{
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IAuthenticationService))).Returns(null);
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IConfiguration))).Returns(_configuration);

Assert.That(() => _authorizationHubFilter.AttachUserToContext(_httpContextMock.Object, "1", new string[1] { "1" }),
Throws.Exception.TypeOf<HttpResponseException>());
}

[Test]
public void AttachUserToContext_IConfigurationIsNull_ThrowHttpResponseException()
{
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IAuthenticationService))).Returns(_authenticationService);
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IConfiguration))).Returns(null);

Assert.That(() => _authorizationHubFilter.AttachUserToContext(_httpContextMock.Object, "1", new string[1] { "1" }),
Throws.Exception.TypeOf<HttpResponseException>());
}

[Test]
public void AttachUserToContext_ThereAreNoRolesForUser_ThrowHttpResponseException()
{
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IAuthenticationService))).Returns(_authenticationService);
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IConfiguration))).Returns(_configuration);
//_authorizationHubFilterMock.Setup(k => k.Proba(It.IsAny<JwtSecurityTokenHandler>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<byte[]>()));
_authorizationHubFilterMock.Setup(k => k.ReturnTokenPayload(It.IsAny<JwtSecurityToken>(), It.IsAny<string>()))
.Returns((string)null);

Assert.That(() => _authorizationHubFilterMock.Object.AttachUserToContext(_httpContextMock.Object, "1", new string[1] { "1" }),
Throws.Exception.TypeOf<HttpResponseException>());
}

[Test]
public void AttachUserToContext_RolesIsNotNullButUserIsNotAuthorized_ThrowUnauthorizedAccessException()
{
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IAuthenticationService))).Returns(_authenticationService);
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IConfiguration))).Returns(_configuration);
_authorizationHubFilterMock.Setup(k => k.ReturnTokenPayload(It.IsAny<JwtSecurityToken>(), It.IsAny<string>()))
.Returns("Support");

Assert.That(() => _authorizationHubFilterMock.Object.AttachUserToContext(_httpContextMock.Object, "1", new string[1] { "Customer" }),
Throws.Exception.TypeOf<UnauthorizedAccessException>());
}

[Test]
public async Task AttachUserToContext_RolesIsNotNullAndUserIAuthorized_GetByUsernameIsCalled()
{
_authenticationServiceMock.Setup(k => k.GetByUserName(It.IsAny<string>())).Returns(Task.FromResult(_customer));
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IAuthenticationService))).Returns(_authenticationServiceMock.Object);
_httpContextMock.Setup(k => k.RequestServices.GetService(typeof(IConfiguration))).Returns(_configuration);
_httpContextMock.Setup(k => k.Items[It.IsAny<string>()]).Returns(Task.CompletedTask);
_authorizationHubFilterMock.Setup(k => k.ReturnTokenPayload(It.IsAny<JwtSecurityToken>(), It.IsAny<string>()))
.Returns("Customer");

await _authorizationHubFilterMock.Object.AttachUserToContext(_httpContextMock.Object, "1", new string[1] { "Customer" });

_authenticationServiceMock.Verify(k => k.GetByUserName(It.IsAny<string>()), Times.Once);
}
}
}

+ 17
- 17
Backend/Tests/NotificationTests.cs Näytä tiedosto

[TestFixture] [TestFixture]
public class NotificationTests public class NotificationTests
{ {
private Mock<ICustomerService> _customerServiceMock;
private Mock<ICustomerRepository> _customerRepositoryMock;


[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_customerServiceMock = new Mock<ICustomerService>();
_customerRepositoryMock = new Mock<ICustomerRepository>();
} }


[Test] [Test]
public async Task DeleteNotification_CustomerIsNull_ThrowNotFoundException() public async Task DeleteNotification_CustomerIsNull_ThrowNotFoundException()
{ {
_customerServiceMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
_customerRepositoryMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
.ReturnsAsync((Customer)null); .ReturnsAsync((Customer)null);


var deleteNotificationCommand = new DeleteNotificationCommand(new NotificationDeleteDTO var deleteNotificationCommand = new DeleteNotificationCommand(new NotificationDeleteDTO
RoomId = "1" RoomId = "1"
}); });


var deleteNotificationHandler = new DeleteNotificationHandler(_customerServiceMock.Object);
var deleteNotificationHandler = new DeleteNotificationHandler(_customerRepositoryMock.Object);


Assert.That(async () => await deleteNotificationHandler.Handle(deleteNotificationCommand, new CancellationToken()), Throws.Exception.TypeOf<NotFoundException>()); Assert.That(async () => await deleteNotificationHandler.Handle(deleteNotificationCommand, new CancellationToken()), Throws.Exception.TypeOf<NotFoundException>());
} }
[Test] [Test]
public async Task DeleteNotification_UserNotificationIsNull_ThrowNotFoundException() public async Task DeleteNotification_UserNotificationIsNull_ThrowNotFoundException()
{ {
_customerServiceMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
_customerRepositoryMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
.ReturnsAsync(new Customer .ReturnsAsync(new Customer
{ {
FirstName = "Dzenis", FirstName = "Dzenis",
RoomId = "3" RoomId = "3"
}); });


var deleteNotificationHandler = new DeleteNotificationHandler(_customerServiceMock.Object);
var deleteNotificationHandler = new DeleteNotificationHandler(_customerRepositoryMock.Object);


Assert.That(async () => await deleteNotificationHandler.Handle(deleteNotificationCommand, new CancellationToken()), Throws.Exception.TypeOf<NotFoundException>()); Assert.That(async () => await deleteNotificationHandler.Handle(deleteNotificationCommand, new CancellationToken()), Throws.Exception.TypeOf<NotFoundException>());
} }
} }
}; };


_customerServiceMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
_customerRepositoryMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
.ReturnsAsync(customer); .ReturnsAsync(customer);


var deleteNotificationCommand = new DeleteNotificationCommand(new NotificationDeleteDTO var deleteNotificationCommand = new DeleteNotificationCommand(new NotificationDeleteDTO
RoomId = "2" RoomId = "2"
}); });


var deleteNotificationHandler = new DeleteNotificationHandler(_customerServiceMock.Object);
var deleteNotificationHandler = new DeleteNotificationHandler(_customerRepositoryMock.Object);
await deleteNotificationHandler.Handle(deleteNotificationCommand, new CancellationToken()); await deleteNotificationHandler.Handle(deleteNotificationCommand, new CancellationToken());


_customerServiceMock.Verify(mock => mock.DeleteNotification(customer, customer.Notifications[1]));
_customerRepositoryMock.Verify(mock => mock.DeleteNotification(customer, customer.Notifications[1]));


} }


[Test] [Test]
public async Task AddNotification_ReceiverIsNull_ThrowsNotFoundException() public async Task AddNotification_ReceiverIsNull_ThrowsNotFoundException()
{ {
_customerServiceMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
_customerRepositoryMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
.ReturnsAsync((Customer)null); .ReturnsAsync((Customer)null);
var command = new AddNotificationCommand(new NotificationSaveDTO var command = new AddNotificationCommand(new NotificationSaveDTO
{ {
ReceiverId = "1", ReceiverId = "1",
RoomId = "1" RoomId = "1"
}); });
var handler = new AddNotificationHandler(_customerServiceMock.Object);
var handler = new AddNotificationHandler(_customerRepositoryMock.Object);


Assert.That(async () => await handler.Handle(command, new CancellationToken()), Throws.Exception.TypeOf<NotFoundException>()); Assert.That(async () => await handler.Handle(command, new CancellationToken()), Throws.Exception.TypeOf<NotFoundException>());
} }
} }
}; };


_customerServiceMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
_customerRepositoryMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
.ReturnsAsync(customer); .ReturnsAsync(customer);
var command = new AddNotificationCommand(new NotificationSaveDTO var command = new AddNotificationCommand(new NotificationSaveDTO
{ {
ReceiverId = "1", ReceiverId = "1",
RoomId = "3" RoomId = "3"
}); });
var handler = new AddNotificationHandler(_customerServiceMock.Object);
var handler = new AddNotificationHandler(_customerRepositoryMock.Object);
await handler.Handle(command, new CancellationToken()); await handler.Handle(command, new CancellationToken());


_customerServiceMock.Verify(mock => mock.AddNotification(customer));
_customerRepositoryMock.Verify(mock => mock.AddNotification(customer));
} }


[Test] [Test]
} }
}; };


_customerServiceMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
_customerRepositoryMock.Setup(x => x.GetCustomerById(It.IsAny<string>()))
.ReturnsAsync(customer); .ReturnsAsync(customer);
var command = new AddNotificationCommand(new NotificationSaveDTO var command = new AddNotificationCommand(new NotificationSaveDTO
{ {
ReceiverId = "1", ReceiverId = "1",
RoomId = "2" RoomId = "2"
}); });
var handler = new AddNotificationHandler(_customerServiceMock.Object);
var handler = new AddNotificationHandler(_customerRepositoryMock.Object);
await handler.Handle(command, new CancellationToken()); await handler.Handle(command, new CancellationToken());


_customerServiceMock.Verify(mock => mock.AddNotification(customer));
_customerRepositoryMock.Verify(mock => mock.AddNotification(customer));
} }
} }
} }

Loading…
Peruuta
Tallenna