Beispiel #1
0
 public SignedHttpRequestAuthenticationOptionsTests()
 {
     _sut = new SignedHttpRequestAuthenticationOptions {
         Realm  = "UnitTests",
         Scheme = "TestScheme",
         RequestSignatureVerifier = A.Fake <IRequestSignatureVerifier>()
     };
 }
 public VerifySignature()
 {
     _httpRequest = new FakeOwinRequest {
         Method = "POST",
         Scheme = "https",
         Host   = new HostString("unittest.com:9000")
     };
     _options = new SignedHttpRequestAuthenticationOptions();
 }
 public HttpRequestSignatureAuthenticationMiddlewareTests()
 {
     _options = new SignedHttpRequestAuthenticationOptions {
         Realm  = "UnitTests",
         Scheme = "TestScheme",
         RequestSignatureVerifier = A.Fake <IRequestSignatureVerifier>()
     };
     _next = new FakeOwinMiddleware();
     _sut  = new HttpRequestSignatureAuthenticationMiddleware(_next, _options);
 }
 public Parse()
 {
     _request      = new OwinRequest();
     _now          = new DateTimeOffset(2020, 2, 25, 10, 29, 29, TimeSpan.Zero);
     _expires      = _now.AddMinutes(10);
     _nowEpoch     = _now.ToUnixTimeSeconds();
     _expiresEpoch = _expires.ToUnixTimeSeconds();
     _options      = new SignedHttpRequestAuthenticationOptions {
         Scheme = "TestScheme"
     };
 }
        public SignedHttpRequestAuthenticationHandlerTests()
        {
            _sut = new SignedHttpRequestAuthenticationHandler();

            _options = new SignedHttpRequestAuthenticationOptions {
                Realm  = "UnitTests",
                Scheme = "TestScheme",
                RequestSignatureVerifier = A.Fake <IRequestSignatureVerifier>()
            };

            _request = new OwinRequest {
                Host = new HostString("unittest.com:9000")
            };
            _response = new OwinResponse();
            var owinContext = A.Fake <IOwinContext>();

            A.CallTo(() => owinContext.Request).Returns(_request);
            A.CallTo(() => owinContext.Response).Returns(_response);

            var init = _sut.GetType().GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            init.Invoke(_sut, new object[] { _options, owinContext });
        }
Beispiel #6
0
 public VerifySignature()
 {
     _httpRequest = new OwinRequest {
         Method = "POST",
         Scheme = "https",
         Host   = new HostString("unittest.com:9000")
     };
     _options = new SignedHttpRequestAuthenticationOptions();
     _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") })));
 }
Beispiel #7
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));
        }
Beispiel #8
0
        public SignatureParsingResult Parse(IOwinRequest request, SignedHttpRequestAuthenticationOptions options)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            var authHeader = request.Headers[AuthorizationHeaderName];

            if (string.IsNullOrEmpty(authHeader))
            {
                return(new SignatureParsingFailure($"The specified request does not specify a value for the {AuthorizationHeaderName} header."));
            }

            var separatorIndex = authHeader.IndexOf(' ');

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

            var authScheme = authHeader.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 >= authHeader.Length - 1)
            {
                return(new SignatureParsingFailure(
                           $"The specified request does not specify a valid authentication parameter in the {AuthorizationHeaderName} header."));
            }

            var authParam = authHeader.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)
            {
                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));
        }
Beispiel #9
0
 public static IAppBuilder UseHttpRequestSignatureAuthentication(this IAppBuilder app, SignedHttpRequestAuthenticationOptions options)
 {
     if (app == null)
     {
         throw new ArgumentNullException(nameof(app));
     }
     app.Use <HttpRequestSignatureAuthenticationMiddleware>(options);
     app.UseStageMarker(PipelineStage.Authenticate);
     return(app);
 }
        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));
            }

            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   = request.ToHttpRequestForSigning();
                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(IOwinRequest request, SignedHttpRequestAuthenticationOptions 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   = request.ToHttpRequestForSigning();
                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));
            }
        }