add u2f tests

This commit is contained in:
Kukks
2020-01-14 11:36:59 +01:00
parent dad3039c06
commit 389695751f
4 changed files with 159 additions and 8 deletions

View File

@@ -0,0 +1,130 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Models.AccountViewModels;
using BTCPayServer.Tests.Logging;
using BTCPayServer.U2F;
using BTCPayServer.U2F.Models;
using Microsoft.AspNetCore.Mvc;
using U2F.Core.Models;
using U2F.Core.Utils;
using Xunit;
using Xunit.Abstractions;
namespace BTCPayServer.Tests
{
public class U2FTests
{
public const int TestTimeout = 60_000;
public U2FTests(ITestOutputHelper helper)
{
Logs.Tester = new XUnitLog(helper) {Name = "Tests"};
Logs.LogProvider = new XUnitLogProvider(helper);
}
[Fact(Timeout = TestTimeout)]
[Trait("Integration", "Integration")]
public async Task U2ftest()
{
using (var tester = ServerTester.Create())
{
await tester.StartAsync();
var user = tester.NewAccount();
user.GrantAccess();
user.RegisterDerivationScheme("BTC");
var accountController = tester.PayTester.GetController<AccountController>();
var manageController = user.GetController<ManageController>();
var mock = new MockU2FService(tester.PayTester.GetService<ApplicationDbContextFactory>());
manageController._u2FService = mock;
accountController._u2FService = mock;
Assert
.IsType<RedirectToActionResult>(await accountController.Login(new LoginViewModel()
{
Email = user.RegisterDetails.Email, Password = user.RegisterDetails.Password
}));
Assert.Empty(Assert.IsType<U2FAuthenticationViewModel>(Assert
.IsType<ViewResult>(await manageController.U2FAuthentication()).Model).Devices);
var addDeviceVM = Assert.IsType<AddU2FDeviceViewModel>(Assert
.IsType<ViewResult>(manageController.AddU2FDevice("testdevice")).Model);
Assert.NotEmpty(addDeviceVM.Challenge);
Assert.Equal(addDeviceVM.Name, "testdevice");
Assert.NotEmpty(addDeviceVM.Version);
Assert.Null(addDeviceVM.DeviceResponse);
var devReg = new DeviceRegistration(Guid.NewGuid().ToByteArray(), Guid.NewGuid().ToByteArray(),
Guid.NewGuid().ToByteArray(), 1);
mock.GetDevReg = () => devReg;
mock.StartedAuthentication = () =>
new StartedAuthentication("chocolate", addDeviceVM.AppId,
devReg.KeyHandle.ByteArrayToBase64String());
addDeviceVM.DeviceResponse = new RegisterResponse("ss",
Convert.ToBase64String(Encoding.UTF8.GetBytes("{typ:'x', challenge: 'fff'}"))).ToJson();
Assert
.IsType<RedirectToActionResult>(await manageController.AddU2FDevice(addDeviceVM));
Assert.Single(Assert.IsType<U2FAuthenticationViewModel>(Assert
.IsType<ViewResult>(await manageController.U2FAuthentication()).Model).Devices);
var secondaryLoginViewModel = Assert.IsType<SecondaryLoginViewModel>(Assert
.IsType<ViewResult>(await accountController.Login(new LoginViewModel()
{
Email = user.RegisterDetails.Email, Password = user.RegisterDetails.Password
})).Model);
Assert.NotNull(secondaryLoginViewModel.LoginWithU2FViewModel);
Assert.Single(secondaryLoginViewModel.LoginWithU2FViewModel.Challenges);
Assert.Equal(secondaryLoginViewModel.LoginWithU2FViewModel.Challenge,
secondaryLoginViewModel.LoginWithU2FViewModel.Challenges.First().challenge);
secondaryLoginViewModel.LoginWithU2FViewModel.DeviceResponse = new AuthenticateResponse(
Convert.ToBase64String(Encoding.UTF8.GetBytes(
"{typ:'x', challenge: '" + secondaryLoginViewModel.LoginWithU2FViewModel.Challenge + "'}")),
"dd", devReg.KeyHandle.ByteArrayToBase64String()).ToJson();
Assert
.IsType<RedirectToActionResult>(
await accountController.LoginWithU2F(secondaryLoginViewModel.LoginWithU2FViewModel));
}
}
public class MockU2FService : U2FService
{
public Func<DeviceRegistration> GetDevReg;
public Func<StartedAuthentication> StartedAuthentication;
public MockU2FService(ApplicationDbContextFactory contextFactory) : base(contextFactory)
{
}
protected override StartedRegistration StartDeviceRegistrationCore(string appId)
{
return global::U2F.Core.Crypto.U2F.StartRegistration(appId);
}
protected override DeviceRegistration FinishRegistrationCore(StartedRegistration startedRegistration,
RegisterResponse registerResponse)
{
return GetDevReg();
}
protected override StartedAuthentication StartAuthenticationCore(string appId, U2FDevice registeredDevice)
{
return StartedAuthentication();
}
protected override void FinishAuthenticationCore(StartedAuthentication authentication,
AuthenticateResponse authenticateResponse, DeviceRegistration registration)
{
}
}
}
}

View File

@@ -39,7 +39,7 @@ namespace BTCPayServer.Controllers
SettingsRepository _SettingsRepository; SettingsRepository _SettingsRepository;
Configuration.BTCPayServerOptions _Options; Configuration.BTCPayServerOptions _Options;
private readonly BTCPayServerEnvironment _btcPayServerEnvironment; private readonly BTCPayServerEnvironment _btcPayServerEnvironment;
private readonly U2FService _u2FService; public U2FService _u2FService;
ILogger _logger; ILogger _logger;
public AccountController( public AccountController(

View File

@@ -32,7 +32,7 @@ namespace BTCPayServer.Controllers
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly UrlEncoder _urlEncoder; private readonly UrlEncoder _urlEncoder;
IWebHostEnvironment _Env; IWebHostEnvironment _Env;
private readonly U2FService _u2FService; public U2FService _u2FService;
private readonly BTCPayServerEnvironment _btcPayServerEnvironment; private readonly BTCPayServerEnvironment _btcPayServerEnvironment;
StoreRepository _StoreRepository; StoreRepository _StoreRepository;

View File

@@ -67,7 +67,7 @@ namespace BTCPayServer.U2F
public ServerRegisterResponse StartDeviceRegistration(string userId, string appId) public ServerRegisterResponse StartDeviceRegistration(string userId, string appId)
{ {
var startedRegistration = global::U2F.Core.Crypto.U2F.StartRegistration(appId); var startedRegistration = StartDeviceRegistrationCore(appId);
UserAuthenticationRequests.AddOrReplace(userId, new List<U2FDeviceAuthenticationRequest>() UserAuthenticationRequests.AddOrReplace(userId, new List<U2FDeviceAuthenticationRequest>()
{ {
@@ -104,7 +104,7 @@ namespace BTCPayServer.U2F
var startedRegistration = var startedRegistration =
new StartedRegistration(authenticationRequest.Challenge, authenticationRequest.AppId); new StartedRegistration(authenticationRequest.Challenge, authenticationRequest.AppId);
var registration = global::U2F.Core.Crypto.U2F.FinishRegistration(startedRegistration, registerResponse); var registration = FinishRegistrationCore(startedRegistration, registerResponse);
UserAuthenticationRequests.AddOrReplace(userId, new List<U2FDeviceAuthenticationRequest>()); UserAuthenticationRequests.AddOrReplace(userId, new List<U2FDeviceAuthenticationRequest>());
using (var context = _contextFactory.CreateContext()) using (var context = _contextFactory.CreateContext())
@@ -174,7 +174,7 @@ namespace BTCPayServer.U2F
{ {
authentication = new StartedAuthentication(challengeAuthenticationRequestMatch.Challenge, authenticationRequest.AppId, authenticationRequest.KeyHandle); authentication = new StartedAuthentication(challengeAuthenticationRequestMatch.Challenge, authenticationRequest.AppId, authenticationRequest.KeyHandle);
} }
global::U2F.Core.Crypto.U2F.FinishAuthentication(authentication, authenticateResponse, registration); FinishAuthenticationCore(authentication, authenticateResponse, registration);
UserAuthenticationRequests.AddOrReplace(userId, new List<U2FDeviceAuthenticationRequest>()); UserAuthenticationRequests.AddOrReplace(userId, new List<U2FDeviceAuthenticationRequest>());
@@ -201,9 +201,7 @@ namespace BTCPayServer.U2F
var serverChallenges = new List<ServerChallenge>(); var serverChallenges = new List<ServerChallenge>();
foreach (var registeredDevice in devices) foreach (var registeredDevice in devices)
{ {
var challenge = global::U2F.Core.Crypto.U2F.StartAuthentication(appId, var challenge = StartAuthenticationCore(appId, registeredDevice);
new DeviceRegistration(registeredDevice.KeyHandle, registeredDevice.PublicKey,
registeredDevice.AttestationCert, (uint)registeredDevice.Counter));
serverChallenges.Add(new ServerChallenge() serverChallenges.Add(new ServerChallenge()
{ {
challenge = challenge.Challenge, challenge = challenge.Challenge,
@@ -226,5 +224,28 @@ namespace BTCPayServer.U2F
return serverChallenges; return serverChallenges;
} }
} }
protected virtual StartedRegistration StartDeviceRegistrationCore(string appId)
{
return global::U2F.Core.Crypto.U2F.StartRegistration(appId);
}
protected virtual DeviceRegistration FinishRegistrationCore(StartedRegistration startedRegistration, RegisterResponse registerResponse)
{
return global::U2F.Core.Crypto.U2F.FinishRegistration(startedRegistration, registerResponse);
}
protected virtual StartedAuthentication StartAuthenticationCore(string appId, U2FDevice registeredDevice)
{
return global::U2F.Core.Crypto.U2F.StartAuthentication(appId,
new DeviceRegistration(registeredDevice.KeyHandle, registeredDevice.PublicKey,
registeredDevice.AttestationCert, (uint)registeredDevice.Counter));
}
protected virtual void FinishAuthenticationCore(StartedAuthentication authentication,
AuthenticateResponse authenticateResponse, DeviceRegistration registration)
{
global::U2F.Core.Crypto.U2F.FinishAuthentication(authentication, authenticateResponse, registration);
}
} }
} }