mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:22:50 +08:00
Release/13.6.0 (#895)
* Fixed Format Issue for Kubernetes ServiceDiscoveryProvider * Fixes broken links (#858) * Fix link to issue 262 * Fixes broken link to issue 340 * Fixed broken link to issue 340 (#857) * Update information for Okta Authorization (#853) * +dynamic claim variables (#855) incl. tests * IOcelotPipelineBuilder.Use(): Return IOcelotPipelineBuilder (#875) Fixes ThreeMammals/Ocelot#685 * Fix UpstreamHost checking when reroutes duplicate validation (#864) * Format json in reame (#877) Format json file in AdministrationApi ReadMe * kubernetes use in cluster (#882) * refactor :kubernetes use in cluster * feat:delete KubeClient * add more flexible method to config ocelot pipeline (#880) * update k8s doc & samples (#885) * refactor :kubernetes use in cluster * feat:delete KubeClient * feat : update k8s doc & samples * Update kubernetes.rst * Fix/issue666 (#889) * cache key now can generate from query string for request with Get Methods and request content for requests with post methods * MD5Helper Added. OutputCacheMiddleware now can generate cache key using method, url and content * unit test created for CacheKeyGenerator * CacheKeyGenerator Registered in OcelotBuilder as singletone * Fix issue #890 IDefinedAggregator can't handle error codes from downstream requests (#892) * Release/13.2.0 (#834) * Fix formatting in getting started page (#752) * updated release docs (#745) * Update README.md (#756) Fixed typo "Ocleot" * Fixed typo there => their (#763) * Some Typo fixes (#765) * Typo algorythm => algorithm (#764) * Typo querystring => query string (#766) * Typo usual => usually (#767) * Typos (#768) * kubernetes provider (#772) * feat: Kubernetes ServiceDiscoveryProvider * 编写k8s测试例子 * feat:fix kube config * feat: remove port * feat : complete the k8s test * feat : add kubeserviceDiscovery test * feat : add kube provider unittest * feat :add kubetnetes docs how to use ocelot with kubetnetes docs * keep the configuration as simple as possible, no qos, no cache * fix: use http * add PollingKubeServiceDiscovery * feat : refactor logger * feat : add pollkube docs * feat:Remove unnecessary code * feat : code-block json * fix issue #661 for Advanced aggregations (#704) * Add Advanced Aggregation Feature * fix overwrite error * distinct data for better performance * remove constructor parameter * fix tests issue * fix tests * fix tests issue * Add UnitTest and AcceptanceTest * fix responseKeys typo * Update SimpleJsonResponseAggregator.cs * change port * Fix code example for SSL Errors (#780) DangerousAcceptAnyServerCertificateValidator has to be set to "true" to disable certification validation, not "false". * Changed wording for ease of reading (#776) Just some wording changes for clarification. * Ignore response content if null (fix #785) (#786) * fix bug #791 (#795) * Update loadbalancer.rst (#796) * UriBuilder - remove leading question mark #747 (#794) * Update qualityofservice.rst (#801) Tiny typo * K8s package (#804) * feat: Kubernetes ServiceDiscoveryProvider * 编写k8s测试例子 * feat:fix kube config * feat: remove port * feat : complete the k8s test * feat : add kubeserviceDiscovery test * feat : add kube provider unittest * feat :add kubetnetes docs how to use ocelot with kubetnetes docs * keep the configuration as simple as possible, no qos, no cache * fix: use http * add PollingKubeServiceDiscovery * feat : refactor logger * feat : add pollkube docs * feat:Remove unnecessary code * feat : code-block json * feat: publish package Ocelot.Provider.Kubernetes * Okta integration (#807) Okta integration * update cliamsParser (#798) * update cliamsParser * update using * IOcelotBuilder opens the IMvcCoreBuilder property for easy customization (#790) * IOcelotBuilder opens the IMvcCoreBuilder property for easy customization * Adjustment code * nuget package (#809) * feat: Kubernetes ServiceDiscoveryProvider * 编写k8s测试例子 * feat:fix kube config * feat: remove port * feat : complete the k8s test * feat : add kubeserviceDiscovery test * feat : add kube provider unittest * feat :add kubetnetes docs how to use ocelot with kubetnetes docs * keep the configuration as simple as possible, no qos, no cache * fix: use http * add PollingKubeServiceDiscovery * feat : refactor logger * feat : add pollkube docs * feat:Remove unnecessary code * feat : code-block json * feat: publish package Ocelot.Provider.Kubernetes * feat : nuget package * fix: Namesapce Spelling wrong * fix:Namesapce Spelling Wrong * Fix: errors when using rate limiting (#811) * Fix: errors when using rate limiting Add: QuotaExceededError class for requesting too much Add: QuotaExceededError error code Add: Add an error when limit is reached Reflact: Extract GetResponseMessage method for getting default or configured response message for requ * Fix: modify check_we_have_considered_all_errors_in_these_tests for adding a new OcelotErrorCode * added missing COPY csproj files (#821) * Add note on In-Process hosting (#816) When using ASP.NET Core 2.2 with In-Process hosting in IIS it's important to use .UseIIS() instead of .UseIISIntegration(). * Fix bug: (#810) If the registered Consul node is unexpectedly down and not restarted immediately, other services should continue to find the registered service. * Fixed Dockerfile (missing Kubernetes) * Revert "Fix bug: (#810)" (#823) This reverts commit 19c80afb05290fac3a144f652cd663c8b513a559. * remove duplicate `IHttpRequester` register (#819) * remove duplicate `IHttpRequester` register * reserve the first * fix HttpRequesterMiddleware does not call next bug (#830) call next so that we can do something with the response, such as add some custom header etc... * Removed Packing to fix issues, will be sorted out after create a nuget package on Nuget.Org (#831) * Allows access to unpass node (#825) * Fix bug: If the registered Consul node is unexpectedly down and not restarted immediately, other services should continue to find the registered service. * fix bug: If the registered Consul node is unexpectedly down and not restarted immediately, other services should continue to find the registered service. * Updated FluentValidations Nuget Package (#833) * Removed Warnings * Make the full DownstreamContext available to user defined aggregators This allows error codes to be handled
This commit is contained in:
parent
5db449b000
commit
57580afa74
@ -40,6 +40,7 @@ A quick list of Ocelot's capabilities for more information see the [documentatio
|
|||||||
* Request Aggregation
|
* Request Aggregation
|
||||||
* Service Discovery with Consul & Eureka
|
* Service Discovery with Consul & Eureka
|
||||||
* Service Fabric
|
* Service Fabric
|
||||||
|
* Kubernetes
|
||||||
* WebSockets
|
* WebSockets
|
||||||
* Authentication
|
* Authentication
|
||||||
* Authorisation
|
* Authorisation
|
||||||
|
@ -138,26 +138,39 @@ Then map the authentication provider key to a ReRoute in your configuration e.g.
|
|||||||
|
|
||||||
Okta
|
Okta
|
||||||
^^^^
|
^^^^
|
||||||
Add nuget package : `"Okta.AspNetCore" https://www.nuget.org/packages/Okta.AspNetCore/`_
|
Add the following to your startup Configure method:
|
||||||
|
|
||||||
In a StartUp.cs file add to a method Configure next lines:
|
.. code-block:: csharp
|
||||||
app.UseAuthentication();
|
|
||||||
app.UseOcelot().Wait();
|
|
||||||
|
|
||||||
In a StartUp.cs file add to a method ConfigureServices lines:
|
app
|
||||||
|
.UseAuthentication()
|
||||||
|
.UseOcelot()
|
||||||
|
.Wait();
|
||||||
|
|
||||||
services.AddAuthentication(options =>
|
|
||||||
|
Add the following, at minimum, to your startup ConfigureServices method:
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddAuthentication()
|
||||||
|
.AddJwtBearer(oktaProviderKey, options =>
|
||||||
{
|
{
|
||||||
options.DefaultAuthenticateScheme = OktaDefaults.ApiAuthenticationScheme;
|
options.Audience = configuration["Authentication:Okta:Audience"]; // Okta Authorization server Audience
|
||||||
options.DefaultChallengeScheme = OktaDefaults.ApiAuthenticationScheme;
|
options.Authority = configuration["Authentication:Okta:Server"]; // Okta Authorization Issuer URI URL e.g. https://{subdomain}.okta.com/oauth2/{authidentifier}
|
||||||
options.DefaultSignInScheme = OktaDefaults.ApiAuthenticationScheme;
|
|
||||||
})
|
|
||||||
.AddOktaWebApi(new OktaWebApiOptions
|
|
||||||
{
|
|
||||||
OktaDomain = _cfg["Okta:OktaDomain"]
|
|
||||||
|
|
||||||
});
|
});
|
||||||
services.AddOcelot(_cfg);
|
services.AddOcelot(configuration);
|
||||||
|
|
||||||
|
|
||||||
|
NOTE: In order to get Ocelot to view the scope claim from Okta properly, you have to add the following to map the default Okta "scp" claim to "scope"
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
// Map Okta scp to scope claims instead of http://schemas.microsoft.com/identity/claims/scope to allow ocelot to read/verify them
|
||||||
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("scp");
|
||||||
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("scp", "scope");
|
||||||
|
|
||||||
|
|
||||||
`Issue 446 <https://github.com/ThreeMammals/Ocelot/issues/446>`_ that contains some code and examples that might help with Okta integration.
|
`Issue 446 <https://github.com/ThreeMammals/Ocelot/issues/446>`_ that contains some code and examples that might help with Okta integration.
|
||||||
|
|
||||||
|
@ -14,11 +14,22 @@ Then add the following to your ConfigureServices method.
|
|||||||
s.AddOcelot()
|
s.AddOcelot()
|
||||||
.AddKubernetes();
|
.AddKubernetes();
|
||||||
|
|
||||||
If you have services deployed in kubernetes you will normally use the naming service to access them.
|
If you have services deployed in kubernetes you will normally use the naming service to access them. Default usePodServiceAccount = True, which means that ServiceAccount using Pod to access the service of the k8s cluster needs to be ServiceAccount based on RABC authorization
|
||||||
|
|
||||||
|
.. code-block::csharp
|
||||||
|
public static class OcelotBuilderExtensions
|
||||||
|
{
|
||||||
|
public static IOcelotBuilder AddKubernetes(this IOcelotBuilder builder, bool usePodServiceAccount = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
You can replicate a Permissive. Using RBAC role bindings.
|
||||||
|
`Permissive RBAC Permissions <https://kubernetes.io/docs/reference/access-authn-authz/rbac/#permissive-rbac-permissions>`_, k8s api server and token will read from pod .
|
||||||
|
|
||||||
|
.. code-block::json
|
||||||
|
kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --user=admin --user=kubelet --group=system:serviceaccounts
|
||||||
|
|
||||||
The following example shows how to set up a ReRoute that will work in kubernetes. The most important thing is the ServiceName which is made up of the
|
The following example shows how to set up a ReRoute that will work in kubernetes. The most important thing is the ServiceName which is made up of the
|
||||||
kubernetes service name. We also need to set up the ServiceDiscoveryProvider in
|
kubernetes service name. We also need to set up the ServiceDiscoveryProvider in GlobalConfiguration. The example here shows a typical configuration.
|
||||||
GlobalConfiguration. The example here shows a typical configuration. It assumes kubernetes api server is running on 192.168.0.13 and that api service is on port 443.
|
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
@ -43,6 +54,8 @@ GlobalConfiguration. The example here shows a typical configuration. It assumes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Service deployment in Namespace Dev , ServiceDiscoveryProvider type is kube, you also can set pollkube ServiceDiscoveryProvider type.
|
||||||
|
Note: Host、 Port and Token are no longer in use。
|
||||||
|
|
||||||
You use Ocelot to poll kubernetes for latest service information rather than per request. If you want to poll kubernetes for the latest services rather than per request (default behaviour) then you need to set the following configuration.
|
You use Ocelot to poll kubernetes for latest service information rather than per request. If you want to poll kubernetes for the latest services rather than per request (default behaviour) then you need to set the following configuration.
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ matched /goods/{catchAll} (because this is the first ReRoute in the list!).
|
|||||||
Dynamic Routing
|
Dynamic Routing
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This feature was requested in `issue 340 <https://github.com/ThreeMammals/Ocelot/issue/340>`_.
|
This feature was requested in `issue 340 <https://github.com/ThreeMammals/Ocelot/issues/340>`_.
|
||||||
|
|
||||||
The idea is to enable dynamic routing when using a service discovery provider so you don't have to provide the ReRoute config. See the docs :ref:`service-discovery` if
|
The idea is to enable dynamic routing when using a service discovery provider so you don't have to provide the ReRoute config. See the docs :ref:`service-discovery` if
|
||||||
this sounds interesting to you.
|
this sounds interesting to you.
|
||||||
|
@ -113,7 +113,7 @@ Ocelot will add this token to the Consul client that it uses to make requests an
|
|||||||
Eureka
|
Eureka
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
This feature was requested as part of `Issue 262 <https://github.com/ThreeMammals/Ocelot/issue/262>`_ . to add support for Netflix's
|
This feature was requested as part of `Issue 262 <https://github.com/ThreeMammals/Ocelot/issues/262>`_ . to add support for Netflix's
|
||||||
Eureka service discovery provider. The main reason for this is it is a key part of `Steeltoe <https://steeltoe.io/>`_ which is something
|
Eureka service discovery provider. The main reason for this is it is a key part of `Steeltoe <https://steeltoe.io/>`_ which is something
|
||||||
to do with `Pivotal <https://pivotal.io/platform>`_! Anyway enough of the background.
|
to do with `Pivotal <https://pivotal.io/platform>`_! Anyway enough of the background.
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ is provided by the Pivotal.Discovery.Client NuGet package so big thanks to them
|
|||||||
Dynamic Routing
|
Dynamic Routing
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This feature was requested in `issue 340 <https://github.com/ThreeMammals/Ocelot/issue/340>`_. The idea is to enable dynamic routing when using a service discovery provider (see that section of the docs for more info). In this mode Ocelot will use the first segment of the upstream path to lookup the downstream service with the service discovery provider.
|
This feature was requested in `issue 340 <https://github.com/ThreeMammals/Ocelot/issues/340>`_. The idea is to enable dynamic routing when using a service discovery provider (see that section of the docs for more info). In this mode Ocelot will use the first segment of the upstream path to lookup the downstream service with the service discovery provider.
|
||||||
|
|
||||||
An example of this would be calling Ocelot with a url like https://api.mywebsite.com/product/products. Ocelot will take the first segment of
|
An example of this would be calling Ocelot with a url like https://api.mywebsite.com/product/products. Ocelot will take the first segment of
|
||||||
the path which is product and use it as a key to look up the service in Consul. If Consul returns a service Ocelot will request it on whatever host and port comes back from Consul plus the remaining path segments in this case products thus making the downstream call http://hostfromconsul:portfromconsul/products. Ocelot will apprend any query string to the downstream url as normal.
|
the path which is product and use it as a key to look up the service in Consul. If Consul returns a service Ocelot will request it on whatever host and port comes back from Consul plus the remaining path segments in this case products thus making the downstream call http://hostfromconsul:portfromconsul/products. Ocelot will apprend any query string to the downstream url as normal.
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
```json
|
||||||
{
|
{
|
||||||
"reRoutes": [
|
"reRoutes": [
|
||||||
{
|
{
|
||||||
@ -90,3 +91,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
@ -10,11 +10,8 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.1" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.1" PrivateAssets="All" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.1.1" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.1.1" />
|
||||||
</ItemGroup>
|
<PackageReference Include="Ocelot" Version="13.6.0-alpha0010"/>
|
||||||
|
<PackageReference Include="Ocelot.Provider.Kubernetes" Version="13.6.0-alpha0010"/>
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\..\src\Ocelot.Provider.Kubernetes\Ocelot.Provider.Kubernetes.csproj" />
|
|
||||||
<ProjectReference Include="..\..\..\src\Ocelot\Ocelot.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
FROM mcr.microsoft.com/dotnet/core/aspnet:2.1-stretch-slim AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/dotnet:2.1-sdk AS build
|
FROM mcr.microsoft.com/dotnet/core/sdk:2.1-stretch AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY ["ApiGateway/ApiGateway.csproj", "ApiGateway/"]
|
COPY ["ApiGateway/ApiGateway.csproj", "ApiGateway/"]
|
||||||
COPY ["../../src/Ocelot/Ocelot.csproj", "../../src/Ocelot/"]
|
|
||||||
COPY ["../../src/Ocelot.Provider.Kubernetes/Ocelot.Provider.Kubernetes.csproj", "../../src/Ocelot.Provider.Kubernetes/"]
|
|
||||||
RUN dotnet restore "ApiGateway/ApiGateway.csproj"
|
RUN dotnet restore "ApiGateway/ApiGateway.csproj"
|
||||||
COPY . .
|
COPY . .
|
||||||
WORKDIR "/src/ApiGateway"
|
WORKDIR "/src/ApiGateway"
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 15.0.28010.2048
|
VisualStudioVersion = 16.0.28803.202
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiGateway", "ApiGateway\ApiGateway.csproj", "{E9AFBFD7-EF20-48E5-BB30-5C63C59D7C1C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiGateway", "ApiGateway\ApiGateway.csproj", "{E9AFBFD7-EF20-48E5-BB30-5C63C59D7C1C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot", "..\..\src\Ocelot\Ocelot.csproj", "{E8551073-622E-45FA-AD09-038EB8AAFFBC}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Provider.Kubernetes", "..\..\src\Ocelot.Provider.Kubernetes\Ocelot.Provider.Kubernetes.csproj", "{EF973868-98A6-4864-BF66-65B5A8C123FE}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DownstreamService", "DownstreamService\DownstreamService.csproj", "{86FFAE3C-648F-4CDE-A260-37C8EBFBF4F2}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DownstreamService", "DownstreamService\DownstreamService.csproj", "{86FFAE3C-648F-4CDE-A260-37C8EBFBF4F2}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
@ -21,14 +17,6 @@ Global
|
|||||||
{E9AFBFD7-EF20-48E5-BB30-5C63C59D7C1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E9AFBFD7-EF20-48E5-BB30-5C63C59D7C1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{E9AFBFD7-EF20-48E5-BB30-5C63C59D7C1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E9AFBFD7-EF20-48E5-BB30-5C63C59D7C1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E9AFBFD7-EF20-48E5-BB30-5C63C59D7C1C}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E9AFBFD7-EF20-48E5-BB30-5C63C59D7C1C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{E8551073-622E-45FA-AD09-038EB8AAFFBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{E8551073-622E-45FA-AD09-038EB8AAFFBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{E8551073-622E-45FA-AD09-038EB8AAFFBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{E8551073-622E-45FA-AD09-038EB8AAFFBC}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{EF973868-98A6-4864-BF66-65B5A8C123FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{EF973868-98A6-4864-BF66-65B5A8C123FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{EF973868-98A6-4864-BF66-65B5A8C123FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{EF973868-98A6-4864-BF66-65B5A8C123FE}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{86FFAE3C-648F-4CDE-A260-37C8EBFBF4F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{86FFAE3C-648F-4CDE-A260-37C8EBFBF4F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{86FFAE3C-648F-4CDE-A260-37C8EBFBF4F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{86FFAE3C-648F-4CDE-A260-37C8EBFBF4F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{86FFAE3C-648F-4CDE-A260-37C8EBFBF4F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{86FFAE3C-648F-4CDE-A260-37C8EBFBF4F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
@ -33,6 +33,10 @@
|
|||||||
builder.Services.RemoveAll(typeof(IOcelotCache<FileConfiguration>));
|
builder.Services.RemoveAll(typeof(IOcelotCache<FileConfiguration>));
|
||||||
builder.Services.AddSingleton<ICacheManager<FileConfiguration>>(fileConfigCacheManagerOutputCache);
|
builder.Services.AddSingleton<ICacheManager<FileConfiguration>>(fileConfigCacheManagerOutputCache);
|
||||||
builder.Services.AddSingleton<IOcelotCache<FileConfiguration>>(fileConfigCacheManager);
|
builder.Services.AddSingleton<IOcelotCache<FileConfiguration>>(fileConfigCacheManager);
|
||||||
|
|
||||||
|
builder.Services.RemoveAll(typeof(ICacheKeyGenerator));
|
||||||
|
builder.Services.AddSingleton<ICacheKeyGenerator, CacheKeyGenerator>();
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,14 @@ namespace Ocelot.Provider.Kubernetes
|
|||||||
private IOcelotLogger logger;
|
private IOcelotLogger logger;
|
||||||
private IKubeApiClient kubeApi;
|
private IKubeApiClient kubeApi;
|
||||||
|
|
||||||
public Kube(KubeRegistryConfiguration kubeRegistryConfiguration, IOcelotLoggerFactory factory, IKubeApiClientFactory kubeClientFactory)
|
public Kube(KubeRegistryConfiguration kubeRegistryConfiguration, IOcelotLoggerFactory factory, IKubeApiClient kubeApi)
|
||||||
{
|
{
|
||||||
this.kubeRegistryConfiguration = kubeRegistryConfiguration;
|
this.kubeRegistryConfiguration = kubeRegistryConfiguration;
|
||||||
this.logger = factory.CreateLogger<Kube>();
|
this.logger = factory.CreateLogger<Kube>();
|
||||||
this.kubeApi = kubeClientFactory.Get(kubeRegistryConfiguration);
|
this.kubeApi = kubeApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<List<Service>> Get()
|
public async Task<List<Service>> Get()
|
||||||
{
|
{
|
||||||
var service = await kubeApi.ServicesV1()
|
var service = await kubeApi.ServicesV1()
|
||||||
|
@ -5,16 +5,8 @@ namespace Ocelot.Provider.Kubernetes
|
|||||||
{
|
{
|
||||||
public class KubeRegistryConfiguration
|
public class KubeRegistryConfiguration
|
||||||
{
|
{
|
||||||
public Uri ApiEndPoint { get; set; }
|
|
||||||
|
|
||||||
public string KubeNamespace { get; set; }
|
public string KubeNamespace { get; set; }
|
||||||
|
|
||||||
public string KeyOfServiceInK8s { get; set; }
|
public string KeyOfServiceInK8s { get; set; }
|
||||||
|
|
||||||
public KubeAuthStrategy AuthStrategy { get; set; }
|
|
||||||
|
|
||||||
public string AccessToken { get; set; }
|
|
||||||
|
|
||||||
public bool AllowInsecure { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,18 +16,14 @@ namespace Ocelot.Provider.Kubernetes
|
|||||||
|
|
||||||
private static ServiceDiscovery.Providers.IServiceDiscoveryProvider GetkubeProvider(IServiceProvider provider, Configuration.ServiceProviderConfiguration config, string name, IOcelotLoggerFactory factory)
|
private static ServiceDiscovery.Providers.IServiceDiscoveryProvider GetkubeProvider(IServiceProvider provider, Configuration.ServiceProviderConfiguration config, string name, IOcelotLoggerFactory factory)
|
||||||
{
|
{
|
||||||
var kubeClientFactory = provider.GetService<IKubeApiClientFactory>();
|
var kubeClient = provider.GetService<IKubeApiClient>();
|
||||||
var k8sRegistryConfiguration = new KubeRegistryConfiguration()
|
var k8sRegistryConfiguration = new KubeRegistryConfiguration()
|
||||||
{
|
{
|
||||||
ApiEndPoint = new Uri($"https://{config.Host}:{config.Port}"),
|
|
||||||
KeyOfServiceInK8s = name,
|
KeyOfServiceInK8s = name,
|
||||||
KubeNamespace = config.Namespace,
|
KubeNamespace = config.Namespace,
|
||||||
AuthStrategy = KubeAuthStrategy.BearerToken,
|
|
||||||
AccessToken = config.Token,
|
|
||||||
AllowInsecure = true // Don't validate server certificate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var k8sServiceDiscoveryProvider = new Kube(k8sRegistryConfiguration, factory, kubeClientFactory);
|
var k8sServiceDiscoveryProvider = new Kube(k8sRegistryConfiguration, factory, kubeClient);
|
||||||
if (config.Type?.ToLower() == "pollkube")
|
if (config.Type?.ToLower() == "pollkube")
|
||||||
{
|
{
|
||||||
return new PollKube(config.PollingInterval, factory, k8sServiceDiscoveryProvider);
|
return new PollKube(config.PollingInterval, factory, k8sServiceDiscoveryProvider);
|
||||||
|
@ -25,7 +25,13 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="KubeClient" Version="2.2.4" />
|
<Compile Remove="IKubeApiClientFactory.cs" />
|
||||||
|
<Compile Remove="KubeApiClientFactory.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="KubeClient" Version="2.2.11" />
|
||||||
|
<PackageReference Include="KubeClient.Extensions.DependencyInjection" Version="2.2.11" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using KubeClient;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Ocelot.DependencyInjection;
|
using Ocelot.DependencyInjection;
|
||||||
|
|
||||||
namespace Ocelot.Provider.Kubernetes
|
namespace Ocelot.Provider.Kubernetes
|
||||||
{
|
{
|
||||||
public static class OcelotBuilderExtensions
|
public static class OcelotBuilderExtensions
|
||||||
{
|
{
|
||||||
public static IOcelotBuilder AddKubernetes(this IOcelotBuilder builder)
|
public static IOcelotBuilder AddKubernetes(this IOcelotBuilder builder, bool usePodServiceAccount = true)
|
||||||
{
|
{
|
||||||
builder.Services.AddSingleton(KubernetesProviderFactory.Get);
|
builder.Services.AddSingleton(KubernetesProviderFactory.Get);
|
||||||
builder.Services.AddSingleton<IKubeApiClientFactory, KubeApiClientFactory>();
|
builder.Services.AddKubeClient(usePodServiceAccount);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
|
using Ocelot.Middleware;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
using Ocelot.Values;
|
||||||
|
|
||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorisation
|
||||||
{
|
{
|
||||||
@ -15,8 +22,11 @@ namespace Ocelot.Authorisation
|
|||||||
_claimsParser = claimsParser;
|
_claimsParser = claimsParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, Dictionary<string, string> routeClaimsRequirement)
|
public Response<bool> Authorise(
|
||||||
{
|
ClaimsPrincipal claimsPrincipal,
|
||||||
|
Dictionary<string, string> routeClaimsRequirement,
|
||||||
|
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
|
||||||
|
){
|
||||||
foreach (var required in routeClaimsRequirement)
|
foreach (var required in routeClaimsRequirement)
|
||||||
{
|
{
|
||||||
var values = _claimsParser.GetValuesByClaimType(claimsPrincipal.Claims, required.Key);
|
var values = _claimsParser.GetValuesByClaimType(claimsPrincipal.Claims, required.Key);
|
||||||
@ -28,6 +38,43 @@ namespace Ocelot.Authorisation
|
|||||||
|
|
||||||
if (values.Data != null)
|
if (values.Data != null)
|
||||||
{
|
{
|
||||||
|
// dynamic claim
|
||||||
|
var match = Regex.Match(required.Value, @"^{(?<variable>.+)}$");
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
var variableName = match.Captures[0].Value;
|
||||||
|
|
||||||
|
var matchingPlaceholders = urlPathPlaceholderNameAndValues.Where(p => p.Name.Equals(variableName)).Take(2).ToArray();
|
||||||
|
if (matchingPlaceholders.Length == 1)
|
||||||
|
{
|
||||||
|
// match
|
||||||
|
var actualValue = matchingPlaceholders[0].Value;
|
||||||
|
var authorised = values.Data.Contains(actualValue);
|
||||||
|
if (!authorised)
|
||||||
|
{
|
||||||
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
||||||
|
$"dynamic claim value for {variableName} of {string.Join(", ", values.Data)} is not the same as required value: {actualValue}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// config error
|
||||||
|
if (matchingPlaceholders.Length == 0)
|
||||||
|
{
|
||||||
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
||||||
|
$"config error: requires variable claim value: {variableName} placeholders does not contain that variable: {string.Join(", ", urlPathPlaceholderNameAndValues.Select(p=>p.Name))}"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
||||||
|
$"config error: requires variable claim value: {required.Value} but placeholders are ambiguous: {string.Join(", ", urlPathPlaceholderNameAndValues.Where(p=>p.Name.Equals(variableName)).Select(p => p.Value))}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// static claim
|
||||||
var authorised = values.Data.Contains(required.Value);
|
var authorised = values.Data.Contains(required.Value);
|
||||||
if (!authorised)
|
if (!authorised)
|
||||||
{
|
{
|
||||||
@ -35,6 +82,7 @@ namespace Ocelot.Authorisation
|
|||||||
$"claim value: {string.Join(", ", values.Data)} is not the same as required value: {required.Value} for type: {required.Key}"));
|
$"claim value: {string.Join(", ", values.Data)} is not the same as required value: {required.Value} for type: {required.Key}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new ErrorResponse<bool>(new UserDoesNotHaveClaimError($"user does not have claim {required.Key}"));
|
return new ErrorResponse<bool>(new UserDoesNotHaveClaimError($"user does not have claim {required.Key}"));
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
using Ocelot.Values;
|
||||||
|
|
||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorisation
|
||||||
{
|
{
|
||||||
@ -7,6 +11,10 @@ namespace Ocelot.Authorisation
|
|||||||
|
|
||||||
public interface IClaimsAuthoriser
|
public interface IClaimsAuthoriser
|
||||||
{
|
{
|
||||||
Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, Dictionary<string, string> routeClaimsRequirement);
|
Response<bool> Authorise(
|
||||||
|
ClaimsPrincipal claimsPrincipal,
|
||||||
|
Dictionary<string, string> routeClaimsRequirement,
|
||||||
|
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
{
|
{
|
||||||
Logger.LogInformation("route is authorised");
|
Logger.LogInformation("route is authorised");
|
||||||
|
|
||||||
var authorised = _claimsAuthoriser.Authorise(context.HttpContext.User, context.DownstreamReRoute.RouteClaimsRequirement);
|
var authorised = _claimsAuthoriser.Authorise(context.HttpContext.User, context.DownstreamReRoute.RouteClaimsRequirement, context.TemplatePlaceholderNameAndValues);
|
||||||
|
|
||||||
if (authorised.IsError)
|
if (authorised.IsError)
|
||||||
{
|
{
|
||||||
|
19
src/Ocelot/Cache/CacheKeyGenerator.cs
Normal file
19
src/Ocelot/Cache/CacheKeyGenerator.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
|
||||||
|
namespace Ocelot.Cache {
|
||||||
|
public class CacheKeyGenerator : ICacheKeyGenerator {
|
||||||
|
public string GenerateRequestCacheKey(DownstreamContext context) {
|
||||||
|
string hashedContent = null;
|
||||||
|
StringBuilder downStreamUrlKeyBuilder = new StringBuilder($"{context.DownstreamRequest.Method}-{context.DownstreamRequest.OriginalString}");
|
||||||
|
if (context.DownstreamRequest.Content != null) {
|
||||||
|
string requestContentString = Task.Run(async () => await context.DownstreamRequest.Content.ReadAsStringAsync()).Result;
|
||||||
|
downStreamUrlKeyBuilder.Append(requestContentString);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashedContent = MD5Helper.GenerateMd5(downStreamUrlKeyBuilder.ToString());
|
||||||
|
return hashedContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
src/Ocelot/Cache/ICacheKeyGenerator.cs
Normal file
7
src/Ocelot/Cache/ICacheKeyGenerator.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
using Ocelot.Middleware;
|
||||||
|
|
||||||
|
namespace Ocelot.Cache {
|
||||||
|
public interface ICacheKeyGenerator {
|
||||||
|
string GenerateRequestCacheKey(DownstreamContext context);
|
||||||
|
}
|
||||||
|
}
|
22
src/Ocelot/Cache/MD5Helper.cs
Normal file
22
src/Ocelot/Cache/MD5Helper.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ocelot.Cache {
|
||||||
|
public static class MD5Helper {
|
||||||
|
public static string GenerateMd5(byte[] contentBytes) {
|
||||||
|
MD5 md5 = MD5.Create();
|
||||||
|
byte[] hash = md5.ComputeHash(contentBytes);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < hash.Length; i++) {
|
||||||
|
sb.Append(hash[i].ToString("X2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GenerateMd5(string contentString) {
|
||||||
|
byte[] contentBytes = Encoding.Unicode.GetBytes(contentString);
|
||||||
|
return GenerateMd5(contentBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,19 +7,23 @@
|
|||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
public class OutputCacheMiddleware : OcelotMiddleware
|
public class OutputCacheMiddleware : OcelotMiddleware
|
||||||
{
|
{
|
||||||
private readonly OcelotRequestDelegate _next;
|
private readonly OcelotRequestDelegate _next;
|
||||||
private readonly IOcelotCache<CachedResponse> _outputCache;
|
private readonly IOcelotCache<CachedResponse> _outputCache;
|
||||||
|
private readonly ICacheKeyGenerator _cacheGeneratot;
|
||||||
|
|
||||||
public OutputCacheMiddleware(OcelotRequestDelegate next,
|
public OutputCacheMiddleware(OcelotRequestDelegate next,
|
||||||
IOcelotLoggerFactory loggerFactory,
|
IOcelotLoggerFactory loggerFactory,
|
||||||
IOcelotCache<CachedResponse> outputCache)
|
IOcelotCache<CachedResponse> outputCache,
|
||||||
|
ICacheKeyGenerator cacheGeneratot)
|
||||||
:base(loggerFactory.CreateLogger<OutputCacheMiddleware>())
|
:base(loggerFactory.CreateLogger<OutputCacheMiddleware>())
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
_outputCache = outputCache;
|
_outputCache = outputCache;
|
||||||
|
_cacheGeneratot = cacheGeneratot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(DownstreamContext context)
|
public async Task Invoke(DownstreamContext context)
|
||||||
@ -31,10 +35,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var downstreamUrlKey = $"{context.DownstreamRequest.Method}-{context.DownstreamRequest.OriginalString}";
|
var downstreamUrlKey = $"{context.DownstreamRequest.Method}-{context.DownstreamRequest.OriginalString}";
|
||||||
|
string downStreamRequestCacheKey = _cacheGeneratot.GenerateRequestCacheKey(context);
|
||||||
|
|
||||||
Logger.LogDebug($"Started checking cache for {downstreamUrlKey}");
|
Logger.LogDebug($"Started checking cache for {downstreamUrlKey}");
|
||||||
|
|
||||||
var cached = _outputCache.Get(downstreamUrlKey, context.DownstreamReRoute.CacheOptions.Region);
|
var cached = _outputCache.Get(downStreamRequestCacheKey, context.DownstreamReRoute.CacheOptions.Region);
|
||||||
|
|
||||||
if (cached != null)
|
if (cached != null)
|
||||||
{
|
{
|
||||||
@ -61,12 +66,13 @@
|
|||||||
|
|
||||||
cached = await CreateCachedResponse(context.DownstreamResponse);
|
cached = await CreateCachedResponse(context.DownstreamResponse);
|
||||||
|
|
||||||
_outputCache.Add(downstreamUrlKey, cached, TimeSpan.FromSeconds(context.DownstreamReRoute.CacheOptions.TtlSeconds), context.DownstreamReRoute.CacheOptions.Region);
|
_outputCache.Add(downStreamRequestCacheKey, cached, TimeSpan.FromSeconds(context.DownstreamReRoute.CacheOptions.TtlSeconds), context.DownstreamReRoute.CacheOptions.Region);
|
||||||
|
|
||||||
Logger.LogDebug($"finished response added to cache for {downstreamUrlKey}");
|
Logger.LogDebug($"finished response added to cache for {downstreamUrlKey}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetHttpResponseMessageThisRequest(DownstreamContext context, DownstreamResponse response)
|
private void SetHttpResponseMessageThisRequest(DownstreamContext context,
|
||||||
|
DownstreamResponse response)
|
||||||
{
|
{
|
||||||
context.DownstreamResponse = response;
|
context.DownstreamResponse = response;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@
|
|||||||
{
|
{
|
||||||
var matchingReRoutes = reRoutes
|
var matchingReRoutes = reRoutes
|
||||||
.Where(r => r.UpstreamPathTemplate == reRoute.UpstreamPathTemplate
|
.Where(r => r.UpstreamPathTemplate == reRoute.UpstreamPathTemplate
|
||||||
&& (r.UpstreamHost != reRoute.UpstreamHost || reRoute.UpstreamHost == null))
|
&& (r.UpstreamHost == reRoute.UpstreamHost || reRoute.UpstreamHost == null))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (matchingReRoutes.Count == 1)
|
if (matchingReRoutes.Count == 1)
|
||||||
|
@ -107,6 +107,7 @@ namespace Ocelot.DependencyInjection
|
|||||||
Services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
|
Services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
|
||||||
Services.TryAddSingleton<IDownstreamAddressesCreator, DownstreamAddressesCreator>();
|
Services.TryAddSingleton<IDownstreamAddressesCreator, DownstreamAddressesCreator>();
|
||||||
Services.TryAddSingleton<IDelegatingHandlerHandlerFactory, DelegatingHandlerHandlerFactory>();
|
Services.TryAddSingleton<IDelegatingHandlerHandlerFactory, DelegatingHandlerHandlerFactory>();
|
||||||
|
Services.TryAddSingleton<ICacheKeyGenerator, CacheKeyGenerator>();
|
||||||
|
|
||||||
// see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
|
// see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
|
||||||
// could maybe use a scoped data repository
|
// could maybe use a scoped data repository
|
||||||
|
@ -5,6 +5,6 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
{
|
{
|
||||||
public interface IDefinedAggregator
|
public interface IDefinedAggregator
|
||||||
{
|
{
|
||||||
Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses);
|
Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
|
|
||||||
@ -21,7 +20,7 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
if (!aggregator.IsError)
|
if (!aggregator.IsError)
|
||||||
{
|
{
|
||||||
var aggregateResponse = await aggregator.Data
|
var aggregateResponse = await aggregator.Data
|
||||||
.Aggregate(downstreamResponses.Select(x => x.DownstreamResponse).ToList());
|
.Aggregate(downstreamResponses);
|
||||||
|
|
||||||
originalContext.DownstreamResponse = aggregateResponse;
|
originalContext.DownstreamResponse = aggregateResponse;
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
namespace Ocelot.Middleware
|
namespace Ocelot.Middleware
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using DependencyInjection;
|
using DependencyInjection;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Creator;
|
using Ocelot.Configuration.Creator;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Repository;
|
using Ocelot.Configuration.Repository;
|
||||||
using Ocelot.Configuration.Setter;
|
using Ocelot.Configuration.Setter;
|
||||||
using Ocelot.Responses;
|
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware.Pipeline;
|
using Ocelot.Middleware.Pipeline;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Ocelot.Responses;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public static class OcelotMiddlewareExtensions
|
public static class OcelotMiddlewareExtensions
|
||||||
{
|
{
|
||||||
@ -42,6 +42,30 @@
|
|||||||
return CreateOcelotPipeline(builder, pipelineConfiguration);
|
return CreateOcelotPipeline(builder, pipelineConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder app, Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction)
|
||||||
|
=> UseOcelot(app, builderAction, new OcelotPipelineConfiguration());
|
||||||
|
|
||||||
|
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder app, Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction, OcelotPipelineConfiguration configuration)
|
||||||
|
{
|
||||||
|
await CreateConfiguration(app); // initConfiguration
|
||||||
|
|
||||||
|
ConfigureDiagnosticListener(app);
|
||||||
|
|
||||||
|
var ocelotPipelineBuilder = new OcelotPipelineBuilder(app.ApplicationServices);
|
||||||
|
builderAction?.Invoke(ocelotPipelineBuilder, configuration ?? new OcelotPipelineConfiguration());
|
||||||
|
|
||||||
|
var ocelotDelegate = ocelotPipelineBuilder.Build();
|
||||||
|
app.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware";
|
||||||
|
|
||||||
|
app.Use(async (context, task) =>
|
||||||
|
{
|
||||||
|
var downstreamContext = new DownstreamContext(context);
|
||||||
|
await ocelotDelegate.Invoke(downstreamContext);
|
||||||
|
});
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
private static IApplicationBuilder CreateOcelotPipeline(IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
|
private static IApplicationBuilder CreateOcelotPipeline(IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
|
||||||
{
|
{
|
||||||
var pipelineBuilder = new OcelotPipelineBuilder(builder.ApplicationServices);
|
var pipelineBuilder = new OcelotPipelineBuilder(builder.ApplicationServices);
|
||||||
|
@ -9,7 +9,7 @@ namespace Ocelot.Middleware.Pipeline
|
|||||||
public interface IOcelotPipelineBuilder
|
public interface IOcelotPipelineBuilder
|
||||||
{
|
{
|
||||||
IServiceProvider ApplicationServices { get; }
|
IServiceProvider ApplicationServices { get; }
|
||||||
OcelotPipelineBuilder Use(Func<OcelotRequestDelegate, OcelotRequestDelegate> middleware);
|
IOcelotPipelineBuilder Use(Func<OcelotRequestDelegate, OcelotRequestDelegate> middleware);
|
||||||
OcelotRequestDelegate Build();
|
OcelotRequestDelegate Build();
|
||||||
IOcelotPipelineBuilder New();
|
IOcelotPipelineBuilder New();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace Ocelot.Middleware.Pipeline
|
|||||||
|
|
||||||
public IServiceProvider ApplicationServices { get; }
|
public IServiceProvider ApplicationServices { get; }
|
||||||
|
|
||||||
public OcelotPipelineBuilder Use(Func<OcelotRequestDelegate, OcelotRequestDelegate> middleware)
|
public IOcelotPipelineBuilder Use(Func<OcelotRequestDelegate, OcelotRequestDelegate> middleware)
|
||||||
{
|
{
|
||||||
_middlewares.Add(middleware);
|
_middlewares.Add(middleware);
|
||||||
return this;
|
return this;
|
||||||
|
@ -19,6 +19,7 @@ namespace Ocelot.Request.Middleware
|
|||||||
Headers = _request.Headers;
|
Headers = _request.Headers;
|
||||||
AbsolutePath = _request.RequestUri.AbsolutePath;
|
AbsolutePath = _request.RequestUri.AbsolutePath;
|
||||||
Query = _request.RequestUri.Query;
|
Query = _request.RequestUri.Query;
|
||||||
|
Content = _request.Content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpRequestHeaders Headers { get; }
|
public HttpRequestHeaders Headers { get; }
|
||||||
@ -37,6 +38,8 @@ namespace Ocelot.Request.Middleware
|
|||||||
|
|
||||||
public string Query { get; set; }
|
public string Query { get; set; }
|
||||||
|
|
||||||
|
public HttpContent Content { get; set; }
|
||||||
|
|
||||||
public HttpRequestMessage ToHttpRequestMessage()
|
public HttpRequestMessage ToHttpRequestMessage()
|
||||||
{
|
{
|
||||||
var uriBuilder = new UriBuilder
|
var uriBuilder = new UriBuilder
|
||||||
|
@ -646,14 +646,14 @@ namespace Ocelot.AcceptanceTests
|
|||||||
_dep = dep;
|
_dep = dep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses)
|
public async Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses)
|
||||||
{
|
{
|
||||||
var one = await responses[0].Content.ReadAsStringAsync();
|
var one = await responses[0].DownstreamResponse.Content.ReadAsStringAsync();
|
||||||
var two = await responses[1].Content.ReadAsStringAsync();
|
var two = await responses[1].DownstreamResponse.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
var merge = $"{one}, {two}";
|
var merge = $"{one}, {two}";
|
||||||
merge = merge.Replace("Hello", "Bye").Replace("{", "").Replace("}", "");
|
merge = merge.Replace("Hello", "Bye").Replace("{", "").Replace("}", "");
|
||||||
var headers = responses.SelectMany(x => x.Headers).ToList();
|
var headers = responses.SelectMany(x => x.DownstreamResponse.Headers).ToList();
|
||||||
return new DownstreamResponse(new StringContent(merge), HttpStatusCode.OK, headers, "some reason");
|
return new DownstreamResponse(new StringContent(merge), HttpStatusCode.OK, headers, "some reason");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,15 +69,21 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
private void GivenTheAuthServiceReturns(Response<bool> expected)
|
private void GivenTheAuthServiceReturns(Response<bool> expected)
|
||||||
{
|
{
|
||||||
_authService
|
_authService
|
||||||
.Setup(x => x.Authorise(It.IsAny<ClaimsPrincipal>(), It.IsAny<Dictionary<string, string>>()))
|
.Setup(x => x.Authorise(
|
||||||
|
It.IsAny<ClaimsPrincipal>(),
|
||||||
|
It.IsAny<Dictionary<string, string>>(),
|
||||||
|
It.IsAny<List<PlaceholderNameAndValue>>()))
|
||||||
.Returns(expected);
|
.Returns(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheAuthServiceIsCalledCorrectly()
|
private void ThenTheAuthServiceIsCalledCorrectly()
|
||||||
{
|
{
|
||||||
_authService
|
_authService
|
||||||
.Verify(x => x.Authorise(It.IsAny<ClaimsPrincipal>(),
|
.Verify(x => x.Authorise(
|
||||||
It.IsAny<Dictionary<string, string>>()), Times.Once);
|
It.IsAny<ClaimsPrincipal>(),
|
||||||
|
It.IsAny<Dictionary<string, string>>(),
|
||||||
|
It.IsAny<List<PlaceholderNameAndValue>>())
|
||||||
|
, Times.Once);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Ocelot.Authorisation;
|
using Ocelot.Authorisation;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
using Ocelot.Values;
|
||||||
|
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -15,6 +19,7 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
private readonly ClaimsAuthoriser _claimsAuthoriser;
|
private readonly ClaimsAuthoriser _claimsAuthoriser;
|
||||||
private ClaimsPrincipal _claimsPrincipal;
|
private ClaimsPrincipal _claimsPrincipal;
|
||||||
private Dictionary<string, string> _requirement;
|
private Dictionary<string, string> _requirement;
|
||||||
|
private List<PlaceholderNameAndValue> _urlPathPlaceholderNameAndValues;
|
||||||
private Response<bool> _result;
|
private Response<bool> _result;
|
||||||
|
|
||||||
public ClaimsAuthoriserTests()
|
public ClaimsAuthoriserTests()
|
||||||
@ -38,6 +43,46 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_authorize_dynamic_user()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim("userid", "14"),
|
||||||
|
}))))
|
||||||
|
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{"userid", "{userId}"}
|
||||||
|
}))
|
||||||
|
.And(x => x.GivenAPlaceHolderNameAndValueList(new List<PlaceholderNameAndValue>
|
||||||
|
{
|
||||||
|
new PlaceholderNameAndValue("{userId}", "14")
|
||||||
|
}))
|
||||||
|
.When(x => x.WhenICallTheAuthoriser())
|
||||||
|
.Then(x => x.ThenTheUserIsAuthorised())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_not_authorize_dynamic_user()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim("userid", "15"),
|
||||||
|
}))))
|
||||||
|
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{"userid", "{userId}"}
|
||||||
|
}))
|
||||||
|
.And(x => x.GivenAPlaceHolderNameAndValueList(new List<PlaceholderNameAndValue>
|
||||||
|
{
|
||||||
|
new PlaceholderNameAndValue("{userId}", "14")
|
||||||
|
}))
|
||||||
|
.When(x => x.WhenICallTheAuthoriser())
|
||||||
|
.Then(x => x.ThenTheUserIsntAuthorised())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_authorise_user_multiple_claims_of_same_type()
|
public void should_authorise_user_multiple_claims_of_same_type()
|
||||||
{
|
{
|
||||||
@ -78,9 +123,14 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
_requirement = requirement;
|
_requirement = requirement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GivenAPlaceHolderNameAndValueList(List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues)
|
||||||
|
{
|
||||||
|
_urlPathPlaceholderNameAndValues = urlPathPlaceholderNameAndValues;
|
||||||
|
}
|
||||||
|
|
||||||
private void WhenICallTheAuthoriser()
|
private void WhenICallTheAuthoriser()
|
||||||
{
|
{
|
||||||
_result = _claimsAuthoriser.Authorise(_claimsPrincipal, _requirement);
|
_result = _claimsAuthoriser.Authorise(_claimsPrincipal, _requirement, _urlPathPlaceholderNameAndValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheUserIsAuthorised()
|
private void ThenTheUserIsAuthorised()
|
||||||
|
34
test/Ocelot.UnitTests/Cache/CacheKeyGeneratorTests.cs
Normal file
34
test/Ocelot.UnitTests/Cache/CacheKeyGeneratorTests.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System.Net.Http;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Ocelot.Cache;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Shouldly;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Cache {
|
||||||
|
public class CacheKeyGeneratorTests {
|
||||||
|
private readonly ICacheKeyGenerator _cacheKeyGenerator;
|
||||||
|
private readonly DownstreamContext _downstreamContext;
|
||||||
|
|
||||||
|
public CacheKeyGeneratorTests() {
|
||||||
|
_cacheKeyGenerator = new CacheKeyGenerator();
|
||||||
|
_cacheKeyGenerator = new CacheKeyGenerator();
|
||||||
|
_downstreamContext = new DownstreamContext(new DefaultHttpContext()) {
|
||||||
|
DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_generate_cache_key_from_context() {
|
||||||
|
this.Given(x => x.GivenCacheKeyFromContext(_downstreamContext))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenCacheKeyFromContext(DownstreamContext context) {
|
||||||
|
string generatedCacheKey = _cacheKeyGenerator.GenerateRequestCacheKey(context);
|
||||||
|
string cachekey = MD5Helper.GenerateMd5("GET-https://some.url/blah?abcd=123");
|
||||||
|
generatedCacheKey.ShouldBe(cachekey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,14 +27,17 @@
|
|||||||
private OutputCacheMiddleware _middleware;
|
private OutputCacheMiddleware _middleware;
|
||||||
private readonly DownstreamContext _downstreamContext;
|
private readonly DownstreamContext _downstreamContext;
|
||||||
private readonly OcelotRequestDelegate _next;
|
private readonly OcelotRequestDelegate _next;
|
||||||
|
private readonly ICacheKeyGenerator _cacheKeyGenerator;
|
||||||
private CachedResponse _response;
|
private CachedResponse _response;
|
||||||
|
|
||||||
|
|
||||||
public OutputCacheMiddlewareTests()
|
public OutputCacheMiddlewareTests()
|
||||||
{
|
{
|
||||||
_cache = new Mock<IOcelotCache<CachedResponse>>();
|
_cache = new Mock<IOcelotCache<CachedResponse>>();
|
||||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||||
_logger = new Mock<IOcelotLogger>();
|
_logger = new Mock<IOcelotLogger>();
|
||||||
|
_cacheKeyGenerator = new CacheKeyGenerator();
|
||||||
_loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
|
_loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
|
||||||
_next = context => Task.CompletedTask;
|
_next = context => Task.CompletedTask;
|
||||||
_downstreamContext.DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
|
_downstreamContext.DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
|
||||||
@ -89,7 +92,7 @@
|
|||||||
|
|
||||||
private void WhenICallTheMiddleware()
|
private void WhenICallTheMiddleware()
|
||||||
{
|
{
|
||||||
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cache.Object);
|
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cache.Object, _cacheKeyGenerator);
|
||||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
public class OutputCacheMiddlewareRealCacheTests
|
public class OutputCacheMiddlewareRealCacheTests
|
||||||
{
|
{
|
||||||
private readonly IOcelotCache<CachedResponse> _cacheManager;
|
private readonly IOcelotCache<CachedResponse> _cacheManager;
|
||||||
|
private readonly ICacheKeyGenerator _cacheKeyGenerator;
|
||||||
private readonly OutputCacheMiddleware _middleware;
|
private readonly OutputCacheMiddleware _middleware;
|
||||||
private readonly DownstreamContext _downstreamContext;
|
private readonly DownstreamContext _downstreamContext;
|
||||||
private OcelotRequestDelegate _next;
|
private OcelotRequestDelegate _next;
|
||||||
@ -39,10 +40,11 @@
|
|||||||
x.WithDictionaryHandle();
|
x.WithDictionaryHandle();
|
||||||
});
|
});
|
||||||
_cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
|
_cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
|
||||||
|
_cacheKeyGenerator = new CacheKeyGenerator();
|
||||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||||
_downstreamContext.DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
|
_downstreamContext.DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
|
||||||
_next = context => Task.CompletedTask;
|
_next = context => Task.CompletedTask;
|
||||||
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager);
|
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager, _cacheKeyGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -69,7 +71,8 @@
|
|||||||
|
|
||||||
private void ThenTheContentTypeHeaderIsCached()
|
private void ThenTheContentTypeHeaderIsCached()
|
||||||
{
|
{
|
||||||
var result = _cacheManager.Get("GET-https://some.url/blah?abcd=123", "kanken");
|
string cacheKey = MD5Helper.GenerateMd5("GET-https://some.url/blah?abcd=123");
|
||||||
|
var result = _cacheManager.Get(cacheKey, "kanken");
|
||||||
var header = result.ContentHeaders["Content-Type"];
|
var header = result.ContentHeaders["Content-Type"];
|
||||||
header.First().ShouldBe("application/json");
|
header.First().ShouldBe("application/json");
|
||||||
}
|
}
|
||||||
|
@ -1023,7 +1023,7 @@
|
|||||||
Host = "bb.co.uk"
|
Host = "bb.co.uk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
UpstreamHost = "host1"
|
UpstreamHost = "host2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using KubeClient.Models;
|
using KubeClient;
|
||||||
|
using KubeClient.Models;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
@ -31,7 +32,7 @@ namespace Ocelot.UnitTests.Kubernetes
|
|||||||
private readonly Mock<IOcelotLoggerFactory> _factory;
|
private readonly Mock<IOcelotLoggerFactory> _factory;
|
||||||
private readonly Mock<IOcelotLogger> _logger;
|
private readonly Mock<IOcelotLogger> _logger;
|
||||||
private string _receivedToken;
|
private string _receivedToken;
|
||||||
private readonly IKubeApiClientFactory _clientFactory;
|
private readonly IKubeApiClient _clientFactory;
|
||||||
|
|
||||||
public KubeServiceDiscoveryProviderTests()
|
public KubeServiceDiscoveryProviderTests()
|
||||||
{
|
{
|
||||||
@ -42,15 +43,20 @@ namespace Ocelot.UnitTests.Kubernetes
|
|||||||
_fakekubeServiceDiscoveryUrl = $"http://{_kubeHost}:{_port}";
|
_fakekubeServiceDiscoveryUrl = $"http://{_kubeHost}:{_port}";
|
||||||
_serviceEntries = new ServiceV1();
|
_serviceEntries = new ServiceV1();
|
||||||
_factory = new Mock<IOcelotLoggerFactory>();
|
_factory = new Mock<IOcelotLoggerFactory>();
|
||||||
_clientFactory = new KubeApiClientFactory();
|
|
||||||
|
var option = new KubeClientOptions
|
||||||
|
{
|
||||||
|
ApiEndPoint = new Uri(_fakekubeServiceDiscoveryUrl),
|
||||||
|
AccessToken = "txpc696iUhbVoudg164r93CxDTrKRVWG",
|
||||||
|
AuthStrategy = KubeClient.KubeAuthStrategy.BearerToken,
|
||||||
|
AllowInsecure = true
|
||||||
|
};
|
||||||
|
|
||||||
|
_clientFactory = KubeApiClient.Create(option);
|
||||||
_logger = new Mock<IOcelotLogger>();
|
_logger = new Mock<IOcelotLogger>();
|
||||||
_factory.Setup(x => x.CreateLogger<Kube>()).Returns(_logger.Object);
|
_factory.Setup(x => x.CreateLogger<Kube>()).Returns(_logger.Object);
|
||||||
var config = new KubeRegistryConfiguration()
|
var config = new KubeRegistryConfiguration()
|
||||||
{
|
{
|
||||||
ApiEndPoint = new Uri(_fakekubeServiceDiscoveryUrl),
|
|
||||||
AccessToken = "txpc696iUhbVoudg164r93CxDTrKRVWG",
|
|
||||||
AllowInsecure = true,
|
|
||||||
AuthStrategy = KubeClient.KubeAuthStrategy.BearerToken,
|
|
||||||
KeyOfServiceInK8s = _serviceName,
|
KeyOfServiceInK8s = _serviceName,
|
||||||
KubeNamespace = _namespaces
|
KubeNamespace = _namespaces
|
||||||
};
|
};
|
||||||
|
@ -140,12 +140,12 @@ namespace Ocelot.UnitTests.Middleware
|
|||||||
|
|
||||||
public class TestDefinedAggregator : IDefinedAggregator
|
public class TestDefinedAggregator : IDefinedAggregator
|
||||||
{
|
{
|
||||||
public async Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses)
|
public async Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses)
|
||||||
{
|
{
|
||||||
var tom = await responses[0].Content.ReadAsStringAsync();
|
var tom = await responses[0].DownstreamResponse.Content.ReadAsStringAsync();
|
||||||
var laura = await responses[1].Content.ReadAsStringAsync();
|
var laura = await responses[1].DownstreamResponse.Content.ReadAsStringAsync();
|
||||||
var content = $"{tom}, {laura}";
|
var content = $"{tom}, {laura}";
|
||||||
var headers = responses.SelectMany(x => x.Headers).ToList();
|
var headers = responses.SelectMany(x => x.DownstreamResponse.Headers).ToList();
|
||||||
return new DownstreamResponse(new StringContent(content), HttpStatusCode.OK, headers, "some reason");
|
return new DownstreamResponse(new StringContent(content), HttpStatusCode.OK, headers, "some reason");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,10 @@
|
|||||||
<DebugSymbols>True</DebugSymbols>
|
<DebugSymbols>True</DebugSymbols>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Kubernetes\KubeProviderFactoryTests.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Ocelot.Provider.Kubernetes\Ocelot.Provider.Kubernetes.csproj" />
|
<ProjectReference Include="..\..\src\Ocelot.Provider.Kubernetes\Ocelot.Provider.Kubernetes.csproj" />
|
||||||
<ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
|
<ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user