mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 15:50:49 +08:00 
			
		
		
		
	hacky auth working
This commit is contained in:
		
							
								
								
									
										46
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								README.md
									
									
									
									
									
								
							@@ -4,6 +4,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[](https://gitter.im/Ocelotey/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 | 
					[](https://gitter.im/Ocelotey/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ Get more details at **codescene.io**.](https://codescene.io/projects/697/jobs/latest-successful/results)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Attempt at a .NET Api Gateway
 | 
					Attempt at a .NET Api Gateway
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This project is aimed at people using .NET running 
 | 
					This project is aimed at people using .NET running 
 | 
				
			||||||
@@ -101,15 +103,14 @@ Currently this is the only way to get configuration into Ocelot.
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            services.AddOcelotOutputCaching(settings);
 | 
					            services.AddOcelotOutputCaching(settings);
 | 
				
			||||||
            services.AddOcelotFileConfiguration(Configuration);
 | 
					            services.AddOcelot(Configuration);
 | 
				
			||||||
            services.AddOcelot();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 | 
					        public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
 | 
					            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            app.UseOcelot();
 | 
					            await app.UseOcelot();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -386,6 +387,43 @@ In orde to use caching on a route in your ReRoute configuration add this setting
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
In this example ttl seconds is set to 15 which means the cache will expire after 15 seconds.
 | 
					In this example ttl seconds is set to 15 which means the cache will expire after 15 seconds.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Administration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ocelot supports changing configuration during runtime via an authenticated HTTP API. The API is authenticated 
 | 
				
			||||||
 | 
					using bearer tokens that you request from iteself. This support is provided by the amazing IdentityServer 
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					initial configuration.json. The value can be anything you want and it is obviously reccomended don't use
 | 
				
			||||||
 | 
					a url you would like to route through with Ocelot as this will not work. The administration uses the
 | 
				
			||||||
 | 
					MapWhen functionality of asp.net core and all requests to root/administration will be sent there not 
 | 
				
			||||||
 | 
					to the Ocelot middleware.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        "GlobalConfiguration": {
 | 
				
			||||||
 | 
					            "AdministrationPath": "/administration"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This will get the admin area set up but not the authentication. You need to set 3 environmental variables.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OCELOT_USERNAME
 | 
				
			||||||
 | 
					    OCELOT_HASH
 | 
				
			||||||
 | 
					    OCELOT_SALT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These need to be the admin username you want to use with Ocelot and the hash and salt of the password you want to 
 | 
				
			||||||
 | 
					use given hashing algorythm. When requesting bearer tokens for use with the administration api you will need to
 | 
				
			||||||
 | 
					supply username and password.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to create a hash and salt of your password please check out HashCreationTests.should_create_hash_and_salt() this technique is based on MS doc I found online TODO find and link...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OK next thing is to get this config into Ocelot...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					At the moment Ocelot supports really limited options in terms of users and authentication for the admin API. At 
 | 
				
			||||||
 | 
					least your stuff needs to be hashed!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Ocelot Middleware injection and overrides
 | 
					## Ocelot Middleware injection and overrides
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Warning use with caution. If you are seeing any exceptions or strange behavior in your middleware 
 | 
					Warning use with caution. If you are seeing any exceptions or strange behavior in your middleware 
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
{"ReRoutes":[{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/","UpstreamHttpMethod":"get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null},{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/test","UpstreamHttpMethod":"get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null}],"GlobalConfiguration":{"RequestIdKey":"RequestId","ServiceDiscoveryProvider":{"Provider":"test","Host":"127.0.0.1","Port":0},"AdministrationPath":"/administration"}}
 | 
					{"ReRoutes":[],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Host":null,"Port":0},"AdministrationPath":"/administration"}}
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/Ocelot/Configuration/Authentication/HashMatcher.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/Ocelot/Configuration/Authentication/HashMatcher.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Cryptography.KeyDerivation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Configuration.Authentication
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class HashMatcher : IHashMatcher
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public bool Match(string password, string salt, string hash)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            byte[] s = Convert.FromBase64String(salt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
 | 
				
			||||||
 | 
					                password: password,
 | 
				
			||||||
 | 
					                salt: s,
 | 
				
			||||||
 | 
					                prf: KeyDerivationPrf.HMACSHA256,
 | 
				
			||||||
 | 
					                iterationCount: 10000,
 | 
				
			||||||
 | 
					                numBytesRequested: 256 / 8));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return hashed == hash;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/Ocelot/Configuration/Authentication/IHashMatcher.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Ocelot/Configuration/Authentication/IHashMatcher.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					namespace Ocelot.Configuration.Authentication
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IHashMatcher
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        bool Match(string password, string salt, string hash);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using IdentityServer4.Models;
 | 
				
			||||||
 | 
					using IdentityServer4.Validation;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.Provider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Configuration.Authentication
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OcelotResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly IHashMatcher _matcher;
 | 
				
			||||||
 | 
					        private readonly IIdentityServerConfiguration _identityServerConfiguration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OcelotResourceOwnerPasswordValidator(IHashMatcher matcher, IIdentityServerConfiguration identityServerConfiguration)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _identityServerConfiguration = identityServerConfiguration;
 | 
				
			||||||
 | 
					            _matcher = matcher;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var user = _identityServerConfiguration.Users.FirstOrDefault(u => u.UserName == context.UserName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(user == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    context.Result = new GrantValidationResult(
 | 
				
			||||||
 | 
					                            TokenRequestErrors.InvalidGrant,
 | 
				
			||||||
 | 
					                            "invalid custom credential");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if(_matcher.Match(context.Password, user.Salt, user.Hash))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    context.Result = new GrantValidationResult(
 | 
				
			||||||
 | 
					                        subject: "admin",
 | 
				
			||||||
 | 
					                        authenticationMethod: "custom");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    context.Result = new GrantValidationResult(
 | 
				
			||||||
 | 
					                        TokenRequestErrors.InvalidGrant,
 | 
				
			||||||
 | 
					                        "invalid custom credential");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch(Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Console.WriteLine(ex);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using IdentityServer4.AccessTokenValidation;
 | 
				
			||||||
 | 
					using IdentityServer4.Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Configuration.Provider
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IIdentityServerConfiguration
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        string ApiName { get;  }
 | 
				
			||||||
 | 
					        bool RequireHttps { get;  }
 | 
				
			||||||
 | 
					        List<string> AllowedScopes { get;  }
 | 
				
			||||||
 | 
					        SupportedTokens SupportedTokens { get;  }
 | 
				
			||||||
 | 
					        string ApiSecret { get;  }
 | 
				
			||||||
 | 
					        string Description {get;}
 | 
				
			||||||
 | 
					        bool Enabled {get;}
 | 
				
			||||||
 | 
					        IEnumerable<string>  AllowedGrantTypes {get;}
 | 
				
			||||||
 | 
					        AccessTokenType AccessTokenType {get;}
 | 
				
			||||||
 | 
					        bool RequireClientSecret {get;}
 | 
				
			||||||
 | 
					        List<User> Users {get;}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,49 +1,12 @@
 | 
				
			|||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using IdentityServer4.AccessTokenValidation;
 | 
					using IdentityServer4.AccessTokenValidation;
 | 
				
			||||||
using IdentityServer4.Models;
 | 
					using IdentityServer4.Models;
 | 
				
			||||||
using IdentityServer4.Test;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Configuration.Provider
 | 
					namespace Ocelot.Configuration.Provider
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class HardCodedIdentityServerConfigurationProvider : IIdentityServerConfigurationProvider
 | 
					    public class IdentityServerConfiguration : IIdentityServerConfiguration
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public IdentityServerConfiguration Get()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var url = "";
 | 
					 | 
				
			||||||
            return new IdentityServerConfiguration(
 | 
					 | 
				
			||||||
                url,
 | 
					 | 
				
			||||||
                "admin",
 | 
					 | 
				
			||||||
                false,
 | 
					 | 
				
			||||||
                SupportedTokens.Both,
 | 
					 | 
				
			||||||
                "secret",
 | 
					 | 
				
			||||||
                new List<string> {"admin", "openid", "offline_access"},
 | 
					 | 
				
			||||||
                "Ocelot Administration",
 | 
					 | 
				
			||||||
                true,
 | 
					 | 
				
			||||||
                GrantTypes.ResourceOwnerPassword,
 | 
					 | 
				
			||||||
                AccessTokenType.Jwt,
 | 
					 | 
				
			||||||
                false,
 | 
					 | 
				
			||||||
                new List<TestUser> {
 | 
					 | 
				
			||||||
                        new TestUser
 | 
					 | 
				
			||||||
                        { 
 | 
					 | 
				
			||||||
                            Username = "admin",
 | 
					 | 
				
			||||||
                            Password = "admin",
 | 
					 | 
				
			||||||
                            SubjectId = "admin",
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public interface IIdentityServerConfigurationProvider
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        IdentityServerConfiguration Get();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class IdentityServerConfiguration
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public IdentityServerConfiguration(
 | 
					        public IdentityServerConfiguration(
 | 
				
			||||||
            string identityServerUrl, 
 | 
					 | 
				
			||||||
            string apiName, 
 | 
					            string apiName, 
 | 
				
			||||||
            bool requireHttps, 
 | 
					            bool requireHttps, 
 | 
				
			||||||
            SupportedTokens supportedTokens, 
 | 
					            SupportedTokens supportedTokens, 
 | 
				
			||||||
@@ -54,9 +17,8 @@ namespace Ocelot.Configuration.Provider
 | 
				
			|||||||
            IEnumerable<string>  grantType,
 | 
					            IEnumerable<string>  grantType,
 | 
				
			||||||
            AccessTokenType accessTokenType,
 | 
					            AccessTokenType accessTokenType,
 | 
				
			||||||
            bool requireClientSecret,
 | 
					            bool requireClientSecret,
 | 
				
			||||||
            List<TestUser> users)
 | 
					            List<User> users)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            IdentityServerUrl = identityServerUrl;
 | 
					 | 
				
			||||||
            ApiName = apiName;
 | 
					            ApiName = apiName;
 | 
				
			||||||
            RequireHttps = requireHttps;
 | 
					            RequireHttps = requireHttps;
 | 
				
			||||||
            SupportedTokens = supportedTokens;
 | 
					            SupportedTokens = supportedTokens;
 | 
				
			||||||
@@ -70,7 +32,6 @@ namespace Ocelot.Configuration.Provider
 | 
				
			|||||||
            Users = users;
 | 
					            Users = users;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string IdentityServerUrl { get; private set; }
 | 
					 | 
				
			||||||
        public string ApiName { get; private set; }
 | 
					        public string ApiName { get; private set; }
 | 
				
			||||||
        public bool RequireHttps { get; private set; }
 | 
					        public bool RequireHttps { get; private set; }
 | 
				
			||||||
        public List<string> AllowedScopes { get; private set; }
 | 
					        public List<string> AllowedScopes { get; private set; }
 | 
				
			||||||
@@ -80,7 +41,7 @@ namespace Ocelot.Configuration.Provider
 | 
				
			|||||||
        public bool Enabled {get;private set;}
 | 
					        public bool Enabled {get;private set;}
 | 
				
			||||||
        public IEnumerable<string>  AllowedGrantTypes {get;private set;}
 | 
					        public IEnumerable<string>  AllowedGrantTypes {get;private set;}
 | 
				
			||||||
        public AccessTokenType AccessTokenType {get;private set;}
 | 
					        public AccessTokenType AccessTokenType {get;private set;}
 | 
				
			||||||
        public bool RequireClientSecret = false;
 | 
					        public bool RequireClientSecret {get;private set;}
 | 
				
			||||||
        public List<TestUser> Users {get;private set;}
 | 
					        public List<User> Users {get;private set;}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/Ocelot/Configuration/Provider/User.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/Ocelot/Configuration/Provider/User.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					namespace Ocelot.Configuration.Provider
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class User
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public User(string subject, string userName, string hash, string salt)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Subject = subject;
 | 
				
			||||||
 | 
					            UserName = userName;
 | 
				
			||||||
 | 
					            Hash = hash;
 | 
				
			||||||
 | 
					            Salt = salt;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public string Subject { get; private set; }
 | 
				
			||||||
 | 
					        public string UserName { get; private set; }
 | 
				
			||||||
 | 
					        public string Hash { get; private set; }
 | 
				
			||||||
 | 
					        public string Salt { get; private set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -14,6 +14,7 @@ using Ocelot.Authentication.Handler.Factory;
 | 
				
			|||||||
using Ocelot.Authorisation;
 | 
					using Ocelot.Authorisation;
 | 
				
			||||||
using Ocelot.Cache;
 | 
					using Ocelot.Cache;
 | 
				
			||||||
using Ocelot.Claims;
 | 
					using Ocelot.Claims;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.Authentication;
 | 
				
			||||||
using Ocelot.Configuration.Creator;
 | 
					using Ocelot.Configuration.Creator;
 | 
				
			||||||
using Ocelot.Configuration.File;
 | 
					using Ocelot.Configuration.File;
 | 
				
			||||||
using Ocelot.Configuration.Parser;
 | 
					using Ocelot.Configuration.Parser;
 | 
				
			||||||
@@ -41,7 +42,6 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public static class ServiceCollectionExtensions
 | 
					    public static class ServiceCollectionExtensions
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					 | 
				
			||||||
        public static IServiceCollection AddOcelotOutputCaching(this IServiceCollection services, Action<ConfigurationBuilderCachePart> settings)
 | 
					        public static IServiceCollection AddOcelotOutputCaching(this IServiceCollection services, Action<ConfigurationBuilderCachePart> settings)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var cacheManagerOutputCache = CacheFactory.Build<HttpResponseMessage>("OcelotOutputCache", settings);
 | 
					            var cacheManagerOutputCache = CacheFactory.Build<HttpResponseMessage>("OcelotOutputCache", settings);
 | 
				
			||||||
@@ -51,24 +51,23 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return services;
 | 
					            return services;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        public static IServiceCollection AddOcelotFileConfiguration(this IServiceCollection services, IConfigurationRoot configurationRoot)
 | 
					
 | 
				
			||||||
 | 
					        public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return AddOcelot(services, configurationRoot, null);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot, IIdentityServerConfiguration identityServerConfiguration)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            services.Configure<FileConfiguration>(configurationRoot);
 | 
					            services.Configure<FileConfiguration>(configurationRoot);
 | 
				
			||||||
            services.AddSingleton<IOcelotConfigurationCreator, FileOcelotConfigurationCreator>();
 | 
					            services.AddSingleton<IOcelotConfigurationCreator, FileOcelotConfigurationCreator>();
 | 
				
			||||||
            services.AddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
 | 
					            services.AddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
 | 
				
			||||||
            services.AddSingleton<IConfigurationValidator, FileConfigurationValidator>();
 | 
					            services.AddSingleton<IConfigurationValidator, FileConfigurationValidator>();
 | 
				
			||||||
            return services;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        public static IServiceCollection AddOcelot(this IServiceCollection services)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return AddOcelot(services, null);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public static IServiceCollection AddOcelot(this IServiceCollection services, IdentityServerConfiguration identityServerConfiguration)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if(identityServerConfiguration != null)
 | 
					            if(identityServerConfiguration != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                services.AddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
 | 
				
			||||||
 | 
					                services.AddSingleton<IHashMatcher, HashMatcher>();
 | 
				
			||||||
                services.AddIdentityServer()
 | 
					                services.AddIdentityServer()
 | 
				
			||||||
                    .AddTemporarySigningCredential()
 | 
					                    .AddTemporarySigningCredential()
 | 
				
			||||||
                    .AddInMemoryApiResources(new List<ApiResource>
 | 
					                    .AddInMemoryApiResources(new List<ApiResource>
 | 
				
			||||||
@@ -101,8 +100,7 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
                            Enabled = identityServerConfiguration.Enabled,
 | 
					                            Enabled = identityServerConfiguration.Enabled,
 | 
				
			||||||
                            RequireClientSecret = identityServerConfiguration.RequireClientSecret
 | 
					                            RequireClientSecret = identityServerConfiguration.RequireClientSecret
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    })
 | 
					                    }).AddResourceOwnerValidator<OcelotResourceOwnerPasswordValidator>();
 | 
				
			||||||
                    .AddTestUsers(identityServerConfiguration.Users);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
            services.AddMvcCore()
 | 
					            services.AddMvcCore()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,21 +37,7 @@ namespace Ocelot.Middleware
 | 
				
			|||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder)
 | 
					        public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await builder.UseOcelot(new OcelotMiddlewareConfiguration(), null);
 | 
					            await builder.UseOcelot(new OcelotMiddlewareConfiguration());
 | 
				
			||||||
 | 
					 | 
				
			||||||
            return builder;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder,IdentityServerConfiguration identityServerConfiguration)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            await builder.UseOcelot(new OcelotMiddlewareConfiguration(), identityServerConfiguration);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return builder;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder,OcelotMiddlewareConfiguration middlewareConfiguration)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            await builder.UseOcelot(middlewareConfiguration, null);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return builder;
 | 
					            return builder;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -62,9 +48,9 @@ namespace Ocelot.Middleware
 | 
				
			|||||||
        /// <param name="builder"></param>
 | 
					        /// <param name="builder"></param>
 | 
				
			||||||
        /// <param name="middlewareConfiguration"></param>
 | 
					        /// <param name="middlewareConfiguration"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration, IdentityServerConfiguration identityServerConfiguration)
 | 
					        public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder,       OcelotMiddlewareConfiguration middlewareConfiguration)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await CreateAdministrationArea(builder, identityServerConfiguration);
 | 
					            await CreateAdministrationArea(builder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // This is registered to catch any global exceptions that are not handled
 | 
					            // This is registered to catch any global exceptions that are not handled
 | 
				
			||||||
            builder.UseExceptionHandlerMiddleware();
 | 
					            builder.UseExceptionHandlerMiddleware();
 | 
				
			||||||
@@ -168,10 +154,12 @@ namespace Ocelot.Middleware
 | 
				
			|||||||
            return ocelotConfiguration.Data;
 | 
					            return ocelotConfiguration.Data;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static async Task CreateAdministrationArea(IApplicationBuilder builder, IdentityServerConfiguration identityServerConfiguration)
 | 
					        private static async Task CreateAdministrationArea(IApplicationBuilder builder)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var configuration = await CreateConfiguration(builder);
 | 
					            var configuration = await CreateConfiguration(builder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var identityServerConfiguration = (IIdentityServerConfiguration)builder.ApplicationServices.GetService(typeof(IIdentityServerConfiguration));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(!string.IsNullOrEmpty(configuration.AdministrationPath) && identityServerConfiguration != null)
 | 
					            if(!string.IsNullOrEmpty(configuration.AdministrationPath) && identityServerConfiguration != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var webHostBuilder = (IWebHostBuilder)builder.ApplicationServices.GetService(typeof(IWebHostBuilder));
 | 
					                var webHostBuilder = (IWebHostBuilder)builder.ApplicationServices.GetService(typeof(IWebHostBuilder));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,8 @@
 | 
				
			|||||||
        "CacheManager.Microsoft.Extensions.Logging": "0.9.2",
 | 
					        "CacheManager.Microsoft.Extensions.Logging": "0.9.2",
 | 
				
			||||||
        "Consul": "0.7.2.1",
 | 
					        "Consul": "0.7.2.1",
 | 
				
			||||||
        "Polly": "5.0.3",
 | 
					        "Polly": "5.0.3",
 | 
				
			||||||
        "IdentityServer4": "1.0.1"
 | 
					        "IdentityServer4": "1.0.1",
 | 
				
			||||||
 | 
					        "Microsoft.AspNetCore.Cryptography.KeyDerivation": "1.1.0"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  "runtimes": {
 | 
					  "runtimes": {
 | 
				
			||||||
    "win10-x64": {},
 | 
					    "win10-x64": {},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -139,8 +139,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                    };
 | 
					                    };
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    s.AddOcelotOutputCaching(settings);
 | 
					                    s.AddOcelotOutputCaching(settings);
 | 
				
			||||||
                    s.AddOcelotFileConfiguration(configuration);
 | 
					                    s.AddOcelot(configuration);
 | 
				
			||||||
                    s.AddOcelot();
 | 
					 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .ConfigureLogging(l =>
 | 
					                .ConfigureLogging(l =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -235,7 +235,7 @@ namespace Ocelot.IntegrationTests
 | 
				
			|||||||
                new KeyValuePair<string, string>("client_secret", "secret"),
 | 
					                new KeyValuePair<string, string>("client_secret", "secret"),
 | 
				
			||||||
                new KeyValuePair<string, string>("scope", "admin"),
 | 
					                new KeyValuePair<string, string>("scope", "admin"),
 | 
				
			||||||
                new KeyValuePair<string, string>("username", "admin"),
 | 
					                new KeyValuePair<string, string>("username", "admin"),
 | 
				
			||||||
                new KeyValuePair<string, string>("password", "admin"),
 | 
					                new KeyValuePair<string, string>("password", "secret"),
 | 
				
			||||||
                new KeyValuePair<string, string>("grant_type", "password")
 | 
					                new KeyValuePair<string, string>("grant_type", "password")
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            var content = new FormUrlEncodedContent(formData);
 | 
					            var content = new FormUrlEncodedContent(formData);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,9 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using CacheManager.Core;
 | 
					using CacheManager.Core;
 | 
				
			||||||
 | 
					using IdentityServer4.AccessTokenValidation;
 | 
				
			||||||
 | 
					using IdentityServer4.Models;
 | 
				
			||||||
using Microsoft.AspNetCore.Builder;
 | 
					using Microsoft.AspNetCore.Builder;
 | 
				
			||||||
using Microsoft.AspNetCore.Hosting;
 | 
					using Microsoft.AspNetCore.Hosting;
 | 
				
			||||||
using Microsoft.Extensions.Configuration;
 | 
					using Microsoft.Extensions.Configuration;
 | 
				
			||||||
@@ -15,7 +18,7 @@ namespace Ocelot.ManualTest
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class Startup
 | 
					    public class Startup
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private IdentityServerConfiguration _identityServerConfig;
 | 
					        private IIdentityServerConfiguration _identityServerConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public Startup(IHostingEnvironment env)
 | 
					        public Startup(IHostingEnvironment env)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -27,9 +30,6 @@ namespace Ocelot.ManualTest
 | 
				
			|||||||
                .AddEnvironmentVariables();
 | 
					                .AddEnvironmentVariables();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Configuration = builder.Build();
 | 
					            Configuration = builder.Build();
 | 
				
			||||||
 | 
					 | 
				
			||||||
            var identityServerConfigProvider = new HardCodedIdentityServerConfigurationProvider();
 | 
					 | 
				
			||||||
            _identityServerConfig = identityServerConfigProvider.Get();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IConfigurationRoot Configuration { get; }
 | 
					        public IConfigurationRoot Configuration { get; }
 | 
				
			||||||
@@ -46,15 +46,36 @@ namespace Ocelot.ManualTest
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            services.AddOcelotOutputCaching(settings);
 | 
					            services.AddOcelotOutputCaching(settings);
 | 
				
			||||||
            services.AddOcelotFileConfiguration(Configuration);
 | 
					
 | 
				
			||||||
            services.AddOcelot(_identityServerConfig);
 | 
					            var username = Environment.GetEnvironmentVariable("OCELOT_USERNAME");
 | 
				
			||||||
 | 
					            var hash = Environment.GetEnvironmentVariable("OCELOT_HASH");
 | 
				
			||||||
 | 
					            var salt = Environment.GetEnvironmentVariable("OCELOT_SALT");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _identityServerConfig = new IdentityServerConfiguration(
 | 
				
			||||||
 | 
					                "admin",
 | 
				
			||||||
 | 
					                false,
 | 
				
			||||||
 | 
					                SupportedTokens.Both,
 | 
				
			||||||
 | 
					                "secret",
 | 
				
			||||||
 | 
					                new List<string> {"admin", "openid", "offline_access"},
 | 
				
			||||||
 | 
					                "Ocelot Administration",
 | 
				
			||||||
 | 
					                true,
 | 
				
			||||||
 | 
					                GrantTypes.ResourceOwnerPassword,
 | 
				
			||||||
 | 
					                AccessTokenType.Jwt,
 | 
				
			||||||
 | 
					                false,
 | 
				
			||||||
 | 
					                new List<User> 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    new User("admin", username, hash, salt)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            services.AddOcelot(Configuration, _identityServerConfig);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 | 
					        public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
 | 
					            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await app.UseOcelot(_identityServerConfig);
 | 
					            await app.UseOcelot();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,8 @@
 | 
				
			|||||||
    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
 | 
					    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
 | 
				
			||||||
    "Microsoft.NETCore.App": "1.1.0",
 | 
					    "Microsoft.NETCore.App": "1.1.0",
 | 
				
			||||||
    "Consul": "0.7.2.1",
 | 
					    "Consul": "0.7.2.1",
 | 
				
			||||||
    "Polly": "5.0.3"
 | 
					    "Polly": "5.0.3",
 | 
				
			||||||
 | 
					      "Microsoft.AspNetCore.Cryptography.KeyDerivation": "1.1.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  "tools": {
 | 
					  "tools": {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								test/Ocelot.UnitTests/Configuration/HashCreationTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								test/Ocelot.UnitTests/Configuration/HashCreationTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Security.Cryptography;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Cryptography.KeyDerivation;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Configuration
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class HashCreationTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_create_hash_and_salt()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var password = "secret";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var salt = new byte[128 / 8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            using (var rng = RandomNumberGenerator.Create())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                rng.GetBytes(salt);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var storedSalt = Convert.ToBase64String(salt);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					            var storedHash = Convert.ToBase64String(KeyDerivation.Pbkdf2(
 | 
				
			||||||
 | 
					                password: password,
 | 
				
			||||||
 | 
					                salt: salt,
 | 
				
			||||||
 | 
					                prf: KeyDerivationPrf.HMACSHA256,
 | 
				
			||||||
 | 
					                iterationCount: 10000,
 | 
				
			||||||
 | 
					                numBytesRequested: 256 / 8));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										76
									
								
								test/Ocelot.UnitTests/Configuration/HashMatcherTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								test/Ocelot.UnitTests/Configuration/HashMatcherTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					using Ocelot.Configuration.Authentication;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Configuration
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class HashMatcherTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private string _password;
 | 
				
			||||||
 | 
					        private string _hash;
 | 
				
			||||||
 | 
					        private string _salt;
 | 
				
			||||||
 | 
					        private bool _result;
 | 
				
			||||||
 | 
					        private HashMatcher _hashMatcher;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public HashMatcherTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _hashMatcher = new HashMatcher();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_match_hash()
 | 
				
			||||||
 | 
					        {   
 | 
				
			||||||
 | 
					            var hash = "kE/mxd1hO9h9Sl2VhGhwJUd9xZEv4NP6qXoN39nIqM4=";
 | 
				
			||||||
 | 
					            var salt = "zzWITpnDximUNKYLiUam/w==";
 | 
				
			||||||
 | 
					            var password = "secret";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenThePassword(password))
 | 
				
			||||||
 | 
					                .And(x => GivenTheHash(hash))
 | 
				
			||||||
 | 
					                .And(x => GivenTheSalt(salt))
 | 
				
			||||||
 | 
					                .When(x => WhenIMatch())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheResultIs(true))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_not_match_hash()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var hash = "kE/mxd1hO9h9Sl2VhGhwJUd9xZEv4NP6qXoN39nIqM4=";
 | 
				
			||||||
 | 
					            var salt = "zzWITpnDximUNKYLiUam/w==";
 | 
				
			||||||
 | 
					            var password = "secret1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenThePassword(password))
 | 
				
			||||||
 | 
					                .And(x => GivenTheHash(hash))
 | 
				
			||||||
 | 
					                .And(x => GivenTheSalt(salt))
 | 
				
			||||||
 | 
					                .When(x => WhenIMatch())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheResultIs(false))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenThePassword(string password)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _password = password;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheHash(string hash)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _hash = hash;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheSalt(string salt)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _salt = salt;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIMatch()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result = _hashMatcher.Match(_password, _salt, _hash);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheResultIs(bool expected)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result.ShouldBe(expected);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					using Ocelot.Configuration.Authentication;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Moq;
 | 
				
			||||||
 | 
					using IdentityServer4.Validation;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.Provider;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Configuration
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OcelotResourceOwnerPasswordValidatorTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private OcelotResourceOwnerPasswordValidator _validator;
 | 
				
			||||||
 | 
					        private Mock<IHashMatcher> _matcher;
 | 
				
			||||||
 | 
					        private string _userName;
 | 
				
			||||||
 | 
					        private string _password;
 | 
				
			||||||
 | 
					        private ResourceOwnerPasswordValidationContext _context;
 | 
				
			||||||
 | 
					        private Mock<IIdentityServerConfiguration> _config;
 | 
				
			||||||
 | 
					        private User _user;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OcelotResourceOwnerPasswordValidatorTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _matcher = new Mock<IHashMatcher>();
 | 
				
			||||||
 | 
					            _config = new Mock<IIdentityServerConfiguration>();
 | 
				
			||||||
 | 
					            _validator = new OcelotResourceOwnerPasswordValidator(_matcher.Object, _config.Object);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_success()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheUserName("tom"))
 | 
				
			||||||
 | 
					                .And(x => GivenThePassword("password"))
 | 
				
			||||||
 | 
					                .And(x => GivenTheUserIs(new User("sub", "tom", "xxx", "xxx")))
 | 
				
			||||||
 | 
					                .And(x => GivenTheMatcherReturns(true))
 | 
				
			||||||
 | 
					                .When(x => WhenIValidate())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheUserIsValidated())
 | 
				
			||||||
 | 
					                .And(x => ThenTheMatcherIsCalledCorrectly())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_fail_when_no_user()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheUserName("bob"))
 | 
				
			||||||
 | 
					                .And(x => GivenTheUserIs(new User("sub", "tom", "xxx", "xxx")))
 | 
				
			||||||
 | 
					                .And(x => GivenTheMatcherReturns(true))
 | 
				
			||||||
 | 
					                .When(x => WhenIValidate())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheUserIsNotValidated())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_fail_when_password_doesnt_match()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheUserName("tom"))
 | 
				
			||||||
 | 
					                .And(x => GivenThePassword("password"))
 | 
				
			||||||
 | 
					                .And(x => GivenTheUserIs(new User("sub", "tom", "xxx", "xxx")))
 | 
				
			||||||
 | 
					                .And(x => GivenTheMatcherReturns(false))
 | 
				
			||||||
 | 
					                .When(x => WhenIValidate())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheUserIsNotValidated())
 | 
				
			||||||
 | 
					                .And(x => ThenTheMatcherIsCalledCorrectly())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheMatcherIsCalledCorrectly()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _matcher
 | 
				
			||||||
 | 
					                .Verify(x => x.Match(_password, _user.Salt, _user.Hash), Times.Once);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenThePassword(string password)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _password = password;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheUserIs(User user)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _user = user;
 | 
				
			||||||
 | 
					            _config
 | 
				
			||||||
 | 
					                .Setup(x => x.Users)
 | 
				
			||||||
 | 
					                .Returns(new List<User>{_user});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheMatcherReturns(bool expected)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _matcher
 | 
				
			||||||
 | 
					                .Setup(x => x.Match(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
 | 
				
			||||||
 | 
					                .Returns(expected);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheUserName(string userName)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _userName = userName;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIValidate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _context = new ResourceOwnerPasswordValidationContext
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                UserName = _userName,
 | 
				
			||||||
 | 
					                Password = _password
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            _validator.ValidateAsync(_context).Wait();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheUserIsValidated()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _context.Result.IsError.ShouldBe(false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         private void ThenTheUserIsNotValidated()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _context.Result.IsError.ShouldBe(true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -24,7 +24,8 @@
 | 
				
			|||||||
    "Shouldly": "2.8.2",
 | 
					    "Shouldly": "2.8.2",
 | 
				
			||||||
    "TestStack.BDDfy": "4.3.2",
 | 
					    "TestStack.BDDfy": "4.3.2",
 | 
				
			||||||
    "Microsoft.AspNetCore.Authentication.OAuth": "1.1.0",
 | 
					    "Microsoft.AspNetCore.Authentication.OAuth": "1.1.0",
 | 
				
			||||||
    "Microsoft.DotNet.InternalAbstractions": "1.0.0"
 | 
					    "Microsoft.DotNet.InternalAbstractions": "1.0.0",
 | 
				
			||||||
 | 
					    "Microsoft.AspNetCore.Cryptography.KeyDerivation": "1.1.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "runtimes": {
 | 
					  "runtimes": {
 | 
				
			||||||
    "win10-x64": {},
 | 
					    "win10-x64": {},
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user