コード例 #1
0
        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);
        }
コード例 #8
0
        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());
        }
コード例 #10
0
        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);
        }
コード例 #11
0
        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());
        }
コード例 #15
0
        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);
        }
コード例 #16
0
        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();
        }
コード例 #17
0
        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();
            }
        }