hacky auth working

This commit is contained in:
Tom Gardham-Pallister
2017-02-24 19:52:48 +00:00
parent bd07af6926
commit 112a9c303e
19 changed files with 448 additions and 94 deletions

View 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;
}
}
}

View File

@ -0,0 +1,7 @@
namespace Ocelot.Configuration.Authentication
{
public interface IHashMatcher
{
bool Match(string password, string salt, string hash);
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;}
}
}

View File

@ -1,49 +1,12 @@
using System;
using System.Collections.Generic;
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Models;
using IdentityServer4.Test;
namespace Ocelot.Configuration.Provider
{
public class HardCodedIdentityServerConfigurationProvider : IIdentityServerConfigurationProvider
{
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 class IdentityServerConfiguration : IIdentityServerConfiguration
{
public IdentityServerConfiguration(
string identityServerUrl,
string apiName,
bool requireHttps,
SupportedTokens supportedTokens,
@ -54,9 +17,8 @@ namespace Ocelot.Configuration.Provider
IEnumerable<string> grantType,
AccessTokenType accessTokenType,
bool requireClientSecret,
List<TestUser> users)
List<User> users)
{
IdentityServerUrl = identityServerUrl;
ApiName = apiName;
RequireHttps = requireHttps;
SupportedTokens = supportedTokens;
@ -70,7 +32,6 @@ namespace Ocelot.Configuration.Provider
Users = users;
}
public string IdentityServerUrl { get; private set; }
public string ApiName { get; private set; }
public bool RequireHttps { 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 IEnumerable<string> AllowedGrantTypes {get;private set;}
public AccessTokenType AccessTokenType {get;private set;}
public bool RequireClientSecret = false;
public List<TestUser> Users {get;private set;}
public bool RequireClientSecret {get;private set;}
public List<User> Users {get;private set;}
}
}

View 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; }
}
}

View File

@ -14,6 +14,7 @@ using Ocelot.Authentication.Handler.Factory;
using Ocelot.Authorisation;
using Ocelot.Cache;
using Ocelot.Claims;
using Ocelot.Configuration.Authentication;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Parser;
@ -41,7 +42,6 @@ namespace Ocelot.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddOcelotOutputCaching(this IServiceCollection services, Action<ConfigurationBuilderCachePart> settings)
{
var cacheManagerOutputCache = CacheFactory.Build<HttpResponseMessage>("OcelotOutputCache", settings);
@ -51,24 +51,23 @@ namespace Ocelot.DependencyInjection
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.AddSingleton<IOcelotConfigurationCreator, FileOcelotConfigurationCreator>();
services.AddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
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)
{
services.AddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
services.AddSingleton<IHashMatcher, HashMatcher>();
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryApiResources(new List<ApiResource>
@ -101,8 +100,7 @@ namespace Ocelot.DependencyInjection
Enabled = identityServerConfiguration.Enabled,
RequireClientSecret = identityServerConfiguration.RequireClientSecret
}
})
.AddTestUsers(identityServerConfiguration.Users);
}).AddResourceOwnerValidator<OcelotResourceOwnerPasswordValidator>();
}
services.AddMvcCore()

View File

@ -37,21 +37,7 @@ namespace Ocelot.Middleware
/// <returns></returns>
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder)
{
await builder.UseOcelot(new OcelotMiddlewareConfiguration(), null);
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);
await builder.UseOcelot(new OcelotMiddlewareConfiguration());
return builder;
}
@ -62,9 +48,9 @@ namespace Ocelot.Middleware
/// <param name="builder"></param>
/// <param name="middlewareConfiguration"></param>
/// <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
builder.UseExceptionHandlerMiddleware();
@ -168,10 +154,12 @@ namespace Ocelot.Middleware
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 identityServerConfiguration = (IIdentityServerConfiguration)builder.ApplicationServices.GetService(typeof(IIdentityServerConfiguration));
if(!string.IsNullOrEmpty(configuration.AdministrationPath) && identityServerConfiguration != null)
{
var webHostBuilder = (IWebHostBuilder)builder.ApplicationServices.GetService(typeof(IWebHostBuilder));

View File

@ -29,7 +29,8 @@
"CacheManager.Microsoft.Extensions.Logging": "0.9.2",
"Consul": "0.7.2.1",
"Polly": "5.0.3",
"IdentityServer4": "1.0.1"
"IdentityServer4": "1.0.1",
"Microsoft.AspNetCore.Cryptography.KeyDerivation": "1.1.0"
},
"runtimes": {
"win10-x64": {},