public void HasReachedLimit_NumberOfRecordsBelowLimit_ReturnsFalse() { //Arrange var records = new[] { new VerificationRecord("pseudo-1", DateTime.UtcNow.AddHours(-23)), new VerificationRecord("pseudo-1", DateTime.UtcNow.AddHours(-21)) }; var config = new VerificationLimitConfig { MaxLimitDuration = TimeSpan.FromHours(24), MaxVerificationsAllowed = 3 }; var automocker = new AutoMocker(); automocker.SetupOptions(config); var target = automocker.CreateInstance <VerificationLimit>(); //Act var result = target.HasReachedLimit(records); //Assert result.Should().BeFalse(); }
public async Task Handle_GivenTokenAlreadyIssuedForJwt_ReturnsAlreadyIssuedErrorResult() { //Arrange var automocker = new AutoMocker(); automocker .SetupOptions(new AnonymousTokensConfig { Enabled = true }); automocker .Setup <IAnonymousTokenIssueRecordRepository, Task <IEnumerable <AnonymousTokenIssueRecord> > >(x => x.RetrieveRecordsJwtToken(It.IsAny <string>())) .Returns <string>(x => Task.FromResult <IEnumerable <AnonymousTokenIssueRecord> >(new[] { new AnonymousTokenIssueRecord(x, DateTime.Now.AddMinutes(10)) })); var target = automocker.CreateInstance <IssueAnonymousToken.Handler>(); //Act var result = await target.Handle(new IssueAnonymousToken.Command { JwtTokenId = "token-a", JwtTokenExpiry = DateTime.Now.AddMinutes(10), RequestData = new AnonymousTokenRequest() }, new CancellationToken()); //Assert using (new AssertionScope()) { result.HasValue.Should().BeFalse(); result.MatchNone(e => e.Should().Be("Anonymous token already issued for the provided JWT-token ID.")); } }
public async Task GetProfileDataAsync_GivenNationalYoungerThanThreshold_GetsUnderagedClaim() { var automocker = new AutoMocker(); automocker .SetupOptions(new AnonymousTokensConfig { Enabled = true, EnabledClientFlags = new[] { "some-flag", "some-other-flag" } }) .SetupOptions(DefaultVerificationLimitConfig); var context = new ProfileDataRequestContext { Subject = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(InternalClaims.NationalIdentifier, "01012068359"), new Claim(InternalClaims.Pseudonym, "pseudo-1") })), RequestedClaimTypes = new[] { JwtClaimTypes.Role, DkSmittestopClaims.Covid19Blocked, DkSmittestopClaims.Covid19Status, DkSmittestopClaims.Covid19LimitCount, DkSmittestopClaims.Covid19LimitDuration, } }; var target = automocker.CreateInstance <ProfileService>(); await target.GetProfileDataAsync(context); context.IssuedClaims.Should().Contain(x => x.Type == JwtClaimTypes.Role && x.Value == VerificationRoles.Underaged); }
public async Task GetProfileDataAsync_AnonymouTokensEnabled_IncludesAnonTokenClaims() { var automocker = new AutoMocker(); automocker .SetupOptions(new AnonymousTokensConfig { Enabled = true, EnabledClientFlags = new[] { "some-flag", "some-other-flag" } }) .SetupOptions(DefaultVerificationLimitConfig);; var context = new ProfileDataRequestContext { Subject = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(InternalClaims.NationalIdentifier, "08089409382"), new Claim(InternalClaims.Pseudonym, "pseudo-1") })), RequestedClaimTypes = new[] { VerificationClaims.AnonymousToken } }; var target = automocker.CreateInstance <ProfileService>(); await target.GetProfileDataAsync(context); context.IssuedClaims.Should().Contain(x => x.Type == VerificationClaims.AnonymousToken && x.Value == "some-flag"); context.IssuedClaims.Should().Contain(x => x.Type == VerificationClaims.AnonymousToken && x.Value == "some-other-flag"); }
public async Task GetProfileDataAsync_AnonymouTokensDisabled_DoesNotIncludeAnonymousTokenClaims() { var automocker = new AutoMocker(); automocker .SetupOptions(new AnonymousTokensConfig { Enabled = false, EnabledClientFlags = new [] { "should-not-be-returned" } }) .SetupOptions(DefaultVerificationLimitConfig); var context = new ProfileDataRequestContext { Subject = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(InternalClaims.NationalIdentifier, "01019098765"), new Claim(InternalClaims.Pseudonym, "pseudo-1") })), RequestedClaimTypes = new[] { VerificationClaims.AnonymousToken } }; var target = automocker.CreateInstance <ProfileService>(); await target.GetProfileDataAsync(context); context.IssuedClaims.Should().NotContain(x => x.Type == VerificationClaims.AnonymousToken); }
public async Task Handle_GivenFeatureNotEnabled_ReturnsNotEnabledErrorResult() { //Arrange var automocker = new AutoMocker(); automocker .SetupOptions(new AnonymousTokensConfig { Enabled = false }); var target = automocker.CreateInstance <IssueAnonymousToken.Handler>(); //Act var result = await target.Handle(new IssueAnonymousToken.Command { JwtTokenId = "token-a", JwtTokenExpiry = DateTime.Now.AddMinutes(10), RequestData = new AnonymousTokenRequest() }, new CancellationToken()); //Assert using (new AssertionScope()) { result.HasValue.Should().BeFalse(); result.MatchNone(e => e.Should().Be("Anonymous tokens are not enabled for this environment.")); } }
public void GetMasterKeyCertificate_CertNotCached_ReturnsFromLocator() { var options = new MsisClientCertLocator.Config { CertId = "key-id" }; var cacheKey = nameof(MsisClientCertLocator); object emptyCachedResult = null; var certificate = CertUtils.GenerateTestEccCert(); var automocker = new AutoMocker(); automocker.SetupOptions(options); automocker .Setup <IMemoryCache, bool>(x => x.TryGetValue(cacheKey, out emptyCachedResult)) .Returns(false); automocker .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry(cacheKey)) .Returns(Mock.Of <ICacheEntry>()); automocker .Setup <ICertificateLocator, Option <X509Certificate2> >(x => x.GetCertificate("key-id")) .Returns(certificate.Some()); var target = automocker.CreateInstance <MsisClientCertLocator>(); var result = target.GetCertificate(); result.Should().Be(certificate); }
public async Task GetActiveSigningKeyPair_GivenRotationAndMasterKeyCert_ReturnsAKeyPairUsableForTokenSigning() { //Arrange var automocker = new AutoMocker(); var masterKey = new byte[256]; object cachedResult = null; automocker .SetupOptions(new AnonymousTokensConfig { KeyRotationEnabled = true, CurveName = "P-256", MasterKeyCertId = "master-key-cert", KeyRotationInterval = TimeSpan.FromDays(3), KeyRotationRollover = TimeSpan.FromDays(4) }); automocker .Setup <IMemoryCache, bool>(x => x.TryGetValue(It.IsAny <string>(), out cachedResult)) .Returns(false); automocker .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry(It.IsAny <string>())) .Returns(Mock.Of <ICacheEntry>()); automocker .Setup <IAnonymousTokenMasterKeyLoader, Task <byte[]> >(x => x.LoadMasterKeyBytes()) .ReturnsAsync(masterKey); var target = automocker.CreateInstance <AnonymousTokenKeyStore>(); //Act var result = await target.GetActiveSigningKeyPair(); //Assert var ecParameters = CustomNamedCurves.GetByOid(X9ObjectIdentifiers.Prime256v1); var initiator = new Initiator(); var init = initiator.Initiate(ecParameters.Curve); var t = init.t; var r = init.r; var P = init.P; var tokenGenerator = new TokenGenerator(); var(Q, c, z) = tokenGenerator.GenerateToken(result.PrivateKey, result.PublicKey, ecParameters, P); var keyDto = result.AsValidationKey().AsKeyDto(); var clientSideEcParameters = CustomNamedCurves.GetByName(keyDto.Crv); // Matches keyDto.Crv == "P-256" var clientSidePublicKeyPoint = clientSideEcParameters.Curve.CreatePoint(new BigInteger(Convert.FromBase64String(keyDto.X)), new BigInteger(Convert.FromBase64String(keyDto.Y))); var W = initiator.RandomiseToken(clientSideEcParameters, clientSidePublicKeyPoint, P, Q, c, z, r); var tokenVerifier = new TokenVerifier(new InMemorySeedStore()); var isVerified = await tokenVerifier.VerifyTokenAsync(result.PrivateKey, ecParameters.Curve, t, W); isVerified.Should().BeTrue(); }
public void GetCertificate_CertNotFound_ThrowsException() { var options = new MsisClientCertLocator.Config { CertId = "key-id" }; var cacheKey = nameof(MsisClientCertLocator); object emptyCachedResult = null; var automocker = new AutoMocker(); automocker.SetupOptions(options); automocker .Setup <IMemoryCache, bool>(x => x.TryGetValue(cacheKey, out emptyCachedResult)) .Returns(false); automocker .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry(cacheKey)) .Returns(Mock.Of <ICacheEntry>()); automocker .Setup <ICertificateLocator, Option <X509Certificate2> >(x => x.GetCertificate("key-id")) .Returns(Option.None <X509Certificate2>()); var target = automocker.CreateInstance <MsisClientCertLocator>(); Assert.Throws <CertificateNotFoundException>(() => target.GetCertificate()); }
public void Config_ReturnsActiveConfig() { //Arrange var config = new VerificationLimitConfig(); var automocker = new AutoMocker(); automocker.SetupOptions(config); var target = automocker.CreateInstance <VerificationLimit>(); //Act var result = target.Config; //Assert result.Should().Be(config); }
public async Task GetActiveSigningKeyPair_GivenRotationAndMasterKeyCert_ReturnsFullKeyPair() { //Arrange var automocker = new AutoMocker(); var masterKey = new byte[256]; object cachedResult = null; automocker .SetupOptions(new AnonymousTokensConfig { KeyRotationEnabled = true, CurveName = "P-256", MasterKeyCertId = "master-key-cert", KeyRotationInterval = TimeSpan.FromDays(3), KeyRotationRollover = TimeSpan.FromDays(4) }); automocker .Setup <IMemoryCache, bool>(x => x.TryGetValue(It.IsAny <string>(), out cachedResult)) .Returns(false); automocker .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry(It.IsAny <string>())) .Returns(Mock.Of <ICacheEntry>()); automocker .Setup <IAnonymousTokenMasterKeyLoader, Task <byte[]> >(x => x.LoadMasterKeyBytes()) .ReturnsAsync(masterKey); var target = automocker.CreateInstance <AnonymousTokenKeyStore>(); //Act var result = await target.GetActiveSigningKeyPair(); //Assert using (new AssertionScope()) { result.Should().NotBeNull(); result.Kid.Should().NotBeNull(); result.PublicKey.Should().NotBeNull(); result.PrivateKey.Should().NotBeNull(); } }
public void LoadMasterKeyBytes_MasterKeyCertNotFound_ThrowsException() { var options = new AnonymousTokensConfig { MasterKeyCertId = "key-id" }; var automocker = new AutoMocker(); automocker.SetupOptions(options); automocker .Setup <ICertificateLocator, Task <Option <X509Certificate2> > >(x => x.GetCertificateAsync("key-id")) .ReturnsAsync(Option.None <X509Certificate2>()); var target = automocker.CreateInstance <AnonymousTokenMasterKeyLoader>(); Assert.ThrowsAsync <AnonymousTokenMasterKeyLoaderException>(() => target.LoadMasterKeyBytes()); }
public async Task GetMasterKeyCertificate_GivenLocalCertificate_ReturnsPrivateKeyBytes() { var automocker = new AutoMocker(); automocker .SetupOptions(new AnonymousTokensConfig { MasterKeyCertId = "F9656C4BFC04586DC844D423148F655088168109" }); automocker.Use <ICertificateLocator>(new LocalCertificateLocator()); var target = automocker.CreateInstance <AnonymousTokenMasterKeyLoader>(); // Some certificates seems to produce the following error: // The CNG key handle being opened was detected to be ephemeral, but the EphemeralKey open option was not specified. (Parameter 'keyHandleOpenOptions') var result = await target.LoadMasterKeyBytes(); result.Should().NotBeNullOrEmpty(); }
public void GetMasterKeyCertificate_NotFoundCertCached_ThrowsException() { var options = new MsisClientCertLocator.Config { CertId = "key-id" }; var cacheKey = nameof(MsisClientCertLocator); object cachedResult = Option.None <X509Certificate2>(); var automocker = new AutoMocker(); automocker.SetupOptions(options); automocker .Setup <IMemoryCache, bool>(x => x.TryGetValue(cacheKey, out cachedResult)) .Returns(true); var target = automocker.CreateInstance <MsisClientCertLocator>(); Assert.Throws <CertificateNotFoundException>(() => target.GetCertificate()); }
public async Task GetActiveValidationKeys_GivenRolloverAndMasterKeyCert_ReturnsKeysIncludingRollover() { //Arrange var automocker = new AutoMocker(); var masterKey = new byte[256]; object cachedResult = null; automocker .SetupOptions(new AnonymousTokensConfig { KeyRotationEnabled = true, CurveName = "P-256", MasterKeyCertId = "master-key-cert", KeyRotationInterval = TimeSpan.FromDays(3), KeyRotationRollover = TimeSpan.FromDays(4) }); automocker .Setup <IMemoryCache, bool>(x => x.TryGetValue(It.IsAny <string>(), out cachedResult)) .Returns(false); automocker .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry(It.IsAny <string>())) .Returns(Mock.Of <ICacheEntry>()); automocker .Setup <IAnonymousTokenMasterKeyLoader, Task <byte[]> >(x => x.LoadMasterKeyBytes()) .ReturnsAsync(masterKey); var target = automocker.CreateInstance <AnonymousTokenKeyStore>(); //Act var result = (await target.GetActiveValidationKeys()).ToList(); //Assert result.Should().HaveCountGreaterThan(1); result.Should().NotContain(c => c.PublicKey == null); }
public async Task GetActiveValidationKeys_GivenNoRotationAndMasterKeyCert_ReturnsOneValidationKey() { //Arrange var automocker = new AutoMocker(); var masterKey = new byte[256]; object cachedResult; automocker .SetupOptions(new AnonymousTokensConfig { KeyRotationEnabled = false, CurveName = "P-256", MasterKeyCertId = "master-key-cert" }); automocker .Setup <IMemoryCache, bool>(x => x.TryGetValue(It.IsAny <string>(), out cachedResult)) .Returns(false); automocker .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry(It.IsAny <string>())) .Returns(Mock.Of <ICacheEntry>()); automocker .Setup <IAnonymousTokenMasterKeyLoader, Task <byte[]> >(x => x.LoadMasterKeyBytes()) .ReturnsAsync(masterKey); var target = automocker.CreateInstance <AnonymousTokenKeyStore>(); //Act var result = (await target.GetActiveValidationKeys()).ToList(); //Assert result.Should().HaveCount(1); var key = result.First(); key.PublicKey.Should().NotBeNull(); }
public void RecordsCutoff_GivenDurationConfig_ReturnsUtcNowMinusDuration() { //Arrange var limitDuration = TimeSpan.FromHours(3); var config = new VerificationLimitConfig { MaxLimitDuration = limitDuration }; var automocker = new AutoMocker(); automocker.SetupOptions(config); var target = automocker.CreateInstance <VerificationLimit>(); //Act var testStart = DateTime.UtcNow; var result = target.RecordsCutoff; var testEnd = DateTime.UtcNow; //Assert result.Should().BeAfter(testStart - limitDuration).And.BeBefore(testEnd - limitDuration); }
public async Task GetMasterKeyCertificate_GivenRsaCertificate_ReturnsPrivateKeyBytes() { var options = new AnonymousTokensConfig { MasterKeyCertId = "key-id" }; var eccCert = CertUtils.GenerateTestRsaCert(); var automocker = new AutoMocker(); automocker.SetupOptions(options); automocker .Setup <ICertificateLocator, Task <Option <X509Certificate2> > >(x => x.GetCertificateAsync("key-id")) .ReturnsAsync(eccCert.Some); var target = automocker.CreateInstance <AnonymousTokenMasterKeyLoader>(); var result = await target.LoadMasterKeyBytes(); result.Should().NotBeNullOrEmpty(); }
public void GetMasterKeyCertificate_CertCached_ReturnsFromCache() { var options = new MsisClientCertLocator.Config { CertId = "key-id" }; var cacheKey = nameof(MsisClientCertLocator); var certificate = CertUtils.GenerateTestEccCert(); object cachedResult = certificate.Some(); var automocker = new AutoMocker(); automocker.SetupOptions(options); automocker .Setup <IMemoryCache, bool>(x => x.TryGetValue(cacheKey, out cachedResult)) .Returns(true); var target = automocker.CreateInstance <MsisClientCertLocator>(); var result = target.GetCertificate(); result.Should().Be(certificate); }
public async Task GetProfileDataAsync_GivenNationalIdentifiedWithPositiveResult_VerifiesStatusAndAddsRequestedClaim() { var automocker = new AutoMocker(); var verificationLimit = new Mock <IVerificationLimit>(); automocker .Setup <IMediator, Task <VerificationResult> >(x => x.Send(It.IsAny <VerifyIdentifiedUser.Command>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new VerificationResult(new PositiveTestResult { PositiveTestDate = DateTime.Today.AddDays(-1).Some() }, new VerificationRecord[0], verificationLimit.Object)); automocker .SetupOptions(new AnonymousTokensConfig { Enabled = false }) .SetupOptions(DefaultVerificationLimitConfig); var context = new ProfileDataRequestContext { Subject = new ClaimsPrincipal(new ClaimsIdentity(new [] { new Claim(InternalClaims.NationalIdentifier, "08089409382"), new Claim(InternalClaims.Pseudonym, "pseudo-1") })), RequestedClaimTypes = new [] { DkSmittestopClaims.Covid19Status } }; var target = automocker.CreateInstance <ProfileService>(); await target.GetProfileDataAsync(context); context.IssuedClaims.Should().Contain(x => x.Type == DkSmittestopClaims.Covid19Status && x.Value == DkSmittestopClaims.StatusValues.Positive); automocker.VerifyAll(); }
public async Task GetProfileDataAsync_GivenPinUser_GetsRejected() { var automocker = new AutoMocker(); automocker .SetupOptions(new AnonymousTokensConfig { Enabled = true, EnabledClientFlags = new [] { "some-flag", "some-other-flag" } }) .SetupOptions(DefaultVerificationLimitConfig); var context = new ProfileDataRequestContext { Subject = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(InternalClaims.PinVerified, "true"), new Claim(InternalClaims.Pseudonym, "pseudo-1") })), RequestedClaimTypes = new[] { DkSmittestopClaims.Covid19Status, DkSmittestopClaims.Covid19Blocked, JwtClaimTypes.Role } }; var target = automocker.CreateInstance <ProfileService>(); await target.GetProfileDataAsync(context); context.IssuedClaims.Should().NotContain(x => x.Type == DkSmittestopClaims.Covid19Status && x.Value == DkSmittestopClaims.StatusValues.Positive); context.IssuedClaims.Should().NotContain(x => x.Type == JwtClaimTypes.Role && x.Value == VerificationRoles.UploadApproved); context.IssuedClaims.Should().Contain(x => x.Type == DkSmittestopClaims.Covid19Blocked && x.Value == "true"); automocker.VerifyAll(); }
public async Task Handle_GivenValidRequest_ShouldCreateResponseClientCanRandomizeAndUseForAuthorization() { //Arrange var config = new AnonymousTokensConfig { Enabled = true, CurveName = "P-256", KeyRotationEnabled = true, //MasterKeyCertId = "<your cert thumprint>", // uncomment to switch to use local certificate KeyRotationInterval = TimeSpan.FromDays(3), KeyRotationRollover = TimeSpan.FromHours(1) }; var masterKey = new byte[256]; var automocker = new AutoMocker(); automocker .SetupOptions(config); automocker .Use <IMemoryCache>(new MemoryCache(new MemoryCacheOptions())); // comment to switch to use local certificate automocker .Setup <IAnonymousTokenMasterKeyLoader, Task <byte[]> >(x => x.LoadMasterKeyBytes()) .ReturnsAsync(masterKey); // uncomment to switch to use local certificate //automocker.Use<ICertificateLocator>(new LocalCertificateLocator()); //automocker.Use<IAnonymousTokenMasterKeyLoader>(automocker.CreateInstance<AnonymousTokenMasterKeyLoader>()); automocker .Use <IAnonymousTokensKeyStore>(automocker.CreateInstance <AnonymousTokenKeyStore>()); automocker .Use <ITokenGenerator>(new TokenGenerator()); automocker .Setup <IAnonymousTokenIssueRecordRepository, Task <IEnumerable <AnonymousTokenIssueRecord> > >(x => x.RetrieveRecordsJwtToken(It.IsAny <string>())) .Returns <string>(x => Task.FromResult(Enumerable.Empty <AnonymousTokenIssueRecord>())); var targetA = automocker.CreateInstance <IssueAnonymousToken.Handler>(); //Act: Part 1 - Issue token var ecParameters = CustomNamedCurves.GetByName("P-256"); var initiator = new Initiator(); var init = initiator.Initiate(ecParameters.Curve); var tokenRequest = new IssueAnonymousToken.Command { JwtTokenId = "token-a", JwtTokenExpiry = DateTime.Now.AddMinutes(10), RequestData = new AnonymousTokenRequest { MaskedPoint = Convert.ToBase64String(init.P.GetEncoded()) } }; var tokenResponse = (await targetA.Handle(tokenRequest, new CancellationToken())).ValueOrFailure(); tokenResponse.Should().NotBeNull(); //Act: Part 2 - Validate, randomize and create auth header var targetB = automocker.CreateInstance <GetAnonymousTokenKeySet.Handler>(); var keysetResponse = await targetB.Handle(new GetAnonymousTokenKeySet.Query(), new CancellationToken()); var rawPublicKey = keysetResponse.Keys.First(x => x.Kid == tokenResponse.Kid); var curve = CustomNamedCurves.GetByName(rawPublicKey.Crv); var publicKey = curve.Curve.CreatePoint( new BigInteger(Convert.FromBase64String(rawPublicKey.X)), new BigInteger(Convert.FromBase64String(rawPublicKey.Y)) ); var signedPoint = ecParameters.Curve.DecodePoint(Convert.FromBase64String(tokenResponse.SignedPoint)); var proofChallenge = new BigInteger(Convert.FromBase64String(tokenResponse.ProofChallenge)); var proofResponse = new BigInteger(Convert.FromBase64String(tokenResponse.ProofResponse)); var randomizedToken = initiator.RandomiseToken(ecParameters, publicKey, init.P, signedPoint, proofChallenge, proofResponse, init.r); var encodedToken = Convert.ToBase64String(randomizedToken.GetEncoded()) + "." + Convert.ToBase64String(init.t) + "." + tokenResponse.Kid; encodedToken.Should().NotBeNullOrEmpty(); }
public async Task Handle_GivenRequestForNewToken_ReturnsAnonymousTokenResponse() { //Arrange var automocker = new AutoMocker(); var curveName = "P-256"; var ecParameters = CustomNamedCurves.GetByName(curveName); var initiator = new Initiator(); var init = initiator.Initiate(ecParameters.Curve); var t = init.t; var r = init.r; var P = init.P; var privateKey = await new InMemoryPrivateKeyStore().GetAsync(); var publicKey = (await new InMemoryPublicKeyStore().GetAsync()).Q; var signingKeyPair = new AnonymousTokenSigningKeypair("some-kid-123", curveName, privateKey, publicKey); var tokenGenerator = new TokenGenerator(); var(expectedSignedPoint, expectedProofChallenge, expectedProofResponse) = tokenGenerator.GenerateToken(privateKey, publicKey, ecParameters, P); var tokenVerifier = new TokenVerifier(new InMemorySeedStore()); var tokenRequest = new IssueAnonymousToken.Command { JwtTokenId = "token-a", JwtTokenExpiry = DateTime.Now.AddMinutes(10), RequestData = new AnonymousTokenRequest { MaskedPoint = Convert.ToBase64String(P.GetEncoded()) } }; automocker .SetupOptions(new AnonymousTokensConfig { Enabled = true }); automocker .Setup <IAnonymousTokenIssueRecordRepository, Task <IEnumerable <AnonymousTokenIssueRecord> > >(x => x.RetrieveRecordsJwtToken(It.IsAny <string>())) .Returns <string>(x => Task.FromResult(Enumerable.Empty <AnonymousTokenIssueRecord>())); automocker .Setup <IAnonymousTokensKeyStore, Task <AnonymousTokenSigningKeypair> >(x => x.GetActiveSigningKeyPair()) .ReturnsAsync(signingKeyPair); automocker .Setup <ITokenGenerator, (ECPoint, BigInteger, BigInteger)>(x => x.GenerateToken(privateKey, publicKey, ecParameters, It.Is <ECPoint>(y => y.Equals(P)))) .Returns((expectedSignedPoint, expectedProofChallenge, expectedProofResponse)); var target = automocker.CreateInstance <IssueAnonymousToken.Handler>(); //Act var result = await target.Handle(tokenRequest, new CancellationToken()); //Assert using (new AssertionScope()) { result.HasValue.Should().BeTrue(); var anonymousTokenResponse = result.ValueOrFailure(); anonymousTokenResponse.Kid.Should().Be("some-kid-123"); var Q = ecParameters.Curve.DecodePoint(Convert.FromBase64String(anonymousTokenResponse.SignedPoint)); var c = new BigInteger(Convert.FromBase64String(anonymousTokenResponse.ProofChallenge)); var z = new BigInteger(Convert.FromBase64String(anonymousTokenResponse.ProofResponse)); Q.Should().Be(expectedSignedPoint); c.Should().Be(expectedProofChallenge); z.Should().Be(expectedProofResponse); var W = initiator.RandomiseToken(ecParameters, publicKey, P, Q, c, z, r); var isVerified = await tokenVerifier.VerifyTokenAsync(privateKey, ecParameters.Curve, t, W); isVerified.Should().BeTrue(); } }