Feature/use any id server for admin area (#232)

* initial commits around using any id servers

* add your own id server for admin area

* lots of refactoring, now instead of injecting IWebHostBuilder we just set the Ocelot base url as a configuration extension method..this means people can pass it in on the command line aswell as hardcode which is OK I guess, also can now use your own IdentityServer to authenticate admin area

* updated docs for #231

* some tests that hopefully bump up coverage
This commit is contained in:
Tom Pallister
2018-02-14 18:53:18 +00:00
committed by GitHub
parent 6f177fbf5b
commit 05481f3af3
31 changed files with 876 additions and 546 deletions

View File

@ -1,39 +0,0 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
namespace Ocelot.AcceptanceTests
{
public class AcceptanceTestsStartup
{
public AcceptanceTestsStartup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("configuration.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
public virtual void ConfigureServices(IServiceCollection services)
{
services.AddOcelot(Configuration);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseOcelot().Wait();
}
}
}

View File

@ -1,40 +0,0 @@
using System;
using CacheManager.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
namespace Ocelot.AcceptanceTests
{
public class ConsulStartup
{
public ConsulStartup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("configuration.json")
.AddEnvironmentVariables();
Config = builder.Build();
}
public static IConfiguration Config { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddOcelot(Config).AddStoreOcelotConfigurationInConsul();
}
public void Configure(IApplicationBuilder app)
{
app.UseOcelot().Wait();
}
}
}

View File

@ -1,29 +0,0 @@
using CacheManager.Core;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Ocelot.DependencyInjection;
using Ocelot.AcceptanceTests.Caching;
namespace Ocelot.AcceptanceTests
{
public class StartupWithConsulAndCustomCacheHandle : AcceptanceTestsStartup
{
public StartupWithConsulAndCustomCacheHandle(IHostingEnvironment env) : base(env) { }
public override void ConfigureServices(IServiceCollection services)
{
services.AddOcelot(Configuration)
.AddCacheManager((x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithJsonSerializer()
.WithHandle(typeof(InMemoryJsonHandle<>));
})
.AddStoreOcelotConfigurationInConsul();
}
}
}

View File

@ -1,28 +0,0 @@
using CacheManager.Core;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Ocelot.DependencyInjection;
using Ocelot.AcceptanceTests.Caching;
namespace Ocelot.AcceptanceTests
{
public class StartupWithCustomCacheHandle : AcceptanceTestsStartup
{
public StartupWithCustomCacheHandle(IHostingEnvironment env) : base(env) { }
public override void ConfigureServices(IServiceCollection services)
{
services.AddOcelot(Configuration)
.AddCacheManager((x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithJsonSerializer()
.WithHandle(typeof(InMemoryJsonHandle<>));
});
}
}
}

View File

@ -38,9 +38,11 @@ namespace Ocelot.AcceptanceTests
public string RequestIdKey = "OcRequestId";
private readonly Random _random;
private IWebHostBuilder _webHostBuilder;
private readonly string _baseUrl;
public Steps()
{
_baseUrl = "http://localhost:5000";
_random = new Random();
}
@ -77,13 +79,26 @@ namespace Ocelot.AcceptanceTests
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
});
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot();
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder
.UseStartup<AcceptanceTestsStartup>());
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
@ -95,25 +110,27 @@ namespace Ocelot.AcceptanceTests
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
s.AddOcelot()
.AddDelegatingHandler(() => handlerOne)
.AddDelegatingHandler(() => handlerTwo);
});
_webHostBuilder.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
}).Configure(a =>
{
a.UseOcelot().Wait();
});
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
s.AddOcelot()
.AddDelegatingHandler(() => handlerOne)
.AddDelegatingHandler(() => handlerTwo);
})
.Configure(a =>
{
a.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
@ -127,15 +144,29 @@ namespace Ocelot.AcceptanceTests
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
s.AddAuthentication()
.AddIdentityServerAuthentication(authenticationProviderKey, options);
});
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddOcelotBaseUrl(_baseUrl);
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot();
s.AddAuthentication()
.AddIdentityServerAuthentication(authenticationProviderKey, options);
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder
.UseStartup<AcceptanceTestsStartup>());
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
@ -150,13 +181,36 @@ namespace Ocelot.AcceptanceTests
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
});
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddOcelotBaseUrl(_baseUrl);
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot()
.AddCacheManager((x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithJsonSerializer()
.WithHandle(typeof(InMemoryJsonHandle<>));
});
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder
.UseStartup<StartupWithCustomCacheHandle>());
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
@ -165,13 +219,27 @@ namespace Ocelot.AcceptanceTests
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
});
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddOcelotBaseUrl(_baseUrl);
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot().AddStoreOcelotConfigurationInConsul();
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder
.UseStartup<ConsulStartup>());
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
@ -180,13 +248,37 @@ namespace Ocelot.AcceptanceTests
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
});
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddOcelotBaseUrl(_baseUrl);
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot()
.AddCacheManager((x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithJsonSerializer()
.WithHandle(typeof(InMemoryJsonHandle<>));
})
.AddStoreOcelotConfigurationInConsul();
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder
.UseStartup<StartupWithConsulAndCustomCacheHandle>());
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}

View File

@ -4,11 +4,21 @@ using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using CacheManager.Core;
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Models;
using IdentityServer4.Test;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Ocelot.Cache;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
@ -18,15 +28,16 @@ namespace Ocelot.IntegrationTests
{
public class AdministrationTests : IDisposable
{
private readonly HttpClient _httpClient;
private HttpClient _httpClient;
private readonly HttpClient _httpClientTwo;
private HttpResponseMessage _response;
private IWebHost _builder;
private IWebHostBuilder _webHostBuilder;
private readonly string _ocelotBaseUrl;
private string _ocelotBaseUrl;
private BearerToken _token;
private IWebHostBuilder _webHostBuilderTwo;
private IWebHost _builderTwo;
private IWebHost _identityServerBuilder;
public AdministrationTests()
{
@ -62,6 +73,24 @@ namespace Ocelot.IntegrationTests
.BDDfy();
}
[Fact]
public void should_return_response_200_with_call_re_routes_controller_using_base_url_added_in_memory_with_no_webhostbuilder_registered()
{
_httpClient = new HttpClient();
_ocelotBaseUrl = "http://localhost:5011";
_httpClient.BaseAddress = new Uri(_ocelotBaseUrl);
var configuration = new FileConfiguration();
this.Given(x => GivenThereIsAConfiguration(configuration))
.And(x => GivenOcelotIsRunningWithNoWebHostBuilder(_ocelotBaseUrl))
.And(x => GivenIHaveAnOcelotToken("/administration"))
.And(x => GivenIHaveAddedATokenToMyRequest())
.When(x => WhenIGetUrlOnTheApiGateway("/administration/configuration"))
.Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_be_able_to_use_token_from_ocelot_a_on_ocelot_b()
{
@ -304,6 +333,115 @@ namespace Ocelot.IntegrationTests
.BDDfy();
}
[Fact]
public void should_return_response_200_with_call_re_routes_controller_when_using_own_identity_server_to_secure_admin_area()
{
var configuration = new FileConfiguration();
var identityServerRootUrl = "http://localhost:5123";
Action<IdentityServerAuthenticationOptions> options = o => {
o.Authority = identityServerRootUrl;
o.ApiName = "api";
o.RequireHttpsMetadata = false;
o.SupportedTokens = SupportedTokens.Both;
o.ApiSecret = "secret";
};
this.Given(x => GivenThereIsAConfiguration(configuration))
.And(x => GivenThereIsAnIdentityServerOn(identityServerRootUrl, "api"))
.And(x => GivenOcelotIsRunningWithIdentityServerSettings(options))
.And(x => GivenIHaveAToken(identityServerRootUrl))
.And(x => GivenIHaveAddedATokenToMyRequest())
.When(x => WhenIGetUrlOnTheApiGateway("/administration/configuration"))
.Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
private void GivenIHaveAToken(string url)
{
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", "api"),
new KeyValuePair<string, string>("client_secret", "secret"),
new KeyValuePair<string, string>("scope", "api"),
new KeyValuePair<string, string>("username", "test"),
new KeyValuePair<string, string>("password", "test"),
new KeyValuePair<string, string>("grant_type", "password")
};
var content = new FormUrlEncodedContent(formData);
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsync($"{url}/connect/token", content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
}
}
private void GivenThereIsAnIdentityServerOn(string url, string apiName)
{
_identityServerBuilder = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureServices(services =>
{
services.AddLogging();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(new List<ApiResource>
{
new ApiResource
{
Name = apiName,
Description = apiName,
Enabled = true,
DisplayName = apiName,
Scopes = new List<Scope>()
{
new Scope(apiName)
}
}
})
.AddInMemoryClients(new List<Client>
{
new Client
{
ClientId = apiName,
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets = new List<Secret> {new Secret("secret".Sha256())},
AllowedScopes = new List<string> { apiName },
AccessTokenType = AccessTokenType.Jwt,
Enabled = true
}
})
.AddTestUsers(new List<TestUser>
{
new TestUser
{
Username = "test",
Password = "test",
SubjectId = "1231231"
}
});
})
.Configure(app =>
{
app.UseIdentityServer();
})
.Build();
_identityServerBuilder.Start();
using (var httpClient = new HttpClient())
{
var response = httpClient.GetAsync($"{url}/.well-known/openid-configuration").Result;
response.EnsureSuccessStatusCode();
}
}
private void GivenAnotherOcelotIsRunning(string baseUrl)
{
_httpClientTwo.BaseAddress = new Uri(baseUrl);
@ -312,10 +450,36 @@ namespace Ocelot.IntegrationTests
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureServices(x => {
x.AddSingleton(_webHostBuilderTwo);
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddOcelotBaseUrl(baseUrl);
config.AddEnvironmentVariables();
})
.UseStartup<IntegrationTestsStartup>();
.ConfigureServices(x =>
{
Action<ConfigurationBuilderCachePart> settings = (s) =>
{
s.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithDictionaryHandle();
};
x.AddOcelot()
.AddCacheManager(settings)
.AddAdministration("/administration", "secret");
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_builderTwo = _webHostBuilderTwo.Build();
@ -400,18 +564,110 @@ namespace Ocelot.IntegrationTests
response.EnsureSuccessStatusCode();
}
private void GivenOcelotIsRunningWithIdentityServerSettings(Action<IdentityServerAuthenticationOptions> configOptions)
{
_webHostBuilder = new WebHostBuilder()
.UseUrls(_ocelotBaseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(x => {
x.AddSingleton(_webHostBuilder);
x.AddOcelot()
.AddCacheManager(c =>
{
c.WithDictionaryHandle();
})
.AddAdministration("/administration", configOptions);
})
.Configure(app => {
app.UseOcelot().Wait();
});
_builder = _webHostBuilder.Build();
_builder.Start();
}
private void GivenOcelotIsRunning()
{
_webHostBuilder = new WebHostBuilder()
.UseUrls(_ocelotBaseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddOcelotBaseUrl(_ocelotBaseUrl);
config.AddEnvironmentVariables();
})
.ConfigureServices(x =>
{
Action<ConfigurationBuilderCachePart> settings = (s) =>
{
s.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithDictionaryHandle();
};
x.AddOcelot()
.AddCacheManager(settings)
.AddAdministration("/administration", "secret");
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_builder = _webHostBuilder.Build();
_builder.Start();
}
private void GivenOcelotIsRunningWithNoWebHostBuilder(string baseUrl)
{
_webHostBuilder = new WebHostBuilder()
.UseUrls(_ocelotBaseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddOcelotBaseUrl(baseUrl);
config.AddEnvironmentVariables();
})
.ConfigureServices(x => {
x.AddSingleton(_webHostBuilder);
x.AddOcelot()
.AddCacheManager(c =>
{
c.WithDictionaryHandle();
})
.AddAdministration("/administration", "secret");
})
.UseStartup<IntegrationTestsStartup>();
.Configure(app => {
app.UseOcelot().Wait();
});
_builder = _webHostBuilder.Build();
_builder = _webHostBuilder.Build();
_builder.Start();
}
@ -464,6 +720,7 @@ namespace Ocelot.IntegrationTests
Environment.SetEnvironmentVariable("OCELOT_CERTIFICATE_PASSWORD", "");
_builder?.Dispose();
_httpClient?.Dispose();
_identityServerBuilder?.Dispose();
}
}
}

View File

@ -1,51 +0,0 @@
using System;
using CacheManager.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
namespace Ocelot.IntegrationTests
{
public class IntegrationTestsStartup
{
public IntegrationTestsStartup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("configuration.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
Action<ConfigurationBuilderCachePart> settings = (x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithDictionaryHandle();
};
services.AddOcelot(Configuration)
.AddCacheManager(settings)
.AddAdministration("/administration", "secret");
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseOcelot().Wait();
}
}
}

View File

@ -1,53 +0,0 @@
using System;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Ocelot.Raft;
using Rafty.Concensus;
using Rafty.FiniteStateMachine;
using Rafty.Infrastructure;
using Rafty.Log;
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
namespace Ocelot.IntegrationTests
{
public class RaftStartup
{
public RaftStartup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("peers.json", optional: true, reloadOnChange: true)
.AddJsonFile("configuration.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
public virtual void ConfigureServices(IServiceCollection services)
{
services
.AddOcelot(Configuration)
.AddAdministration("/administration", "secret")
.AddRafty()
;
}
public virtual void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseOcelot().Wait();
}
}
}

View File

@ -17,6 +17,9 @@ using Shouldly;
using Xunit;
using static Rafty.Infrastructure.Wait;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Configuration;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
namespace Ocelot.IntegrationTests
{
@ -28,7 +31,6 @@ namespace Ocelot.IntegrationTests
private FilePeers _peers;
private readonly HttpClient _httpClient;
private readonly HttpClient _httpClientForAssertions;
private string _ocelotBaseUrl;
private BearerToken _token;
private HttpResponseMessage _response;
private static readonly object _lock = new object();
@ -37,8 +39,8 @@ namespace Ocelot.IntegrationTests
{
_httpClientForAssertions = new HttpClient();
_httpClient = new HttpClient();
_ocelotBaseUrl = "http://localhost:5000";
_httpClient.BaseAddress = new Uri(_ocelotBaseUrl);
var ocelotBaseUrl = "http://localhost:5000";
_httpClient.BaseAddress = new Uri(ocelotBaseUrl);
_webHostBuilders = new List<IWebHostBuilder>();
_builders = new List<IWebHost>();
_threads = new List<Thread>();
@ -331,12 +333,29 @@ namespace Ocelot.IntegrationTests
webHostBuilder.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddJsonFile("peers.json", optional: true, reloadOnChange: true);
config.AddOcelotBaseUrl(url);
config.AddEnvironmentVariables();
})
.ConfigureServices(x =>
{
x.AddSingleton(webHostBuilder);
x.AddSingleton(new NodeId(url));
x
.AddOcelot()
.AddAdministration("/administration", "secret")
.AddRafty();
})
.UseStartup<RaftStartup>();
.Configure(app =>
{
app.UseOcelot().Wait();
});
var builder = webHostBuilder.Build();
builder.Start();

View File

@ -13,6 +13,11 @@ using Xunit;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using CacheManager.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
namespace Ocelot.IntegrationTests
{
@ -97,11 +102,35 @@ namespace Ocelot.IntegrationTests
.UseUrls(_ocelotBaseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddOcelotBaseUrl(_ocelotBaseUrl);
config.AddEnvironmentVariables();
})
.ConfigureServices(x =>
{
x.AddSingleton(_webHostBuilder);
Action<ConfigurationBuilderCachePart> settings = (s) =>
{
s.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithDictionaryHandle();
};
x.AddOcelot()
.AddCacheManager(settings)
.AddAdministration("/administration", "secret");
})
.UseStartup<IntegrationTestsStartup>();
.Configure(app =>
{
app.UseOcelot().Wait();
});
_builder = _webHostBuilder.Build();

View File

@ -1,37 +0,0 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
namespace Ocelot.ManualTest
{
public class ManualTestStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication()
.AddJwtBearer("TestKey", x =>
{
x.Authority = "test";
x.Audience = "test";
});
services.AddOcelot()
.AddCacheManager(x =>
{
x.WithDictionaryHandle();
})
.AddOpenTracing(option =>
{
option.CollectorUrl = "http://localhost:9618";
option.Service = "Ocelot.ManualTest";
})
.AddAdministration("/administration", "secret");
}
public void Configure(IApplicationBuilder app)
{
app.UseOcelot().Wait();
}
}
}

View File

@ -3,6 +3,8 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
namespace Ocelot.ManualTest
{
@ -10,20 +12,39 @@ namespace Ocelot.ManualTest
{
public static void Main(string[] args)
{
IWebHostBuilder builder = new WebHostBuilder();
builder.ConfigureServices(s => {
s.AddSingleton(builder);
});
builder.UseKestrel()
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddJsonFile("configuration.json")
.AddEnvironmentVariables()
.AddOcelotBaseUrl("http://localhost:5000");
})
.ConfigureServices(s => {
s.AddAuthentication()
.AddJwtBearer("TestKey", x =>
{
x.Authority = "test";
x.Audience = "test";
});
s.AddOcelot()
.AddCacheManager(x =>
{
x.WithDictionaryHandle();
})
.AddOpenTracing(option =>
{
option.CollectorUrl = "http://localhost:9618";
option.Service = "Ocelot.ManualTest";
})
.AddAdministration("/administration", "secret");
})
.ConfigureLogging((hostingContext, logging) =>
{
@ -31,9 +52,12 @@ namespace Ocelot.ManualTest
logging.AddConsole();
})
.UseIISIntegration()
.UseStartup<ManualTestStartup>();
var host = builder.Build();
host.Run();
.Configure(app =>
{
app.UseOcelot().Wait();
})
.Build()
.Run();
}
}
}

View File

@ -0,0 +1,41 @@
using Microsoft.Extensions.Configuration;
using Ocelot.DependencyInjection;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.DependencyInjection
{
public class ConfigurationBuilderExtensionsTests
{
private IConfigurationRoot _configuration;
private string _result;
[Fact]
public void should_add_base_url_to_config()
{
this.Given(x => GivenTheBaseUrl("test"))
.When(x => WhenIGet("BaseUrl"))
.Then(x => ThenTheResultIs("test"))
.BDDfy();
}
private void GivenTheBaseUrl(string baseUrl)
{
var builder = new ConfigurationBuilder()
.AddOcelotBaseUrl(baseUrl);
_configuration = builder.Build();
}
private void WhenIGet(string key)
{
_result = _configuration.GetValue("BaseUrl", "");
}
private void ThenTheResultIs(string expected)
{
_result.ShouldBe(expected);
}
}
}

View File

@ -16,6 +16,7 @@ using Ocelot.Requester;
using Ocelot.UnitTests.Requester;
using Shouldly;
using System;
using IdentityServer4.AccessTokenValidation;
using TestStack.BDDfy;
using Xunit;
@ -31,13 +32,11 @@ namespace Ocelot.UnitTests.DependencyInjection
public OcelotBuilderTests()
{
IWebHostBuilder builder = new WebHostBuilder();
_configRoot = new ConfigurationRoot(new List<IConfigurationProvider>());
_services = new ServiceCollection();
_services.AddSingleton(builder);
_services.AddSingleton<IHostingEnvironment, HostingEnvironment>();
_services.AddSingleton<IConfiguration>(_configRoot);
_maxRetries = 100;
_configRoot = new ConfigurationRoot(new List<IConfigurationProvider>());
_services = new ServiceCollection();
_services.AddSingleton<IHostingEnvironment, HostingEnvironment>();
_services.AddSingleton<IConfiguration>(_configRoot);
_maxRetries = 100;
}
private Exception _ex;
@ -100,6 +99,40 @@ namespace Ocelot.UnitTests.DependencyInjection
.BDDfy();
}
[Fact]
public void should_set_up_administration_with_identity_server_options()
{
Action<IdentityServerAuthenticationOptions> options = o => {
};
this.Given(x => WhenISetUpOcelotServices())
.When(x => WhenISetUpAdministration(options))
.Then(x => ThenAnExceptionIsntThrown())
.Then(x => ThenTheCorrectAdminPathIsRegitered())
.BDDfy();
}
[Fact]
public void should_set_up_administration()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => WhenISetUpAdministration())
.Then(x => ThenAnExceptionIsntThrown())
.Then(x => ThenTheCorrectAdminPathIsRegitered())
.BDDfy();
}
private void WhenISetUpAdministration()
{
_ocelotBuilder.AddAdministration("/administration", "secret");
}
private void WhenISetUpAdministration(Action<IdentityServerAuthenticationOptions> options)
{
_ocelotBuilder.AddAdministration("/administration", options);
}
[Fact]
public void should_use_logger_factory()
{
@ -255,6 +288,7 @@ namespace Ocelot.UnitTests.DependencyInjection
{
try
{
_serviceProvider = _services.BuildServiceProvider();
var logger = _serviceProvider.GetService<IFileConfigurationSetter>();
}
catch (Exception e)

View File

@ -15,6 +15,7 @@ namespace Ocelot.UnitTests.Errors
using Moq;
using Ocelot.Configuration;
using Rafty.Concensus;
using Ocelot.Errors;
public class ExceptionHandlerMiddlewareTests : ServerHostedMiddlewareTest
{
@ -40,11 +41,6 @@ namespace Ocelot.UnitTests.Errors
.BDDfy();
}
private void TheRequestIdIsNotSet()
{
ScopedRepository.Verify(x => x.Add<string>(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
}
[Fact]
public void DownstreamException()
{
@ -83,6 +79,55 @@ namespace Ocelot.UnitTests.Errors
.BDDfy();
}
[Fact]
public void should_throw_exception_if_config_provider_returns_error()
{
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
.And(_ => GivenTheConfigReturnsError())
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
.Then(_ => ThenAnExceptionIsThrown())
.BDDfy();
}
[Fact]
public void should_throw_exception_if_config_provider_throws()
{
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
.And(_ => GivenTheConfigThrows())
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
.Then(_ => ThenAnExceptionIsThrown())
.BDDfy();
}
private void GivenTheConfigThrows()
{
var ex = new Exception("outer", new Exception("inner"));
_provider
.Setup(x => x.Get()).ThrowsAsync(ex);
}
private void ThenAnExceptionIsThrown()
{
ResponseMessage.StatusCode.ShouldBe(HttpStatusCode.InternalServerError);
}
private void GivenTheConfigReturnsError()
{
var config = new OcelotConfiguration(null, null, null, null);
var response = new Ocelot.Responses.ErrorResponse<IOcelotConfiguration>(new FakeError());
_provider
.Setup(x => x.Get()).ReturnsAsync(response);
}
public class FakeError : Error
{
public FakeError()
: base("meh", OcelotErrorCode.CannotAddDataError)
{
}
}
private void TheRequestIdIsSet(string key, string value)
{
ScopedRepository.Verify(x => x.Add<string>(key, value), Times.Once);
@ -140,5 +185,10 @@ namespace Ocelot.UnitTests.Errors
{
ResponseMessage.StatusCode.ShouldBe(HttpStatusCode.InternalServerError);
}
private void TheRequestIdIsNotSet()
{
ScopedRepository.Verify(x => x.Add<string>(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
}
}
}

View File

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Memory;
using Moq;
using Ocelot.Middleware;
using Shouldly;
@ -14,38 +16,41 @@ namespace Ocelot.UnitTests.Middleware
public class BaseUrlFinderTests
{
private readonly BaseUrlFinder _baseUrlFinder;
private readonly Mock<IWebHostBuilder> _webHostBuilder;
private readonly Mock<IConfiguration> _config;
private string _result;
public BaseUrlFinderTests()
{
_webHostBuilder = new Mock<IWebHostBuilder>();
_baseUrlFinder = new BaseUrlFinder(_webHostBuilder.Object);
}
[Fact]
public void should_find_base_url_based_on_webhostbuilder()
{
this.Given(x => GivenTheWebHostBuilderReturns("http://localhost:7000"))
.When(x => WhenIFindTheUrl())
.Then(x => ThenTheUrlIs("http://localhost:7000"))
.BDDfy();
_config = new Mock<IConfiguration>();
_baseUrlFinder = new BaseUrlFinder(_config.Object);
}
[Fact]
public void should_use_default_base_url()
{
this.Given(x => GivenTheWebHostBuilderReturns(""))
this.Given(x => GivenTheConfigBaseUrlIs(""))
.And(x => GivenTheConfigBaseUrlIs(""))
.When(x => WhenIFindTheUrl())
.Then(x => ThenTheUrlIs("http://localhost:5000"))
.BDDfy();
}
private void GivenTheWebHostBuilderReturns(string url)
[Fact]
public void should_use_file_config_base_url()
{
_webHostBuilder
.Setup(x => x.GetSetting(WebHostDefaults.ServerUrlsKey))
.Returns(url);
this.Given(x => GivenTheConfigBaseUrlIs("http://localhost:7000"))
.And(x => GivenTheConfigBaseUrlIs("http://baseurlfromconfig.com:5181"))
.When(x => WhenIFindTheUrl())
.Then(x => ThenTheUrlIs("http://baseurlfromconfig.com:5181"))
.BDDfy();
}
private void GivenTheConfigBaseUrlIs(string configValue)
{
var configSection = new ConfigurationSection(new ConfigurationRoot(new List<IConfigurationProvider>{new MemoryConfigurationProvider(new MemoryConfigurationSource())}), "");
configSection.Value = configValue;
_config.Setup(x => x.GetSection(It.IsAny<string>())).Returns(configSection);
}
private void WhenIFindTheUrl()