diff --git a/src/Ocelot/Authentication/JsonConverters/AuthenticationConfigConverter.cs b/src/Ocelot/Authentication/JsonConverters/AuthenticationConfigConverter.cs index 6aca01be..1c94e9d3 100644 --- a/src/Ocelot/Authentication/JsonConverters/AuthenticationConfigConverter.cs +++ b/src/Ocelot/Authentication/JsonConverters/AuthenticationConfigConverter.cs @@ -1,4 +1,5 @@ -using System; +/* +using System; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Ocelot.Configuration; @@ -57,3 +58,4 @@ namespace Ocelot.Authentication.JsonConverters } +*/ diff --git a/src/Ocelot/Configuration/AuthenticationOptions.cs b/src/Ocelot/Configuration/AuthenticationOptions.cs index 1c71d68b..477d7283 100644 --- a/src/Ocelot/Configuration/AuthenticationOptions.cs +++ b/src/Ocelot/Configuration/AuthenticationOptions.cs @@ -2,52 +2,13 @@ namespace Ocelot.Configuration { - using Newtonsoft.Json; - public class AuthenticationOptions { - public AuthenticationOptions(string provider, List allowedScopes, IAuthenticationConfig config) + public AuthenticationOptions(List allowedScopes) { - Provider = provider; AllowedScopes = allowedScopes; - Config = config; } - public string Provider { get; private set; } - public List AllowedScopes { get; private set; } - - public IAuthenticationConfig Config { get; private set; } } - - public class IdentityServerConfig : IAuthenticationConfig - { - public IdentityServerConfig(string providerRootUrl, string apiName, bool requireHttps, string apiSecret) - { - ProviderRootUrl = providerRootUrl; - ApiName = apiName; - RequireHttps = requireHttps; - ApiSecret = apiSecret; - } - - public string ProviderRootUrl { get; private set; } - public string ApiName { get; private set; } - public string ApiSecret { get; private set; } - public bool RequireHttps { get; private set; } - } - - public class JwtConfig : IAuthenticationConfig - { - public JwtConfig(string authority, string audience) - { - Audience = audience; - Authority = authority; - } - - public string Audience { get; } - - public string Authority { get; } - } - - public interface IAuthenticationConfig {} } diff --git a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs index ea43a23e..3a5f14b0 100644 --- a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs +++ b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs @@ -4,18 +4,7 @@ namespace Ocelot.Configuration.Builder { public class AuthenticationOptionsBuilder { - - private string _provider; - - private List _allowedScopes; - - private IAuthenticationConfig _identityServerConfig; - - public AuthenticationOptionsBuilder WithProvider(string provider) - { - _provider = provider; - return this; - } + private List _allowedScopes = new List(); public AuthenticationOptionsBuilder WithAllowedScopes(List allowedScopes) { @@ -23,76 +12,9 @@ namespace Ocelot.Configuration.Builder return this; } - public AuthenticationOptionsBuilder WithConfig(IAuthenticationConfig config) - { - _identityServerConfig = config; - return this; - } - public AuthenticationOptions Build() { - return new AuthenticationOptions(_provider, _allowedScopes, _identityServerConfig); - } - } - - public class IdentityServerConfigBuilder - { - private string _providerRootUrl; - private string _apiName; - private string _apiSecret; - private bool _requireHttps; - - public IdentityServerConfigBuilder WithProviderRootUrl(string providerRootUrl) - { - _providerRootUrl = providerRootUrl; - return this; - } - - public IdentityServerConfigBuilder WithApiName(string apiName) - { - _apiName = apiName; - return this; - } - - public IdentityServerConfigBuilder WithApiSecret(string apiSecret) - { - _apiSecret = apiSecret; - return this; - } - - public IdentityServerConfigBuilder WithRequireHttps(bool requireHttps) - { - _requireHttps = requireHttps; - return this; - } - - public IdentityServerConfig Build() - { - return new IdentityServerConfig(_providerRootUrl, _apiName, _requireHttps, _apiSecret); - } - } - - public class JwtConfigBuilder - { - public string _authority; - - public string _audience; - - public JwtConfigBuilder WithAuthority(string authority) - { - _authority = authority; - return this; - } - - public JwtConfigBuilder WithAudience(string audience) - { - _audience = audience; - return this; - } - - public JwtConfig Build() - { - return new JwtConfig(_authority, _audience); + return new AuthenticationOptions(_allowedScopes); } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs index 4140ed46..5f4d8ba8 100644 --- a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs @@ -1,38 +1,12 @@ -using System.Collections.Generic; -using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; -using Ocelot.Creator.Configuration; namespace Ocelot.Configuration.Creator { public class AuthenticationOptionsCreator : IAuthenticationOptionsCreator { - private readonly IAuthenticationProviderConfigCreator _creator; - - public AuthenticationOptionsCreator(IAuthenticationProviderConfigCreator creator) + public AuthenticationOptions Create(FileReRoute reRoute) { - _creator = creator; - } - - public AuthenticationOptions Create(FileReRoute reRoute, List authOptions) - { - //todo - loop is crap.. - foreach(var authOption in authOptions) - { - if(reRoute.AuthenticationProviderKey == authOption.AuthenticationProviderKey) - { - var authenticationConfig = _creator.Create(authOption); - - return new AuthenticationOptionsBuilder() - .WithProvider(authOption.Provider) - .WithAllowedScopes(authOption.AllowedScopes) - .WithConfig(authenticationConfig) - .Build(); - } - } - - //todo - should not return null? - return null; + return new AuthenticationOptions(reRoute.AuthenticationOptions.AllowedScopes); } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/AuthenticationProviderConfigCreator.cs b/src/Ocelot/Configuration/Creator/AuthenticationProviderConfigCreator.cs index c7a25799..a9bb2cc6 100644 --- a/src/Ocelot/Configuration/Creator/AuthenticationProviderConfigCreator.cs +++ b/src/Ocelot/Configuration/Creator/AuthenticationProviderConfigCreator.cs @@ -1,4 +1,4 @@ -using Ocelot.Creator.Configuration; +/*using Ocelot.Creator.Configuration; namespace Ocelot.Configuration.Creator { @@ -34,4 +34,4 @@ namespace Ocelot.Configuration.Creator .WithRequireHttps(authenticationOptions.IdentityServerConfig.RequireHttps).Build(); } } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index f241c8f2..88019907 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -92,7 +92,7 @@ namespace Ocelot.Configuration.Creator private async Task SetUpConfiguration(FileConfiguration fileConfiguration) { - var response = _configurationValidator.IsValid(fileConfiguration); + var response = await _configurationValidator.IsValid(fileConfiguration); if (response.Data.IsError) { @@ -110,14 +110,14 @@ namespace Ocelot.Configuration.Creator foreach (var reRoute in fileConfiguration.ReRoutes) { - var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration, fileConfiguration.AuthenticationOptions); + var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration); reRoutes.Add(ocelotReRoute); } return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath); } - private async Task SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, List authOptions) + private async Task SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration) { var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute); @@ -129,7 +129,7 @@ namespace Ocelot.Configuration.Creator var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration); - var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute, authOptions); + var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute); var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest); @@ -168,7 +168,7 @@ namespace Ocelot.Configuration.Creator .WithQosOptions(qosOptions) .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) .WithRateLimitOptions(rateLimitOption) - .WithAuthenticationProviderKey(fileReRoute.AuthenticationProviderKey) + .WithAuthenticationProviderKey(fileReRoute.AuthenticationOptions.AuthenticationProviderKey) .Build(); await SetupLoadBalancer(reRoute); diff --git a/src/Ocelot/Configuration/Creator/IAuthenticationOptionsCreator.cs b/src/Ocelot/Configuration/Creator/IAuthenticationOptionsCreator.cs index 9fe50e14..b7ea8141 100644 --- a/src/Ocelot/Configuration/Creator/IAuthenticationOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/IAuthenticationOptionsCreator.cs @@ -5,6 +5,6 @@ namespace Ocelot.Configuration.Creator { public interface IAuthenticationOptionsCreator { - AuthenticationOptions Create(FileReRoute reRoute, List authOptions); + AuthenticationOptions Create(FileReRoute reRoute); } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs b/src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs index b84db19a..f98a77c6 100644 --- a/src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs @@ -36,7 +36,7 @@ namespace Ocelot.Configuration.Creator private bool IsAuthenticated(FileReRoute fileReRoute) { - return !string.IsNullOrEmpty(fileReRoute.AuthenticationProviderKey); + return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.AuthenticationProviderKey); } private bool IsAuthorised(FileReRoute fileReRoute) diff --git a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs index 9f962daa..81fc9d28 100644 --- a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs +++ b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs @@ -7,14 +7,9 @@ namespace Ocelot.Configuration.File public FileAuthenticationOptions() { AllowedScopes = new List(); - IdentityServerConfig = new FileIdentityServerConfig(); - JwtConfig = new FileJwtConfig(); } public string AuthenticationProviderKey {get; set;} - public string Provider { get; set; } public List AllowedScopes { get; set; } - public FileIdentityServerConfig IdentityServerConfig { get; set; } - public FileJwtConfig JwtConfig { get; set; } } } diff --git a/src/Ocelot/Configuration/File/FileConfiguration.cs b/src/Ocelot/Configuration/File/FileConfiguration.cs index dd7ac1b5..18938a0e 100644 --- a/src/Ocelot/Configuration/File/FileConfiguration.cs +++ b/src/Ocelot/Configuration/File/FileConfiguration.cs @@ -8,11 +8,9 @@ namespace Ocelot.Configuration.File { ReRoutes = new List(); GlobalConfiguration = new FileGlobalConfiguration(); - AuthenticationOptions = new List(); } public List ReRoutes { get; set; } public FileGlobalConfiguration GlobalConfiguration { get; set; } - public List AuthenticationOptions { get; set; } } } diff --git a/src/Ocelot/Configuration/File/FileReRoute.cs b/src/Ocelot/Configuration/File/FileReRoute.cs index 77a323f5..af946a6c 100644 --- a/src/Ocelot/Configuration/File/FileReRoute.cs +++ b/src/Ocelot/Configuration/File/FileReRoute.cs @@ -14,6 +14,7 @@ namespace Ocelot.Configuration.File FileCacheOptions = new FileCacheOptions(); QoSOptions = new FileQoSOptions(); RateLimitOptions = new FileRateLimitRule(); + AuthenticationOptions = new FileAuthenticationOptions(); } public string DownstreamPathTemplate { get; set; } @@ -33,6 +34,6 @@ namespace Ocelot.Configuration.File public FileQoSOptions QoSOptions { get; set; } public string LoadBalancer {get;set;} public FileRateLimitRule RateLimitOptions { get; set; } - public string AuthenticationProviderKey {get; set;} + public FileAuthenticationOptions AuthenticationOptions { get; set; } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs index 6fa6f72a..25c5b00a 100644 --- a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs @@ -3,8 +3,6 @@ using System.Text; using System.Threading.Tasks; using Consul; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Ocelot.Authentication.JsonConverters; using Ocelot.Responses; using Ocelot.ServiceDiscovery; @@ -49,9 +47,7 @@ namespace Ocelot.Configuration.Repository var json = Encoding.UTF8.GetString(bytes); - var settings = new JsonSerializerSettings(); - settings.Converters.Add(new AuthenticationConfigConverter()); - var consulConfig = JsonConvert.DeserializeObject(json, settings); + var consulConfig = JsonConvert.DeserializeObject(json); return new OkResponse(consulConfig); } diff --git a/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs b/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs index 6e6f120a..a3a77511 100644 --- a/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs +++ b/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using Ocelot.Authentication.Handler; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; using Ocelot.Configuration.File; using Ocelot.Errors; using Ocelot.Responses; @@ -10,7 +10,14 @@ namespace Ocelot.Configuration.Validator { public class FileConfigurationValidator : IConfigurationValidator { - public Response IsValid(FileConfiguration configuration) + private readonly IAuthenticationSchemeProvider _provider; + + public FileConfigurationValidator(IAuthenticationSchemeProvider provider) + { + _provider = provider; + } + + public async Task> IsValid(FileConfiguration configuration) { var result = CheckForDuplicateReRoutes(configuration); @@ -19,7 +26,7 @@ namespace Ocelot.Configuration.Validator return new OkResponse(result); } - result = CheckForUnsupportedAuthenticationProviders(configuration); + result = await CheckForUnsupportedAuthenticationProviders(configuration); if (result.IsError) { @@ -42,38 +49,27 @@ namespace Ocelot.Configuration.Validator return new OkResponse(result); } - private ConfigurationValidationResult CheckForUnsupportedAuthenticationProviders(FileConfiguration configuration) + private async Task CheckForUnsupportedAuthenticationProviders(FileConfiguration configuration) { var errors = new List(); - //todo - these loops break seperation of concerns...unit tests should fail also.. - foreach(var authProvider in configuration.AuthenticationOptions) - { - if (IsSupportedAuthenticationProvider(authProvider.Provider)) - { - continue; - } - - var error = new UnsupportedAuthenticationProviderError($"{authProvider.Provider} is unsupported authentication provider"); - errors.Add(error); - } - foreach (var reRoute in configuration.ReRoutes) { - var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationProviderKey); + var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationOptions.AuthenticationProviderKey); if (!isAuthenticated) { continue; } - //todo is this correct? - if(configuration.AuthenticationOptions.Exists(x => x.AuthenticationProviderKey == reRoute.AuthenticationProviderKey)) + var data = await _provider.GetAllSchemesAsync(); + var schemes = data.ToList(); + if (schemes.Any(x => x.Name == reRoute.AuthenticationOptions.AuthenticationProviderKey)) { continue; } - var error = new UnsupportedAuthenticationProviderError($"{reRoute.AuthenticationProviderKey} is unsupported authentication provider, upstream template is {reRoute.UpstreamPathTemplate}, upstream method is {reRoute.UpstreamHttpMethod}"); + var error = new UnsupportedAuthenticationProviderError($"{reRoute.AuthenticationOptions.AuthenticationProviderKey} is unsupported authentication provider, upstream template is {reRoute.UpstreamPathTemplate}, upstream method is {reRoute.UpstreamHttpMethod}"); errors.Add(error); } @@ -82,13 +78,6 @@ namespace Ocelot.Configuration.Validator : new ConfigurationValidationResult(false); } - private bool IsSupportedAuthenticationProvider(string provider) - { - SupportedAuthenticationProviders supportedProvider; - - return Enum.TryParse(provider, true, out supportedProvider); - } - private ConfigurationValidationResult CheckForReRoutesContainingDownstreamSchemeInDownstreamPathTemplate(FileConfiguration configuration) { var errors = new List(); diff --git a/src/Ocelot/Configuration/Validator/IConfigurationValidator.cs b/src/Ocelot/Configuration/Validator/IConfigurationValidator.cs index 09bf7dae..5f6ae6ba 100644 --- a/src/Ocelot/Configuration/Validator/IConfigurationValidator.cs +++ b/src/Ocelot/Configuration/Validator/IConfigurationValidator.cs @@ -1,10 +1,11 @@ -using Ocelot.Configuration.File; +using System.Threading.Tasks; +using Ocelot.Configuration.File; using Ocelot.Responses; namespace Ocelot.Configuration.Validator { public interface IConfigurationValidator { - Response IsValid(FileConfiguration configuration); + Task> IsValid(FileConfiguration configuration); } } diff --git a/src/Ocelot/Creator/Configuration/IAuthenticationProviderConfigCreator.cs b/src/Ocelot/Creator/Configuration/IAuthenticationProviderConfigCreator.cs index f5cd4fda..354af4c5 100644 --- a/src/Ocelot/Creator/Configuration/IAuthenticationProviderConfigCreator.cs +++ b/src/Ocelot/Creator/Configuration/IAuthenticationProviderConfigCreator.cs @@ -1,4 +1,4 @@ -using Ocelot.Configuration; +/*using Ocelot.Configuration; using Ocelot.Configuration.File; namespace Ocelot.Creator.Configuration @@ -7,4 +7,4 @@ namespace Ocelot.Creator.Configuration { IAuthenticationConfig Create(FileAuthenticationOptions authenticationOptions); } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 567e3659..bacae519 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -42,15 +42,10 @@ using System.Net.Http; using System.Reflection; using System.Security.Cryptography.X509Certificates; using IdentityServer4.AccessTokenValidation; -using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.IdentityModel.Tokens; using Ocelot.Configuration; -using Ocelot.Creator.Configuration; using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider; -using System.IO; -using Newtonsoft.Json; namespace Ocelot.DependencyInjection { @@ -77,7 +72,6 @@ namespace Ocelot.DependencyInjection services.Configure(configurationRoot); services.TryAddSingleton(); - services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); @@ -149,38 +143,6 @@ namespace Ocelot.DependencyInjection services.AddIdentityServer(identityServerConfiguration, configurationRoot); } - //todo - this means we need to break auth providers into there own section in the config - //then join onto them from reroutes based on a key - var data = File.ReadAllText("configuration.json"); - var config = JsonConvert.DeserializeObject(data); - - foreach(var authOptions in config.AuthenticationOptions) - { - if(authOptions.Provider.ToLower() == "identityserver") - { - Action options = o => - { - o.Authority = authOptions.IdentityServerConfig.ProviderRootUrl; - o.ApiName = authOptions.IdentityServerConfig.ApiName; - o.RequireHttpsMetadata = authOptions.IdentityServerConfig.RequireHttps; - o.SupportedTokens = SupportedTokens.Both; - o.ApiSecret = authOptions.IdentityServerConfig.ApiSecret; - }; - - services.AddAuthentication() - .AddIdentityServerAuthentication(authOptions.AuthenticationProviderKey, options); - } - else if (authOptions.Provider.ToLower() == "jwt") - { - services.AddAuthentication() - .AddJwtBearer(x => - { - x.Authority = authOptions.JwtConfig.Authority; - x.Audience = authOptions.JwtConfig.Audience; - }); - } - } - return services; } diff --git a/src/Ocelot/Ocelot.csproj b/src/Ocelot/Ocelot.csproj index 0ce399c0..243953b5 100644 --- a/src/Ocelot/Ocelot.csproj +++ b/src/Ocelot/Ocelot.csproj @@ -26,7 +26,7 @@ - + @@ -42,7 +42,7 @@ - + diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 8e30c651..eb51e889 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Security.Claims; +using IdentityServer4.AccessTokenValidation; using IdentityServer4.Models; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -14,7 +15,6 @@ using Xunit; namespace Ocelot.AcceptanceTests { - using IdentityServer4; using IdentityServer4.Test; public class AuthenticationTests : IDisposable @@ -28,10 +28,19 @@ namespace Ocelot.AcceptanceTests private int _downstreamServicePort = 51876; private string _downstreamServiceScheme = "http"; private string _downstreamServiceUrl = "http://localhost:51876"; + private readonly Action _options; public AuthenticationTests() { _steps = new Steps(); + _options = o => + { + o.Authority = _identityServerRootUrl; + o.ApiName = "api"; + o.RequireHttpsMetadata = false; + o.SupportedTokens = SupportedTokens.Both; + o.ApiSecret = "secret"; + }; } [Fact] @@ -49,30 +58,18 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Post" }, - AuthenticationProviderKey = "Test" + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test" + } } - }, - AuthenticationOptions = new List - { - new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - IdentityServerConfig = new FileIdentityServerConfig{ - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - }, - AuthenticationProviderKey = "Test" - } } }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenThePostHasContent("postContent")) .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) @@ -94,31 +91,19 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, - AuthenticationProviderKey = "Test" + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test" + } } - }, - AuthenticationOptions = new List - { - new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - IdentityServerConfig = new FileIdentityServerConfig{ - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - }, - AuthenticationProviderKey = "Test" - } - } + } }; this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) @@ -141,31 +126,19 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, - AuthenticationProviderKey = "Test" + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test" + } } - }, - AuthenticationOptions = new List - { - new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - IdentityServerConfig = new FileIdentityServerConfig{ - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - }, - AuthenticationProviderKey = "Test" - } - } + } }; this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) .And(x => _steps.GivenIHaveATokenForApi2(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) @@ -187,31 +160,19 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Post" }, - AuthenticationProviderKey = "Test" - } - }, - AuthenticationOptions = new List - { - new FileAuthenticationOptions + AuthenticationOptions = new FileAuthenticationOptions { - AllowedScopes = new List(), - Provider = "IdentityServer", - IdentityServerConfig = new FileIdentityServerConfig{ - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - }, AuthenticationProviderKey = "Test" } - } + } + } }; this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenThePostHasContent("postContent")) .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) @@ -234,31 +195,19 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Post" }, - AuthenticationProviderKey = "Test" + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test" + } } - }, - AuthenticationOptions = new List - { - new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - IdentityServerConfig = new FileIdentityServerConfig{ - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - }, - AuthenticationProviderKey = "Test" - } - } + } }; this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenThePostHasContent("postContent")) .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs index 59c97612..14a61f02 100644 --- a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Security.Claims; +using IdentityServer4.AccessTokenValidation; using IdentityServer4.Models; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -22,10 +23,20 @@ namespace Ocelot.AcceptanceTests private IWebHost _servicebuilder; private IWebHost _identityServerBuilder; private readonly Steps _steps; + private Action _options; + private string _identityServerRootUrl = "http://localhost:51888"; public AuthorisationTests() { _steps = new Steps(); + _options = o => + { + o.Authority = _identityServerRootUrl; + o.ApiName = "api"; + o.RequireHttpsMetadata = false; + o.SupportedTokens = SupportedTokens.Both; + o.ApiSecret = "secret"; + }; } [Fact] @@ -33,7 +44,7 @@ namespace Ocelot.AcceptanceTests { var configuration = new FileConfiguration { - AuthenticationOptions = new List +/* AuthenticationOptions = new List { new FileAuthenticationOptions { @@ -47,7 +58,7 @@ namespace Ocelot.AcceptanceTests }, AuthenticationProviderKey = "Test" } - }, + },*/ ReRoutes = new List { new FileReRoute @@ -58,7 +69,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, - AuthenticationProviderKey = "Test", + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test" + }, AddHeadersToRequest = { {"CustomerId", "Claims[CustomerId] > value"}, @@ -84,7 +98,7 @@ namespace Ocelot.AcceptanceTests .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) @@ -97,7 +111,7 @@ namespace Ocelot.AcceptanceTests { var configuration = new FileConfiguration { - AuthenticationOptions = new List +/* AuthenticationOptions = new List { new FileAuthenticationOptions { @@ -111,7 +125,7 @@ namespace Ocelot.AcceptanceTests }, AuthenticationProviderKey = "Test" } - }, + },*/ ReRoutes = new List { new FileReRoute @@ -122,7 +136,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, - AuthenticationProviderKey = "Test", + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test" + }, AddHeadersToRequest = { {"CustomerId", "Claims[CustomerId] > value"}, @@ -147,7 +164,7 @@ namespace Ocelot.AcceptanceTests .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) @@ -159,7 +176,7 @@ namespace Ocelot.AcceptanceTests { var configuration = new FileConfiguration { - AuthenticationOptions = new List + /* AuthenticationOptions = new List { new FileAuthenticationOptions { @@ -173,7 +190,7 @@ namespace Ocelot.AcceptanceTests }, AuthenticationProviderKey = "Test" } - }, + },*/ ReRoutes = new List { new FileReRoute @@ -184,7 +201,11 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, - AuthenticationProviderKey = "Test" + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test", + AllowedScopes = new List{ "api", "api.readOnly", "openid", "offline_access" }, + }, } } }; @@ -193,7 +214,7 @@ namespace Ocelot.AcceptanceTests .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) @@ -205,7 +226,7 @@ namespace Ocelot.AcceptanceTests { var configuration = new FileConfiguration { - AuthenticationOptions = new List + /* AuthenticationOptions = new List { new FileAuthenticationOptions { @@ -219,7 +240,7 @@ namespace Ocelot.AcceptanceTests }, AuthenticationProviderKey = "Test" } - }, + },*/ ReRoutes = new List { new FileReRoute @@ -230,7 +251,11 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, - AuthenticationProviderKey = "Test" + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test", + AllowedScopes = new List{ "api", "openid", "offline_access" }, + }, } } }; @@ -239,7 +264,7 @@ namespace Ocelot.AcceptanceTests .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index 32094441..8ab0c0ba 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Net; using System.Security.Claims; +using IdentityServer4.AccessTokenValidation; using IdentityServer4.Models; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -24,10 +25,20 @@ namespace Ocelot.AcceptanceTests private IWebHost _servicebuilder; private IWebHost _identityServerBuilder; private readonly Steps _steps; + private Action _options; + private string _identityServerRootUrl = "http://localhost:52888"; public ClaimsToHeadersForwardingTests() { _steps = new Steps(); + _options = o => + { + o.Authority = _identityServerRootUrl; + o.ApiName = "api"; + o.RequireHttpsMetadata = false; + o.SupportedTokens = SupportedTokens.Both; + o.ApiSecret = "secret"; + }; } [Fact] @@ -47,7 +58,7 @@ namespace Ocelot.AcceptanceTests var configuration = new FileConfiguration { - AuthenticationOptions = new List + /* AuthenticationOptions = new List { new FileAuthenticationOptions { @@ -64,7 +75,7 @@ namespace Ocelot.AcceptanceTests }, AuthenticationProviderKey = "Test" } - }, + },*/ ReRoutes = new List { new FileReRoute @@ -75,7 +86,14 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, - AuthenticationProviderKey = "Test", + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test", + AllowedScopes = new List + { + "openid", "offline_access", "api" + }, + }, AddHeadersToRequest = { {"CustomerId", "Claims[CustomerId] > value"}, @@ -91,7 +109,7 @@ namespace Ocelot.AcceptanceTests .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:52876", 200)) .And(x => _steps.GivenIHaveAToken("http://localhost:52888")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) diff --git a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs index 3cd5da4a..cbc55638 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Net; using System.Security.Claims; +using IdentityServer4.AccessTokenValidation; using IdentityServer4.Models; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -24,10 +25,20 @@ namespace Ocelot.AcceptanceTests private IWebHost _servicebuilder; private IWebHost _identityServerBuilder; private readonly Steps _steps; + private Action _options; + private string _identityServerRootUrl = "http://localhost:57888"; public ClaimsToQueryStringForwardingTests() { _steps = new Steps(); + _options = o => + { + o.Authority = _identityServerRootUrl; + o.ApiName = "api"; + o.RequireHttpsMetadata = false; + o.SupportedTokens = SupportedTokens.Both; + o.ApiSecret = "secret"; + }; } [Fact] @@ -47,7 +58,7 @@ namespace Ocelot.AcceptanceTests var configuration = new FileConfiguration { - AuthenticationOptions = new List + /* AuthenticationOptions = new List { new FileAuthenticationOptions { @@ -64,7 +75,7 @@ namespace Ocelot.AcceptanceTests }, AuthenticationProviderKey = "Test" } - }, + },*/ ReRoutes = new List { new FileReRoute @@ -75,7 +86,14 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, - AuthenticationProviderKey = "Test", + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test", + AllowedScopes = new List + { + "openid", "offline_access", "api" + }, + }, AddQueriesToRequest = { {"CustomerId", "Claims[CustomerId] > value"}, @@ -91,7 +109,7 @@ namespace Ocelot.AcceptanceTests .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:57876", 200)) .And(x => _steps.GivenIHaveAToken("http://localhost:57888")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenOcelotIsRunning(_options, "Test")) .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) diff --git a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs index 231f8410..87476533 100644 --- a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs +++ b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs @@ -3,15 +3,12 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Text; -using Consul; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; -using Ocelot.Authentication.JsonConverters; using Ocelot.Configuration; using Ocelot.Configuration.File; -using Ocelot.Configuration.Repository; using Ocelot.ServiceDiscovery; using TestStack.BDDfy; using Xunit; @@ -105,9 +102,7 @@ namespace Ocelot.AcceptanceTests var json = reader.ReadToEnd(); - var settings = new JsonSerializerSettings(); - settings.Converters.Add(new AuthenticationConfigConverter()); - _config = JsonConvert.DeserializeObject(json, settings); + _config = JsonConvert.DeserializeObject(json); var response = JsonConvert.SerializeObject(true); diff --git a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj index 271823ac..6380b5f9 100644 --- a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj +++ b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj @@ -32,8 +32,8 @@ - - + + @@ -42,11 +42,11 @@ - - + + - + diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index 44bdf8f4..7aba9c48 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -8,6 +8,8 @@ using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using CacheManager.Core; +using IdentityServer4.AccessTokenValidation; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Configuration; @@ -86,6 +88,26 @@ namespace Ocelot.AcceptanceTests _ocelotClient = _ocelotServer.CreateClient(); } + /// + /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step. + /// + public void GivenOcelotIsRunning(Action options, string authenticationProviderKey) + { + _webHostBuilder = new WebHostBuilder(); + + _webHostBuilder.ConfigureServices(s => + { + s.AddSingleton(_webHostBuilder); + s.AddAuthentication() + .AddIdentityServerAuthentication(authenticationProviderKey, options); + }); + + _ocelotServer = new TestServer(_webHostBuilder + .UseStartup()); + + _ocelotClient = _ocelotServer.CreateClient(); + } + public void GivenOcelotIsRunningUsingConsulToStoreConfig(ConsulRegistryConfiguration consulConfig) { _webHostBuilder = new WebHostBuilder(); diff --git a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj index 73097d57..5d1d4841 100644 --- a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj +++ b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj @@ -31,8 +31,8 @@ - - + + @@ -40,10 +40,10 @@ - - - - + + + + diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs index cfa017a6..63282da5 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs @@ -1,4 +1,11 @@ using System.Collections.Generic; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; using Ocelot.Configuration.File; using Ocelot.Configuration.Validator; using Ocelot.Responses; @@ -13,10 +20,12 @@ namespace Ocelot.UnitTests.Configuration private readonly IConfigurationValidator _configurationValidator; private FileConfiguration _fileConfiguration; private Response _result; + private Mock _provider; public ConfigurationValidationTests() { - _configurationValidator = new FileConfigurationValidator(); + _provider = new Mock(); + _configurationValidator = new FileConfigurationValidator(_provider.Object); } [Fact] @@ -62,50 +71,48 @@ namespace Ocelot.UnitTests.Configuration { this.Given(x => x.GivenAConfiguration(new FileConfiguration { - AuthenticationOptions = new List - { - new FileAuthenticationOptions - { - Provider = "IdentityServer", - AuthenticationProviderKey = "Test" - } - }, ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/products/", UpstreamPathTemplate = "http://asdf.com", - AuthenticationProviderKey = "Test" + AuthenticationOptions = new FileAuthenticationOptions() + { + AuthenticationProviderKey = "Test" + } } } })) + .And(x => x.GivenTheAuthSchemeExists("Test")) .When(x => x.WhenIValidateTheConfiguration()) .Then(x => x.ThenTheResultIsValid()) .BDDfy(); } + private void GivenTheAuthSchemeExists(string name) + { + _provider.Setup(x => x.GetAllSchemesAsync()).ReturnsAsync(new List + { + new AuthenticationScheme(name, name, typeof(TestHandler)) + }); + } + [Fact] public void configuration_is_invalid_with_invalid_authentication_provider() { this.Given(x => x.GivenAConfiguration(new FileConfiguration { - AuthenticationOptions = new List - { - new FileAuthenticationOptions - { - Provider = "BootyBootyBottyRockinEverywhere", - AuthenticationProviderKey = "Test" - } - }, ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/products/", UpstreamPathTemplate = "http://asdf.com", - AuthenticationProviderKey = "Test" - } + AuthenticationOptions = new FileAuthenticationOptions() + { + AuthenticationProviderKey = "Test" + } } } })) .When(x => x.WhenIValidateTheConfiguration()) @@ -146,7 +153,7 @@ namespace Ocelot.UnitTests.Configuration private void WhenIValidateTheConfiguration() { - _result = _configurationValidator.IsValid(_fileConfiguration); + _result = _configurationValidator.IsValid(_fileConfiguration).Result; } private void ThenTheResultIsValid() @@ -163,5 +170,23 @@ namespace Ocelot.UnitTests.Configuration { _result.Data.Errors[0].ShouldBeOfType(); } + + private class TestOptions : AuthenticationSchemeOptions + { + } + + private class TestHandler : AuthenticationHandler + { + public TestHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + { + } + + protected override Task HandleAuthenticateAsync() + { + var principal = new ClaimsPrincipal(); + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name))); + } + } + } } \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index e1bbdb0d..17e5a2b4 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -446,16 +446,14 @@ namespace Ocelot.UnitTests.Configuration [Theory] [MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))] - public void should_create_with_headers_to_extract(string provider, IAuthenticationConfig config, FileConfiguration fileConfig) + public void should_create_with_headers_to_extract(FileConfiguration fileConfig) { var reRouteOptions = new ReRouteOptionsBuilder() .WithIsAuthenticated(true) .Build(); var authenticationOptions = new AuthenticationOptionsBuilder() - .WithProvider(provider) .WithAllowedScopes(new List()) - .WithConfig(config) .Build(); var expected = new List @@ -480,23 +478,21 @@ namespace Ocelot.UnitTests.Configuration .And(x => x.GivenTheLoadBalancerFactoryReturns()) .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(expected)) - .And(x => x.ThenTheAuthenticationOptionsAre(provider, expected)) + .And(x => x.ThenTheAuthenticationOptionsAre(expected)) .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) .BDDfy(); } [Theory] [MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))] - public void should_create_with_authentication_properties(string provider, IAuthenticationConfig config, FileConfiguration fileConfig) + public void should_create_with_authentication_properties(FileConfiguration fileConfig) { var reRouteOptions = new ReRouteOptionsBuilder() .WithIsAuthenticated(true) .Build(); var authenticationOptions = new AuthenticationOptionsBuilder() - .WithProvider(provider) .WithAllowedScopes(new List()) - .WithConfig(config) .Build(); var expected = new List @@ -516,7 +512,7 @@ namespace Ocelot.UnitTests.Configuration .And(x => x.GivenTheLoadBalancerFactoryReturns()) .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(expected)) - .And(x => x.ThenTheAuthenticationOptionsAre(provider, expected)) + .And(x => x.ThenTheAuthenticationOptionsAre(expected)) .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) .BDDfy(); } @@ -538,7 +534,7 @@ namespace Ocelot.UnitTests.Configuration { _validator .Setup(x => x.IsValid(It.IsAny())) - .Returns(new OkResponse(new ConfigurationValidationResult(false))); + .ReturnsAsync(new OkResponse(new ConfigurationValidationResult(false))); } private void GivenTheConfigIs(FileConfiguration fileConfiguration) @@ -587,34 +583,13 @@ namespace Ocelot.UnitTests.Configuration } } - private void ThenTheAuthenticationOptionsAre(string provider, List expectedReRoutes) + private void ThenTheAuthenticationOptionsAre(List expectedReRoutes) { for (int i = 0; i < _config.Data.ReRoutes.Count; i++) { var result = _config.Data.ReRoutes[i].AuthenticationOptions; var expected = expectedReRoutes[i].AuthenticationOptions; - result.AllowedScopes.ShouldBe(expected.AllowedScopes); - result.Provider.ShouldBe(expected.Provider); - - if (provider.ToLower() == "identityserver") - { - var config = result.Config as IdentityServerConfig; - var expectedConfig = expected.Config as IdentityServerConfig; - - config.ProviderRootUrl.ShouldBe(expectedConfig.ProviderRootUrl); - config.RequireHttps.ShouldBe(expectedConfig.RequireHttps); - config.ApiName.ShouldBe(expectedConfig.ApiName); - config.ApiSecret.ShouldBe(expectedConfig.ApiSecret); - } - else - { - var config = result.Config as JwtConfig; - var expectedConfig = expected.Config as JwtConfig; - - config.Audience.ShouldBe(expectedConfig.Audience); - config.Authority.ShouldBe(expectedConfig.Authority); - } } } @@ -666,14 +641,14 @@ namespace Ocelot.UnitTests.Configuration private void GivenTheAuthOptionsCreatorReturns(AuthenticationOptions authOptions) { _authOptionsCreator - .Setup(x => x.Create(It.IsAny(), It.IsAny>())) + .Setup(x => x.Create(It.IsAny())) .Returns(authOptions); } private void ThenTheAuthOptionsCreatorIsCalledCorrectly() { _authOptionsCreator - .Verify(x => x.Create(_fileConfiguration.ReRoutes[0], _fileConfiguration.AuthenticationOptions), Times.Once); + .Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once); } private void GivenTheUpstreamTemplatePatternCreatorReturns(string pattern) diff --git a/test/Ocelot.UnitTests/Configuration/ReRouteOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ReRouteOptionsCreatorTests.cs index f2d5ad8e..3c1b7561 100644 --- a/test/Ocelot.UnitTests/Configuration/ReRouteOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ReRouteOptionsCreatorTests.cs @@ -34,7 +34,10 @@ namespace Ocelot.UnitTests.Configuration ExceptionsAllowedBeforeBreaking = 1, TimeoutValue = 1 }, - AuthenticationProviderKey = "Test", + AuthenticationOptions = new FileAuthenticationOptions() + { + AuthenticationProviderKey = "Test" + }, RouteClaimsRequirement = new Dictionary() { {"",""} diff --git a/test/Ocelot.UnitTests/DynamicSchemeTests.cs b/test/Ocelot.UnitTests/DynamicSchemeTests.cs deleted file mode 100644 index b699161a..00000000 --- a/test/Ocelot.UnitTests/DynamicSchemeTests.cs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. - -using System; -using System.Net; -using System.Security.Claims; -using System.Text.Encodings.Web; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Shouldly; -using Xunit; - -namespace Ocelot.UnitTests -{ - public class DynamicSchemeTests - { - [Fact] - public async Task OptionsAreConfiguredOnce() - { - var server = CreateServer(s => - { - s.Configure("One", o => o.Instance = new Singleton()); - }); - // Add One scheme - var response = await server.CreateClient().GetAsync("http://example.com/add/One"); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - var transaction = await server.CreateClient().GetAsync("http://example.com/auth/One"); - var result = await transaction.Content.ReadAsStringAsync(); - result.ShouldBe("True"); - } - - public class TestOptions : AuthenticationSchemeOptions - { - public Singleton Instance { get; set; } - } - - public class Singleton - { - public static int _count; - - public Singleton() - { - _count++; - Count = _count; - } - - public int Count { get; } - } - - private class TestHandler : AuthenticationHandler - { - public TestHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) - { - } - - protected override Task HandleAuthenticateAsync() - { - var principal = new ClaimsPrincipal(); - var id = new ClaimsIdentity("Ocelot"); - id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name)); - if (Options.Instance != null) - { - id.AddClaim(new Claim("Count", Options.Instance.Count.ToString())); - } - principal.AddIdentity(id); - return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name))); - } - } - - private static TestServer CreateServer(Action configureServices = null) - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseAuthentication(); - app.Use(async (context, next) => - { - var req = context.Request; - var res = context.Response; - if (req.Path.StartsWithSegments(new PathString("/add"), out var remainder)) - { - var name = remainder.Value.Substring(1); - var auth = context.RequestServices.GetRequiredService(); - var scheme = new AuthenticationScheme(name, name, typeof(TestHandler)); - auth.AddScheme(scheme); - } - else if (req.Path.StartsWithSegments(new PathString("/auth"), out remainder)) - { - var name = (remainder.Value.Length > 0) ? remainder.Value.Substring(1) : null; - var result = await context.AuthenticateAsync(name); - context.User = result.Principal; - await res.WriteJsonAsync(context.User.Identity.IsAuthenticated.ToString()); - } - else if (req.Path.StartsWithSegments(new PathString("/remove"), out remainder)) - { - var name = remainder.Value.Substring(1); - var auth = context.RequestServices.GetRequiredService(); - auth.RemoveScheme(name); - } - else - { - await next(); - } - }); - }) - .ConfigureServices(services => - { - configureServices?.Invoke(services); - services.AddAuthentication(); - }); - return new TestServer(builder); - } - } -} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj b/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj index 26677800..415fb07b 100644 --- a/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj +++ b/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj @@ -34,9 +34,9 @@ - - - + + + @@ -44,10 +44,10 @@ - - + + - + diff --git a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs index b0455e38..426fd1d4 100644 --- a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs +++ b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs @@ -42,7 +42,7 @@ namespace Ocelot.UnitTests.Responder [InlineData(OcelotErrorCode.RequestTimedOutError)] public void should_return_service_unavailable(OcelotErrorCode errorCode) { - ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.ServiceUnavailable); + ShouldMapErrorToStatusCode(OcelotErrorCode.RequestTimedOutError, HttpStatusCode.ServiceUnavailable); } diff --git a/test/Ocelot.UnitTests/TestData/AuthenticationConfigTestData.cs b/test/Ocelot.UnitTests/TestData/AuthenticationConfigTestData.cs index 2d92378b..ef9a454a 100644 --- a/test/Ocelot.UnitTests/TestData/AuthenticationConfigTestData.cs +++ b/test/Ocelot.UnitTests/TestData/AuthenticationConfigTestData.cs @@ -1,8 +1,6 @@ namespace Ocelot.UnitTests.TestData { using System.Collections.Generic; - - using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; public class AuthenticationConfigTestData @@ -11,31 +9,8 @@ { yield return new object[] { - "IdentityServer", - new IdentityServerConfigBuilder() - .WithRequireHttps(true) - .WithApiName("test") - .WithApiSecret("test") - .WithProviderRootUrl("test") - .Build(), new FileConfiguration { - AuthenticationOptions = new List - { - new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - IdentityServerConfig = new FileIdentityServerConfig - { - ProviderRootUrl = "http://localhost:51888", - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } , - AuthenticationProviderKey = "Test" - } - }, ReRoutes = new List { new FileReRoute @@ -44,11 +19,15 @@ DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = true, - AuthenticationProviderKey = "Test", + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test", + AllowedScopes = new List(), + }, AddHeadersToRequest = - { - { "CustomerId", "Claims[CustomerId] > value" }, - } + { + { "CustomerId", "Claims[CustomerId] > value" }, + } } } } @@ -56,27 +35,8 @@ yield return new object[] { - "Jwt", - new JwtConfigBuilder() - .WithAudience("a") - .WithAuthority("au") - .Build(), new FileConfiguration { - AuthenticationOptions = new List - { - new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - JwtConfig = new FileJwtConfig - { - Audience = "a", - Authority = "au" - }, - AuthenticationProviderKey = "Test" - } - }, ReRoutes = new List { new FileReRoute @@ -85,7 +45,11 @@ DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = new List { "Get" }, ReRouteIsCaseSensitive = true, - AuthenticationProviderKey = "Test", + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test", + AllowedScopes = new List(), + }, AddHeadersToRequest = { { "CustomerId", "Claims[CustomerId] > value" },