public async Task ItShouldSign() { var parameters = new SignatureBodyParameters(Array.Empty <byte>(), "clientSecret"); var signer = new HashAlgorithmSignatureBodySigner(); var result = await signer.Sign(parameters); result.Should().NotBeEmpty(); var bytes = Convert.FromBase64String(result); bytes.Should().HaveCount(32); }
private async Task SignRequest(HttpRequestMessage request) { request.Headers.Remove(_options.HeaderName); var signatureBodySourceComponents = _options.SignatureBodySourceComponents.Any() ? _options.SignatureBodySourceComponents : DefaultConstants.SignatureBodySourceComponents; byte[] body = null; if (request.Content != null && signatureBodySourceComponents.Contains(SignatureBodySourceComponents.Body)) { body = await request.Content.ReadAsByteArrayAsync(); } var signatureBodySourceParameters = new SignatureBodySourceParameters( request.Method.ToString(), request.RequestUri, request.Headers.ToDictionary(x => x.Key, x => x.Value.ToString()), Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture), GetTimestamp(request), _options.ClientId, signatureBodySourceComponents, body); var signatureBodySource = await _signatureBodySourceBuilder.Build(signatureBodySourceParameters); var signatureBodyParameters = new SignatureBodyParameters(signatureBodySource, _options.ClientSecret); var signatureBody = await _signatureBodySigner.Sign(signatureBodyParameters); var signature = _options.SignaturePattern .Replace("{ClientId}", _options.ClientId) .Replace("{Nonce}", signatureBodySourceParameters.Nonce) .Replace("{Timestamp}", signatureBodySourceParameters.Timestamp.ToString(CultureInfo.InvariantCulture)) .Replace("{SignatureBody}", signatureBody); request.Headers.TryAddWithoutValidation(_options.HeaderName, signature); }
/// <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); }