test passing with authentication being provided by the user and mapped to the re route in config

This commit is contained in:
Tom Pallister 2017-11-01 15:25:55 +00:00
parent 967f0f7128
commit 3f2af85969
32 changed files with 280 additions and 606 deletions

View File

@ -1,4 +1,5 @@
using System; /*
using System;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Ocelot.Configuration; using Ocelot.Configuration;
@ -57,3 +58,4 @@ namespace Ocelot.Authentication.JsonConverters
} }
*/

View File

@ -2,52 +2,13 @@
namespace Ocelot.Configuration namespace Ocelot.Configuration
{ {
using Newtonsoft.Json;
public class AuthenticationOptions public class AuthenticationOptions
{ {
public AuthenticationOptions(string provider, List<string> allowedScopes, IAuthenticationConfig config) public AuthenticationOptions(List<string> allowedScopes)
{ {
Provider = provider;
AllowedScopes = allowedScopes; AllowedScopes = allowedScopes;
Config = config;
} }
public string Provider { get; private set; }
public List<string> AllowedScopes { get; private set; } public List<string> 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 {}
} }

View File

@ -4,18 +4,7 @@ namespace Ocelot.Configuration.Builder
{ {
public class AuthenticationOptionsBuilder public class AuthenticationOptionsBuilder
{ {
private List<string> _allowedScopes = new List<string>();
private string _provider;
private List<string> _allowedScopes;
private IAuthenticationConfig _identityServerConfig;
public AuthenticationOptionsBuilder WithProvider(string provider)
{
_provider = provider;
return this;
}
public AuthenticationOptionsBuilder WithAllowedScopes(List<string> allowedScopes) public AuthenticationOptionsBuilder WithAllowedScopes(List<string> allowedScopes)
{ {
@ -23,76 +12,9 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public AuthenticationOptionsBuilder WithConfig(IAuthenticationConfig config)
{
_identityServerConfig = config;
return this;
}
public AuthenticationOptions Build() public AuthenticationOptions Build()
{ {
return new AuthenticationOptions(_provider, _allowedScopes, _identityServerConfig); return new AuthenticationOptions(_allowedScopes);
}
}
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);
} }
} }
} }

View File

@ -1,38 +1,12 @@
using System.Collections.Generic;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Creator.Configuration;
namespace Ocelot.Configuration.Creator namespace Ocelot.Configuration.Creator
{ {
public class AuthenticationOptionsCreator : IAuthenticationOptionsCreator public class AuthenticationOptionsCreator : IAuthenticationOptionsCreator
{ {
private readonly IAuthenticationProviderConfigCreator _creator; public AuthenticationOptions Create(FileReRoute reRoute)
public AuthenticationOptionsCreator(IAuthenticationProviderConfigCreator creator)
{ {
_creator = creator; return new AuthenticationOptions(reRoute.AuthenticationOptions.AllowedScopes);
}
public AuthenticationOptions Create(FileReRoute reRoute, List<FileAuthenticationOptions> 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;
} }
} }
} }

View File

@ -1,4 +1,4 @@
using Ocelot.Creator.Configuration; /*using Ocelot.Creator.Configuration;
namespace Ocelot.Configuration.Creator namespace Ocelot.Configuration.Creator
{ {
@ -34,4 +34,4 @@ namespace Ocelot.Configuration.Creator
.WithRequireHttps(authenticationOptions.IdentityServerConfig.RequireHttps).Build(); .WithRequireHttps(authenticationOptions.IdentityServerConfig.RequireHttps).Build();
} }
} }
} }*/

View File

@ -92,7 +92,7 @@ namespace Ocelot.Configuration.Creator
private async Task<IOcelotConfiguration> SetUpConfiguration(FileConfiguration fileConfiguration) private async Task<IOcelotConfiguration> SetUpConfiguration(FileConfiguration fileConfiguration)
{ {
var response = _configurationValidator.IsValid(fileConfiguration); var response = await _configurationValidator.IsValid(fileConfiguration);
if (response.Data.IsError) if (response.Data.IsError)
{ {
@ -110,14 +110,14 @@ namespace Ocelot.Configuration.Creator
foreach (var reRoute in fileConfiguration.ReRoutes) 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); reRoutes.Add(ocelotReRoute);
} }
return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath); return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath);
} }
private async Task<ReRoute> SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, List<FileAuthenticationOptions> authOptions) private async Task<ReRoute> SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
{ {
var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute); var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute);
@ -129,7 +129,7 @@ namespace Ocelot.Configuration.Creator
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration); var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration);
var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute, authOptions); var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest); var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest);
@ -168,7 +168,7 @@ namespace Ocelot.Configuration.Creator
.WithQosOptions(qosOptions) .WithQosOptions(qosOptions)
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
.WithRateLimitOptions(rateLimitOption) .WithRateLimitOptions(rateLimitOption)
.WithAuthenticationProviderKey(fileReRoute.AuthenticationProviderKey) .WithAuthenticationProviderKey(fileReRoute.AuthenticationOptions.AuthenticationProviderKey)
.Build(); .Build();
await SetupLoadBalancer(reRoute); await SetupLoadBalancer(reRoute);

View File

@ -5,6 +5,6 @@ namespace Ocelot.Configuration.Creator
{ {
public interface IAuthenticationOptionsCreator public interface IAuthenticationOptionsCreator
{ {
AuthenticationOptions Create(FileReRoute reRoute, List<FileAuthenticationOptions> authOptions); AuthenticationOptions Create(FileReRoute reRoute);
} }
} }

View File

@ -36,7 +36,7 @@ namespace Ocelot.Configuration.Creator
private bool IsAuthenticated(FileReRoute fileReRoute) private bool IsAuthenticated(FileReRoute fileReRoute)
{ {
return !string.IsNullOrEmpty(fileReRoute.AuthenticationProviderKey); return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.AuthenticationProviderKey);
} }
private bool IsAuthorised(FileReRoute fileReRoute) private bool IsAuthorised(FileReRoute fileReRoute)

View File

@ -7,14 +7,9 @@ namespace Ocelot.Configuration.File
public FileAuthenticationOptions() public FileAuthenticationOptions()
{ {
AllowedScopes = new List<string>(); AllowedScopes = new List<string>();
IdentityServerConfig = new FileIdentityServerConfig();
JwtConfig = new FileJwtConfig();
} }
public string AuthenticationProviderKey {get; set;} public string AuthenticationProviderKey {get; set;}
public string Provider { get; set; }
public List<string> AllowedScopes { get; set; } public List<string> AllowedScopes { get; set; }
public FileIdentityServerConfig IdentityServerConfig { get; set; }
public FileJwtConfig JwtConfig { get; set; }
} }
} }

View File

@ -8,11 +8,9 @@ namespace Ocelot.Configuration.File
{ {
ReRoutes = new List<FileReRoute>(); ReRoutes = new List<FileReRoute>();
GlobalConfiguration = new FileGlobalConfiguration(); GlobalConfiguration = new FileGlobalConfiguration();
AuthenticationOptions = new List<FileAuthenticationOptions>();
} }
public List<FileReRoute> ReRoutes { get; set; } public List<FileReRoute> ReRoutes { get; set; }
public FileGlobalConfiguration GlobalConfiguration { get; set; } public FileGlobalConfiguration GlobalConfiguration { get; set; }
public List<FileAuthenticationOptions> AuthenticationOptions { get; set; }
} }
} }

View File

@ -14,6 +14,7 @@ namespace Ocelot.Configuration.File
FileCacheOptions = new FileCacheOptions(); FileCacheOptions = new FileCacheOptions();
QoSOptions = new FileQoSOptions(); QoSOptions = new FileQoSOptions();
RateLimitOptions = new FileRateLimitRule(); RateLimitOptions = new FileRateLimitRule();
AuthenticationOptions = new FileAuthenticationOptions();
} }
public string DownstreamPathTemplate { get; set; } public string DownstreamPathTemplate { get; set; }
@ -33,6 +34,6 @@ namespace Ocelot.Configuration.File
public FileQoSOptions QoSOptions { get; set; } public FileQoSOptions QoSOptions { get; set; }
public string LoadBalancer {get;set;} public string LoadBalancer {get;set;}
public FileRateLimitRule RateLimitOptions { get; set; } public FileRateLimitRule RateLimitOptions { get; set; }
public string AuthenticationProviderKey {get; set;} public FileAuthenticationOptions AuthenticationOptions { get; set; }
} }
} }

View File

@ -3,8 +3,6 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Consul; using Consul;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Ocelot.Authentication.JsonConverters;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.ServiceDiscovery; using Ocelot.ServiceDiscovery;
@ -49,9 +47,7 @@ namespace Ocelot.Configuration.Repository
var json = Encoding.UTF8.GetString(bytes); var json = Encoding.UTF8.GetString(bytes);
var settings = new JsonSerializerSettings(); var consulConfig = JsonConvert.DeserializeObject<OcelotConfiguration>(json);
settings.Converters.Add(new AuthenticationConfigConverter());
var consulConfig = JsonConvert.DeserializeObject<OcelotConfiguration>(json, settings);
return new OkResponse<IOcelotConfiguration>(consulConfig); return new OkResponse<IOcelotConfiguration>(consulConfig);
} }

View File

@ -1,7 +1,7 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Ocelot.Authentication.Handler; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Errors; using Ocelot.Errors;
using Ocelot.Responses; using Ocelot.Responses;
@ -10,7 +10,14 @@ namespace Ocelot.Configuration.Validator
{ {
public class FileConfigurationValidator : IConfigurationValidator public class FileConfigurationValidator : IConfigurationValidator
{ {
public Response<ConfigurationValidationResult> IsValid(FileConfiguration configuration) private readonly IAuthenticationSchemeProvider _provider;
public FileConfigurationValidator(IAuthenticationSchemeProvider provider)
{
_provider = provider;
}
public async Task<Response<ConfigurationValidationResult>> IsValid(FileConfiguration configuration)
{ {
var result = CheckForDuplicateReRoutes(configuration); var result = CheckForDuplicateReRoutes(configuration);
@ -19,7 +26,7 @@ namespace Ocelot.Configuration.Validator
return new OkResponse<ConfigurationValidationResult>(result); return new OkResponse<ConfigurationValidationResult>(result);
} }
result = CheckForUnsupportedAuthenticationProviders(configuration); result = await CheckForUnsupportedAuthenticationProviders(configuration);
if (result.IsError) if (result.IsError)
{ {
@ -42,38 +49,27 @@ namespace Ocelot.Configuration.Validator
return new OkResponse<ConfigurationValidationResult>(result); return new OkResponse<ConfigurationValidationResult>(result);
} }
private ConfigurationValidationResult CheckForUnsupportedAuthenticationProviders(FileConfiguration configuration) private async Task<ConfigurationValidationResult> CheckForUnsupportedAuthenticationProviders(FileConfiguration configuration)
{ {
var errors = new List<Error>(); var errors = new List<Error>();
//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) foreach (var reRoute in configuration.ReRoutes)
{ {
var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationProviderKey); var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationOptions.AuthenticationProviderKey);
if (!isAuthenticated) if (!isAuthenticated)
{ {
continue; continue;
} }
//todo is this correct? var data = await _provider.GetAllSchemesAsync();
if(configuration.AuthenticationOptions.Exists(x => x.AuthenticationProviderKey == reRoute.AuthenticationProviderKey)) var schemes = data.ToList();
if (schemes.Any(x => x.Name == reRoute.AuthenticationOptions.AuthenticationProviderKey))
{ {
continue; 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); errors.Add(error);
} }
@ -82,13 +78,6 @@ namespace Ocelot.Configuration.Validator
: new ConfigurationValidationResult(false); : new ConfigurationValidationResult(false);
} }
private bool IsSupportedAuthenticationProvider(string provider)
{
SupportedAuthenticationProviders supportedProvider;
return Enum.TryParse(provider, true, out supportedProvider);
}
private ConfigurationValidationResult CheckForReRoutesContainingDownstreamSchemeInDownstreamPathTemplate(FileConfiguration configuration) private ConfigurationValidationResult CheckForReRoutesContainingDownstreamSchemeInDownstreamPathTemplate(FileConfiguration configuration)
{ {
var errors = new List<Error>(); var errors = new List<Error>();

View File

@ -1,10 +1,11 @@
using Ocelot.Configuration.File; using System.Threading.Tasks;
using Ocelot.Configuration.File;
using Ocelot.Responses; using Ocelot.Responses;
namespace Ocelot.Configuration.Validator namespace Ocelot.Configuration.Validator
{ {
public interface IConfigurationValidator public interface IConfigurationValidator
{ {
Response<ConfigurationValidationResult> IsValid(FileConfiguration configuration); Task<Response<ConfigurationValidationResult>> IsValid(FileConfiguration configuration);
} }
} }

View File

@ -1,4 +1,4 @@
using Ocelot.Configuration; /*using Ocelot.Configuration;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
namespace Ocelot.Creator.Configuration namespace Ocelot.Creator.Configuration
@ -7,4 +7,4 @@ namespace Ocelot.Creator.Configuration
{ {
IAuthenticationConfig Create(FileAuthenticationOptions authenticationOptions); IAuthenticationConfig Create(FileAuthenticationOptions authenticationOptions);
} }
} }*/

View File

@ -42,15 +42,10 @@ using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using IdentityServer4.AccessTokenValidation; using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.IdentityModel.Tokens;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Creator.Configuration;
using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider; using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider;
using System.IO;
using Newtonsoft.Json;
namespace Ocelot.DependencyInjection namespace Ocelot.DependencyInjection
{ {
@ -77,7 +72,6 @@ namespace Ocelot.DependencyInjection
services.Configure<FileConfiguration>(configurationRoot); services.Configure<FileConfiguration>(configurationRoot);
services.TryAddSingleton<IOcelotConfigurationCreator, FileOcelotConfigurationCreator>(); services.TryAddSingleton<IOcelotConfigurationCreator, FileOcelotConfigurationCreator>();
services.TryAddSingleton<IAuthenticationProviderConfigCreator, AuthenticationProviderConfigCreator>();
services.TryAddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>(); services.TryAddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
services.TryAddSingleton<IConfigurationValidator, FileConfigurationValidator>(); services.TryAddSingleton<IConfigurationValidator, FileConfigurationValidator>();
services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>(); services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
@ -149,38 +143,6 @@ namespace Ocelot.DependencyInjection
services.AddIdentityServer(identityServerConfiguration, configurationRoot); 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<FileConfiguration>(data);
foreach(var authOptions in config.AuthenticationOptions)
{
if(authOptions.Provider.ToLower() == "identityserver")
{
Action<IdentityServerAuthenticationOptions> 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; return services;
} }

View File

@ -26,7 +26,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.0.2" /> <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
@ -42,7 +42,7 @@
<PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="1.1.1" /> <PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="1.1.1" />
<PackageReference Include="Consul" Version="0.7.2.3" /> <PackageReference Include="Consul" Version="0.7.2.3" />
<PackageReference Include="Polly" Version="5.3.1" /> <PackageReference Include="Polly" Version="5.3.1" />
<PackageReference Include="IdentityServer4" Version="2.0.1" /> <PackageReference Include="IdentityServer4" Version="2.0.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Security.Claims; using System.Security.Claims;
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Models; using IdentityServer4.Models;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -14,7 +15,6 @@ using Xunit;
namespace Ocelot.AcceptanceTests namespace Ocelot.AcceptanceTests
{ {
using IdentityServer4;
using IdentityServer4.Test; using IdentityServer4.Test;
public class AuthenticationTests : IDisposable public class AuthenticationTests : IDisposable
@ -28,10 +28,19 @@ namespace Ocelot.AcceptanceTests
private int _downstreamServicePort = 51876; private int _downstreamServicePort = 51876;
private string _downstreamServiceScheme = "http"; private string _downstreamServiceScheme = "http";
private string _downstreamServiceUrl = "http://localhost:51876"; private string _downstreamServiceUrl = "http://localhost:51876";
private readonly Action<IdentityServerAuthenticationOptions> _options;
public AuthenticationTests() public AuthenticationTests()
{ {
_steps = new Steps(); _steps = new Steps();
_options = o =>
{
o.Authority = _identityServerRootUrl;
o.ApiName = "api";
o.RequireHttpsMetadata = false;
o.SupportedTokens = SupportedTokens.Both;
o.ApiSecret = "secret";
};
} }
[Fact] [Fact]
@ -49,22 +58,10 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = _downstreamServiceScheme, DownstreamScheme = _downstreamServiceScheme,
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" }, UpstreamHttpMethod = new List<string> { "Post" },
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
},
AuthenticationOptions = new List<FileAuthenticationOptions>
{
new FileAuthenticationOptions
{
AllowedScopes = new List<string>(),
Provider = "IdentityServer",
IdentityServerConfig = new FileIdentityServerConfig{
ProviderRootUrl = _identityServerRootUrl,
RequireHttps = false,
ApiName = "api",
ApiSecret = "secret"
},
AuthenticationProviderKey = "Test"
} }
} }
}; };
@ -72,7 +69,7 @@ namespace Ocelot.AcceptanceTests
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 => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenThePostHasContent("postContent")) .And(x => _steps.GivenThePostHasContent("postContent"))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) .When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized))
@ -94,22 +91,10 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = _downstreamServiceScheme, DownstreamScheme = _downstreamServiceScheme,
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
},
AuthenticationOptions = new List<FileAuthenticationOptions>
{
new FileAuthenticationOptions
{
AllowedScopes = new List<string>(),
Provider = "IdentityServer",
IdentityServerConfig = new FileIdentityServerConfig{
ProviderRootUrl = _identityServerRootUrl,
RequireHttps = false,
ApiName = "api",
ApiSecret = "secret"
},
AuthenticationProviderKey = "Test"
} }
} }
}; };
@ -118,7 +103,7 @@ namespace Ocelot.AcceptanceTests
.And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura"))
.And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
@ -141,22 +126,10 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = _downstreamServiceScheme, DownstreamScheme = _downstreamServiceScheme,
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
},
AuthenticationOptions = new List<FileAuthenticationOptions>
{
new FileAuthenticationOptions
{
AllowedScopes = new List<string>(),
Provider = "IdentityServer",
IdentityServerConfig = new FileIdentityServerConfig{
ProviderRootUrl = _identityServerRootUrl,
RequireHttps = false,
ApiName = "api",
ApiSecret = "secret"
},
AuthenticationProviderKey = "Test"
} }
} }
}; };
@ -165,7 +138,7 @@ namespace Ocelot.AcceptanceTests
.And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura"))
.And(x => _steps.GivenIHaveATokenForApi2(_identityServerRootUrl)) .And(x => _steps.GivenIHaveATokenForApi2(_identityServerRootUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized))
@ -187,22 +160,10 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = _downstreamServiceScheme, DownstreamScheme = _downstreamServiceScheme,
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" }, UpstreamHttpMethod = new List<string> { "Post" },
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
},
AuthenticationOptions = new List<FileAuthenticationOptions>
{
new FileAuthenticationOptions
{
AllowedScopes = new List<string>(),
Provider = "IdentityServer",
IdentityServerConfig = new FileIdentityServerConfig{
ProviderRootUrl = _identityServerRootUrl,
RequireHttps = false,
ApiName = "api",
ApiSecret = "secret"
},
AuthenticationProviderKey = "Test"
} }
} }
}; };
@ -211,7 +172,7 @@ namespace Ocelot.AcceptanceTests
.And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
.And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.And(x => _steps.GivenThePostHasContent("postContent")) .And(x => _steps.GivenThePostHasContent("postContent"))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) .When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
@ -234,22 +195,10 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = _downstreamServiceScheme, DownstreamScheme = _downstreamServiceScheme,
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" }, UpstreamHttpMethod = new List<string> { "Post" },
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
},
AuthenticationOptions = new List<FileAuthenticationOptions>
{
new FileAuthenticationOptions
{
AllowedScopes = new List<string>(),
Provider = "IdentityServer",
IdentityServerConfig = new FileIdentityServerConfig{
ProviderRootUrl = _identityServerRootUrl,
RequireHttps = false,
ApiName = "api",
ApiSecret = "secret"
},
AuthenticationProviderKey = "Test"
} }
} }
}; };
@ -258,7 +207,7 @@ namespace Ocelot.AcceptanceTests
.And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty))
.And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.And(x => _steps.GivenThePostHasContent("postContent")) .And(x => _steps.GivenThePostHasContent("postContent"))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) .When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Security.Claims; using System.Security.Claims;
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Models; using IdentityServer4.Models;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -22,10 +23,20 @@ namespace Ocelot.AcceptanceTests
private IWebHost _servicebuilder; private IWebHost _servicebuilder;
private IWebHost _identityServerBuilder; private IWebHost _identityServerBuilder;
private readonly Steps _steps; private readonly Steps _steps;
private Action<IdentityServerAuthenticationOptions> _options;
private string _identityServerRootUrl = "http://localhost:51888";
public AuthorisationTests() public AuthorisationTests()
{ {
_steps = new Steps(); _steps = new Steps();
_options = o =>
{
o.Authority = _identityServerRootUrl;
o.ApiName = "api";
o.RequireHttpsMetadata = false;
o.SupportedTokens = SupportedTokens.Both;
o.ApiSecret = "secret";
};
} }
[Fact] [Fact]
@ -33,7 +44,7 @@ namespace Ocelot.AcceptanceTests
{ {
var configuration = new FileConfiguration var configuration = new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions> /* AuthenticationOptions = new List<FileAuthenticationOptions>
{ {
new FileAuthenticationOptions new FileAuthenticationOptions
{ {
@ -47,7 +58,7 @@ namespace Ocelot.AcceptanceTests
}, },
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
}, },*/
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
@ -58,7 +69,10 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationProviderKey = "Test", AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test"
},
AddHeadersToRequest = AddHeadersToRequest =
{ {
{"CustomerId", "Claims[CustomerId] > value"}, {"CustomerId", "Claims[CustomerId] > value"},
@ -84,7 +98,7 @@ namespace Ocelot.AcceptanceTests
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura"))
.And(x => _steps.GivenIHaveAToken("http://localhost:51888")) .And(x => _steps.GivenIHaveAToken("http://localhost:51888"))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
@ -97,7 +111,7 @@ namespace Ocelot.AcceptanceTests
{ {
var configuration = new FileConfiguration var configuration = new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions> /* AuthenticationOptions = new List<FileAuthenticationOptions>
{ {
new FileAuthenticationOptions new FileAuthenticationOptions
{ {
@ -111,7 +125,7 @@ namespace Ocelot.AcceptanceTests
}, },
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
}, },*/
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
@ -122,7 +136,10 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationProviderKey = "Test", AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test"
},
AddHeadersToRequest = AddHeadersToRequest =
{ {
{"CustomerId", "Claims[CustomerId] > value"}, {"CustomerId", "Claims[CustomerId] > value"},
@ -147,7 +164,7 @@ namespace Ocelot.AcceptanceTests
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura"))
.And(x => _steps.GivenIHaveAToken("http://localhost:51888")) .And(x => _steps.GivenIHaveAToken("http://localhost:51888"))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden))
@ -159,7 +176,7 @@ namespace Ocelot.AcceptanceTests
{ {
var configuration = new FileConfiguration var configuration = new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions> /* AuthenticationOptions = new List<FileAuthenticationOptions>
{ {
new FileAuthenticationOptions new FileAuthenticationOptions
{ {
@ -173,7 +190,7 @@ namespace Ocelot.AcceptanceTests
}, },
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
}, },*/
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
@ -184,7 +201,11 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http", DownstreamScheme = "http",
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationProviderKey = "Test" AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test",
AllowedScopes = new List<string>{ "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 => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura"))
.And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888"))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
@ -205,7 +226,7 @@ namespace Ocelot.AcceptanceTests
{ {
var configuration = new FileConfiguration var configuration = new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions> /* AuthenticationOptions = new List<FileAuthenticationOptions>
{ {
new FileAuthenticationOptions new FileAuthenticationOptions
{ {
@ -219,7 +240,7 @@ namespace Ocelot.AcceptanceTests
}, },
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
}, },*/
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
@ -230,7 +251,11 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http", DownstreamScheme = "http",
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationProviderKey = "Test" AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test",
AllowedScopes = new List<string>{ "api", "openid", "offline_access" },
},
} }
} }
}; };
@ -239,7 +264,7 @@ namespace Ocelot.AcceptanceTests
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura"))
.And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888"))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden))

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Security.Claims; using System.Security.Claims;
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Models; using IdentityServer4.Models;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -24,10 +25,20 @@ namespace Ocelot.AcceptanceTests
private IWebHost _servicebuilder; private IWebHost _servicebuilder;
private IWebHost _identityServerBuilder; private IWebHost _identityServerBuilder;
private readonly Steps _steps; private readonly Steps _steps;
private Action<IdentityServerAuthenticationOptions> _options;
private string _identityServerRootUrl = "http://localhost:52888";
public ClaimsToHeadersForwardingTests() public ClaimsToHeadersForwardingTests()
{ {
_steps = new Steps(); _steps = new Steps();
_options = o =>
{
o.Authority = _identityServerRootUrl;
o.ApiName = "api";
o.RequireHttpsMetadata = false;
o.SupportedTokens = SupportedTokens.Both;
o.ApiSecret = "secret";
};
} }
[Fact] [Fact]
@ -47,7 +58,7 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration var configuration = new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions> /* AuthenticationOptions = new List<FileAuthenticationOptions>
{ {
new FileAuthenticationOptions new FileAuthenticationOptions
{ {
@ -64,7 +75,7 @@ namespace Ocelot.AcceptanceTests
}, },
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
}, },*/
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
@ -75,7 +86,14 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test", AuthenticationProviderKey = "Test",
AllowedScopes = new List<string>
{
"openid", "offline_access", "api"
},
},
AddHeadersToRequest = AddHeadersToRequest =
{ {
{"CustomerId", "Claims[CustomerId] > value"}, {"CustomerId", "Claims[CustomerId] > value"},
@ -91,7 +109,7 @@ namespace Ocelot.AcceptanceTests
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:52876", 200)) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:52876", 200))
.And(x => _steps.GivenIHaveAToken("http://localhost:52888")) .And(x => _steps.GivenIHaveAToken("http://localhost:52888"))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Security.Claims; using System.Security.Claims;
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Models; using IdentityServer4.Models;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -24,10 +25,20 @@ namespace Ocelot.AcceptanceTests
private IWebHost _servicebuilder; private IWebHost _servicebuilder;
private IWebHost _identityServerBuilder; private IWebHost _identityServerBuilder;
private readonly Steps _steps; private readonly Steps _steps;
private Action<IdentityServerAuthenticationOptions> _options;
private string _identityServerRootUrl = "http://localhost:57888";
public ClaimsToQueryStringForwardingTests() public ClaimsToQueryStringForwardingTests()
{ {
_steps = new Steps(); _steps = new Steps();
_options = o =>
{
o.Authority = _identityServerRootUrl;
o.ApiName = "api";
o.RequireHttpsMetadata = false;
o.SupportedTokens = SupportedTokens.Both;
o.ApiSecret = "secret";
};
} }
[Fact] [Fact]
@ -47,7 +58,7 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration var configuration = new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions> /* AuthenticationOptions = new List<FileAuthenticationOptions>
{ {
new FileAuthenticationOptions new FileAuthenticationOptions
{ {
@ -64,7 +75,7 @@ namespace Ocelot.AcceptanceTests
}, },
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
}, },*/
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
@ -75,7 +86,14 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test", AuthenticationProviderKey = "Test",
AllowedScopes = new List<string>
{
"openid", "offline_access", "api"
},
},
AddQueriesToRequest = AddQueriesToRequest =
{ {
{"CustomerId", "Claims[CustomerId] > value"}, {"CustomerId", "Claims[CustomerId] > value"},
@ -91,7 +109,7 @@ namespace Ocelot.AcceptanceTests
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:57876", 200)) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:57876", 200))
.And(x => _steps.GivenIHaveAToken("http://localhost:57888")) .And(x => _steps.GivenIHaveAToken("http://localhost:57888"))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest()) .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))

View File

@ -3,15 +3,12 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text; using System.Text;
using Consul;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Newtonsoft.Json; using Newtonsoft.Json;
using Ocelot.Authentication.JsonConverters;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Ocelot.ServiceDiscovery; using Ocelot.ServiceDiscovery;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
@ -105,9 +102,7 @@ namespace Ocelot.AcceptanceTests
var json = reader.ReadToEnd(); var json = reader.ReadToEnd();
var settings = new JsonSerializerSettings(); _config = JsonConvert.DeserializeObject<OcelotConfiguration>(json);
settings.Converters.Add(new AuthenticationConfigConverter());
_config = JsonConvert.DeserializeObject<OcelotConfiguration>(json, settings);
var response = JsonConvert.SerializeObject(true); var response = JsonConvert.SerializeObject(true);

View File

@ -32,8 +32,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20171031-01" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta2-build1317" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
@ -42,11 +42,11 @@
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.0" />
<PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" /> <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
<PackageReference Include="Shouldly" Version="2.8.3" /> <PackageReference Include="Shouldly" Version="3.0.0-beta0003" />
<PackageReference Include="TestStack.BDDfy" Version="4.3.2" /> <PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
<PackageReference Include="Consul" Version="0.7.2.3" /> <PackageReference Include="Consul" Version="0.7.2.3" />
<PackageReference Include="xunit" Version="2.3.0-beta2-build3683" /> <PackageReference Include="xunit" Version="2.3.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -8,6 +8,8 @@ using System.Net.Http.Headers;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CacheManager.Core; using CacheManager.Core;
using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -86,6 +88,26 @@ namespace Ocelot.AcceptanceTests
_ocelotClient = _ocelotServer.CreateClient(); _ocelotClient = _ocelotServer.CreateClient();
} }
/// <summary>
/// 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.
/// </summary>
public void GivenOcelotIsRunning(Action<IdentityServerAuthenticationOptions> options, string authenticationProviderKey)
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
s.AddAuthentication()
.AddIdentityServerAuthentication(authenticationProviderKey, options);
});
_ocelotServer = new TestServer(_webHostBuilder
.UseStartup<Startup>());
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningUsingConsulToStoreConfig(ConsulRegistryConfiguration consulConfig) public void GivenOcelotIsRunningUsingConsulToStoreConfig(ConsulRegistryConfiguration consulConfig)
{ {
_webHostBuilder = new WebHostBuilder(); _webHostBuilder = new WebHostBuilder();

View File

@ -31,8 +31,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20171031-01" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta2-build1317" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
@ -40,10 +40,10 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" /> <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
<PackageReference Include="xunit" Version="2.3.0-beta2-build3683" /> <PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="IdentityServer4" Version="2.0.1" /> <PackageReference Include="IdentityServer4" Version="2.0.2" />
<PackageReference Include="Shouldly" Version="2.8.3" /> <PackageReference Include="Shouldly" Version="3.0.0-beta0003" />
<PackageReference Include="TestStack.BDDfy" Version="4.3.2" /> <PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
<PackageReference Include="Consul" Version="0.7.2.3" /> <PackageReference Include="Consul" Version="0.7.2.3" />
</ItemGroup> </ItemGroup>

View File

@ -1,4 +1,11 @@
using System.Collections.Generic; 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.File;
using Ocelot.Configuration.Validator; using Ocelot.Configuration.Validator;
using Ocelot.Responses; using Ocelot.Responses;
@ -13,10 +20,12 @@ namespace Ocelot.UnitTests.Configuration
private readonly IConfigurationValidator _configurationValidator; private readonly IConfigurationValidator _configurationValidator;
private FileConfiguration _fileConfiguration; private FileConfiguration _fileConfiguration;
private Response<ConfigurationValidationResult> _result; private Response<ConfigurationValidationResult> _result;
private Mock<IAuthenticationSchemeProvider> _provider;
public ConfigurationValidationTests() public ConfigurationValidationTests()
{ {
_configurationValidator = new FileConfigurationValidator(); _provider = new Mock<IAuthenticationSchemeProvider>();
_configurationValidator = new FileConfigurationValidator(_provider.Object);
} }
[Fact] [Fact]
@ -62,50 +71,48 @@ namespace Ocelot.UnitTests.Configuration
{ {
this.Given(x => x.GivenAConfiguration(new FileConfiguration this.Given(x => x.GivenAConfiguration(new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions>
{
new FileAuthenticationOptions
{
Provider = "IdentityServer",
AuthenticationProviderKey = "Test"
}
},
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
{ {
DownstreamPathTemplate = "/api/products/", DownstreamPathTemplate = "/api/products/",
UpstreamPathTemplate = "http://asdf.com", UpstreamPathTemplate = "http://asdf.com",
AuthenticationOptions = new FileAuthenticationOptions()
{
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} }
} }
}
})) }))
.And(x => x.GivenTheAuthSchemeExists("Test"))
.When(x => x.WhenIValidateTheConfiguration()) .When(x => x.WhenIValidateTheConfiguration())
.Then(x => x.ThenTheResultIsValid()) .Then(x => x.ThenTheResultIsValid())
.BDDfy(); .BDDfy();
} }
private void GivenTheAuthSchemeExists(string name)
{
_provider.Setup(x => x.GetAllSchemesAsync()).ReturnsAsync(new List<AuthenticationScheme>
{
new AuthenticationScheme(name, name, typeof(TestHandler))
});
}
[Fact] [Fact]
public void configuration_is_invalid_with_invalid_authentication_provider() public void configuration_is_invalid_with_invalid_authentication_provider()
{ {
this.Given(x => x.GivenAConfiguration(new FileConfiguration this.Given(x => x.GivenAConfiguration(new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions>
{
new FileAuthenticationOptions
{
Provider = "BootyBootyBottyRockinEverywhere",
AuthenticationProviderKey = "Test"
}
},
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
{ {
DownstreamPathTemplate = "/api/products/", DownstreamPathTemplate = "/api/products/",
UpstreamPathTemplate = "http://asdf.com", UpstreamPathTemplate = "http://asdf.com",
AuthenticationOptions = new FileAuthenticationOptions()
{
AuthenticationProviderKey = "Test" AuthenticationProviderKey = "Test"
} } }
} }
})) }))
.When(x => x.WhenIValidateTheConfiguration()) .When(x => x.WhenIValidateTheConfiguration())
@ -146,7 +153,7 @@ namespace Ocelot.UnitTests.Configuration
private void WhenIValidateTheConfiguration() private void WhenIValidateTheConfiguration()
{ {
_result = _configurationValidator.IsValid(_fileConfiguration); _result = _configurationValidator.IsValid(_fileConfiguration).Result;
} }
private void ThenTheResultIsValid() private void ThenTheResultIsValid()
@ -163,5 +170,23 @@ namespace Ocelot.UnitTests.Configuration
{ {
_result.Data.Errors[0].ShouldBeOfType<T>(); _result.Data.Errors[0].ShouldBeOfType<T>();
} }
private class TestOptions : AuthenticationSchemeOptions
{
}
private class TestHandler : AuthenticationHandler<TestOptions>
{
public TestHandler(IOptionsMonitor<TestOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var principal = new ClaimsPrincipal();
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name)));
}
}
} }
} }

View File

@ -446,16 +446,14 @@ namespace Ocelot.UnitTests.Configuration
[Theory] [Theory]
[MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))] [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() var reRouteOptions = new ReRouteOptionsBuilder()
.WithIsAuthenticated(true) .WithIsAuthenticated(true)
.Build(); .Build();
var authenticationOptions = new AuthenticationOptionsBuilder() var authenticationOptions = new AuthenticationOptionsBuilder()
.WithProvider(provider)
.WithAllowedScopes(new List<string>()) .WithAllowedScopes(new List<string>())
.WithConfig(config)
.Build(); .Build();
var expected = new List<ReRoute> var expected = new List<ReRoute>
@ -480,23 +478,21 @@ namespace Ocelot.UnitTests.Configuration
.And(x => x.GivenTheLoadBalancerFactoryReturns()) .And(x => x.GivenTheLoadBalancerFactoryReturns())
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(expected)) .Then(x => x.ThenTheReRoutesAre(expected))
.And(x => x.ThenTheAuthenticationOptionsAre(provider, expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected))
.And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
[Theory] [Theory]
[MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))] [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() var reRouteOptions = new ReRouteOptionsBuilder()
.WithIsAuthenticated(true) .WithIsAuthenticated(true)
.Build(); .Build();
var authenticationOptions = new AuthenticationOptionsBuilder() var authenticationOptions = new AuthenticationOptionsBuilder()
.WithProvider(provider)
.WithAllowedScopes(new List<string>()) .WithAllowedScopes(new List<string>())
.WithConfig(config)
.Build(); .Build();
var expected = new List<ReRoute> var expected = new List<ReRoute>
@ -516,7 +512,7 @@ namespace Ocelot.UnitTests.Configuration
.And(x => x.GivenTheLoadBalancerFactoryReturns()) .And(x => x.GivenTheLoadBalancerFactoryReturns())
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(expected)) .Then(x => x.ThenTheReRoutesAre(expected))
.And(x => x.ThenTheAuthenticationOptionsAre(provider, expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected))
.And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
@ -538,7 +534,7 @@ namespace Ocelot.UnitTests.Configuration
{ {
_validator _validator
.Setup(x => x.IsValid(It.IsAny<FileConfiguration>())) .Setup(x => x.IsValid(It.IsAny<FileConfiguration>()))
.Returns(new OkResponse<ConfigurationValidationResult>(new ConfigurationValidationResult(false))); .ReturnsAsync(new OkResponse<ConfigurationValidationResult>(new ConfigurationValidationResult(false)));
} }
private void GivenTheConfigIs(FileConfiguration fileConfiguration) private void GivenTheConfigIs(FileConfiguration fileConfiguration)
@ -587,34 +583,13 @@ namespace Ocelot.UnitTests.Configuration
} }
} }
private void ThenTheAuthenticationOptionsAre(string provider, List<ReRoute> expectedReRoutes) private void ThenTheAuthenticationOptionsAre(List<ReRoute> expectedReRoutes)
{ {
for (int i = 0; i < _config.Data.ReRoutes.Count; i++) for (int i = 0; i < _config.Data.ReRoutes.Count; i++)
{ {
var result = _config.Data.ReRoutes[i].AuthenticationOptions; var result = _config.Data.ReRoutes[i].AuthenticationOptions;
var expected = expectedReRoutes[i].AuthenticationOptions; var expected = expectedReRoutes[i].AuthenticationOptions;
result.AllowedScopes.ShouldBe(expected.AllowedScopes); 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) private void GivenTheAuthOptionsCreatorReturns(AuthenticationOptions authOptions)
{ {
_authOptionsCreator _authOptionsCreator
.Setup(x => x.Create(It.IsAny<FileReRoute>(), It.IsAny<List<FileAuthenticationOptions>>())) .Setup(x => x.Create(It.IsAny<FileReRoute>()))
.Returns(authOptions); .Returns(authOptions);
} }
private void ThenTheAuthOptionsCreatorIsCalledCorrectly() private void ThenTheAuthOptionsCreatorIsCalledCorrectly()
{ {
_authOptionsCreator _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) private void GivenTheUpstreamTemplatePatternCreatorReturns(string pattern)

View File

@ -34,7 +34,10 @@ namespace Ocelot.UnitTests.Configuration
ExceptionsAllowedBeforeBreaking = 1, ExceptionsAllowedBeforeBreaking = 1,
TimeoutValue = 1 TimeoutValue = 1
}, },
AuthenticationProviderKey = "Test", AuthenticationOptions = new FileAuthenticationOptions()
{
AuthenticationProviderKey = "Test"
},
RouteClaimsRequirement = new Dictionary<string, string>() RouteClaimsRequirement = new Dictionary<string, string>()
{ {
{"",""} {"",""}

View File

@ -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<TestOptions>("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<TestOptions>
{
public TestHandler(IOptionsMonitor<TestOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> 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<IServiceCollection> 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<IAuthenticationSchemeProvider>();
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<IAuthenticationSchemeProvider>();
auth.RemoveScheme(name);
}
else
{
await next();
}
});
})
.ConfigureServices(services =>
{
configureServices?.Invoke(services);
services.AddAuthentication();
});
return new TestServer(builder);
}
}
}

View File

@ -34,9 +34,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20171031-01" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta2-build1317" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" /> <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
@ -44,10 +44,10 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
<PackageReference Include="Moq" Version="4.7.99" /> <PackageReference Include="Moq" Version="4.7.142" />
<PackageReference Include="Shouldly" Version="2.8.3" /> <PackageReference Include="Shouldly" Version="3.0.0-beta0003" />
<PackageReference Include="TestStack.BDDfy" Version="4.3.2" /> <PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
<PackageReference Include="xunit" Version="2.3.0-beta2-build3683" /> <PackageReference Include="xunit" Version="2.3.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -42,7 +42,7 @@ namespace Ocelot.UnitTests.Responder
[InlineData(OcelotErrorCode.RequestTimedOutError)] [InlineData(OcelotErrorCode.RequestTimedOutError)]
public void should_return_service_unavailable(OcelotErrorCode errorCode) public void should_return_service_unavailable(OcelotErrorCode errorCode)
{ {
ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.ServiceUnavailable); ShouldMapErrorToStatusCode(OcelotErrorCode.RequestTimedOutError, HttpStatusCode.ServiceUnavailable);
} }

View File

@ -1,8 +1,6 @@
namespace Ocelot.UnitTests.TestData namespace Ocelot.UnitTests.TestData
{ {
using System.Collections.Generic; using System.Collections.Generic;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
public class AuthenticationConfigTestData public class AuthenticationConfigTestData
@ -11,31 +9,8 @@
{ {
yield return new object[] yield return new object[]
{ {
"IdentityServer",
new IdentityServerConfigBuilder()
.WithRequireHttps(true)
.WithApiName("test")
.WithApiSecret("test")
.WithProviderRootUrl("test")
.Build(),
new FileConfiguration new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions>
{
new FileAuthenticationOptions
{
AllowedScopes = new List<string>(),
Provider = "IdentityServer",
IdentityServerConfig = new FileIdentityServerConfig
{
ProviderRootUrl = "http://localhost:51888",
RequireHttps = false,
ApiName = "api",
ApiSecret = "secret"
} ,
AuthenticationProviderKey = "Test"
}
},
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
@ -44,7 +19,11 @@
DownstreamPathTemplate = "/products/{productId}", DownstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
ReRouteIsCaseSensitive = true, ReRouteIsCaseSensitive = true,
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test", AuthenticationProviderKey = "Test",
AllowedScopes = new List<string>(),
},
AddHeadersToRequest = AddHeadersToRequest =
{ {
{ "CustomerId", "Claims[CustomerId] > value" }, { "CustomerId", "Claims[CustomerId] > value" },
@ -56,27 +35,8 @@
yield return new object[] yield return new object[]
{ {
"Jwt",
new JwtConfigBuilder()
.WithAudience("a")
.WithAuthority("au")
.Build(),
new FileConfiguration new FileConfiguration
{ {
AuthenticationOptions = new List<FileAuthenticationOptions>
{
new FileAuthenticationOptions
{
AllowedScopes = new List<string>(),
Provider = "IdentityServer",
JwtConfig = new FileJwtConfig
{
Audience = "a",
Authority = "au"
},
AuthenticationProviderKey = "Test"
}
},
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
new FileReRoute new FileReRoute
@ -85,7 +45,11 @@
DownstreamPathTemplate = "/products/{productId}", DownstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
ReRouteIsCaseSensitive = true, ReRouteIsCaseSensitive = true,
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test", AuthenticationProviderKey = "Test",
AllowedScopes = new List<string>(),
},
AddHeadersToRequest = AddHeadersToRequest =
{ {
{ "CustomerId", "Claims[CustomerId] > value" }, { "CustomerId", "Claims[CustomerId] > value" },