Skip to content

Commit

Permalink
Merge branch 'release-3.1.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Gardham-Pallister committed Feb 14, 2018
2 parents 065a013 + d6a86b9 commit 6919d2b
Show file tree
Hide file tree
Showing 37 changed files with 1,044 additions and 551 deletions.
38 changes: 34 additions & 4 deletions docs/features/administration.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@
Administration
==============

Ocelot supports changing configuration during runtime via an authenticated HTTP API. The API is authenticated
using bearer tokens that you request from Ocelot iteself. This is provided by the amazing
Ocelot supports changing configuration during runtime via an authenticated HTTP API. This can be authenticated in two ways either using Ocelot's
internal IdentityServer (for authenticating requests to the administration API only) or hooking the administration API authentication into your own
IdentityServer.

Providing your own IdentityServer
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

All you need to do to hook into your own IdentityServer is add the following to your ConfigureServices method.

.. code-block:: csharp
public virtual void ConfigureServices(IServiceCollection services)
{
Action<IdentityServerAuthenticationOptions> options = o => {
// o.Authority = ;
// o.ApiName = ;
// etc....
};
services
.AddOcelot(Configuration)
.AddAdministration("/administration", options);
}
You now need to get a token from your IdentityServer and use in subsequent requests to Ocelot's administration API.

This feature was implemented for `issue 228 <https://github.com/TomPallister/Ocelot/issues/228>`_. It is useful because the IdentityServer authentication
middleware needs the URL of the IdentityServer. If you are using the internal IdentityServer it might not alaways be possible to have the Ocelot URL.

Internal IdentityServer
^^^^^^^^^^^^^^^^^^^^^^^

The API is authenticated using bearer tokens that you request from Ocelot iteself. This is provided by the amazing
`Identity Server <https://github.com/IdentityServer/IdentityServer4>`_ project that I have been using for a few years now. Check them out.

In order to enable the administration section you need to do a few things. First of all add this to your
Expand Down Expand Up @@ -31,8 +62,6 @@ will need to be changed if you are running Ocelot on a different url to http://l
The scripts show you how to request a bearer token from ocelot and then use it to GET the existing configuration and POST
a configuration.

Administration running multiple Ocelot's
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you are running multiple Ocelot's in a cluster then you need to use a certificate to sign the bearer tokens used to access the administration API.

In order to do this you need to add two more environmental variables for each Ocelot in the cluster.
Expand All @@ -44,6 +73,7 @@ In order to do this you need to add two more environmental variables for each Oc

Normally Ocelot just uses temporary signing credentials but if you set these environmental variables then it will use the certificate. If all the other Ocelots in the cluster have the same certificate then you are good!


Administration API
^^^^^^^^^^^^^^^^^^

Expand Down
7 changes: 7 additions & 0 deletions docs/features/authentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,10 @@ Then map the authentication provider key to a ReRoute in your configuration e.g.
"AllowedScopes": []
}
}]
Allowed Scopes
^^^^^^^^^^^^^

If you add scopes to AllowedScopes Ocelot will get all the user claims (from the token) of the type scope and make sure that the user has all of the scopes in the list.

This is a way to restrict access to a ReRoute on a per scope basis.
72 changes: 30 additions & 42 deletions docs/introduction/gettingstarted.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,62 +29,53 @@ The following is a very basic configuration.json. It won't do anything but shoul
**Program**

Then in your Program.cs you will want to have the following. This can be changed if you
don't wan't to use the default url e.g. UseUrls(someUrls) and should work as long as you keep the WebHostBuilder registration.
Then in your Program.cs you will want to have the following. The main things to note are AddOcelotBaseUrl("http://localhost:5000") (adds the url this instance of Ocelot will run under),
AddOcelot() (adds ocelot services), UseOcelot().Wait() (sets up all the Ocelot middleware). It is important to call AddOcelotBaseUrl as Ocelot needs to know the URL that it is exposed to the outside world on.

.. code-block:: csharp
public class Program
{
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.AddOcelot();
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
//add your logging
})
.UseIISIntegration()
.UseStartup<ManualTestStartup>();
var host = builder.Build();
host.Run();
.Configure(app =>
{
app.UseOcelot().Wait();
})
.Build()
.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.

**Startup**
AddOcelotBaseUrl
^^^^^^^^^^^^^^^^

An example startup using a json file for configuration can be seen below. This is the most basic startup and Ocelot has quite a few more options. Detailed in the rest of these docs! If you get a stuck a good place to look is at the ManualTests project in the source code.
The most important thing to note here is AddOcelotBaseUrl. Ocelot needs to know the URL it is running under
in order to do Header find & replace and for certain administration configurations. When setting this URL it should be the external URL that clients will see Ocelot running on e.g. If you are running containers Ocelot might run on the url http://123.12.1.1:6543 but has something like nginx in front of it responding on https://api.mybusiness.com. In this case the Ocelot base url should be https://api.mybusiness.com.

.. code-block:: csharp
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddOcelot();
}
public void Configure(IApplicationBuilder app)
{
app.UseOcelot().Wait();
}
}
If for some reason you are using containers and do want Ocelot to respond to client on http://123.12.1.1:6543
then you can do this but if you are deploying multiple Ocelot's you will probably want to pass this on the command line in some kind of script. Hopefully whatever scheduler you are using can pass the IP.

.NET Core 1.0
^^^^^^^^^^^^^
Expand All @@ -109,8 +100,7 @@ The following is a very basic configuration.json. It won't do anything but shoul
**Program**

Then in your Program.cs you will want to have the following. This can be changed if you
don't wan't to use the default url e.g. UseUrls(someUrls) and should work as long as you keep the WebHostBuilder registration.
Then in your Program.cs you will want to have the following.

.. code-block:: csharp
Expand All @@ -121,7 +111,6 @@ don't wan't to use the default url e.g. UseUrls(someUrls) and should work as lon
IWebHostBuilder builder = new WebHostBuilder();
builder.ConfigureServices(s => {
s.AddSingleton(builder);
});
builder.UseKestrel()
Expand All @@ -134,8 +123,6 @@ don't wan't to use the default url e.g. UseUrls(someUrls) and should work as lon
}
}
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.

**Startup**

An example startup using a json file for configuration can be seen below.
Expand All @@ -151,7 +138,8 @@ An example startup using a json file for configuration can be seen below.
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("configuration.json")
.AddEnvironmentVariables();
.AddEnvironmentVariables()
.AddOcelotBaseUrl("http://localhost:5000");
Configuration = builder.Build();
}
Expand Down
11 changes: 8 additions & 3 deletions src/Ocelot/Cache/CachedResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,25 @@ namespace Ocelot.Cache
public class CachedResponse
{
public CachedResponse(
HttpStatusCode statusCode = HttpStatusCode.OK,
Dictionary<string, IEnumerable<string>> headers = null,
string body = null
HttpStatusCode statusCode,
Dictionary<string, IEnumerable<string>> headers,
string body,
Dictionary<string, IEnumerable<string>> contentHeaders

)
{
StatusCode = statusCode;
Headers = headers ?? new Dictionary<string, IEnumerable<string>>();
ContentHeaders = contentHeaders ?? new Dictionary<string, IEnumerable<string>>();
Body = body ?? "";
}

public HttpStatusCode StatusCode { get; private set; }

public Dictionary<string, IEnumerable<string>> Headers { get; private set; }

public Dictionary<string, IEnumerable<string>> ContentHeaders { get; private set; }

public string Body { get; private set; }
}
}
13 changes: 12 additions & 1 deletion src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,21 @@ internal HttpResponseMessage CreateHttpResponseMessage(CachedResponse cached)
}

var response = new HttpResponseMessage(cached.StatusCode);

foreach (var header in cached.Headers)
{
response.Headers.Add(header.Key, header.Value);
}

var content = new MemoryStream(Convert.FromBase64String(cached.Body));

response.Content = new StreamContent(content);

foreach (var header in cached.ContentHeaders)
{
response.Content.Headers.Add(header.Key, header.Value);
}

return response;
}

Expand All @@ -109,7 +117,10 @@ internal async Task<CachedResponse> CreateCachedResponse(HttpResponseMessage res
body = Convert.ToBase64String(content);
}

var cached = new CachedResponse(statusCode, headers, body);
var contentHeaders = response?.Content?.Headers.ToDictionary(v => v.Key, v => v.Value);


var cached = new CachedResponse(statusCode, headers, body, contentHeaders);
return cached;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@ namespace Ocelot.Configuration.Creator
public class HeaderFindAndReplaceCreator : IHeaderFindAndReplaceCreator
{
private IBaseUrlFinder _finder;
private Dictionary<string, Func<string>> _placeholders;
private readonly Dictionary<string, Func<string>> _placeholders;

public HeaderFindAndReplaceCreator(IBaseUrlFinder finder)
{
_finder = finder;
_placeholders = new Dictionary<string, Func<string>>();
_placeholders.Add("{BaseUrl}", () => {
return _finder.Find();
});
_placeholders.Add("{BaseUrl}", () => _finder.Find());
}

public HeaderTransformations Create(FileReRoute fileReRoute)
Expand Down
2 changes: 1 addition & 1 deletion src/Ocelot/Configuration/OcelotConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ public OcelotConfiguration(List<ReRoute> reRoutes, string administrationPath, Se
public ServiceProviderConfiguration ServiceProviderConfiguration {get;}
public string RequestId {get;}
}
}
}
20 changes: 20 additions & 0 deletions src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Memory;

namespace Ocelot.DependencyInjection
{
public static class ConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddOcelotBaseUrl(this IConfigurationBuilder builder, string baseUrl)
{
var memorySource = new MemoryConfigurationSource();
memorySource.InitialData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("BaseUrl", baseUrl)
};
builder.Add(memorySource);
return builder;
}
}
}
4 changes: 3 additions & 1 deletion src/Ocelot/DependencyInjection/IOcelotBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
using CacheManager.Core;
using System;
using System.Net.Http;
using IdentityServer4.AccessTokenValidation;

namespace Ocelot.DependencyInjection
{
public interface IOcelotBuilder
{
IOcelotBuilder AddStoreOcelotConfigurationInConsul();
IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings);
IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings);
IOcelotAdministrationBuilder AddAdministration(string path, string secret);
IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions);
IOcelotBuilder AddDelegatingHandler(Func<DelegatingHandler> delegatingHandler);
}
}
Loading

0 comments on commit 6919d2b

Please sign in to comment.