internal static HttpRequestForVerification ToHttpRequestForVerification(this IOwinRequest owinRequest, Signature signature)
        {
            if (owinRequest == null)
            {
                return(null);
            }
            if (signature == null)
            {
                throw new ArgumentNullException(nameof(signature));
            }

            var request = new HttpRequestForVerification {
                Method     = new HttpMethod(owinRequest.Method),
                RequestUri = owinRequest.Uri,
                Signature  = signature
            };

            foreach (var header in owinRequest.Headers)
            {
                request.Headers[header.Key] = header.Value;
            }

            if (ShouldReadBody(owinRequest, signature) && owinRequest.Body != null)
            {
                using (var memoryStream = new MemoryStream()) {
                    owinRequest.Body.CopyTo(memoryStream);
                    request.Body = memoryStream.ToArray();

                    owinRequest.Body?.Dispose();
                    owinRequest.Body = new MemoryStream(request.Body);
                }
            }

            return(request);
        }
        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 async Task VerifiesUsingSignatureManipulatedByCallback()
            {
                A.CallTo(() => _signatureParser.Parse(_httpRequest, _options))
                .Returns(new SignatureParsingSuccess(_requestForVerification.Signature));

                HttpRequestForVerification intercepted = null;

                A.CallTo(() => _requestSignatureVerificationOrchestrator.VerifySignature(A <HttpRequestForVerification> ._))
                .Invokes(call => intercepted = call.GetArgument <HttpRequestForVerification>(0))
                .Returns(_verificationSuccessResult);

                _options.OnSignatureParsed = (request, sig) => {
                    sig.KeyId = new KeyId("xyz");
                    return(Task.CompletedTask);
                };

                await _sut.VerifySignature(_httpRequest, _options);

                var expectedSignature = (Signature)_requestForVerification.Signature.Clone();

                expectedSignature.KeyId = new KeyId("xyz");
                intercepted.Should().NotBeNull();
                intercepted.Signature.Should().NotBeNull();
                intercepted.Signature.Should().BeEquivalentTo(expectedSignature);
            }
Exemple #4
0
 public Verify()
 {
     _signature     = (Signature)TestModels.Signature.Clone();
     _signedRequest = (HttpRequestForVerification)TestModels.RequestForVerification.Clone();
     _client        = (Client)TestModels.Client.Clone();
     _method        = (request, signature, client) => _sut.Verify(request, signature, client);
 }
Exemple #5
0
            public Verify()
            {
                _signature     = (Signature)TestModels.Signature.Clone();
                _signedRequest = (HttpRequestForVerification)TestModels.RequestForVerification.Clone();
                _client        = (Client)TestModels.Client.Clone();
                _method        = (request, signature, client) => _sut.Verify(request, signature, client);

                _now = new DateTimeOffset(2020, 3, 20, 11, 52, 23, TimeSpan.Zero);
                A.CallTo(() => _systemClock.UtcNow).Returns(_now);
            }
            public Verify()
            {
                _signature     = (Signature)TestModels.Signature.Clone();
                _signedRequest = (HttpRequestForVerification)TestModels.RequestForVerification.Clone();
                _client        = (Client)TestModels.Client.Clone();
                _method        = (request, signature, client) => _sut.Verify(request, signature, client);

                _now = _signature.Created.Value.AddSeconds(3);
                A.CallTo(() => _systemClock.UtcNow).Returns(_now);
            }
        public override SignatureVerificationFailure VerifySync(HttpRequestForVerification 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);
        }
Exemple #8
0
 public Verify()
 {
     _signature         = (Signature)TestModels.Signature.Clone();
     _signature.Headers = _signature.Headers.Concat(new[] { HeaderName.PredefinedHeaderNames.Expires }).ToArray();
     _signedRequest     = (HttpRequestForVerification)TestModels.RequestForVerification.Clone();
     _client            = new Client(
         TestModels.Client.Id,
         TestModels.Client.Name,
         new CustomSignatureAlgorithm("RSA"),
         TimeSpan.FromMinutes(1),
         TimeSpan.FromMinutes(1),
         RequestTargetEscaping.RFC3986);
     _method = (request, signature, client) => _sut.Verify(request, signature, client);
 }
 public Verify()
 {
     _signature     = (Signature)TestModels.Signature.Clone();
     _signedRequest = (HttpRequestForVerification)TestModels.RequestForVerification.Clone();
     _client        = new Client(
         TestModels.Client.Id,
         TestModels.Client.Name,
         new HMACSignatureAlgorithm("s3cr3t", HashAlgorithmName.MD5),
         TestModels.Client.NonceLifetime,
         TestModels.Client.ClockSkew,
         TestModels.Client.RequestTargetEscaping,
         TestModels.Client.Claims);
     _method = (request, signature, client) => _sut.Verify(request, signature, client);
 }
        public override SignatureVerificationFailure VerifySync(HttpRequestForVerification 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);
        }
Exemple #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);
        }
        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);
        }
Exemple #13
0
        public override SignatureVerificationFailure VerifySync(HttpRequestForVerification 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);
        }
            public Verify()
            {
                _signature     = (Signature)TestModels.Signature.Clone();
                _signedRequest = (HttpRequestForVerification)TestModels.RequestForVerification.Clone();
                _client        = (Client)TestModels.Client.Clone();
                _method        = (request, signature, client) => _sut.Verify(request, signature, client);

                _signedRequest.Body = Encoding.UTF8.GetBytes("I am the body payload");
                using (var hashAlgorithm = HashAlgorithm.Create("SHA-384")) {
                    var digestBytes  = hashAlgorithm.ComputeHash(_signedRequest.Body);
                    var digestString = new Base64Converter().ToBase64(digestBytes);
                    _signedRequest.Headers.Add(HeaderName.PredefinedHeaderNames.Digest, "SHA-384=" + digestString);
                }

                _signature.Headers = _signature.Headers.Concat(new[] { HeaderName.PredefinedHeaderNames.Digest }).ToArray();
            }
        internal static async Task <HttpRequestForVerification> ToHttpRequestForVerification(this HttpRequest request, Signature signature)
        {
            if (signature == null)
            {
                throw new ArgumentNullException(nameof(signature));
            }
            if (request == null)
            {
                return(null);
            }

            var requestMessage = new HttpRequestForVerification {
                RequestUri = new Uri(request.GetDisplayUrl(), UriKind.Absolute),
                Method     = string.IsNullOrEmpty(request.Method)
                    ? HttpMethod.Get
                    : new HttpMethod(request.Method),
                Signature = signature
            };

            foreach (var header in request.Headers)
            {
                requestMessage.Headers[header.Key] = new StringValues((string[])header.Value);
            }

            if (ShouldReadBody(request, signature) && request.Body != null)
            {
                request.EnableBuffering();

                // ReSharper disable once UseAwaitUsing
                // ReSharper disable once ConvertToUsingDeclaration
                using (var memoryStream = new MemoryStream()) {
                    await request.Body.CopyToAsync(memoryStream).ConfigureAwait(false);

                    requestMessage.Body = memoryStream.ToArray();
                    request.Body.Seek(0, SeekOrigin.Begin);
                }
            }

            return(requestMessage);
        }
Exemple #16
0
        public override async Task <SignatureVerificationFailure> Verify(HttpRequestForVerification 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 Verify()
            {
                _now = new DateTimeOffset(2020, 2, 24, 10, 20, 14, TimeSpan.FromHours(0));

                _signature          = (Signature)TestModels.Signature.Clone();
                _signedRequest      = (HttpRequestForVerification)TestModels.RequestForVerification.Clone();
                _signatureAlgorithm = new CustomSignatureAlgorithm("TEST");
                _client             = new Client(
                    TestModels.Client.Id,
                    TestModels.Client.Name,
                    _signatureAlgorithm,
                    TestModels.Client.NonceLifetime,
                    TestModels.Client.ClockSkew,
                    TestModels.Client.RequestTargetEscaping,
                    TestModels.Client.Claims);
                _method = (request, signature, client) => _sut.Verify(request, signature, client);

                _composedSignatureString = "abc123";
                _composeCall             = () => A.CallTo(() => _signingStringComposer.Compose(A <SigningStringCompositionRequest> ._));
                _composeCall().Returns(_composedSignatureString);
                _signature.String = _base64Converter.ToBase64(_client.SignatureAlgorithm.ComputeHash(_composedSignatureString));
            }
 public VerifySignature()
 {
     _httpRequest            = new DefaultHttpContext().Request;
     _httpRequest.Method     = "POST";
     _httpRequest.Scheme     = "https";
     _httpRequest.Host       = new HostString("unittest.com", 9000);
     _options                = new SignedRequestAuthenticationOptions();
     _requestForVerification = new HttpRequestForVerification {
         Method     = HttpMethod.Post,
         RequestUri = "https://unittest.com:9000".ToUri(),
         Signature  = (Signature)TestModels.Signature.Clone()
     };
     _verificationSuccessResult = new RequestSignatureVerificationResultSuccess(
         new Client(
             _requestForVerification.Signature.KeyId,
             "Unit test app",
             new HMACSignatureAlgorithm("s3cr3t", HashAlgorithmName.SHA256),
             TimeSpan.FromMinutes(1),
             TimeSpan.FromMinutes(1),
             RequestTargetEscaping.RFC3986),
         _requestForVerification,
         new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim("name", "john.doe") })));
 }
        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);
        }
Exemple #20
0
 public UnknownResult(Client client, HttpRequestForVerification requestForVerification) : base(client, requestForVerification)
 {
 }
Exemple #21
0
 public virtual Task <SignatureVerificationFailure> Verify(HttpRequestForVerification signedRequest, Signature signature, Client client)
 {
     return(VerifySync(signedRequest, signature, client).ToTask());
 }
Exemple #22
0
 public virtual SignatureVerificationFailure VerifySync(HttpRequestForVerification signedRequest, Signature signature, Client client)
 {
     throw new System.NotSupportedException();
 }
        public override SignatureVerificationFailure VerifySync(HttpRequestForVerification 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);
        }
Exemple #24
0
 /// <summary>
 ///     Creates a new instance of this class.
 /// </summary>
 /// <param name="client">The client for which the verification happened.</param>
 /// <param name="requestForVerification">The data of the request that was used to verify.</param>
 protected RequestSignatureVerificationResult(Client client, HttpRequestForVerification requestForVerification)
 {
     Client = client;                                 // Can be null, because a failure might have occurred when looking up the client
     RequestForVerification = requestForVerification; // Can be null, because a failure might have occurred before extracting the data
 }