diff --git a/src/Ocelot/Configuration/Creator/IdentityServerConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/IdentityServerConfigurationCreator.cs index 48819608..6ed3b6c0 100644 --- a/src/Ocelot/Configuration/Creator/IdentityServerConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/IdentityServerConfigurationCreator.cs @@ -13,6 +13,8 @@ namespace Ocelot.Configuration.Creator var username = Environment.GetEnvironmentVariable("OCELOT_USERNAME"); var hash = Environment.GetEnvironmentVariable("OCELOT_HASH"); var salt = Environment.GetEnvironmentVariable("OCELOT_SALT"); + var credentialsSigningCertificateLocation = Environment.GetEnvironmentVariable("OCELOT_CERTIFICATE"); + var credentialsSigningCertificatePassword = Environment.GetEnvironmentVariable("OCELOT_CERTIFICATE_PASSWORD"); return new IdentityServerConfiguration( "admin", @@ -28,7 +30,9 @@ namespace Ocelot.Configuration.Creator new List { new User("admin", username, hash, salt) - } + }, + credentialsSigningCertificateLocation, + credentialsSigningCertificatePassword ); } } diff --git a/src/Ocelot/Configuration/Provider/IIdentityServerConfiguration.cs b/src/Ocelot/Configuration/Provider/IIdentityServerConfiguration.cs index bb66265f..0a388abb 100644 --- a/src/Ocelot/Configuration/Provider/IIdentityServerConfiguration.cs +++ b/src/Ocelot/Configuration/Provider/IIdentityServerConfiguration.cs @@ -17,5 +17,7 @@ namespace Ocelot.Configuration.Provider AccessTokenType AccessTokenType {get;} bool RequireClientSecret {get;} List Users {get;} + string CredentialsSigningCertificateLocation { get; } + string CredentialsSigningCertificatePassword { get; } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Provider/IdentityServerConfiguration.cs b/src/Ocelot/Configuration/Provider/IdentityServerConfiguration.cs index f0f6897d..881d6f5a 100644 --- a/src/Ocelot/Configuration/Provider/IdentityServerConfiguration.cs +++ b/src/Ocelot/Configuration/Provider/IdentityServerConfiguration.cs @@ -17,7 +17,7 @@ namespace Ocelot.Configuration.Provider IEnumerable grantType, AccessTokenType accessTokenType, bool requireClientSecret, - List users) + List users, string credentialsSigningCertificateLocation, string credentialsSigningCertificatePassword) { ApiName = apiName; RequireHttps = requireHttps; @@ -30,6 +30,8 @@ namespace Ocelot.Configuration.Provider AccessTokenType = accessTokenType; RequireClientSecret = requireClientSecret; Users = users; + CredentialsSigningCertificateLocation = credentialsSigningCertificateLocation; + CredentialsSigningCertificatePassword = credentialsSigningCertificatePassword; } public string ApiName { get; private set; } @@ -43,5 +45,7 @@ namespace Ocelot.Configuration.Provider public AccessTokenType AccessTokenType {get;private set;} public bool RequireClientSecret {get;private set;} public List Users {get;private set;} + public string CredentialsSigningCertificateLocation { get; private set; } + public string CredentialsSigningCertificatePassword { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index d52341fe..6b33f5c7 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -41,6 +41,8 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using Microsoft.IdentityModel.Tokens; using Ocelot.Configuration; using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider; @@ -87,8 +89,7 @@ namespace Ocelot.DependencyInjection { services.TryAddSingleton(identityServerConfiguration); services.TryAddSingleton(); - services.AddIdentityServer() - .AddTemporarySigningCredential() + var identityServerBuilder = services.AddIdentityServer() .AddInMemoryApiResources(new List { new ApiResource @@ -120,6 +121,16 @@ namespace Ocelot.DependencyInjection RequireClientSecret = identityServerConfiguration.RequireClientSecret } }).AddResourceOwnerValidator(); + + if (string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificateLocation) || string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificatePassword)) + { + identityServerBuilder.AddTemporarySigningCredential(); + } + else + { + var cert = new X509Certificate2(identityServerConfiguration.CredentialsSigningCertificateLocation, identityServerConfiguration.CredentialsSigningCertificatePassword); + identityServerBuilder.AddSigningCredential(cert); + } } var assembly = typeof(FileConfigurationController).GetTypeInfo().Assembly; diff --git a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj index 0faafe84..94e30391 100644 --- a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj +++ b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj @@ -15,7 +15,7 @@ - + PreserveNewest diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index 2fa2c05c..3f7ea18a 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -19,15 +19,19 @@ namespace Ocelot.IntegrationTests public class AdministrationTests : IDisposable { private readonly HttpClient _httpClient; + private readonly HttpClient _httpClientTwo; private HttpResponseMessage _response; private IWebHost _builder; private IWebHostBuilder _webHostBuilder; private readonly string _ocelotBaseUrl; private BearerToken _token; + private IWebHostBuilder _webHostBuilderTwo; + private IWebHost _builderTwo; public AdministrationTests() { _httpClient = new HttpClient(); + _httpClientTwo = new HttpClient(); _ocelotBaseUrl = "http://localhost:5000"; _httpClient.BaseAddress = new Uri(_ocelotBaseUrl); } @@ -70,6 +74,27 @@ namespace Ocelot.IntegrationTests .BDDfy(); } + [Fact] + public void should_be_able_to_use_token_from_ocelot_a_on_ocelot_b() + { + var configuration = new FileConfiguration + { + GlobalConfiguration = new FileGlobalConfiguration + { + AdministrationPath = "/administration" + } + }; + + this.Given(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .And(x => GivenIHaveAnOcelotToken("/administration")) + .And(x => GivenIHaveAddedATokenToMyRequest()) + .And(x => GivenAnotherOcelotIsRunning("http://localhost:5007")) + .When(x => WhenIGetUrlOnTheSecondOcelot("/administration/configuration")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } + [Fact] public void should_return_file_configuration() { @@ -193,6 +218,29 @@ namespace Ocelot.IntegrationTests .BDDfy(); } + private void GivenAnotherOcelotIsRunning(string baseUrl) + { + _httpClientTwo.BaseAddress = new Uri(baseUrl); + + _webHostBuilderTwo = new WebHostBuilder() + .UseUrls(baseUrl) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .ConfigureServices(x => { + x.AddSingleton(_webHostBuilder); + }) + .UseStartup(); + + _builderTwo = _webHostBuilderTwo.Build(); + + _builderTwo.Start(); + } + + private void WhenIGetUrlOnTheSecondOcelot(string url) + { + _response = _httpClientTwo.GetAsync(url).Result; + } + private void WhenIPostOnTheApiGateway(string url, FileConfiguration updatedConfiguration) { var json = JsonConvert.SerializeObject(updatedConfiguration); diff --git a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj index db4b23d2..59513b38 100644 --- a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj +++ b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj @@ -15,7 +15,7 @@ - + PreserveNewest