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(); } }
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(); }