commit to move to my back after hacking around at work..this is not simple :(

This commit is contained in:
Tom Pallister 2017-10-30 18:06:45 +00:00
parent 120532bb0d
commit fd9eae0152
3 changed files with 178 additions and 11 deletions

View File

@ -1,7 +1,9 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Extensions; using IdentityServer4.Extensions;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
@ -71,17 +73,37 @@ namespace Ocelot.Authentication.Middleware
{ {
_logger.LogDebug($"{context.Request.Path} is an authenticated route. {MiddlewareName} checking if client is authenticated"); _logger.LogDebug($"{context.Request.Path} is an authenticated route. {MiddlewareName} checking if client is authenticated");
var authenticationHandler = _authHandlerFactory.Get(_app, DownstreamRoute.ReRoute.AuthenticationOptions); //var authenticationHandler = _authHandlerFactory.Get(_app, DownstreamRoute.ReRoute.AuthenticationOptions);
if (authenticationHandler.IsError) /* if (authenticationHandler.IsError)
{ {
_logger.LogError($"Error getting authentication handler for {context.Request.Path}. {authenticationHandler.Errors.ToErrorString()}"); _logger.LogError($"Error getting authentication handler for {context.Request.Path}. {authenticationHandler.Errors.ToErrorString()}");
SetPipelineError(authenticationHandler.Errors); SetPipelineError(authenticationHandler.Errors);
return; return;
} }
await authenticationHandler.Data.Handler.Handle(context); await authenticationHandler.Data.Handler.Handle(context);*/
//todo - add the scheme for this route??
var auth = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
/* Action<IdentityServerAuthenticationOptions> configureOptions = o =>
{
o.Authority = "";
o.ApiName = "";
o.RequireHttpsMetadata = true;
o.SupportedTokens = SupportedTokens.Both;
o.ApiSecret = "";
};
*/
//var scheme = new AuthenticationScheme(DownstreamRoute.ReRoute.AuthenticationOptions.Provider, DownstreamRoute.ReRoute.AuthenticationOptions.Provider, typeof(IdentityServerAuthenticationHandler));
//auth.AddScheme(scheme);
//todo - call the next middleware to authenticate? Does this need to be on a different branch so it doesnt call any further middlewares?
var result = await context.AuthenticateAsync(DownstreamRoute.ReRoute.AuthenticationOptions.Provider);
context.User = result.Principal;
if (context.User.Identity.IsAuthenticated) if (context.User.Identity.IsAuthenticated)
{ {
@ -98,8 +120,10 @@ namespace Ocelot.Authentication.Middleware
_logger.LogError($"Client has NOT been authenticated for {context.Request.Path} and pipeline error set. {error.ToErrorString()}"); _logger.LogError($"Client has NOT been authenticated for {context.Request.Path} and pipeline error set. {error.ToErrorString()}");
SetPipelineError(error); SetPipelineError(error);
return;
} }
//todo - remove the scheme or do we leave it?
auth.RemoveScheme(DownstreamRoute.ReRoute.AuthenticationOptions.Provider);
} }
else else
{ {
@ -124,7 +148,7 @@ namespace Ocelot.Authentication.Middleware
protected override Task<AuthenticateResult> HandleAuthenticateAsync() protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{ {
var principal = new ClaimsPrincipal(); var principal = new ClaimsPrincipal();
var id = new ClaimsIdentity(); var id = new ClaimsIdentity("Ocelot");
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name)); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name));
if (Options.Instance != null) if (Options.Instance != null)
{ {

View File

@ -44,6 +44,7 @@ using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using IdentityServer4.AccessTokenValidation; using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@ -149,6 +150,27 @@ namespace Ocelot.DependencyInjection
{ {
services.AddIdentityServer(identityServerConfiguration, configurationRoot); services.AddIdentityServer(identityServerConfiguration, configurationRoot);
} }
services.AddSingleton(services);
Action<AuthenticationSchemeBuilder> builder = schemeBuilder =>
{
}
services.AddAuthentication(x =>
{
x.AddScheme("", );
})
.AddIdentityServerAuthentication(o =>
{
o.Authority = "http://localhost:51888";
o.ApiName = "api";
o.RequireHttpsMetadata = false;
o.SupportedTokens = SupportedTokens.Both;
o.ApiSecret = "secret";
});
return services; return services;
} }

View File

@ -0,0 +1,121 @@
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Net;
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Shouldly;
using Xunit;
namespace Ocelot.UnitTests
{
public class DynamicSchemeTests
{
[Fact]
public async Task OptionsAreConfiguredOnce()
{
var server = CreateServer(s =>
{
s.Configure<TestOptions>("One", o => o.Instance = new Singleton());
});
// Add One scheme
var response = await server.CreateClient().GetAsync("http://example.com/add/One");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var transaction = await server.CreateClient().GetAsync("http://example.com/auth/One");
var result = await transaction.Content.ReadAsStringAsync();
result.ShouldBe("True");
}
public class TestOptions : AuthenticationSchemeOptions
{
public Singleton Instance { get; set; }
}
public class Singleton
{
public static int _count;
public Singleton()
{
_count++;
Count = _count;
}
public int Count { get; }
}
private class TestHandler : AuthenticationHandler<TestOptions>
{
public TestHandler(IOptionsMonitor<TestOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var principal = new ClaimsPrincipal();
var id = new ClaimsIdentity("Ocelot");
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name));
if (Options.Instance != null)
{
id.AddClaim(new Claim("Count", Options.Instance.Count.ToString()));
}
principal.AddIdentity(id);
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name)));
}
}
private static TestServer CreateServer(Action<IServiceCollection> configureServices = null)
{
var builder = new WebHostBuilder()
.Configure(app =>
{
app.UseAuthentication();
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
if (req.Path.StartsWithSegments(new PathString("/add"), out var remainder))
{
var name = remainder.Value.Substring(1);
var auth = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = new AuthenticationScheme(name, name, typeof(TestHandler));
auth.AddScheme(scheme);
}
else if (req.Path.StartsWithSegments(new PathString("/auth"), out remainder))
{
var name = (remainder.Value.Length > 0) ? remainder.Value.Substring(1) : null;
var result = await context.AuthenticateAsync(name);
context.User = result.Principal;
await res.WriteJsonAsync(context.User.Identity.IsAuthenticated.ToString());
}
else if (req.Path.StartsWithSegments(new PathString("/remove"), out remainder))
{
var name = remainder.Value.Substring(1);
var auth = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
auth.RemoveScheme(name);
}
else
{
await next();
}
});
})
.ConfigureServices(services =>
{
configureServices?.Invoke(services);
services.AddAuthentication();
});
return new TestServer(builder);
}
}
}