示例#1
0
            public async Task WhenVerificationFails_ReturnsFailureResult()
            {
                A.CallTo(() => _signatureParser.Parse(_httpRequest, _options))
                .Returns(_signature);

                var client = new Client(_signature.KeyId, "Unit test app", new HMACSignatureAlgorithm("s3cr3t", HashAlgorithmName.SHA256), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));

                A.CallTo(() => _clientStore.Get(_signature.KeyId))
                .Returns(client);

                var verificationResultCreator = A.Fake <IVerificationResultCreator>();

                A.CallTo(() => _verificationResultCreatorFactory.Create(client, _signature))
                .Returns(verificationResultCreator);

                var failure = SignatureVerificationFailure.SignatureExpired("Invalid signature.");

                A.CallTo(() => _signatureVerifier.VerifySignature(A <HttpRequestForSigning> ._, A <Signature> ._, A <Client> ._))
                .Returns(failure);

                A.CallTo(() => verificationResultCreator.CreateForFailure(failure))
                .Returns(new RequestSignatureVerificationResultFailure(client, _signature, failure));

                var actual = await _sut.VerifySignature(_httpRequest, _options);

                actual.Should().BeAssignableTo <RequestSignatureVerificationResultFailure>();
                actual.As <RequestSignatureVerificationResultFailure>().IsSuccess.Should().BeFalse();
                actual.As <RequestSignatureVerificationResultFailure>().Failure.Should().Be(failure);
            }
示例#2
0
            public async Task WhenVerificationFails_InvokesConfiguredCallback()
            {
                _httpRequest.Headers["Authorization"] = "tests-scheme abc123";

                var cause         = SignatureVerificationFailure.InvalidSignatureString("Invalid signature");
                var failureResult = new RequestSignatureVerificationResultFailure(
                    new Client(
                        "app1",
                        "Unit test app",
                        new CustomSignatureAlgorithm("test"),
                        TimeSpan.FromMinutes(1),
                        TimeSpan.FromMinutes(1),
                        RequestTargetEscaping.RFC3986),
                    new HttpRequestForVerification(),
                    cause);

                A.CallTo(() => _requestSignatureVerifier.VerifySignature(_httpRequest, _options))
                .Returns(failureResult);

                RequestSignatureVerificationResult resultFromCallback = null;

                _options.OnIdentityVerificationFailed = (request, failure) => {
                    resultFromCallback = failure;
                    return(Task.CompletedTask);
                };

                await _sut.DoAuthenticate();

                resultFromCallback.Should().Be(failureResult);
            }
示例#3
0
        public override SignatureVerificationFailure VerifySync(HttpRequestForSigning signedRequest, Signature signature, Client client)
        {
            var expires = signature.Created.HasValue && signature.Expires.HasValue
                ? signature.Expires.Value - signature.Created.Value
                : new TimeSpan?();

            var signingString = _signingStringComposer.Compose(
                signedRequest,
                signature.Headers,
                signature.Created,
                expires,
                signature.Nonce);

            _logger?.LogDebug("Composed the following signing string for request verification: {0}", signingString);

            byte[] receivedSignature;
            try {
                receivedSignature = _base64Converter.FromBase64(signature.String);
            }
            catch (FormatException ex) {
                return(SignatureVerificationFailure.InvalidSignatureString(ex.Message, ex));
            }

            var isValidSignature = client.SignatureAlgorithm.VerifySignature(signingString, receivedSignature);

            _logger?.LogDebug("The verification of the signature {0}.", isValidSignature ? "succeeded" : "failed");

            if (!isValidSignature)
            {
                return(SignatureVerificationFailure.InvalidSignatureString("The signature string does not match the expected value."));
            }

            return(null);
        }
示例#4
0
        public async Task <RequestSignatureVerificationResult> VerifySignature(IOwinRequest request, SignedHttpRequestAuthenticationOptions options)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            var signatureParsingResult = _signatureParser.Parse(request, options);

            if (signatureParsingResult is SignatureParsingFailure parsingFailure)
            {
                var failure = SignatureVerificationFailure.InvalidSignature(parsingFailure.Description, parsingFailure.Failure);
                _logger?.LogWarning("Request signature verification failed ({0}): {1}", failure.Code, failure.Message);
                return(new RequestSignatureVerificationResultFailure(client: null, requestForVerification: null, failure));
            }

            var parsedSignature = ((SignatureParsingSuccess)signatureParsingResult).Signature;

            var eventTask = options.OnSignatureParsed;

            if (eventTask != null)
            {
                await eventTask.Invoke(request, parsedSignature).ConfigureAwait(continueOnCapturedContext: false);
            }

            var requestForVerification = request.ToHttpRequestForVerification(parsedSignature);

            return(await _verificationOrchestrator.VerifySignature(requestForVerification).ConfigureAwait(continueOnCapturedContext: false));
        }
        public override SignatureVerificationFailure VerifySync(HttpRequestForSigning signedRequest, Signature signature, Client client)
        {
            if (
                signature.Headers.Contains(HeaderName.PredefinedHeaderNames.Created) &&
                AlgorithmNamesThatDoNotAllowCreatedHeader.Contains(client.SignatureAlgorithm.Name, StringComparer.OrdinalIgnoreCase))
            {
                return(SignatureVerificationFailure.InvalidCreatedHeader(
                           $"It is not allowed to take the {HeaderName.PredefinedHeaderNames.Created} into account, when the signature algorithm is {client.SignatureAlgorithm.Name}."));
            }

            if (!signature.Created.HasValue)
            {
                return(SignatureVerificationFailure.InvalidCreatedHeader($"The signature does not contain a value for the {nameof(signature.Created)} property, but it is required."));
            }

            var createdHeaderValues = signedRequest.Headers.GetValues(HeaderName.PredefinedHeaderNames.Created);

            if (createdHeaderValues != StringValues.Empty && signature.Headers.Contains(HeaderName.PredefinedHeaderNames.Created))
            {
                if (!long.TryParse(createdHeaderValues.First(), out var parsedCreatedValue))
                {
                    return(SignatureVerificationFailure.InvalidCreatedHeader(
                               $"The request does not contain a valid value for the {HeaderName.PredefinedHeaderNames.Created} header."));
                }

                var createdHeaderValue = DateTimeOffset.FromUnixTimeSeconds(parsedCreatedValue);
                if (createdHeaderValue != signature.Created.Value)
                {
                    return(SignatureVerificationFailure.InvalidCreatedHeader(
                               $"The signature creation time does not match the value of the {HeaderName.PredefinedHeaderNames.Created} request header."));
                }
            }

            return(null);
        }
            public async Task WhenSignatureVerificationFails_InvokesConfiguredCallback()
            {
                _request.Headers["Authorization"] = "TestScheme abc123";

                var failureResult = new RequestSignatureVerificationResultFailure(
                    new Client("c1", "test", SignatureAlgorithm.CreateForVerification("s3cr3t"), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)),
                    new Signature(),
                    SignatureVerificationFailure.HeaderMissing("A header is missing.", null));

                A.CallTo(() => _options.RequestSignatureVerifier.VerifySignature(
                             A <IOwinRequest> .That.Matches(ConvertedRequest),
                             A <SignedHttpRequestAuthenticationOptions> ._))
                .Returns(failureResult);

                RequestSignatureVerificationResult resultFromCallback = null;

                _options.OnIdentityVerificationFailed = (request, failure) => {
                    resultFromCallback = failure;
                    return(Task.CompletedTask);
                };

                await _method();

                resultFromCallback.Should().Be(failureResult);
            }
        public override SignatureVerificationFailure VerifySync(HttpRequestForVerification signedRequest, Signature signature, Client client)
        {
            var compositionRequest = _stringCompositionRequestFactory.CreateForVerification(signedRequest, client, signature);
            var signingString      = _signingStringComposer.Compose(compositionRequest);

            _logger?.LogDebug("Composed the following signing string for request verification: {0}", signingString);

            byte[] receivedSignature;
            try {
                receivedSignature = _base64Converter.FromBase64(signature.String);
            }
            catch (FormatException ex) {
                return(SignatureVerificationFailure.InvalidSignatureString(ex.Message, ex));
            }

            var isValidSignature = client.SignatureAlgorithm.VerifySignature(signingString, receivedSignature);

            _logger?.LogDebug("The verification of the signature {0}.", isValidSignature ? "succeeded" : "failed");

            if (!isValidSignature)
            {
                return(SignatureVerificationFailure.InvalidSignatureString("The signature string does not match the expected value."));
            }

            return(null);
        }
        public override SignatureVerificationFailure VerifySync(HttpRequestForSigning signedRequest, Signature signature, Client client)
        {
            if (!signature.Headers.Contains(HeaderName.PredefinedHeaderNames.RequestTarget))
            {
                return(SignatureVerificationFailure.HeaderMissing($"The {HeaderName.PredefinedHeaderNames.RequestTarget} header is required to be included in the signature."));
            }

            if (client.SignatureAlgorithm.ShouldIncludeDateHeader() && !signature.Headers.Contains(HeaderName.PredefinedHeaderNames.Date))
            {
                return(SignatureVerificationFailure.HeaderMissing($"The inclusion of the {HeaderName.PredefinedHeaderNames.Date} header is required when using security algorithm '{client.SignatureAlgorithm.Name}'."));
            }

            if (client.SignatureAlgorithm.ShouldIncludeCreatedHeader() && !signature.Headers.Contains(HeaderName.PredefinedHeaderNames.Created))
            {
                return(SignatureVerificationFailure.HeaderMissing($"The inclusion of the {HeaderName.PredefinedHeaderNames.Created} header is required when using security algorithm '{client.SignatureAlgorithm.Name}'."));
            }

            if (client.SignatureAlgorithm.ShouldIncludeExpiresHeader() && !signature.Headers.Contains(HeaderName.PredefinedHeaderNames.Expires))
            {
                return(SignatureVerificationFailure.HeaderMissing($"The inclusion of the {HeaderName.PredefinedHeaderNames.Expires} header is required when using security algorithm '{client.SignatureAlgorithm.Name}'."));
            }

            foreach (var headerName in signature.Headers)
            {
                if (headerName != HeaderName.PredefinedHeaderNames.RequestTarget)
                {
                    if (!signedRequest.Headers.Contains(headerName))
                    {
                        return(SignatureVerificationFailure.HeaderMissing($"The request header {headerName} is missing, but it is required to validate the signature."));
                    }
                }
            }

            return(null);
        }
示例#9
0
        public override SignatureVerificationFailure VerifySync(HttpRequestForSigning signedRequest, Signature signature, Client client)
        {
            if (
                signature.Headers.Contains(HeaderName.PredefinedHeaderNames.Created) &&
                AlgorithmNamesThatDoNotAllowCreatedValue.Any(alg => signature.Algorithm.StartsWith(alg, StringComparison.OrdinalIgnoreCase)))
            {
                return(SignatureVerificationFailure.InvalidCreatedHeader(
                           $"It is not allowed to take the {HeaderName.PredefinedHeaderNames.Created} into account, when the signature algorithm is {signature.Algorithm}."));
            }

            return(null);
        }
        public override SignatureVerificationFailure VerifySync(HttpRequestForSigning signedRequest, Signature signature, Client client)
        {
            if (!signature.Expires.HasValue)
            {
                return(SignatureVerificationFailure.HeaderMissing($"The signature does not contain a value for the {nameof(signature.Expires)} property, but it is required."));
            }

            if (signature.Expires.Value < _systemClock.UtcNow)
            {
                return(SignatureVerificationFailure.SignatureExpired("The signature is expired."));
            }

            return(null);
        }
示例#11
0
        public override SignatureVerificationFailure VerifySync(HttpRequestForVerification signedRequest, Signature signature, Client client)
        {
            if (signature.Headers.Contains(HeaderName.PredefinedHeaderNames.Expires) && !signature.Expires.HasValue)
            {
                return(SignatureVerificationFailure.HeaderMissing($"The signature does not contain a value for the {nameof(signature.Expires)} property, but it is required."));
            }

            if (signature.Expires.HasValue && signature.Expires.Value < _systemClock.UtcNow.Add(-client.ClockSkew))
            {
                return(SignatureVerificationFailure.SignatureExpired("The signature is expired."));
            }

            return(null);
        }
示例#12
0
        public override SignatureVerificationFailure VerifySync(HttpRequestForSigning signedRequest, Signature signature, Client client)
        {
            if (signature.Headers.Contains(HeaderName.PredefinedHeaderNames.Created) && !signature.Created.HasValue)
            {
                return(SignatureVerificationFailure.InvalidCreatedHeader($"The signature does not contain a value for the {nameof(signature.Created)} property, but it is required."));
            }

            if (signature.Created.HasValue && signature.Created.Value > _systemClock.UtcNow.Add(client.ClockSkew))
            {
                return(SignatureVerificationFailure.InvalidCreatedHeader("The signature is not valid yet. Its creation time is in the future."));
            }

            return(null);
        }
        public override SignatureVerificationFailure VerifySync(HttpRequestForVerification signedRequest, Signature signature, Client client)
        {
            // Algorithm parameter is not required
            if (string.IsNullOrEmpty(signature.Algorithm))
            {
                _logger?.LogDebug("Algorithm verification is not required, because there is no algorithm specified in the signature.");
                return(null);
            }

            // hs2019 is always allowed
            if (signature.Algorithm == Signature.DefaultSignatureAlgorithm)
            {
                return(null);
            }

            var algorithmParts = new List <string>();

            if (!string.IsNullOrEmpty(signature.Algorithm))
            {
                var separatorIndex = signature.Algorithm.IndexOf('-');
                if (separatorIndex < 0 || separatorIndex >= signature.Algorithm.Length - 1)
                {
                    algorithmParts.Add(signature.Algorithm);
                }
                else
                {
                    algorithmParts.Add(signature.Algorithm.Substring(0, separatorIndex));
                    algorithmParts.Add(signature.Algorithm.Substring(separatorIndex + 1));
                }
            }

            if (algorithmParts.Count < 2)
            {
                return(SignatureVerificationFailure.InvalidSignatureAlgorithm($"The specified signature algorithm ({signature.Algorithm}) is not supported."));
            }

            if (!SupportedSignatureAlgorithmNames.Contains(algorithmParts[0]))
            {
                return(SignatureVerificationFailure.InvalidSignatureAlgorithm($"The specified signature algorithm ({signature.Algorithm}) is not supported."));
            }

            if (!SupportedHashAlgorithmNames.Contains(algorithmParts[1].ToUpperInvariant()))
            {
                return(SignatureVerificationFailure.InvalidSignatureAlgorithm($"The specified hash algorithm ({algorithmParts[1]}) is not supported."));
            }

            return(null);
        }
        public override SignatureVerificationFailure VerifySync(HttpRequestForSigning signedRequest, Signature signature, Client client)
        {
            // Algorithm parameter is not required
            if (string.IsNullOrEmpty(signature.Algorithm))
            {
                _logger?.LogDebug("Algorithm match verification is not required, because there is no algorithm specified in the signature.");
                return(null);
            }

            // hs2019 is always ok
            if (signature.Algorithm == Signature.DefaultSignatureAlgorithm)
            {
                return(null);
            }

            var algorithmParts = new List <string>();

            if (!string.IsNullOrEmpty(signature.Algorithm))
            {
                var separatorIndex = signature.Algorithm.IndexOf('-');
                if (separatorIndex < 0 || separatorIndex >= signature.Algorithm.Length - 1)
                {
                    algorithmParts.Add(signature.Algorithm);
                }
                else
                {
                    algorithmParts.Add(signature.Algorithm.Substring(0, separatorIndex));
                    algorithmParts.Add(signature.Algorithm.Substring(separatorIndex + 1));
                }
            }

            if (algorithmParts.Count < 2)
            {
                return(SignatureVerificationFailure.InvalidSignatureAlgorithm($"The specified signature algorithm ({signature.Algorithm}) is not supported."));
            }

            if (!client.SignatureAlgorithm.Name.Equals(algorithmParts[0], StringComparison.OrdinalIgnoreCase))
            {
                return(SignatureVerificationFailure.InvalidSignatureAlgorithm($"The specified signature algorithm ({algorithmParts[0]}) does not match the registered signature algorithm for the client with id {client.Id}."));
            }

            if (!client.SignatureAlgorithm.HashAlgorithm.Name.Equals(algorithmParts[1], StringComparison.OrdinalIgnoreCase))
            {
                return(SignatureVerificationFailure.InvalidSignatureAlgorithm($"The specified hash algorithm ({algorithmParts[1]}) does not match the registered hash algorithm for the client with id {client.Id}."));
            }

            return(null);
        }
示例#15
0
        public async Task <RequestSignatureVerificationResult> VerifySignature(HttpRequest request, SignedRequestAuthenticationOptions options)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            Client    client    = null;
            Signature signature = null;

            try {
                signature = _signatureParser.Parse(request);
                client    = await _clientStore.Get(signature.KeyId);

                var requestForSigning = await request.ToRequestForSigning(signature);

                var verificationFailure = await _signatureVerifier.VerifySignature(requestForSigning, signature, client);

                var verificationResultCreator = _verificationResultCreatorFactory.Create(client, signature);
                var result = verificationFailure == null
                    ? verificationResultCreator.CreateForSuccess()
                    : verificationResultCreator.CreateForFailure(verificationFailure);

                if (result is RequestSignatureVerificationResultSuccess success)
                {
                    _logger?.LogDebug($"Request signature verification succeeded for principal {success.Principal?.Identity?.Name ?? "[null]"}.");
                }
                else if (result is RequestSignatureVerificationResultFailure failure)
                {
                    _logger?.LogWarning("Request signature verification failed ({0}): {1}", failure.Failure.Code, failure.Failure.Message);
                }

                return(result);
            }
            catch (InvalidClientException ex) {
                var failure = SignatureVerificationFailure.InvalidClient(ex.Message, ex);
                _logger?.LogWarning("Request signature verification failed ({0}): {1}", failure.Code, failure.Message);
                return(new RequestSignatureVerificationResultFailure(client, signature, failure));
            }
            catch (InvalidSignatureException ex) {
                var failure = SignatureVerificationFailure.InvalidSignature(ex.Message, ex);
                _logger?.LogWarning("Request signature verification failed ({0}): {1}", failure.Code, failure.Message);
                return(new RequestSignatureVerificationResultFailure(client, signature, failure));
            }
        }
示例#16
0
            public async Task WhenVerificationFails_ReturnsFailureResult()
            {
                _httpRequest.Headers["Authorization"] = "tests-scheme abc123";

                var cause = SignatureVerificationFailure.InvalidSignatureString("Invalid signature");

                A.CallTo(() => _requestSignatureVerifier.VerifySignature(_httpRequest, _options))
                .Returns(new RequestSignatureVerificationResultFailure(
                             new Client("app1", "Unit test app", new CustomSignatureAlgorithm("test"), TimeSpan.FromMinutes(1)),
                             new Signature(),
                             cause));

                var actual = await _sut.DoAuthenticate();

                actual.Succeeded.Should().BeFalse();
                actual.Failure.Should().BeAssignableTo <SignatureVerificationException>();
                actual.Failure.Message.Should().Be(cause.ToString());
            }
            public async Task WhenSignatureVerificationFails_ReturnsNull()
            {
                _request.Headers["Authorization"] = "TestScheme abc123";

                var failureResult = new RequestSignatureVerificationResultFailure(
                    new Client("c1", "test", SignatureAlgorithm.CreateForVerification("s3cr3t"), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)),
                    new Signature(),
                    SignatureVerificationFailure.HeaderMissing("A header is missing.", null));

                A.CallTo(() => _options.RequestSignatureVerifier.VerifySignature(
                             A <IOwinRequest> .That.Matches(ConvertedRequest),
                             A <SignedHttpRequestAuthenticationOptions> ._))
                .Returns(failureResult);

                var actual = await _method();

                actual.Should().BeNull();
            }
示例#18
0
        public override async Task <SignatureVerificationFailure> Verify(HttpRequestForSigning signedRequest, Signature signature, Client client)
        {
            if (string.IsNullOrEmpty(signature.Nonce))
            {
                return(null);
            }

            var previousNonce = await _nonceStore.Get(client.Id, signature.Nonce).ConfigureAwait(false);

            if (previousNonce != null && previousNonce.Expiration >= _systemClock.UtcNow)
            {
                return(SignatureVerificationFailure.ReplayedRequest($"The nonce '{previousNonce.Value}' for client {client.Id} ({client.Name}) is not unique and has been used before. It expires at {previousNonce.Expiration:R}."));
            }

            var nonce = new Nonce(
                clientId: client.Id,
                value: signature.Nonce,
                expiration: _systemClock.UtcNow.Add(client.NonceLifetime));
            await _nonceStore.Register(nonce).ConfigureAwait(false);

            return(null);
        }
        public override SignatureVerificationFailure VerifySync(HttpRequestForVerification signedRequest, Signature signature, Client client)
        {
            if (signature.Headers.Contains(HeaderName.PredefinedHeaderNames.RequestTarget) && !signature.Headers.Contains(HeaderName.PredefinedHeaderNames.RequestTarget))
            {
                return(SignatureVerificationFailure.HeaderMissing($"The {HeaderName.PredefinedHeaderNames.RequestTarget} header is required to be included in the signature."));
            }

            foreach (var headerName in signature.Headers)
            {
                var isPresent = PseudoHeaders.Contains(headerName);

                if (!isPresent)
                {
                    isPresent = signedRequest.Headers.Contains(headerName);
                }

                if (!isPresent)
                {
                    return(SignatureVerificationFailure.HeaderMissing($"The request header {headerName} is missing, but it is required to validate the signature."));
                }
            }

            return(null);
        }
示例#20
0
        public override SignatureVerificationFailure VerifySync(HttpRequestForSigning signedRequest, Signature signature, Client client)
        {
            if (signature.Headers.Contains(HeaderName.PredefinedHeaderNames.Digest) &&
                !signedRequest.Headers.Contains(HeaderName.PredefinedHeaderNames.Digest))
            {
                return(SignatureVerificationFailure.HeaderMissing($"The {HeaderName.PredefinedHeaderNames.Digest} header is indicated as part of the signature, but it is not included in the request."));
            }

            if (!signedRequest.Headers.Contains(HeaderName.PredefinedHeaderNames.Digest))
            {
                _logger?.LogDebug("{0} header verification is not required, because it is not present in the request to verify.", HeaderName.PredefinedHeaderNames.Digest);
                return(null);
            }

            if (signedRequest.Body == null)
            {
                return(SignatureVerificationFailure.InvalidDigestHeader($"The {HeaderName.PredefinedHeaderNames.Digest} header verification failed. The request has no body."));
            }

            var digestHeaderValue = signedRequest.Headers.GetValues(HeaderName.PredefinedHeaderNames.Digest).FirstOrDefault();
            var digestParams      = new List <string>();

            if (!string.IsNullOrEmpty(digestHeaderValue))
            {
                var separatorIndex = digestHeaderValue.IndexOf('=');
                if (separatorIndex < 0 || separatorIndex >= digestHeaderValue.Length - 1)
                {
                    digestParams.Add(digestHeaderValue);
                }
                else
                {
                    digestParams.Add(digestHeaderValue.Substring(0, separatorIndex));
                    digestParams.Add(digestHeaderValue.Substring(separatorIndex + 1));
                }
            }

            if (digestParams.Count < 2)
            {
                return(SignatureVerificationFailure.InvalidDigestHeader($"The {HeaderName.PredefinedHeaderNames.Digest} request header is invalid."));
            }

            if (!Constants.DigestHashAlgorithms.TryGetValue(digestParams[0], out var digestAlgorithmName))
            {
                return(SignatureVerificationFailure.InvalidDigestHeader($"The {HeaderName.PredefinedHeaderNames.Digest} algorithm name ({digestParams[0] ?? "[null]"}) is invalid."));
            }

            using (var hashAlgorithm = HashAlgorithmFactory.Create(new HashAlgorithmName(digestAlgorithmName))) {
                if (hashAlgorithm == null)
                {
                    return(SignatureVerificationFailure.InvalidDigestHeader($"The {HeaderName.PredefinedHeaderNames.Digest} algorithm name ({digestParams[0] ?? "[null]"}) is currently not supported."));
                }

                var payloadBytes     = hashAlgorithm.ComputeHash(signedRequest.Body);
                var calculatedDigest = _base64Converter.ToBase64(payloadBytes);
                var receivedDigest   = digestParams[1];

                if (calculatedDigest != receivedDigest)
                {
                    return(SignatureVerificationFailure.InvalidDigestHeader("The digest header verification failed."));
                }
            }

            return(null);
        }
        public async Task <RequestSignatureVerificationResult> VerifySignature(HttpRequest request, SignedRequestAuthenticationOptions options)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            Client    client    = null;
            Signature signature = null;

            try {
                signature = _signatureParser.Parse(request, options);

                var eventTask = options.OnSignatureParsed;
                if (eventTask != null)
                {
                    await eventTask.Invoke(request, signature).ConfigureAwait(false);
                }

                try {
                    signature.Validate();
                }
                catch (ValidationException ex) {
                    throw new InvalidSignatureException(
                              "The signature is invalid. See inner exception.",
                              ex);
                }

                client = await _clientStore.Get(signature.KeyId).ConfigureAwait(false);

                if (client == null)
                {
                    var failure = SignatureVerificationFailure.InvalidClient($"No {nameof(Client)}s with id '{signature.KeyId}' are registered in the server store.");
                    _logger?.LogWarning("Request signature verification failed ({0}): {1}", failure.Code, failure.Message);
                    return(new RequestSignatureVerificationResultFailure(client, signature, failure));
                }

                var requestForSigning = await request.ToRequestForSigning(signature).ConfigureAwait(false);

                var verificationFailure = await _signatureVerifier.VerifySignature(requestForSigning, signature, client).ConfigureAwait(false);

                var verificationResultCreator = _verificationResultCreatorFactory.Create(client, signature);
                var result = verificationFailure == null
                    ? verificationResultCreator.CreateForSuccess()
                    : verificationResultCreator.CreateForFailure(verificationFailure);

                if (result is RequestSignatureVerificationResultSuccess success)
                {
                    _logger?.LogDebug($"Request signature verification succeeded for principal {success.Principal?.Identity?.Name ?? "[null]"}.");
                }
                else if (result is RequestSignatureVerificationResultFailure failure)
                {
                    _logger?.LogWarning("Request signature verification failed ({0}): {1}", failure.Failure.Code, failure.Failure.Message);
                }

                return(result);
            }
            catch (InvalidSignatureException ex) {
                var failure = SignatureVerificationFailure.InvalidSignature(ex.Message, ex);
                _logger?.LogWarning("Request signature verification failed ({0}): {1}", failure.Code, failure.Message);
                return(new RequestSignatureVerificationResultFailure(client, signature, failure));
            }
        }