mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	[New feature] Support claims to path transformation (#968)
* Add the option to change DownstreamPath based on Claims * Add tests for Claims to downstream path
This commit is contained in:
		
				
					committed by
					
						
						Thiago Loureiro
					
				
			
			
				
	
			
			
			
						parent
						
							b32850a804
						
					
				
				
					commit
					8117366313
				
			
							
								
								
									
										201
									
								
								test/Ocelot.AcceptanceTests/ClaimsToDownstreamPathTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								test/Ocelot.AcceptanceTests/ClaimsToDownstreamPathTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,201 @@
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using IdentityServer4.AccessTokenValidation;
 | 
			
		||||
    using IdentityServer4.Models;
 | 
			
		||||
    using IdentityServer4.Test;
 | 
			
		||||
    using Microsoft.AspNetCore.Builder;
 | 
			
		||||
    using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
 | 
			
		||||
    public class ClaimsToDownstreamPathTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private IWebHost _servicebuilder;
 | 
			
		||||
        private IWebHost _identityServerBuilder;
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private Action<IdentityServerAuthenticationOptions> _options;
 | 
			
		||||
        private string _identityServerRootUrl = "http://localhost:57888";
 | 
			
		||||
        private string _downstreamFinalPath;
 | 
			
		||||
 | 
			
		||||
        public ClaimsToDownstreamPathTests()
 | 
			
		||||
        {
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
            _options = o =>
 | 
			
		||||
            {
 | 
			
		||||
                o.Authority = _identityServerRootUrl;
 | 
			
		||||
                o.ApiName = "api";
 | 
			
		||||
                o.RequireHttpsMetadata = false;
 | 
			
		||||
                o.SupportedTokens = SupportedTokens.Both;
 | 
			
		||||
                o.ApiSecret = "secret";
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_200_and_change_downstream_path()
 | 
			
		||||
        {
 | 
			
		||||
            var user = new TestUser()
 | 
			
		||||
            {
 | 
			
		||||
                Username = "test",
 | 
			
		||||
                Password = "test",
 | 
			
		||||
                SubjectId = "registered|1231231",
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                   {
 | 
			
		||||
                       new FileReRoute
 | 
			
		||||
                       {
 | 
			
		||||
                           DownstreamPathTemplate = "/users/{userId}",
 | 
			
		||||
                           DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                           {
 | 
			
		||||
                               new FileHostAndPort
 | 
			
		||||
                               {
 | 
			
		||||
                                   Host = "localhost",
 | 
			
		||||
                                   Port = 57876,
 | 
			
		||||
                               },
 | 
			
		||||
                           },
 | 
			
		||||
                           DownstreamScheme = "http",
 | 
			
		||||
                           UpstreamPathTemplate = "/users",
 | 
			
		||||
                           UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                           AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                           {
 | 
			
		||||
                               AuthenticationProviderKey = "Test",
 | 
			
		||||
                               AllowedScopes = new List<string>
 | 
			
		||||
                               {
 | 
			
		||||
                                   "openid", "offline_access", "api",
 | 
			
		||||
                               },
 | 
			
		||||
                           },
 | 
			
		||||
                           ChangeDownstreamPathTemplate =
 | 
			
		||||
                           {
 | 
			
		||||
                               {"userId", "Claims[sub] > value[1] > |"},
 | 
			
		||||
                           },
 | 
			
		||||
                       },
 | 
			
		||||
                   },
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:57888", "api", AccessTokenType.Jwt, user))
 | 
			
		||||
                .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:57876", 200))
 | 
			
		||||
                .And(x => _steps.GivenIHaveAToken("http://localhost:57888"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
 | 
			
		||||
                .And(x => _steps.GivenIHaveAddedATokenToMyRequest())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/users"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("UserId: 1231231"))
 | 
			
		||||
                .And(x => _downstreamFinalPath.ShouldBe("/users/1231231"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode)
 | 
			
		||||
        {
 | 
			
		||||
            _servicebuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .UseIISIntegration()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.Run(async context =>
 | 
			
		||||
                    {
 | 
			
		||||
                        _downstreamFinalPath = context.Request.Path.Value;
 | 
			
		||||
 | 
			
		||||
                        string userId = _downstreamFinalPath.Replace("/users/", string.Empty);
 | 
			
		||||
 | 
			
		||||
                        var responseBody = $"UserId: {userId}";
 | 
			
		||||
                        context.Response.StatusCode = statusCode;
 | 
			
		||||
                        await context.Response.WriteAsync(responseBody);
 | 
			
		||||
                    });
 | 
			
		||||
                })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _servicebuilder.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAnIdentityServerOn(string url, string apiName, AccessTokenType tokenType, TestUser user)
 | 
			
		||||
        {
 | 
			
		||||
            _identityServerBuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .UseIISIntegration()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .ConfigureServices(services =>
 | 
			
		||||
                {
 | 
			
		||||
                    services.AddLogging();
 | 
			
		||||
                    services.AddIdentityServer()
 | 
			
		||||
                        .AddDeveloperSigningCredential()
 | 
			
		||||
                        .AddInMemoryApiResources(new List<ApiResource>
 | 
			
		||||
                        {
 | 
			
		||||
                            new ApiResource
 | 
			
		||||
                            {
 | 
			
		||||
                                Name = apiName,
 | 
			
		||||
                                Description = "My API",
 | 
			
		||||
                                Enabled = true,
 | 
			
		||||
                                DisplayName = "test",
 | 
			
		||||
                                Scopes = new List<Scope>()
 | 
			
		||||
                                {
 | 
			
		||||
                                    new Scope("api"),
 | 
			
		||||
                                    new Scope("openid"),
 | 
			
		||||
                                    new Scope("offline_access")
 | 
			
		||||
                                },
 | 
			
		||||
                                ApiSecrets = new List<Secret>()
 | 
			
		||||
                                {
 | 
			
		||||
                                    new Secret
 | 
			
		||||
                                    {
 | 
			
		||||
                                        Value = "secret".Sha256()
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                                UserClaims = new List<string>()
 | 
			
		||||
                                {
 | 
			
		||||
                                    "CustomerId", "LocationId", "UserType", "UserId"
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        })
 | 
			
		||||
                        .AddInMemoryClients(new List<Client>
 | 
			
		||||
                        {
 | 
			
		||||
                            new Client
 | 
			
		||||
                            {
 | 
			
		||||
                                ClientId = "client",
 | 
			
		||||
                                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
 | 
			
		||||
                                ClientSecrets = new List<Secret> {new Secret("secret".Sha256())},
 | 
			
		||||
                                AllowedScopes = new List<string> { apiName, "openid", "offline_access" },
 | 
			
		||||
                                AccessTokenType = tokenType,
 | 
			
		||||
                                Enabled = true,
 | 
			
		||||
                                RequireClientSecret = false
 | 
			
		||||
                            }
 | 
			
		||||
                        })
 | 
			
		||||
                        .AddTestUsers(new List<TestUser>
 | 
			
		||||
                        {
 | 
			
		||||
                            user
 | 
			
		||||
                        });
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseIdentityServer();
 | 
			
		||||
                })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _identityServerBuilder.Start();
 | 
			
		||||
 | 
			
		||||
            _steps.VerifyIdentiryServerStarted(url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _servicebuilder?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
            _identityServerBuilder?.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user