From bd07af692657e140b67f9638d7ae856e136dfb96 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Wed, 22 Feb 2017 22:13:35 +0000 Subject: [PATCH] more work towards getting identity server and admin area set up --- README.md | 18 +++++ configuration.json | 2 +- .../ServiceCollectionExtensions.cs | 68 ++++++++++--------- .../Middleware/OcelotMiddlewareExtensions.cs | 43 ++++++++---- test/Ocelot.AcceptanceTests/Steps.cs | 22 +++++- .../AdministrationTests.cs | 12 +++- test/Ocelot.ManualTest/Program.cs | 15 ++-- test/Ocelot.ManualTest/Startup.cs | 10 ++- 8 files changed, 132 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index dfbdfd1e..d0db1e39 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,24 @@ Currently this is the only way to get configuration into Ocelot. } } +Then in your Program.cs you will want to have the following.. + + IWebHostBuilder builder = new WebHostBuilder(); + + builder.ConfigureServices(s => { + s.AddSingleton(builder); + }); + + builder.UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup(); + + var host = builder.Build(); + + host.Run(); + +Sadly we need to inject the IWebHostBuilder interface to get the applications scheme, url and port later. I cannot +find a better way of doing this at the moment without setting this in a static or some kind of config. This is pretty much all you need to get going.......more to come! diff --git a/configuration.json b/configuration.json index a2784d8c..2faeadfa 100755 --- a/configuration.json +++ b/configuration.json @@ -1 +1 @@ -{"ReRoutes":[{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/","UpstreamHttpMethod":"get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null},{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/test","UpstreamHttpMethod":"get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null}],"GlobalConfiguration":{"RequestIdKey":"RequestId","ServiceDiscoveryProvider":{"Provider":null,"Host":null,"Port":0},"AdministrationPath":"/administration"}} \ No newline at end of file +{"ReRoutes":[{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/","UpstreamHttpMethod":"get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null},{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/test","UpstreamHttpMethod":"get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null}],"GlobalConfiguration":{"RequestIdKey":"RequestId","ServiceDiscoveryProvider":{"Provider":"test","Host":"127.0.0.1","Port":0},"AdministrationPath":"/administration"}} \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 0529c938..52c47a25 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -5,6 +5,7 @@ using System.Net.Http; using CacheManager.Core; using IdentityServer4.Models; using IdentityServer4.Test; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -61,44 +62,49 @@ namespace Ocelot.DependencyInjection public static IServiceCollection AddOcelot(this IServiceCollection services) { - var authProvider = new HardCodedIdentityServerConfigurationProvider(); - var identityServerConfig = authProvider.Get(); + return AddOcelot(services, null); + } - services.AddIdentityServer() - .AddTemporarySigningCredential() - .AddInMemoryApiResources(new List - { - new ApiResource + public static IServiceCollection AddOcelot(this IServiceCollection services, IdentityServerConfiguration identityServerConfiguration) + { + if(identityServerConfiguration != null) + { + services.AddIdentityServer() + .AddTemporarySigningCredential() + .AddInMemoryApiResources(new List { - Name = identityServerConfig.ApiName, - Description = identityServerConfig.Description, - Enabled = identityServerConfig.Enabled, - DisplayName = identityServerConfig.ApiName, - Scopes = identityServerConfig.AllowedScopes.Select(x => new Scope(x)).ToList(), - ApiSecrets = new List + new ApiResource { - new Secret + Name = identityServerConfiguration.ApiName, + Description = identityServerConfiguration.Description, + Enabled = identityServerConfiguration.Enabled, + DisplayName = identityServerConfiguration.ApiName, + Scopes = identityServerConfiguration.AllowedScopes.Select(x => new Scope(x)).ToList(), + ApiSecrets = new List { - Value = identityServerConfig.ApiSecret.Sha256() + new Secret + { + Value = identityServerConfiguration.ApiSecret.Sha256() + } } } - } - }) - .AddInMemoryClients(new List - { - new Client + }) + .AddInMemoryClients(new List { - ClientId = identityServerConfig.ApiName, - AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, - ClientSecrets = new List {new Secret(identityServerConfig.ApiSecret.Sha256())}, - AllowedScopes = identityServerConfig.AllowedScopes, - AccessTokenType = identityServerConfig.AccessTokenType, - Enabled = identityServerConfig.Enabled, - RequireClientSecret = identityServerConfig.RequireClientSecret - } - }) - .AddTestUsers(identityServerConfig.Users); - + new Client + { + ClientId = identityServerConfiguration.ApiName, + AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, + ClientSecrets = new List {new Secret(identityServerConfiguration.ApiSecret.Sha256())}, + AllowedScopes = identityServerConfiguration.AllowedScopes, + AccessTokenType = identityServerConfiguration.AccessTokenType, + Enabled = identityServerConfiguration.Enabled, + RequireClientSecret = identityServerConfiguration.RequireClientSecret + } + }) + .AddTestUsers(identityServerConfiguration.Users); + } + services.AddMvcCore() .AddAuthorization() .AddJsonFormatters(); diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 57ed9bf3..99509650 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -19,6 +19,7 @@ namespace Ocelot.Middleware using System; using System.Threading.Tasks; using Authorisation.Middleware; + using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Ocelot.Configuration; @@ -36,7 +37,21 @@ namespace Ocelot.Middleware /// public static async Task UseOcelot(this IApplicationBuilder builder) { - await builder.UseOcelot(new OcelotMiddlewareConfiguration()); + await builder.UseOcelot(new OcelotMiddlewareConfiguration(), null); + + return builder; + } + + public static async Task UseOcelot(this IApplicationBuilder builder,IdentityServerConfiguration identityServerConfiguration) + { + await builder.UseOcelot(new OcelotMiddlewareConfiguration(), identityServerConfiguration); + + return builder; + } + + public static async Task UseOcelot(this IApplicationBuilder builder,OcelotMiddlewareConfiguration middlewareConfiguration) + { + await builder.UseOcelot(middlewareConfiguration, null); return builder; } @@ -47,9 +62,9 @@ namespace Ocelot.Middleware /// /// /// - public static async Task UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration) + public static async Task UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration, IdentityServerConfiguration identityServerConfiguration) { - await CreateAdministrationArea(builder); + await CreateAdministrationArea(builder, identityServerConfiguration); // This is registered to catch any global exceptions that are not handled builder.UseExceptionHandlerMiddleware(); @@ -153,27 +168,28 @@ namespace Ocelot.Middleware return ocelotConfiguration.Data; } - private static async Task CreateAdministrationArea(IApplicationBuilder builder) + private static async Task CreateAdministrationArea(IApplicationBuilder builder, IdentityServerConfiguration identityServerConfiguration) { var configuration = await CreateConfiguration(builder); - var authProvider = new HardCodedIdentityServerConfigurationProvider(); - var identityServerConfig = authProvider.Get(); - - if(!string.IsNullOrEmpty(configuration.AdministrationPath)) + if(!string.IsNullOrEmpty(configuration.AdministrationPath) && identityServerConfiguration != null) { + var webHostBuilder = (IWebHostBuilder)builder.ApplicationServices.GetService(typeof(IWebHostBuilder)); + + var baseSchemeUrlAndPort = webHostBuilder.GetSetting(WebHostDefaults.ServerUrlsKey); + builder.Map(configuration.AdministrationPath, app => { - var identityServerUrl = $"http://localhost:5000/{configuration.AdministrationPath.Remove(0,1)}"; + var identityServerUrl = $"{baseSchemeUrlAndPort}/{configuration.AdministrationPath.Remove(0,1)}"; app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { Authority = identityServerUrl, - ApiName = identityServerConfig.ApiName, - RequireHttpsMetadata = identityServerConfig.RequireHttps, - AllowedScopes = identityServerConfig.AllowedScopes, + ApiName = identityServerConfiguration.ApiName, + RequireHttpsMetadata = identityServerConfiguration.RequireHttps, + AllowedScopes = identityServerConfiguration.AllowedScopes, SupportedTokens = SupportedTokens.Both, - ApiSecret = identityServerConfig.ApiSecret + ApiSecret = identityServerConfiguration.ApiSecret }); app.UseIdentityServer(); @@ -182,7 +198,6 @@ namespace Ocelot.Middleware }); } } - private static void UseIfNotNull(this IApplicationBuilder builder, Func, Task> middleware) { if (middleware != null) diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index 1f4a8da1..d923148a 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -11,6 +11,7 @@ using CacheManager.Core; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Ocelot.Configuration.File; @@ -32,6 +33,7 @@ namespace Ocelot.AcceptanceTests public HttpClient OcelotClient => _ocelotClient; public string RequestIdKey = "OcRequestId"; private readonly Random _random; + private IWebHostBuilder _webHostBuilder; public Steps() { @@ -69,7 +71,14 @@ namespace Ocelot.AcceptanceTests /// public void GivenOcelotIsRunning() { - _ocelotServer = new TestServer(new WebHostBuilder() + _webHostBuilder = new WebHostBuilder(); + + _webHostBuilder.ConfigureServices(s => + { + s.AddSingleton(_webHostBuilder); + }); + + _ocelotServer = new TestServer(_webHostBuilder .UseStartup()); _ocelotClient = _ocelotServer.CreateClient(); @@ -109,7 +118,14 @@ namespace Ocelot.AcceptanceTests var configuration = builder.Build(); - _ocelotServer = new TestServer(new WebHostBuilder() + _webHostBuilder = new WebHostBuilder(); + + _webHostBuilder.ConfigureServices(s => + { + s.AddSingleton(_webHostBuilder); + }); + + _ocelotServer = new TestServer(_webHostBuilder .UseConfiguration(configuration) .ConfigureServices(s => { @@ -121,7 +137,7 @@ namespace Ocelot.AcceptanceTests }) .WithDictionaryHandle(); }; - + s.AddOcelotOutputCaching(settings); s.AddOcelotFileConfiguration(configuration); s.AddOcelot(); diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index 6661a2cc..06e7bd5d 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -5,6 +5,7 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.ManualTest; @@ -19,6 +20,7 @@ namespace Ocelot.IntegrationTests private readonly HttpClient _httpClient; private HttpResponseMessage _response; private IWebHost _builder; + private IWebHostBuilder _webHostBuilder; private readonly string _ocelotBaseUrl; private BearerToken _token; @@ -246,12 +248,16 @@ namespace Ocelot.IntegrationTests private void GivenOcelotIsRunning() { - _builder = new WebHostBuilder() + _webHostBuilder = new WebHostBuilder() .UseUrls(_ocelotBaseUrl) .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .Build(); + .ConfigureServices(x => { + x.AddSingleton(_webHostBuilder); + }) + .UseStartup(); + + _builder = _webHostBuilder.Build(); _builder.Start(); } diff --git a/test/Ocelot.ManualTest/Program.cs b/test/Ocelot.ManualTest/Program.cs index a049d3ea..a545819a 100644 --- a/test/Ocelot.ManualTest/Program.cs +++ b/test/Ocelot.ManualTest/Program.cs @@ -1,5 +1,6 @@ using System.IO; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; namespace Ocelot.ManualTest { @@ -7,11 +8,17 @@ namespace Ocelot.ManualTest { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() + IWebHostBuilder builder = new WebHostBuilder(); + + builder.ConfigureServices(s => { + s.AddSingleton(builder); + }); + + builder.UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .Build(); + .UseStartup(); + + var host = builder.Build(); host.Run(); } diff --git a/test/Ocelot.ManualTest/Startup.cs b/test/Ocelot.ManualTest/Startup.cs index b187f6b4..aa34c9a2 100644 --- a/test/Ocelot.ManualTest/Startup.cs +++ b/test/Ocelot.ManualTest/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Ocelot.Configuration.Provider; using Ocelot.DependencyInjection; using Ocelot.Middleware; using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder; @@ -14,6 +15,8 @@ namespace Ocelot.ManualTest { public class Startup { + private IdentityServerConfiguration _identityServerConfig; + public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() @@ -24,6 +27,9 @@ namespace Ocelot.ManualTest .AddEnvironmentVariables(); Configuration = builder.Build(); + + var identityServerConfigProvider = new HardCodedIdentityServerConfigurationProvider(); + _identityServerConfig = identityServerConfigProvider.Get(); } public IConfigurationRoot Configuration { get; } @@ -41,14 +47,14 @@ namespace Ocelot.ManualTest services.AddOcelotOutputCaching(settings); services.AddOcelotFileConfiguration(Configuration); - services.AddOcelot(); + services.AddOcelot(_identityServerConfig); } public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); - await app.UseOcelot(); + await app.UseOcelot(_identityServerConfig); } } }