Beispiel #1
0
 /// <summary>
 /// Logs an ignored signature validation.
 /// </summary>
 /// <param name="logger">The <see cref="ILogger"/>.</param>
 /// <param name="result">The <see cref="SignatureValidationResult"/>.</param>
 /// <param name="ex">The <see cref="Exception"/>, if any.</param>
 public static void SignatureValidationIgnored(this ILogger logger, SignatureValidationResult result, Exception ex = null)
 {
     _signatureValidationIgnored(
         logger,
         result?.Status ?? SignatureValidationResultStatus.Disabled,
         ex);
 }
Beispiel #2
0
 /// <summary>
 /// Logs a successful signature validation.
 /// </summary>
 /// <param name="logger">The <see cref="ILogger"/>.</param>
 /// <param name="result">The <see cref="SignatureValidationResult"/>.</param>
 /// <param name="ex">The <see cref="Exception"/>, if any.</param>
 public static void SignatureValidationSucceeded(this ILogger logger, SignatureValidationResult result, Exception ex = null)
 {
     _signatureValidationSucceeded(
         logger,
         result?.Status ?? SignatureValidationResultStatus.OK,
         result?.ClientId,
         ex);
 }
Beispiel #3
0
 /// <summary>
 /// Logs a failed signature validation.
 /// </summary>
 /// <param name="logger">The <see cref="ILogger"/>.</param>
 /// <param name="result">The <see cref="SignatureValidationResult"/>.</param>
 /// <param name="ex">The <see cref="Exception"/>, if any.</param>
 public static void SignatureValidationFailed(this ILogger logger, SignatureValidationResult result, Exception ex = null)
 {
     _signatureValidationFailed(
         logger,
         result?.Status ?? SignatureValidationResultStatus.InternalError,
         result?.ServerTimestamp ?? 0,
         result?.SignatureValue,
         result?.ClientId,
         result?.ComputedSignature,
         result?.SignatureBodySource == null ? null : Convert.ToBase64String(result.SignatureBodySource),
         ex);
 }
Beispiel #4
0
        /// <inheritdoc />
        public async Task <SignatureValidationResult> Validate(HttpRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var serverTimestamp = _clock.UtcNow.ToUnixTimeSeconds();
            SignatureValidationResult result;

            if (_options.Disabled)
            {
                result = new SignatureValidationResult(
                    SignatureValidationResultStatus.Disabled,
                    serverTimestamp);
                _logger.SignatureValidationIgnored(result);
                return(result);
            }

            var headerValue = request.Headers[_options.HeaderName];

            if (string.IsNullOrWhiteSpace(headerValue))
            {
                result = new SignatureValidationResult(
                    SignatureValidationResultStatus.HeaderNotFound,
                    serverTimestamp);
                _logger.SignatureValidationFailed(result);
                return(result);
            }

            var signatureValue = headerValue.ToString().Trim();
            var headerMatch    = _signaturePatternParser.Match(signatureValue);

            if (!headerMatch.Success)
            {
                result = new SignatureValidationResult(
                    SignatureValidationResultStatus.HeaderParseError,
                    serverTimestamp,
                    signatureValue: signatureValue);
                _logger.SignatureValidationFailed(result);
                return(result);
            }

            var signatureComponents = new SignatureValueComponents
            {
                ClientId      = headerMatch.Groups["ClientId"]?.Value,
                Nonce         = headerMatch.Groups["Nonce"]?.Value,
                Timestamp     = long.Parse(headerMatch.Groups["Timestamp"]?.Value ?? "0", CultureInfo.InvariantCulture),
                SignatureBody = headerMatch.Groups["SignatureBody"]?.Value,
            };

            var clientOptions = _options.Clients.FirstOrDefault(x => string.Equals(x.ClientId, signatureComponents.ClientId, StringComparison.Ordinal));

            if (clientOptions == null)
            {
                result = new SignatureValidationResult(
                    SignatureValidationResultStatus.ClientIdNotFound,
                    serverTimestamp,
                    signatureValue: signatureValue,
                    clientId: signatureComponents.ClientId);
                _logger.SignatureValidationFailed(result);
                return(result);
            }

            if (await _nonceRepository.Exists(signatureComponents.Nonce))
            {
                result = new SignatureValidationResult(
                    SignatureValidationResultStatus.NonceHasBeenUsedBefore,
                    serverTimestamp,
                    signatureValue: signatureValue,
                    clientId: clientOptions.ClientId);
                _logger.SignatureValidationFailed(result);
                return(result);
            }

            if (Math.Abs(serverTimestamp - signatureComponents.Timestamp) > _options.ClockSkew.TotalSeconds)
            {
                result = new SignatureValidationResult(
                    SignatureValidationResultStatus.TimestampIsOff,
                    serverTimestamp,
                    signatureValue: signatureValue,
                    clientId: clientOptions.ClientId);
                _logger.SignatureValidationFailed(result);
                return(result);
            }

            var signatureBodySourceComponents = clientOptions.SignatureBodySourceComponents.Any()
                ? clientOptions.SignatureBodySourceComponents
                : DefaultConstants.SignatureBodySourceComponents;

            byte[] body = null;
            if (signatureBodySourceComponents.Contains(SignatureBodySourceComponents.Body))
            {
#if NETCOREAPP2_1
                request.EnableRewind();
#endif
#if NETCOREAPP3_0
                request.EnableBuffering();
#endif
                request.Body.Seek(0, SeekOrigin.Begin);
                using (var memoryStream = _memoryStreamManager.GetStream())
                {
                    await request.Body.CopyToAsync(memoryStream);

                    body = memoryStream.ToArray();
                }

                request.Body.Seek(0, SeekOrigin.Begin);
            }

            var signatureBodySourceParameters = new SignatureBodySourceParameters(
                request.Method,
                new Uri($"{request.Scheme}://{request.Host}{request.Path}{request.QueryString}"),
                request.Headers.ToDictionary(x => x.Key, x => x.Value.ToString()),
                signatureComponents.Nonce,
                signatureComponents.Timestamp,
                clientOptions.ClientId,
                signatureBodySourceComponents,
                body);

            var signatureBodySource = await _signatureBodySourceBuilder.Build(signatureBodySourceParameters);

            var signatureBodyParameters = new SignatureBodyParameters(signatureBodySource, clientOptions.ClientSecret);
            var signature = await _signatureBodySigner.Sign(signatureBodyParameters);

            if (!string.Equals(signature, signatureComponents.SignatureBody, StringComparison.Ordinal))
            {
                result = new SignatureValidationResult(
                    SignatureValidationResultStatus.SignatureDoesntMatch,
                    serverTimestamp,
                    signatureValue: signatureValue,
                    clientId: clientOptions.ClientId,
                    computedSignature: signature,
                    signatureBodySource: signatureBodySource);
                _logger.SignatureValidationFailed(result);
                return(result);
            }

            await _nonceRepository.Add(signatureComponents.Nonce);

            result = new SignatureValidationResult(
                SignatureValidationResultStatus.OK,
                serverTimestamp,
                signatureValue: signatureValue,
                clientId: clientOptions.ClientId,
                computedSignature: signature);
            _logger.SignatureValidationSucceeded(result);
            return(result);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="RequestsSignatureValidationException"/> class with a specified <see cref="SignatureValidationResult"/>.
 /// </summary>
 /// <param name="result">The <see cref="SignatureValidationResult"/>.</param>
 public RequestsSignatureValidationException(SignatureValidationResult result)
     : base(result?.Status.ToString())
 {
     Result = result;
 }