diff --git a/build.bat b/build.bat index 03856cfb..e1de8546 100644 --- a/build.bat +++ b/build.bat @@ -1,7 +1,6 @@ echo ------------------------- echo Building Ocelot - dotnet restore src/Ocelot dotnet restore src/Ocelot.Library dotnet build src/Ocelot diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs index aa3a0d00..577fe18c 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Configuration.Yaml diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs index 777a6c84..64b72929 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Configuration.Yaml diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs index 5a256f91..533f1bb3 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs @@ -1,10 +1,11 @@ -using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Configuration.Yaml { public class DownstreamTemplateAlreadyUsedError : Error { - public DownstreamTemplateAlreadyUsedError(string message) : base(message) + public DownstreamTemplateAlreadyUsedError(string message) : base(message, OcelotErrorCode.DownstreamTemplateAlreadyUsedError) { } } diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs index 3063cf76..4d58b549 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Options; using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlMatcher; diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs index 62618951..e0f8d26a 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs @@ -2,13 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder { public class UnableToFindDownstreamRouteError : Error { - public UnableToFindDownstreamRouteError() : base("UnableToFindDownstreamRouteError") + public UnableToFindDownstreamRouteError() : base("UnableToFindDownstreamRouteError", OcelotErrorCode.UnableToFindDownstreamRouteError) { } } diff --git a/src/Ocelot.Library/Infrastructure/Errors/Error.cs b/src/Ocelot.Library/Infrastructure/Errors/Error.cs new file mode 100644 index 00000000..50b27354 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Errors/Error.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Library.Infrastructure.Errors +{ + public abstract class Error + { + protected Error(string message, OcelotErrorCode code) + { + Message = message; + Code = code; + } + + public string Message { get; private set; } + public OcelotErrorCode Code { get; private set; } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs b/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs new file mode 100644 index 00000000..e746de55 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs @@ -0,0 +1,13 @@ +namespace Ocelot.Library.Infrastructure.Errors +{ + public enum OcelotErrorCode + { + UnauthenticatedError, + UnknownError, + DownstreamTemplateAlreadyUsedError, + UnableToFindDownstreamRouteError, + CannotAddDataError, + CannotFindDataError, + UnableToCompleteRequestError + } +} diff --git a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs new file mode 100644 index 00000000..4a72d412 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Middleware +{ + public class AuthenticationMiddleware : OcelotMiddleware + { + private readonly RequestDelegate _next; + private RequestDelegate _authenticationNext; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + private readonly IApplicationBuilder _app; + + public AuthenticationMiddleware(RequestDelegate next, IApplicationBuilder app, + IScopedRequestDataRepository scopedRequestDataRepository) + : base(scopedRequestDataRepository) + { + _next = next; + _scopedRequestDataRepository = scopedRequestDataRepository; + _app = app; + } + + public async Task Invoke(HttpContext context) + { + var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); + + if (downstreamRoute.IsError) + { + SetPipelineError(downstreamRoute.Errors); + return; + } + + if (IsAuthenticatedRoute(downstreamRoute.Data.ReRoute)) + { + //todo - build auth pipeline and then call normal pipeline if all good? + //create new app builder + var builder = _app.New(); + //set up any options for the authentication + var jwtBearerOptions = new JwtBearerOptions + { + AutomaticAuthenticate = true, + AutomaticChallenge = true, + RequireHttpsMetadata = false, + }; + //set the authentication middleware + builder.UseJwtBearerAuthentication(jwtBearerOptions); + //use mvc so we hit the catch all authorised controller + builder.UseMvc(); + //then build it + _authenticationNext = builder.Build(); + //then call it + await _authenticationNext(context); + //check if the user is authenticated + if (context.User.Identity.IsAuthenticated) + { + await _next.Invoke(context); + } + else + { + SetPipelineError(new List {new UnauthenticatedError($"Request for authenticated route {context.Request.Path} by {context.User.Identity.Name} was unauthenticated")}); + } + } + else + { + await _next.Invoke(context); + } + } + + private static bool IsAuthenticatedRoute(ReRoute reRoute) + { + return reRoute.IsAuthenticated; + } + } +} diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs similarity index 82% rename from src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs index 3655e470..43b90856 100644 --- a/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs @@ -1,12 +1,12 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class AuthenticationMiddlewareMiddlewareExtensions { public static IApplicationBuilder UseAuthenticationMiddleware(this IApplicationBuilder builder) { - return builder.UseMiddleware(); + return builder.UseMiddleware(builder); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddleware.cs similarity index 96% rename from src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddleware.cs index 598f953e..1537ab45 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddleware.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Repository; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class DownstreamRouteFinderMiddleware : OcelotMiddleware { diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs similarity index 86% rename from src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs index ec454bf4..7f23d1de 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class DownstreamRouteFinderMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddleware.cs similarity index 96% rename from src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddleware.cs index 00d5d76b..955e983a 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -4,7 +4,7 @@ using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class DownstreamUrlCreatorMiddleware : OcelotMiddleware { diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs similarity index 86% rename from src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs index 325a7454..b0997b7b 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class DownstreamUrlCreatorMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddleware.cs similarity index 97% rename from src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddleware.cs index b800a3d7..aa2c4017 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddleware.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class HttpRequestBuilderMiddleware : OcelotMiddleware { diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddlewareExtensions.cs similarity index 86% rename from src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddlewareExtensions.cs index 0b51ccaa..fa36ce01 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class HttpRequestBuilderMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddleware.cs similarity index 96% rename from src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddleware.cs index 7c2c4b9d..3cf988e4 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddleware.cs @@ -4,7 +4,7 @@ using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Requester; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class HttpRequesterMiddleware : OcelotMiddleware { diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddlewareExtensions.cs similarity index 85% rename from src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddlewareExtensions.cs index 8aead7bc..b8b31f40 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class HttpRequesterMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs similarity index 68% rename from src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs index 7974ad62..3f268a62 100644 --- a/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs @@ -4,22 +4,25 @@ using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class HttpResponderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; private readonly IHttpResponder _responder; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + private readonly IErrorsToHttpStatusCodeMapper _codeMapper; public HttpResponderMiddleware(RequestDelegate next, IHttpResponder responder, - IScopedRequestDataRepository scopedRequestDataRepository) + IScopedRequestDataRepository scopedRequestDataRepository, + IErrorsToHttpStatusCodeMapper codeMapper) :base(scopedRequestDataRepository) { _next = next; _responder = responder; _scopedRequestDataRepository = scopedRequestDataRepository; + _codeMapper = codeMapper; } public async Task Invoke(HttpContext context) @@ -28,11 +31,19 @@ namespace Ocelot.Library.Middleware if (PipelineError()) { - //todo obviously this needs to be better...prob look at response errors - // and make a decision i guess var errors = GetPipelineErrors(); + + var statusCode = _codeMapper.Map(errors); + + if (!statusCode.IsError) + { + await _responder.CreateErrorResponse(context, statusCode.Data); + } + else + { + await _responder.CreateErrorResponse(context, 500); + } - await _responder.CreateNotFoundResponse(context); } else { diff --git a/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddlewareExtensions.cs similarity index 85% rename from src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddlewareExtensions.cs index 4cec7fd0..30d69ae7 100644 --- a/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class HttpResponderMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/OcelotMiddleware.cs similarity index 91% rename from src/Ocelot.Library/Middleware/OcelotMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/OcelotMiddleware.cs index dda41207..7af593e0 100644 --- a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/OcelotMiddleware.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public abstract class OcelotMiddleware { diff --git a/src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs b/src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs new file mode 100644 index 00000000..3a7c3ec6 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs @@ -0,0 +1,11 @@ +using Ocelot.Library.Infrastructure.Errors; + +namespace Ocelot.Library.Infrastructure.Middleware +{ + public class UnauthenticatedError : Error + { + public UnauthenticatedError(string message) : base(message, OcelotErrorCode.UnauthenticatedError) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs b/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs index ea9d9b75..1bc0f26a 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs @@ -1,10 +1,11 @@ -using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Repository { public class CannotAddDataError : Error { - public CannotAddDataError(string message) : base(message) + public CannotAddDataError(string message) : base(message, OcelotErrorCode.CannotAddDataError) { } } diff --git a/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs b/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs index 41699f12..08a814f4 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs @@ -1,10 +1,11 @@ -using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Repository { public class CannotFindDataError : Error { - public CannotFindDataError(string message) : base(message) + public CannotFindDataError(string message) : base(message, OcelotErrorCode.CannotFindDataError) { } } diff --git a/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs b/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs index f49de35b..9b41d655 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Repository diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs index 260a6843..912d7bff 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Responses; diff --git a/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs b/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs index 6e7a042c..003e84e7 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs @@ -1,4 +1,5 @@ using System; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Requester @@ -6,7 +7,7 @@ namespace Ocelot.Library.Infrastructure.Requester public class UnableToCompleteRequestError : Error { public UnableToCompleteRequestError(Exception exception) - : base($"Error making http request, exception: {exception.Message}") + : base($"Error making http request, exception: {exception.Message}", OcelotErrorCode.UnableToCompleteRequestError) { } } diff --git a/src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs b/src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs new file mode 100644 index 00000000..4798343e --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Linq; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Responder +{ + public class ErrorsToHttpStatusCodeMapper : IErrorsToHttpStatusCodeMapper + { + public Response Map(List errors) + { + if (errors.Any(e => e.Code == OcelotErrorCode.UnauthenticatedError)) + { + return new OkResponse(401); + } + + return new OkResponse(404); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs index 5339ff92..e1cfa8a1 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs +++ b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs @@ -1,5 +1,4 @@ -using System.Net; -using System.Net.Http; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -23,11 +22,11 @@ namespace Ocelot.Library.Infrastructure.Responder return context; } - public async Task CreateNotFoundResponse(HttpContext context) + public async Task CreateErrorResponse(HttpContext context, int statusCode) { context.Response.OnStarting(x => { - context.Response.StatusCode = (int)HttpStatusCode.NotFound; + context.Response.StatusCode = statusCode; return Task.CompletedTask; }, context); return context; diff --git a/src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs b/src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs new file mode 100644 index 00000000..21932bdf --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Responder +{ + public interface IErrorsToHttpStatusCodeMapper + { + Response Map(List errors); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs index 97bb4995..9e18647b 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs +++ b/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs @@ -7,7 +7,6 @@ namespace Ocelot.Library.Infrastructure.Responder public interface IHttpResponder { Task CreateResponse(HttpContext context, HttpResponseMessage response); - Task CreateNotFoundResponse(HttpContext context); - + Task CreateErrorResponse(HttpContext context, int statusCode); } } diff --git a/src/Ocelot.Library/Infrastructure/Responses/Error.cs b/src/Ocelot.Library/Infrastructure/Responses/Error.cs deleted file mode 100644 index 57684854..00000000 --- a/src/Ocelot.Library/Infrastructure/Responses/Error.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Responses -{ - public abstract class Error - { - public Error(string message) - { - Message = message; - } - - public string Message { get; private set; } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs index 5233f358..2ceb83a2 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; namespace Ocelot.Library.Infrastructure.Responses { diff --git a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs index 95bda1b7..86d884c1 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; namespace Ocelot.Library.Infrastructure.Responses { diff --git a/src/Ocelot.Library/Infrastructure/Responses/Response.cs b/src/Ocelot.Library/Infrastructure/Responses/Response.cs index ead3141c..9818df78 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/Response.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/Response.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; namespace Ocelot.Library.Infrastructure.Responses { diff --git a/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs b/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs index ed020292..790fe5c1 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; namespace Ocelot.Library.Infrastructure.Responses { diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs deleted file mode 100644 index 6fc73817..00000000 --- a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace Ocelot.Library.Middleware -{ - using System.Threading.Tasks; - using Infrastructure.Configuration; - using Infrastructure.DownstreamRouteFinder; - using Infrastructure.Repository; - using Microsoft.AspNetCore.Http; - - public class AuthenticationMiddleware : OcelotMiddleware - { - private readonly RequestDelegate _next; - private readonly IScopedRequestDataRepository _scopedRequestDataRepository; - - public AuthenticationMiddleware(RequestDelegate next, - IScopedRequestDataRepository scopedRequestDataRepository) - : base(scopedRequestDataRepository) - { - _next = next; - _scopedRequestDataRepository = scopedRequestDataRepository; - } - - public async Task Invoke(HttpContext context) - { - var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); - - if (downstreamRoute.IsError) - { - SetPipelineError(downstreamRoute.Errors); - return; - } - - if (IsAuthenticatedRoute(downstreamRoute.Data.ReRoute)) - { - //todo - build auth pipeline and then call normal pipeline if all good? - await _next.Invoke(context); - } - else - { - await _next.Invoke(context); - } - } - - private static bool IsAuthenticatedRoute(ReRoute reRoute) - { - return reRoute.IsAuthenticated; - } - } -} diff --git a/src/Ocelot/Controllers/HomeController.cs b/src/Ocelot/Controllers/HomeController.cs new file mode 100644 index 00000000..c6dbe9d2 --- /dev/null +++ b/src/Ocelot/Controllers/HomeController.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Ocelot.Controllers +{ + /// + /// This controller is a catch all for requests so that if we build it into a pipeline + /// the requests get authorised. + /// + public class HomeController : Controller + { + //[Authorize] + [Route("{*url}")] + public void Index() + { + if (true == true) + { + + } + } + } +} diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index b9298d0a..5c9e44e6 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -10,13 +10,13 @@ using Microsoft.Extensions.Options; using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.Configuration.Yaml; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Requester; using Ocelot.Library.Infrastructure.Responder; using Ocelot.Library.Infrastructure.UrlMatcher; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; -using Ocelot.Library.Middleware; namespace Ocelot { @@ -40,8 +40,10 @@ namespace Ocelot public void ConfigureServices(IServiceCollection services) { services.AddOptions(); - + services.AddMvc(); + services.Configure(Configuration); + services.AddAuthentication(); // Add framework services. services.AddSingleton(); @@ -52,6 +54,7 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc services.AddSingleton(); diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs new file mode 100644 index 00000000..6b7ca01c --- /dev/null +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Text.Encodings.Web; +using IdentityServer4.Models; +using IdentityServer4.Services.InMemory; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Ocelot.Library.Infrastructure.Configuration.Yaml; +using Shouldly; +using TestStack.BDDfy; +using Xunit; +using YamlDotNet.Serialization; + +namespace Ocelot.AcceptanceTests +{ + public class AuthenticationTests : IDisposable + { + private TestServer _server; + private HttpClient _client; + private HttpResponseMessage _response; + private readonly string _configurationPath; + private StringContent _postContent; + private IWebHost _builder; + + // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly + private double _netCoreAppVersion = 1.4; + private HttpClient _idServerClient; + private TestServer _idServer; + + public AuthenticationTests() + { + _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + } + + [Fact] + public void should_return_401_using_jwt() + { + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888")) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Post", + Authentication = "JwtBearerAuthentication" + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenThePostHasContent("postContent")) + .When(x => x.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + .BDDfy(); + } + + private void GivenThePostHasContent(string postcontent) + { + _postContent = new StringContent(postcontent); + } + + /// + /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. + /// + private void GivenTheApiGatewayIsRunning() + { + _server = new TestServer(new WebHostBuilder() + .UseStartup()); + + _client = _server.CreateClient(); + } + + private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) + { + var serializer = new Serializer(); + + if (File.Exists(_configurationPath)) + { + File.Delete(_configurationPath); + } + + using (TextWriter writer = File.CreateText(_configurationPath)) + { + serializer.Serialize(writer, yamlConfiguration); + } + } + + private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) + { + _builder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .Configure(app => + { + app.Run(async context => + { + context.Response.StatusCode = statusCode; + await context.Response.WriteAsync(responseBody); + }); + }) + .Build(); + + _builder.Start(); + } + + private void GivenThereIsAnIdentityServerOn(string url) + { + var builder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .ConfigureServices(services => + { + services.AddDeveloperIdentityServer() + .AddInMemoryClients(new List { + new Client + { + ClientId = "test", + AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, + ClientSecrets = new List { new Secret("test".Sha256()) }, + AllowedScopes = new List { "api1" }, + AllowAccessToAllScopes = true, + AccessTokenType = AccessTokenType.Jwt, + Enabled = true + + } }) + .AddInMemoryScopes(new List { new Scope + { + Name = "api1", + Description = "My API", + Enabled = true + + }}) + .AddInMemoryUsers(new List { new InMemoryUser + { + Username = "test", Password = "test", Enabled = true, Subject = "asdads" + }}); + }) + .Configure(app => + { + app.UseIdentityServer(); + }); + + _idServer = new TestServer(builder); + _idServerClient = _idServer.CreateClient(); + + var response = _idServerClient.GetAsync($"{url}/.well-known/openid-configuration").Result; + response.EnsureSuccessStatusCode(); + var content = response.Content.ReadAsStringAsync().Result; + } + + private void GivenIHaveAToken(string url) + { + var tokenUrl = $"{url}/connect/token"; + var formData = new List> + { + new KeyValuePair("client_id", "test"), + new KeyValuePair("client_secret", "test".Sha256()), + new KeyValuePair("scope", "api1"), + new KeyValuePair("username", "test"), + new KeyValuePair("password", "test"), + new KeyValuePair("grant_type", "password") + }; + var content = new FormUrlEncodedContent(formData); + var response = _idServerClient.PostAsync(tokenUrl, content).Result; + var responseContent = response.Content.ReadAsStringAsync().Result; + } + + private void WhenIPostUrlOnTheApiGateway(string url) + { + _response = _client.PostAsync(url, _postContent).Result; + } + + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); + } + + public void Dispose() + { + _idServerClient?.Dispose(); + _idServer?.Dispose(); + _builder?.Dispose(); + _client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 299f67bf..2f4fb53b 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -110,6 +110,7 @@ namespace Ocelot.AcceptanceTests .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) .BDDfy(); } + private void GivenThePostHasContent(string postcontent) { _postContent = new StringContent(postcontent); @@ -184,10 +185,7 @@ namespace Ocelot.AcceptanceTests public void Dispose() { - if (_builder != null) - { - _builder.Dispose(); - } + _builder?.Dispose(); _client.Dispose(); _server.Dispose(); } diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index ba6d6162..722e58e4 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -11,31 +11,32 @@ "testRunner": "xunit", - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Ocelot.Library": "1.0.0-*", + "xunit": "2.1.0", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Shouldly": "2.8.0", + "Ocelot": "1.0.0-*", + "Microsoft.AspNetCore.TestHost": "1.0.0", + "TestStack.BDDfy": "4.3.1", + "YamlDotNet": "3.9.0", + "IdentityServer4": "1.0.0-rc2" }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "Ocelot.Library": "1.0.0-*", - "xunit": "2.1.0", - "dotnet-test-xunit": "2.2.0-preview2-build1029", - "Shouldly": "2.8.0", - "Ocelot": "1.0.0-*", - "Microsoft.AspNetCore.TestHost": "1.0.0", - "TestStack.BDDfy": "4.3.1", - "YamlDotNet": "3.9.0" - }, "frameworks": { "netcoreapp1.4": { diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs index f5cc37f5..fb4e2d32 100644 --- a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs @@ -7,10 +7,10 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlMatcher; -using Ocelot.Library.Middleware; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs index b960e399..ec48f886 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs @@ -1,4 +1,6 @@ -namespace Ocelot.UnitTests.Middleware +using Ocelot.Library.Infrastructure.Middleware; + +namespace Ocelot.UnitTests.Middleware { using System; using System.Collections.Generic; @@ -9,7 +11,6 @@ using Library.Infrastructure.Repository; using Library.Infrastructure.Responses; using Library.Infrastructure.UrlMatcher; - using Library.Middleware; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs index df9260c8..d9545f2f 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs @@ -1,4 +1,6 @@ -namespace Ocelot.UnitTests.Middleware +using Ocelot.Library.Infrastructure.Middleware; + +namespace Ocelot.UnitTests.Middleware { using System; using System.Collections.Generic; @@ -10,7 +12,6 @@ using Library.Infrastructure.Responses; using Library.Infrastructure.UrlMatcher; using Library.Infrastructure.UrlTemplateReplacer; - using Library.Middleware; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs index 56142b70..2a483330 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs @@ -7,10 +7,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Middleware; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs index ecb62b19..a2e24133 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs @@ -6,11 +6,11 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Requester; using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Middleware; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs index d565dbf8..e8f6ef10 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs @@ -6,10 +6,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responder; using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Middleware; using TestStack.BDDfy; using Xunit; @@ -19,6 +19,7 @@ namespace Ocelot.UnitTests.Middleware { private readonly Mock _responder; private readonly Mock _scopedRepository; + private readonly Mock _codeMapper; private readonly string _url; private readonly TestServer _server; private readonly HttpClient _client; @@ -30,10 +31,12 @@ namespace Ocelot.UnitTests.Middleware _url = "http://localhost:51879"; _responder = new Mock(); _scopedRepository = new Mock(); + _codeMapper = new Mock(); var builder = new WebHostBuilder() .ConfigureServices(x => { + x.AddSingleton(_codeMapper.Object); x.AddSingleton(_responder.Object); x.AddSingleton(_scopedRepository.Object); }) diff --git a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs new file mode 100644 index 00000000..cc976b6d --- /dev/null +++ b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Middleware; +using Ocelot.Library.Infrastructure.Responder; +using Ocelot.Library.Infrastructure.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Responder +{ + public class ErrorsToHttpStatusCodeMapperTests + { + private readonly IErrorsToHttpStatusCodeMapper _codeMapper; + private Response _result; + private List _errors; + + public ErrorsToHttpStatusCodeMapperTests() + { + _codeMapper = new ErrorsToHttpStatusCodeMapper(); + } + + [Fact] + public void should_create_unauthenticated_response_code() + { + this.Given(x => x.GivenThereAreErrors(new List + { + new UnauthenticatedError("no matter") + })) + .When(x => x.WhenIGetErrorStatusCode()) + .Then(x => x.ThenTheResponseIsStatusCodeIs(401)) + .BDDfy(); + } + + [Fact] + public void should_create_not_found_response_response_code() + { + this.Given(x => x.GivenThereAreErrors(new List + { + new AnyError() + })) + .When(x => x.WhenIGetErrorStatusCode()) + .Then(x => x.ThenTheResponseIsStatusCodeIs(404)) + .BDDfy(); + } + + class AnyError : Error + { + public AnyError() : base("blahh", OcelotErrorCode.UnknownError) + { + } + } + + private void GivenThereAreErrors(List errors) + { + _errors = errors; + } + + private void WhenIGetErrorStatusCode() + { + _result = _codeMapper.Map(_errors); + } + + private void ThenTheResponseIsStatusCodeIs(int expectedCode) + { + _result.Data.ShouldBe(expectedCode); + } + } +} diff --git a/test/Ocelot.UnitTests/Responder/ResponderTests.cs b/test/Ocelot.UnitTests/Responder/ResponderTests.cs deleted file mode 100644 index 60a20153..00000000 --- a/test/Ocelot.UnitTests/Responder/ResponderTests.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Xunit; - -namespace Ocelot.UnitTests.Responder -{ - public class ResponderTests - { - [Fact] - public void should_do_something() - { - - } - } -}