public PostConfigure()
 {
     _options = new SignedRequestAuthenticationOptions {
         Realm  = "r",
         Scheme = "s"
     };
 }
Exemple #2
0
 public VerifySignature()
 {
     _httpRequest        = new DefaultHttpContext().Request;
     _httpRequest.Method = "POST";
     _httpRequest.Scheme = "https";
     _httpRequest.Host   = new HostString("unittest.com", 9000);
     _options            = new SignedRequestAuthenticationOptions();
 }
Exemple #3
0
 public Parse()
 {
     _request      = new DefaultHttpContext().Request;
     _now          = new DateTimeOffset(2020, 2, 25, 10, 29, 29, TimeSpan.Zero);
     _expires      = _now.AddMinutes(10);
     _nowEpoch     = _now.ToUnixTimeSeconds();
     _expiresEpoch = _expires.ToUnixTimeSeconds();
     _options      = new SignedRequestAuthenticationOptions {
         Scheme = "TestScheme"
     };
 }
Exemple #4
0
        public SignedRequestAuthenticationHandlerTests()
        {
            FakeFactory.Create(out _logger, out _clock, out _requestSignatureVerifier);
            _encoder    = new UrlTestEncoder();
            _schemeName = "tests-scheme";
            _options    = new SignedRequestAuthenticationOptions {
                Realm = "test-app"
            };
            var optionsMonitor = A.Fake <IOptionsMonitor <SignedRequestAuthenticationOptions> >();

            A.CallTo(() => optionsMonitor.Get(_schemeName)).Returns(_options);
            _sut         = new SignedRequestAuthenticationHandlerForTests(optionsMonitor, _encoder, _clock, _requestSignatureVerifier, _logger);
            _httpRequest = new DefaultHttpContext().Request;
            _sut.InitializeAsync(
                new AuthenticationScheme(
                    _schemeName,
                    _schemeName,
                    _sut.GetType()),
                _httpRequest.HttpContext);
        }
 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 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));
            }
        }
        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));
            }

            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 requestForSigning = await request.ToHttpRequestForVerification(parsedSignature).ConfigureAwait(continueOnCapturedContext: false);

            return(await _verificationOrchestrator.VerifySignature(requestForSigning).ConfigureAwait(continueOnCapturedContext: false));
        }
        public SignatureParsingResult Parse(HttpRequest request, SignedRequestAuthenticationOptions options)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            var authHeader = request.Headers[AuthorizationHeaderName];

            if (authHeader == Microsoft.Extensions.Primitives.StringValues.Empty)
            {
                return(new SignatureParsingFailure($"The specified request does not specify a value for the {AuthorizationHeaderName} header."));
            }

            var rawAuthHeader  = (string)authHeader;
            var separatorIndex = rawAuthHeader.IndexOf(' ');

            if (separatorIndex < 0)
            {
                return(new SignatureParsingFailure(
                           $"The specified request does not specify a valid authentication parameter in the {AuthorizationHeaderName} header."));
            }
            var authScheme = rawAuthHeader.Substring(0, separatorIndex);

            if (authScheme != options.Scheme && authScheme != options.Scheme)
            {
                return(new SignatureParsingFailure(
                           $"The specified request does not specify the expected {options.Scheme} scheme in the {AuthorizationHeaderName} header."));
            }

            if (separatorIndex >= rawAuthHeader.Length - 1)
            {
                return(new SignatureParsingFailure(
                           $"The specified request does not specify a valid authentication parameter in the {AuthorizationHeaderName} header."));
            }
            var authParam = rawAuthHeader.Substring(separatorIndex + 1);

            _logger?.LogDebug("Parsing authorization header parameter for verification: {0}.", authParam);

            var authParamParts = authParam.Split(',');

            var    keyId         = KeyId.Empty;
            var    algorithm     = string.Empty;
            var    createdString = string.Empty;
            var    expiresString = string.Empty;
            var    headersString = string.Empty;
            string nonce         = null;
            var    signature     = string.Empty;

            foreach (var authParamPart in authParamParts)
            {
                if (authParamPart == null)
                {
                    continue;
                }

                var keyIdSelector = "keyId=";
                if (authParamPart.StartsWith(keyIdSelector, StringComparison.Ordinal))
                {
                    if (keyId != KeyId.Empty)
                    {
                        return(new SignatureParsingFailure($"Duplicate '{keyIdSelector}' found in signature."));
                    }
                    var value = authParamPart.Substring(keyIdSelector.Length).Trim('"');
                    keyId = new KeyId(value);
                }

                var algorithmSelector = "algorithm=";
                if (authParamPart.StartsWith(algorithmSelector, StringComparison.Ordinal))
                {
                    if (algorithm != string.Empty)
                    {
                        return(new SignatureParsingFailure($"Duplicate '{algorithmSelector}' found in signature."));
                    }
                    var value = authParamPart.Substring(algorithmSelector.Length).Trim('"');
                    algorithm = value;
                }

                var createdSelector = "created=";
                if (authParamPart.StartsWith(createdSelector, StringComparison.Ordinal))
                {
                    if (createdString != string.Empty)
                    {
                        return(new SignatureParsingFailure($"Duplicate '{createdSelector}' found in signature."));
                    }
                    var value = authParamPart.Substring(createdSelector.Length).Trim('"');
                    createdString = value;
                }

                var expiresSelector = "expires=";
                if (authParamPart.StartsWith(expiresSelector, StringComparison.Ordinal))
                {
                    if (expiresString != string.Empty)
                    {
                        return(new SignatureParsingFailure($"Duplicate '{expiresSelector}' found in signature."));
                    }
                    var value = authParamPart.Substring(expiresSelector.Length).Trim('"');
                    expiresString = value;
                }

                var headersSelector = "headers=";
                if (authParamPart.StartsWith(headersSelector, StringComparison.Ordinal))
                {
                    if (headersString != string.Empty)
                    {
                        return(new SignatureParsingFailure($"Duplicate '{headersSelector}' found in signature."));
                    }
                    var value = authParamPart.Substring(headersSelector.Length).Trim('"');
                    headersString = value;
                }

                var nonceSelector = "nonce=";
                if (authParamPart.StartsWith(nonceSelector, StringComparison.Ordinal))
                {
                    if (!string.IsNullOrEmpty(nonce))
                    {
                        return(new SignatureParsingFailure($"Duplicate '{nonceSelector}' found in signature."));
                    }
                    var value = authParamPart.Substring(nonceSelector.Length).Trim('"');
                    nonce = value;
                }

                var signatureSelector = "signature=";
                if (authParamPart.StartsWith(signatureSelector, StringComparison.Ordinal))
                {
                    if (signature != string.Empty)
                    {
                        return(new SignatureParsingFailure($"Duplicate '{signatureSelector}' found in signature."));
                    }
                    var value = authParamPart.Substring(signatureSelector.Length).Trim('"');
                    signature = value;
                }
            }

            DateTimeOffset?created = null;

            if (long.TryParse(createdString, out var createdEpoch))
            {
                created = DateTimeOffset.FromUnixTimeSeconds(createdEpoch);
            }

            DateTimeOffset?expires = null;

            if (long.TryParse(expiresString, out var expiresEpoch))
            {
                expires = DateTimeOffset.FromUnixTimeSeconds(expiresEpoch);
            }

            var headerNames = Array.Empty <HeaderName>();

            if (!string.IsNullOrEmpty(headersString))
            {
                headerNames = headersString
                              .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                              .Select(s => new HeaderName(s)).ToArray();
            }

            var parsedSignature = new Signature {
                KeyId     = keyId,
                Algorithm = string.IsNullOrEmpty(algorithm) ? null : algorithm.Trim(),
                Created   = created,
                Expires   = expires,
                Headers   = headerNames.Any() ? headerNames : null,
                Nonce     = nonce,
                String    = signature
            };

            try {
                parsedSignature.Validate();
            }
            catch (ValidationException ex) {
                return(new SignatureParsingFailure(
                           $"The specified request does not specify a valid signature in the {AuthorizationHeaderName} header. See inner exception.",
                           ex));
            }

            return(new SignatureParsingSuccess(parsedSignature));
        }
Exemple #9
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));
            }
        }
Exemple #10
0
 public PostConfigure()
 {
     _options = new SignedRequestAuthenticationOptions();
 }