Bladeren bron

unit test for authorizationHubFilter completed

feature/mongo-services-with-interfaces
Dzenis Hadzifejzovic 3 jaren geleden
bovenliggende
commit
6042b77ff1

+ 1
- 0
Backend/Diligent.WebAPI.Business/Interfaces/IAuthenticationService.cs Bestand weergeven

@@ -11,5 +11,6 @@ namespace Diligent.WebAPI.Business.Interfaces
{
Task<bool> ValidateCustomer(string username, string password);
Task<string?> GenerateToken();
Task<Customer> GetByUserName(string username);
}
}

Backend/Diligent.WebAPI.Business/Interfaces/ICustomerService.cs → Backend/Diligent.WebAPI.Business/Interfaces/ICustomerRepository.cs Bestand weergeven

@@ -7,7 +7,7 @@ using System.Threading.Tasks;

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


+ 9
- 8
Backend/Diligent.WebAPI.Business/Services/AuthenticationService.cs Bestand weergeven

@@ -3,28 +3,24 @@ using Diligent.WebAPI.Data.Entities;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace Diligent.WebAPI.Business.Services
{
public class AuthenticationService:IAuthenticationService
public class AuthenticationService : IAuthenticationService
{
private readonly UserManager<Customer> _customerManager;
private readonly IConfiguration _configuration;
private Customer _customer;
public AuthenticationService(UserManager<Customer> customerManager,IConfiguration configuration)
public AuthenticationService(UserManager<Customer> customerManager, IConfiguration configuration)
{
_customerManager = customerManager;
_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);
return (_customer != null && await _customerManager.CheckPasswordAsync
@@ -44,7 +40,7 @@ namespace Diligent.WebAPI.Business.Services
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.
Claim claim = new (ClaimTypes.Name, _customer.UserName);
Claim claim = new(ClaimTypes.Name, _customer.UserName);

var claims = new List<Claim>
{
@@ -70,6 +66,11 @@ namespace Diligent.WebAPI.Business.Services
return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
}

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

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

+ 0
- 26
Backend/Diligent.WebAPI.Business/Services/AuthorizationService.cs Bestand weergeven

@@ -1,26 +0,0 @@
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 Bestand weergeven

@@ -1,21 +1,16 @@
using Diligent.WebAPI.Business.Interfaces;
using Diligent.WebAPI.Data.Entities;
using Microsoft.AspNetCore.Identity;
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 CustomerService : ICustomerService
public class CustomerRepository : ICustomerRepository
{
private readonly UserManager<Customer> _customerManager;

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

+ 1
- 3
Backend/Diligent.WebAPI.Host/Extensions/WebAppBuilder.cs Bestand weergeven

@@ -33,9 +33,7 @@ public static class WebAppBuilder
builder.Services.AddScoped<IRoomRepository, RoomRepository>();
builder.Services.AddScoped<IMongoDBContext, MongoDBContext>();
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.AddSignalR(options =>

+ 4
- 4
Backend/Diligent.WebAPI.Host/Mediator/Authentication/Handlers/LoginUserHandler.cs Bestand weergeven

@@ -13,15 +13,15 @@ namespace Diligent.WebAPI.Host.Mediator.Authentication.Handlers
private readonly UserManager<Customer> _customerManager;
private readonly IAuthenticationService _authenticationService;
private readonly IMapper _mapper;
private readonly ICustomerService _customerService;
private readonly ICustomerRepository _customerRepository;

public LoginUserHandler(UserManager<Customer> customerManager, IAuthenticationService authenticationService,
IMapper mapper, ICustomerService customerService)
IMapper mapper, ICustomerRepository customerService)
{
_customerManager = customerManager;
_authenticationService = authenticationService;
_mapper = mapper;
_customerService = customerService;
_customerRepository = customerService;
}
public async Task<CustomerReadDTO> Handle(LoginUserQuery request, CancellationToken cancellationToken)
{
@@ -29,7 +29,7 @@ namespace Diligent.WebAPI.Host.Mediator.Authentication.Handlers
if (!await _authenticationService.ValidateCustomer(customerLoginDTO.Username, customerLoginDTO.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);
customerReadDTO.Token = await _authenticationService.GenerateToken() ?? "";
customerReadDTO.Roles = (List<string>)await _customerManager.GetRolesAsync(customer);

+ 3
- 3
Backend/Diligent.WebAPI.Host/Mediator/Notifications/Handlers/AddNotificationHandler.cs Bestand weergeven

@@ -8,11 +8,11 @@ namespace Diligent.WebAPI.Host.Mediator.Notifications.Handlers
{
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)

+ 5
- 5
Backend/Diligent.WebAPI.Host/Mediator/Notifications/Handlers/DeleteNotificationHandler.cs Bestand weergeven

@@ -7,16 +7,16 @@ namespace Diligent.WebAPI.Host.Mediator.Notifications.Handlers
{
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)
{
var user = await _customerService.GetCustomerById(request.NotificationData.UserId);
var user = await _customerRepository.GetCustomerById(request.NotificationData.UserId);

if (user == null)
{
@@ -30,7 +30,7 @@ namespace Diligent.WebAPI.Host.Mediator.Notifications.Handlers
throw new NotFoundException();
}

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

return new Unit();
}

+ 4
- 4
Backend/Diligent.WebAPI.Host/Mediator/Notifications/Handlers/GetNotificationsHandler.cs Bestand weergeven

@@ -8,18 +8,18 @@ namespace Diligent.WebAPI.Host.Mediator.Notifications.Handlers
{
public class GetNotificationsHandler : IRequestHandler<GetNotificationsQuery, List<NotificationReadDTO>>
{
private readonly ICustomerService _customerService;
private readonly ICustomerRepository _customerRepository;
private readonly IMapper _mapper;

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

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 Bestand weergeven

@@ -1,8 +1,10 @@
using Diligent.WebAPI.Business.Services;
using Diligent.WebAPI.Business.Interfaces;
using Microsoft.AspNetCore.SignalR;
using Microsoft.IdentityModel.Tokens;
using System.Diagnostics.CodeAnalysis;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Reflection;
using System.Text;
using System.Web.Http;

@@ -12,19 +14,22 @@ namespace Diligent.WebAPI.Host.Middlewares
public class AuthorizationHubFilter : Attribute, IHubFilter
{
public string Roles;
private JwtSecurityToken _token;

public async ValueTask<object> InvokeMethodAsync(
HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next)
{
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
if (!arguments.Any())
return await next(invocationContext);

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

if (roles is null)
throw new NullReferenceException();
@@ -32,7 +37,7 @@ namespace Diligent.WebAPI.Host.Middlewares
// get roles from filter attribute and split roles into an array
var arrayOfRoles = ((AuthorizationHubFilter)roles).Roles.Split(",");

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

if (context is null)
throw new NullReferenceException();
@@ -44,12 +49,12 @@ namespace Diligent.WebAPI.Host.Middlewares
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;
try
{
var authorizationService = context.RequestServices.GetService(typeof(AuthorizationService));
var authorizationService = context.RequestServices.GetService(typeof(IAuthenticationService));
var configuration = context.RequestServices.GetService(typeof(IConfiguration));

if (authorizationService is null || configuration is null)
@@ -61,20 +66,9 @@ namespace Diligent.WebAPI.Host.Middlewares
var audience = jwtSettings["validAudience"];
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)
throw new Exception();
@@ -93,13 +87,14 @@ namespace Diligent.WebAPI.Host.Middlewares

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

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

}
@@ -113,5 +108,46 @@ namespace Diligent.WebAPI.Host.Middlewares
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 Bestand weergeven

@@ -0,0 +1,101 @@
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 Bestand weergeven

@@ -0,0 +1,105 @@
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 Bestand weergeven

@@ -21,7 +21,7 @@ namespace Tests
private IAuthenticationService _authenticationService;
private IMapper _mapper;
private IConfiguration _configuration;
private Mock<ICustomerService> _customerServiceMock;
private Mock<ICustomerRepository> _customerServiceMock;
private Mock<UserManager<Customer>> _userManagerMock;
private readonly Customer _customer = new()
{
@@ -53,7 +53,7 @@ namespace Tests
.AddInMemoryCollection(inMemorySettings)
.Build();
_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);
_authenticationService = new AuthenticationService(_userManagerMock.Object, _configuration);
var configuration = new MapperConfiguration(cfg => cfg.AddProfile(new CustomerMappingProfile()));

+ 181
- 0
Backend/Tests/AuthorizationFilterHubTests.cs Bestand weergeven

@@ -0,0 +1,181 @@
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 Bestand weergeven

@@ -16,18 +16,18 @@ namespace Tests
[TestFixture]
public class NotificationTests
{
private Mock<ICustomerService> _customerServiceMock;
private Mock<ICustomerRepository> _customerRepositoryMock;

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

[Test]
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);

var deleteNotificationCommand = new DeleteNotificationCommand(new NotificationDeleteDTO
@@ -36,7 +36,7 @@ namespace Tests
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>());
}
@@ -44,7 +44,7 @@ namespace Tests
[Test]
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
{
FirstName = "Dzenis",
@@ -70,7 +70,7 @@ namespace Tests
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>());
}
@@ -97,7 +97,7 @@ namespace Tests
}
};

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

var deleteNotificationCommand = new DeleteNotificationCommand(new NotificationDeleteDTO
@@ -106,24 +106,24 @@ namespace Tests
RoomId = "2"
});

var deleteNotificationHandler = new DeleteNotificationHandler(_customerServiceMock.Object);
var deleteNotificationHandler = new DeleteNotificationHandler(_customerRepositoryMock.Object);
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]
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);
var command = new AddNotificationCommand(new NotificationSaveDTO
{
ReceiverId = "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>());
}
@@ -150,17 +150,17 @@ namespace Tests
}
};

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

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

[Test]
@@ -185,17 +185,17 @@ namespace Tests
}
};

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

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

Laden…
Annuleren
Opslaan