Switch to new host apis (#23783)

* Update tests

* Switch to new host apis

* Update host apis

* Update CookieTests.cs

* Update tests

* PR feedback/cleanup

* More cleanup
This commit is contained in:
Hao Kung 2020-07-10 17:56:18 -07:00 committed by GitHub
parent 241e45d2b9
commit fae3dd12ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1482 additions and 1151 deletions

View File

@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity.Test; using Microsoft.AspNetCore.Identity.Test;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Xunit; using Xunit;
@ -31,7 +32,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CanChangePasswordOptions() public async Task CanChangePasswordOptions()
{ {
var clock = new TestClock(); var clock = new TestClock();
var server = CreateServer(services => services.Configure<IdentityOptions>(options => var server = await CreateServer(services => services.Configure<IdentityOptions>(options =>
{ {
options.Password.RequireUppercase = false; options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false; options.Password.RequireNonAlphanumeric = false;
@ -49,7 +50,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CookieContainsRoleClaim() public async Task CookieContainsRoleClaim()
{ {
var clock = new TestClock(); var clock = new TestClock();
var server = CreateServer(null, null, null, testCore: true); var server = await CreateServer(null, null, null, testCore: true);
var transaction1 = await SendAsync(server, "http://example.com/createMe"); var transaction1 = await SendAsync(server, "http://example.com/createMe");
Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode);
@ -70,7 +71,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CanCreateMeLoginAndCookieStopsWorkingAfterExpiration() public async Task CanCreateMeLoginAndCookieStopsWorkingAfterExpiration()
{ {
var clock = new TestClock(); var clock = new TestClock();
var server = CreateServer(services => var server = await CreateServer(services =>
{ {
services.ConfigureApplicationCookie(options => services.ConfigureApplicationCookie(options =>
{ {
@ -112,7 +113,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CanCreateMeLoginAndSecurityStampExtendsExpiration(bool rememberMe) public async Task CanCreateMeLoginAndSecurityStampExtendsExpiration(bool rememberMe)
{ {
var clock = new TestClock(); var clock = new TestClock();
var server = CreateServer(services => services.AddSingleton<ISystemClock>(clock)); var server = await CreateServer(services => services.AddSingleton<ISystemClock>(clock));
var transaction1 = await SendAsync(server, "http://example.com/createMe"); var transaction1 = await SendAsync(server, "http://example.com/createMe");
Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode);
@ -156,7 +157,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CanAccessOldPrincipalDuringSecurityStampReplacement() public async Task CanAccessOldPrincipalDuringSecurityStampReplacement()
{ {
var clock = new TestClock(); var clock = new TestClock();
var server = CreateServer(services => var server = await CreateServer(services =>
{ {
services.Configure<SecurityStampValidatorOptions>(options => services.Configure<SecurityStampValidatorOptions>(options =>
{ {
@ -207,7 +208,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task TwoFactorRememberCookieVerification() public async Task TwoFactorRememberCookieVerification()
{ {
var clock = new TestClock(); var clock = new TestClock();
var server = CreateServer(services => services.AddSingleton<ISystemClock>(clock)); var server = await CreateServer(services => services.AddSingleton<ISystemClock>(clock));
var transaction1 = await SendAsync(server, "http://example.com/createMe"); var transaction1 = await SendAsync(server, "http://example.com/createMe");
Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode);
@ -234,7 +235,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task TwoFactorRememberCookieClearedBySecurityStampChange() public async Task TwoFactorRememberCookieClearedBySecurityStampChange()
{ {
var clock = new TestClock(); var clock = new TestClock();
var server = CreateServer(services => services.AddSingleton<ISystemClock>(clock)); var server = await CreateServer(services => services.AddSingleton<ISystemClock>(clock));
var transaction1 = await SendAsync(server, "http://example.com/createMe"); var transaction1 = await SendAsync(server, "http://example.com/createMe");
Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode);
@ -285,111 +286,115 @@ namespace Microsoft.AspNetCore.Identity.InMemory
return me; return me;
} }
private static TestServer CreateServer(Action<IServiceCollection> configureServices = null, Func<HttpContext, Task> testpath = null, Uri baseAddress = null, bool testCore = false) private static async Task<TestServer> CreateServer(Action<IServiceCollection> configureServices = null, Func<HttpContext, Task> testpath = null, Uri baseAddress = null, bool testCore = false)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.Configure(app =>
app.UseAuthentication();
app.Use(async (context, next) =>
{ {
var req = context.Request; app.UseAuthentication();
var res = context.Response; app.Use(async (context, next) =>
var userManager = context.RequestServices.GetRequiredService<UserManager<PocoUser>>();
var roleManager = context.RequestServices.GetRequiredService<RoleManager<PocoRole>>();
var signInManager = context.RequestServices.GetRequiredService<SignInManager<PocoUser>>();
PathString remainder;
if (req.Path == new PathString("/normal"))
{ {
res.StatusCode = 200; var req = context.Request;
} var res = context.Response;
else if (req.Path == new PathString("/createMe")) var userManager = context.RequestServices.GetRequiredService<UserManager<PocoUser>>();
{ var roleManager = context.RequestServices.GetRequiredService<RoleManager<PocoRole>>();
var user = new PocoUser("hao"); var signInManager = context.RequestServices.GetRequiredService<SignInManager<PocoUser>>();
var result = await userManager.CreateAsync(user, TestPassword); PathString remainder;
if (result.Succeeded) if (req.Path == new PathString("/normal"))
{ {
result = await roleManager.CreateAsync(new PocoRole("role")); res.StatusCode = 200;
} }
if (result.Succeeded) else if (req.Path == new PathString("/createMe"))
{ {
result = await userManager.AddToRoleAsync(user, "role"); var user = new PocoUser("hao");
var result = await userManager.CreateAsync(user, TestPassword);
if (result.Succeeded)
{
result = await roleManager.CreateAsync(new PocoRole("role"));
}
if (result.Succeeded)
{
result = await userManager.AddToRoleAsync(user, "role");
}
res.StatusCode = result.Succeeded ? 200 : 500;
} }
res.StatusCode = result.Succeeded ? 200 : 500; else if (req.Path == new PathString("/createSimple"))
} {
else if (req.Path == new PathString("/createSimple")) var result = await userManager.CreateAsync(new PocoUser("simple"), "aaaaaa");
res.StatusCode = result.Succeeded ? 200 : 500;
}
else if (req.Path == new PathString("/signoutEverywhere"))
{
var user = await userManager.FindByNameAsync("hao");
var result = await userManager.UpdateSecurityStampAsync(user);
res.StatusCode = result.Succeeded ? 200 : 500;
}
else if (req.Path.StartsWithSegments(new PathString("/pwdLogin"), out remainder))
{
var isPersistent = bool.Parse(remainder.Value.Substring(1));
var result = await signInManager.PasswordSignInAsync("hao", TestPassword, isPersistent, false);
res.StatusCode = result.Succeeded ? 200 : 500;
}
else if (req.Path == new PathString("/twofactorRememeber"))
{
var user = await userManager.FindByNameAsync("hao");
await signInManager.RememberTwoFactorClientAsync(user);
res.StatusCode = 200;
}
else if (req.Path == new PathString("/isTwoFactorRememebered"))
{
var user = await userManager.FindByNameAsync("hao");
var result = await signInManager.IsTwoFactorClientRememberedAsync(user);
res.StatusCode = result ? 200 : 500;
}
else if (req.Path == new PathString("/hasTwoFactorUserId"))
{
var result = await context.AuthenticateAsync(IdentityConstants.TwoFactorUserIdScheme);
res.StatusCode = result.Succeeded ? 200 : 500;
}
else if (req.Path == new PathString("/me"))
{
await DescribeAsync(res, AuthenticateResult.Success(new AuthenticationTicket(context.User, null, "Application")));
}
else if (req.Path.StartsWithSegments(new PathString("/me"), out remainder))
{
var auth = await context.AuthenticateAsync(remainder.Value.Substring(1));
await DescribeAsync(res, auth);
}
else if (req.Path == new PathString("/testpath") && testpath != null)
{
await testpath(context);
}
else
{
await next();
}
});
})
.ConfigureServices(services =>
{
if (testCore)
{ {
var result = await userManager.CreateAsync(new PocoUser("simple"), "aaaaaa"); services.AddIdentityCore<PocoUser>()
res.StatusCode = result.Succeeded ? 200 : 500; .AddRoles<PocoRole>()
} .AddSignInManager()
else if (req.Path == new PathString("/signoutEverywhere")) .AddDefaultTokenProviders();
{ services.AddAuthentication(IdentityConstants.ApplicationScheme).AddIdentityCookies();
var user = await userManager.FindByNameAsync("hao");
var result = await userManager.UpdateSecurityStampAsync(user);
res.StatusCode = result.Succeeded ? 200 : 500;
}
else if (req.Path.StartsWithSegments(new PathString("/pwdLogin"), out remainder))
{
var isPersistent = bool.Parse(remainder.Value.Substring(1));
var result = await signInManager.PasswordSignInAsync("hao", TestPassword, isPersistent, false);
res.StatusCode = result.Succeeded ? 200 : 500;
}
else if (req.Path == new PathString("/twofactorRememeber"))
{
var user = await userManager.FindByNameAsync("hao");
await signInManager.RememberTwoFactorClientAsync(user);
res.StatusCode = 200;
}
else if (req.Path == new PathString("/isTwoFactorRememebered"))
{
var user = await userManager.FindByNameAsync("hao");
var result = await signInManager.IsTwoFactorClientRememberedAsync(user);
res.StatusCode = result ? 200 : 500;
}
else if (req.Path == new PathString("/hasTwoFactorUserId"))
{
var result = await context.AuthenticateAsync(IdentityConstants.TwoFactorUserIdScheme);
res.StatusCode = result.Succeeded ? 200 : 500;
}
else if (req.Path == new PathString("/me"))
{
await DescribeAsync(res, AuthenticateResult.Success(new AuthenticationTicket(context.User, null, "Application")));
}
else if (req.Path.StartsWithSegments(new PathString("/me"), out remainder))
{
var auth = await context.AuthenticateAsync(remainder.Value.Substring(1));
await DescribeAsync(res, auth);
}
else if (req.Path == new PathString("/testpath") && testpath != null)
{
await testpath(context);
} }
else else
{ {
await next(); services.AddIdentity<PocoUser, PocoRole>().AddDefaultTokenProviders();
} }
}); var store = new InMemoryStore<PocoUser, PocoRole>();
}) services.AddSingleton<IUserStore<PocoUser>>(store);
.ConfigureServices(services => services.AddSingleton<IRoleStore<PocoRole>>(store);
{ configureServices?.Invoke(services);
if (testCore) })
{ .UseTestServer())
services.AddIdentityCore<PocoUser>() .Build();
.AddRoles<PocoRole>() await host.StartAsync();
.AddSignInManager() var server = host.GetTestServer();
.AddDefaultTokenProviders();
services.AddAuthentication(IdentityConstants.ApplicationScheme).AddIdentityCookies();
}
else
{
services.AddIdentity<PocoUser, PocoRole>().AddDefaultTokenProviders();
}
var store = new InMemoryStore<PocoUser, PocoRole>();
services.AddSingleton<IUserStore<PocoUser>>(store);
services.AddSingleton<IRoleStore<PocoRole>>(store);
configureServices?.Invoke(services);
});
var server = new TestServer(builder);
server.BaseAddress = baseAddress; server.BaseAddress = baseAddress;
return server; return server;
} }

View File

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Authentication namespace Microsoft.AspNetCore.Authentication
@ -17,33 +18,38 @@ namespace Microsoft.AspNetCore.Authentication
[Fact] [Fact]
public async Task OnlyInvokesCanHandleRequestHandlers() public async Task OnlyInvokesCanHandleRequestHandlers()
{ {
var builder = new WebHostBuilder() using var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
app.UseAuthentication(); .Configure(app =>
}) {
.ConfigureServices(services => services.AddAuthentication(o => app.UseAuthentication();
{ })
o.AddScheme("Skip", s => .ConfigureServices(services => services.AddAuthentication(o =>
{ {
s.HandlerType = typeof(SkipHandler); o.AddScheme("Skip", s =>
}); {
// Won't get hit since CanHandleRequests is false s.HandlerType = typeof(SkipHandler);
o.AddScheme("throws", s => });
{ // Won't get hit since CanHandleRequests is false
s.HandlerType = typeof(ThrowsHandler); o.AddScheme("throws", s =>
}); {
o.AddScheme("607", s => s.HandlerType = typeof(ThrowsHandler);
{ });
s.HandlerType = typeof(SixOhSevenHandler); o.AddScheme("607", s =>
}); {
// Won't get run since 607 will finish s.HandlerType = typeof(SixOhSevenHandler);
o.AddScheme("305", s => });
{ // Won't get run since 607 will finish
s.HandlerType = typeof(ThreeOhFiveHandler); o.AddScheme("305", s =>
}); {
})); s.HandlerType = typeof(ThreeOhFiveHandler);
var server = new TestServer(builder); });
})))
.Build();
await host.StartAsync();
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("http://example.com/"); var response = await server.CreateClient().GetAsync("http://example.com/");
Assert.Equal(607, (int)response.StatusCode); Assert.Equal(607, (int)response.StatusCode);
} }
@ -191,6 +197,5 @@ namespace Microsoft.AspNetCore.Authentication
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }
} }
} }

View File

@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Authentication.Certificate.Test namespace Microsoft.AspNetCore.Authentication.Certificate.Test
@ -44,7 +45,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyValidSelfSignedWithClientEkuAuthenticates() public async Task VerifyValidSelfSignedWithClientEkuAuthenticates()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -52,6 +53,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithClientEku); Certificates.SelfSignedValidWithClientEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
@ -59,7 +61,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyValidSelfSignedWithNoEkuAuthenticates() public async Task VerifyValidSelfSignedWithNoEkuAuthenticates()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -67,6 +69,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithNoEku); Certificates.SelfSignedValidWithNoEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
@ -74,13 +77,14 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyValidSelfSignedWithClientEkuFailsWhenSelfSignedCertsNotAllowed() public async Task VerifyValidSelfSignedWithClientEkuFailsWhenSelfSignedCertsNotAllowed()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.Chained AllowedCertificateTypes = CertificateTypes.Chained
}, },
Certificates.SelfSignedValidWithClientEku); Certificates.SelfSignedValidWithClientEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -88,7 +92,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyValidSelfSignedWithNoEkuFailsWhenSelfSignedCertsNotAllowed() public async Task VerifyValidSelfSignedWithNoEkuFailsWhenSelfSignedCertsNotAllowed()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.Chained, AllowedCertificateTypes = CertificateTypes.Chained,
@ -96,6 +100,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithNoEku); Certificates.SelfSignedValidWithNoEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -103,7 +108,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyValidSelfSignedWithServerFailsEvenIfSelfSignedCertsAreAllowed() public async Task VerifyValidSelfSignedWithServerFailsEvenIfSelfSignedCertsAreAllowed()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -111,6 +116,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithServerEku); Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -118,7 +124,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyValidSelfSignedWithServerPassesWhenSelfSignedCertsAreAllowedAndPurposeValidationIsOff() public async Task VerifyValidSelfSignedWithServerPassesWhenSelfSignedCertsAreAllowedAndPurposeValidationIsOff()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -127,6 +133,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithServerEku); Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
@ -134,7 +141,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyValidSelfSignedWithServerFailsPurposeValidationIsOffButSelfSignedCertsAreNotAllowed() public async Task VerifyValidSelfSignedWithServerFailsPurposeValidationIsOffButSelfSignedCertsAreNotAllowed()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.Chained, AllowedCertificateTypes = CertificateTypes.Chained,
@ -143,6 +150,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithServerEku); Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -150,7 +158,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyExpiredSelfSignedFails() public async Task VerifyExpiredSelfSignedFails()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -159,6 +167,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedExpired); Certificates.SelfSignedExpired);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -166,7 +175,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyExpiredSelfSignedPassesIfDateRangeValidationIsDisabled() public async Task VerifyExpiredSelfSignedPassesIfDateRangeValidationIsDisabled()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -175,6 +184,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedExpired); Certificates.SelfSignedExpired);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
@ -182,7 +192,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyNotYetValidSelfSignedFails() public async Task VerifyNotYetValidSelfSignedFails()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -191,6 +201,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedNotYetValid); Certificates.SelfSignedNotYetValid);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -198,7 +209,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyNotYetValidSelfSignedPassesIfDateRangeValidationIsDisabled() public async Task VerifyNotYetValidSelfSignedPassesIfDateRangeValidationIsDisabled()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -207,6 +218,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedNotYetValid); Certificates.SelfSignedNotYetValid);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
@ -214,7 +226,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyFailingInTheValidationEventReturnsForbidden() public async Task VerifyFailingInTheValidationEventReturnsForbidden()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
ValidateCertificateUse = false, ValidateCertificateUse = false,
@ -222,6 +234,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithServerEku); Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -229,7 +242,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task DoingNothingInTheValidationEventReturnsOK() public async Task DoingNothingInTheValidationEventReturnsOK()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -238,6 +251,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithServerEku); Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
@ -245,12 +259,13 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyNotSendingACertificateEndsUpInForbidden() public async Task VerifyNotSendingACertificateEndsUpInForbidden()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
Events = successfulValidationEvents Events = successfulValidationEvents
}); });
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -258,12 +273,13 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyUntrustedClientCertEndsUpInForbidden() public async Task VerifyUntrustedClientCertEndsUpInForbidden()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
Events = successfulValidationEvents Events = successfulValidationEvents
}, Certificates.SignedClient); }, Certificates.SignedClient);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -271,7 +287,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyClientCertWithUntrustedRootAndTrustedChainEndsUpInForbidden() public async Task VerifyClientCertWithUntrustedRootAndTrustedChainEndsUpInForbidden()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
Events = successfulValidationEvents, Events = successfulValidationEvents,
@ -280,6 +296,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
RevocationMode = X509RevocationMode.NoCheck RevocationMode = X509RevocationMode.NoCheck
}, Certificates.SignedClient); }, Certificates.SignedClient);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
} }
@ -287,7 +304,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyValidClientCertWithTrustedChainAuthenticates() public async Task VerifyValidClientCertWithTrustedChainAuthenticates()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
Events = successfulValidationEvents, Events = successfulValidationEvents,
@ -296,6 +313,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
RevocationMode = X509RevocationMode.NoCheck RevocationMode = X509RevocationMode.NoCheck
}, Certificates.SignedClient); }, Certificates.SignedClient);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
@ -303,7 +321,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyHeaderIsUsedIfCertIsNotPresent() public async Task VerifyHeaderIsUsedIfCertIsNotPresent()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -311,6 +329,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
wireUpHeaderMiddleware: true); wireUpHeaderMiddleware: true);
using var server = host.GetTestServer();
var client = server.CreateClient(); var client = server.CreateClient();
client.DefaultRequestHeaders.Add("X-Client-Cert", Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData)); client.DefaultRequestHeaders.Add("X-Client-Cert", Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData));
var response = await client.GetAsync("https://example.com/"); var response = await client.GetAsync("https://example.com/");
@ -320,13 +339,14 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyHeaderEncodedCertFailsOnBadEncoding() public async Task VerifyHeaderEncodedCertFailsOnBadEncoding()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
Events = successfulValidationEvents Events = successfulValidationEvents
}, },
wireUpHeaderMiddleware: true); wireUpHeaderMiddleware: true);
using var server = host.GetTestServer();
var client = server.CreateClient(); var client = server.CreateClient();
client.DefaultRequestHeaders.Add("X-Client-Cert", "OOPS" + Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData)); client.DefaultRequestHeaders.Add("X-Client-Cert", "OOPS" + Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData));
var response = await client.GetAsync("https://example.com/"); var response = await client.GetAsync("https://example.com/");
@ -336,7 +356,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifySettingTheAzureHeaderOnTheForwarderOptionsWorks() public async Task VerifySettingTheAzureHeaderOnTheForwarderOptionsWorks()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -345,6 +365,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
wireUpHeaderMiddleware: true, wireUpHeaderMiddleware: true,
headerName: "X-ARR-ClientCert"); headerName: "X-ARR-ClientCert");
using var server = host.GetTestServer();
var client = server.CreateClient(); var client = server.CreateClient();
client.DefaultRequestHeaders.Add("X-ARR-ClientCert", Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData)); client.DefaultRequestHeaders.Add("X-ARR-ClientCert", Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData));
var response = await client.GetAsync("https://example.com/"); var response = await client.GetAsync("https://example.com/");
@ -354,7 +375,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyACustomHeaderFailsIfTheHeaderIsNotPresent() public async Task VerifyACustomHeaderFailsIfTheHeaderIsNotPresent()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
Events = successfulValidationEvents Events = successfulValidationEvents
@ -362,6 +383,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
wireUpHeaderMiddleware: true, wireUpHeaderMiddleware: true,
headerName: "X-ARR-ClientCert"); headerName: "X-ARR-ClientCert");
using var server = host.GetTestServer();
var client = server.CreateClient(); var client = server.CreateClient();
client.DefaultRequestHeaders.Add("random-Weird-header", Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData)); client.DefaultRequestHeaders.Add("random-Weird-header", Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData));
var response = await client.GetAsync("https://example.com/"); var response = await client.GetAsync("https://example.com/");
@ -371,13 +393,14 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact] [Fact]
public async Task VerifyNoEventWireupWithAValidCertificateCreatesADefaultUser() public async Task VerifyNoEventWireupWithAValidCertificateCreatesADefaultUser()
{ {
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned AllowedCertificateTypes = CertificateTypes.SelfSigned
}, },
Certificates.SelfSignedValidWithNoEku); Certificates.SelfSignedValidWithNoEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -481,7 +504,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
const string Expected = "John Doe"; const string Expected = "John Doe";
var validationCount = 0; var validationCount = 0;
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -508,6 +531,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithNoEku, null, null, false, "", cache); Certificates.SelfSignedValidWithNoEku, null, null, false, "", cache);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -554,7 +578,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
{ {
const string Expected = "John Doe"; const string Expected = "John Doe";
var server = CreateServer( using var host = await CreateHost(
new CertificateAuthenticationOptions new CertificateAuthenticationOptions
{ {
AllowedCertificateTypes = CertificateTypes.SelfSigned, AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -577,6 +601,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
}, },
Certificates.SelfSignedValidWithNoEku); Certificates.SelfSignedValidWithNoEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/"); var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -596,7 +621,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
Assert.Single(responseAsXml.Elements("claim")); Assert.Single(responseAsXml.Elements("claim"));
} }
private static TestServer CreateServer( private static async Task<IHost> CreateHost(
CertificateAuthenticationOptions configureOptions, CertificateAuthenticationOptions configureOptions,
X509Certificate2 clientCertificate = null, X509Certificate2 clientCertificate = null,
Func<HttpContext, bool> handler = null, Func<HttpContext, bool> handler = null,
@ -605,92 +630,95 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
string headerName = "", string headerName = "",
bool useCache = false) bool useCache = false)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
app.Use((context, next) => .Configure(app =>
{
if (clientCertificate != null)
{ {
context.Connection.ClientCertificate = clientCertificate; app.Use((context, next) =>
}
return next();
});
if (wireUpHeaderMiddleware)
{
app.UseCertificateForwarding();
}
app.UseAuthentication();
app.Use(async (context, next) =>
{
var request = context.Request;
var response = context.Response;
var authenticationResult = await context.AuthenticateAsync();
if (authenticationResult.Succeeded)
{
response.StatusCode = (int)HttpStatusCode.OK;
response.ContentType = "text/xml";
await response.WriteAsync("<claims>");
foreach (Claim claim in context.User.Claims)
{ {
await response.WriteAsync($"<claim Type=\"{claim.Type}\" Issuer=\"{claim.Issuer}\">{claim.Value}</claim>"); if (clientCertificate != null)
{
context.Connection.ClientCertificate = clientCertificate;
}
return next();
});
if (wireUpHeaderMiddleware)
{
app.UseCertificateForwarding();
} }
await response.WriteAsync("</claims>");
app.UseAuthentication();
app.Use(async (context, next) =>
{
var request = context.Request;
var response = context.Response;
var authenticationResult = await context.AuthenticateAsync();
if (authenticationResult.Succeeded)
{
response.StatusCode = (int)HttpStatusCode.OK;
response.ContentType = "text/xml";
await response.WriteAsync("<claims>");
foreach (Claim claim in context.User.Claims)
{
await response.WriteAsync($"<claim Type=\"{claim.Type}\" Issuer=\"{claim.Issuer}\">{claim.Value}</claim>");
}
await response.WriteAsync("</claims>");
}
else
{
await context.ChallengeAsync();
}
});
})
.ConfigureServices(services =>
{
AuthenticationBuilder authBuilder;
if (configureOptions != null)
{
authBuilder = services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>
{
options.CustomTrustStore = configureOptions.CustomTrustStore;
options.ChainTrustValidationMode = configureOptions.ChainTrustValidationMode;
options.AllowedCertificateTypes = configureOptions.AllowedCertificateTypes;
options.Events = configureOptions.Events;
options.ValidateCertificateUse = configureOptions.ValidateCertificateUse;
options.RevocationFlag = configureOptions.RevocationFlag;
options.RevocationMode = configureOptions.RevocationMode;
options.ValidateValidityPeriod = configureOptions.ValidateValidityPeriod;
});
} }
else else
{ {
await context.ChallengeAsync(); authBuilder = services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate();
}
if (useCache)
{
authBuilder.AddCertificateCache();
} }
});
})
.ConfigureServices(services =>
{
AuthenticationBuilder authBuilder;
if (configureOptions != null)
{
authBuilder = services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>
{
options.CustomTrustStore = configureOptions.CustomTrustStore;
options.ChainTrustValidationMode = configureOptions.ChainTrustValidationMode;
options.AllowedCertificateTypes = configureOptions.AllowedCertificateTypes;
options.Events = configureOptions.Events;
options.ValidateCertificateUse = configureOptions.ValidateCertificateUse;
options.RevocationFlag = configureOptions.RevocationFlag;
options.RevocationMode = configureOptions.RevocationMode;
options.ValidateValidityPeriod = configureOptions.ValidateValidityPeriod;
});
}
else
{
authBuilder = services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate();
}
if (useCache)
{
authBuilder.AddCertificateCache();
}
if (wireUpHeaderMiddleware && !string.IsNullOrEmpty(headerName)) if (wireUpHeaderMiddleware && !string.IsNullOrEmpty(headerName))
{ {
services.AddCertificateForwarding(options => services.AddCertificateForwarding(options =>
{ {
options.CertificateHeader = headerName; options.CertificateHeader = headerName;
}); });
} }
}); }))
.Build();
var server = new TestServer(builder) await host.StartAsync();
{
BaseAddress = baseAddress
};
return server;
var server = host.GetTestServer();
server.BaseAddress = baseAddress;
return host;
} }
private CertificateAuthenticationEvents successfulValidationEvents = new CertificateAuthenticationEvents() private CertificateAuthenticationEvents successfulValidationEvents = new CertificateAuthenticationEvents()

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Xunit; using Xunit;
@ -21,12 +22,13 @@ namespace Microsoft.AspNetCore.Authentication
[Fact] [Fact]
public async Task OptionsAreConfiguredOnce() public async Task OptionsAreConfiguredOnce()
{ {
var server = CreateServer(s => using var host = await CreateHost(s =>
{ {
s.Configure<TestOptions>("One", o => o.Instance = new Singleton()); s.Configure<TestOptions>("One", o => o.Instance = new Singleton());
s.Configure<TestOptions>("Two", o => o.Instance = new Singleton()); s.Configure<TestOptions>("Two", o => o.Instance = new Singleton());
}); });
// Add One scheme // Add One scheme
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("http://example.com/add/One"); var response = await server.CreateClient().GetAsync("http://example.com/add/One");
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var transaction = await server.SendAsync("http://example.com/auth/One"); var transaction = await server.SendAsync("http://example.com/auth/One");
@ -57,7 +59,8 @@ namespace Microsoft.AspNetCore.Authentication
[Fact] [Fact]
public async Task CanAddAndRemoveSchemes() public async Task CanAddAndRemoveSchemes()
{ {
var server = CreateServer(); using var host = await CreateHost();
using var server = host.GetTestServer();
await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("http://example.com/auth/One")); await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("http://example.com/auth/One"));
// Add One scheme // Add One scheme
@ -124,47 +127,52 @@ namespace Microsoft.AspNetCore.Authentication
} }
} }
private static TestServer CreateServer(Action<IServiceCollection> configureServices = null) private static async Task<IHost> CreateHost(Action<IServiceCollection> configureServices = null)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
app.UseAuthentication(); .Configure(app =>
app.Use(async (context, next) => {
{ app.UseAuthentication();
var req = context.Request; app.Use(async (context, next) =>
var res = context.Response; {
if (req.Path.StartsWithSegments(new PathString("/add"), out var remainder)) 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);
await res.DescribeAsync(result?.Ticket?.Principal);
}
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 =>
{ {
var name = remainder.Value.Substring(1); configureServices?.Invoke(services);
var auth = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>(); services.AddAuthentication();
var scheme = new AuthenticationScheme(name, name, typeof(TestHandler)); }))
auth.AddScheme(scheme); .Build();
}
else if (req.Path.StartsWithSegments(new PathString("/auth"), out remainder)) await host.StartAsync();
{ return host;
var name = (remainder.Value.Length > 0) ? remainder.Value.Substring(1) : null;
var result = await context.AuthenticateAsync(name);
await res.DescribeAsync(result?.Ticket?.Principal);
}
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);
} }
} }
} }

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using System; using System;
using System.Linq; using System.Linq;
@ -47,7 +48,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact] [Fact]
public async Task ThrowsIfAppIdMissing() public async Task ThrowsIfAppIdMissing()
{ {
var server = CreateServer( using var host = await CreateHost(
app => { }, app => { },
services => services.AddAuthentication().AddFacebook(o => o.SignInScheme = "Whatever"), services => services.AddAuthentication().AddFacebook(o => o.SignInScheme = "Whatever"),
async context => async context =>
@ -55,6 +56,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
await Assert.ThrowsAsync<ArgumentException>("AppId", () => context.ChallengeAsync("Facebook")); await Assert.ThrowsAsync<ArgumentException>("AppId", () => context.ChallengeAsync("Facebook"));
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -62,7 +64,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact] [Fact]
public async Task ThrowsIfAppSecretMissing() public async Task ThrowsIfAppSecretMissing()
{ {
var server = CreateServer( using var host = await CreateHost(
app => { }, app => { },
services => services.AddAuthentication().AddFacebook(o => o.AppId = "Whatever"), services => services.AddAuthentication().AddFacebook(o => o.AppId = "Whatever"),
async context => async context =>
@ -70,6 +72,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
await Assert.ThrowsAsync<ArgumentException>("AppSecret", () => context.ChallengeAsync("Facebook")); await Assert.ThrowsAsync<ArgumentException>("AppSecret", () => context.ChallengeAsync("Facebook"));
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -77,7 +80,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact] [Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent() public async Task ChallengeWillTriggerApplyRedirectEvent()
{ {
var server = CreateServer( using var host = await CreateHost(
app => app =>
{ {
app.UseAuthentication(); app.UseAuthentication();
@ -105,6 +108,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
await context.ChallengeAsync("Facebook"); await context.ChallengeAsync("Facebook");
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var query = transaction.Response.Headers.Location.Query; var query = transaction.Response.Headers.Location.Query;
@ -114,7 +118,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact] [Fact]
public async Task ChallengeWillIncludeScopeAsConfigured() public async Task ChallengeWillIncludeScopeAsConfigured()
{ {
var server = CreateServer( using var host = await CreateHost(
app => app.UseAuthentication(), app => app.UseAuthentication(),
services => services =>
{ {
@ -133,6 +137,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
var res = transaction.Response; var res = transaction.Response;
@ -143,7 +148,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact] [Fact]
public async Task ChallengeWillIncludeScopeAsOverwritten() public async Task ChallengeWillIncludeScopeAsOverwritten()
{ {
var server = CreateServer( using var host = await CreateHost(
app => app.UseAuthentication(), app => app.UseAuthentication(),
services => services =>
{ {
@ -164,6 +169,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
var res = transaction.Response; var res = transaction.Response;
@ -174,7 +180,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact] [Fact]
public async Task ChallengeWillIncludeScopeAsOverwrittenWithBaseAuthenticationProperties() public async Task ChallengeWillIncludeScopeAsOverwrittenWithBaseAuthenticationProperties()
{ {
var server = CreateServer( using var host = await CreateHost(
app => app.UseAuthentication(), app => app.UseAuthentication(),
services => services =>
{ {
@ -195,6 +201,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
var res = transaction.Response; var res = transaction.Response;
@ -205,7 +212,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact] [Fact]
public async Task NestedMapWillNotAffectRedirect() public async Task NestedMapWillNotAffectRedirect()
{ {
var server = CreateServer(app => app.Map("/base", map => using var host = await CreateHost(app => app.Map("/base", map =>
{ {
map.UseAuthentication(); map.UseAuthentication();
map.Map("/login", signoutApp => signoutApp.Run(context => context.ChallengeAsync("Facebook", new AuthenticationProperties() { RedirectUri = "/" }))); map.Map("/login", signoutApp => signoutApp.Run(context => context.ChallengeAsync("Facebook", new AuthenticationProperties() { RedirectUri = "/" })));
@ -222,6 +229,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
}, },
handler: null); handler: null);
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/base/login"); var transaction = await server.SendAsync("http://example.com/base/login");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri; var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -236,7 +244,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact] [Fact]
public async Task MapWillNotAffectRedirect() public async Task MapWillNotAffectRedirect()
{ {
var server = CreateServer( using var host = await CreateHost(
app => app =>
{ {
app.UseAuthentication(); app.UseAuthentication();
@ -254,6 +262,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
}); });
}, },
handler: null); handler: null);
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/login"); var transaction = await server.SendAsync("http://example.com/login");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri; var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -268,7 +277,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact] [Fact]
public async Task ChallengeWillTriggerRedirection() public async Task ChallengeWillTriggerRedirection()
{ {
var server = CreateServer( using var host = await CreateHost(
app => app.UseAuthentication(), app => app.UseAuthentication(),
services => services =>
{ {
@ -288,6 +297,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
await context.ChallengeAsync("Facebook"); await context.ChallengeAsync("Facebook");
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri; var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -305,7 +315,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
var customUserInfoEndpoint = "https://graph.facebook.com/me?fields=email,timezone,picture"; var customUserInfoEndpoint = "https://graph.facebook.com/me?fields=email,timezone,picture";
var finalUserInfoEndpoint = string.Empty; var finalUserInfoEndpoint = string.Empty;
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("FacebookTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("FacebookTest"));
var server = CreateServer( using var host = await CreateHost(
app => app.UseAuthentication(), app => app.UseAuthentication(),
services => services =>
{ {
@ -350,6 +360,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-facebook?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-facebook?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Facebook.{correlationValue}=N"); $".AspNetCore.Correlation.Facebook.{correlationValue}=N");
@ -360,22 +371,27 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
Assert.Contains("&access_token=", finalUserInfoEndpoint); Assert.Contains("&access_token=", finalUserInfoEndpoint);
} }
private static TestServer CreateServer(Action<IApplicationBuilder> configure, Action<IServiceCollection> configureServices, Func<HttpContext, Task<bool>> handler) private static async Task<IHost> CreateHost(Action<IApplicationBuilder> configure, Action<IServiceCollection> configureServices, Func<HttpContext, Task<bool>> handler)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
configure?.Invoke(app); .Configure(app =>
app.Use(async (context, next) =>
{
if (handler == null || !await handler(context))
{ {
await next(); configure?.Invoke(app);
} app.Use(async (context, next) =>
}); {
}) if (handler == null || !await handler(context))
.ConfigureServices(configureServices); {
return new TestServer(builder); await next();
}
});
})
.ConfigureServices(configureServices))
.Build();
await host.StartAsync();
return host;
} }
} }
} }

View File

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -48,11 +49,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task ChallengeWillTriggerRedirection() public async Task ChallengeWillTriggerRedirection()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge"); var transaction = await server.SendAsync("https://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.ToString(); var location = transaction.Response.Headers.Location.ToString();
@ -72,11 +74,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task SignInThrows() public async Task SignInThrows()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signIn"); var transaction = await server.SendAsync("https://example.com/signIn");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -84,11 +87,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task SignOutThrows() public async Task SignOutThrows()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut"); var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -96,11 +100,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task ForbidThrows() public async Task ForbidThrows()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut"); var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -108,11 +113,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task Challenge401WillNotTriggerRedirection() public async Task Challenge401WillNotTriggerRedirection()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/401"); var transaction = await server.SendAsync("https://example.com/401");
Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode);
} }
@ -120,11 +126,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task ChallengeWillSetCorrelationCookie() public async Task ChallengeWillSetCorrelationCookie()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge"); var transaction = await server.SendAsync("https://example.com/challenge");
Assert.Contains(transaction.SetCookie, cookie => cookie.StartsWith(".AspNetCore.Correlation.Google.")); Assert.Contains(transaction.SetCookie, cookie => cookie.StartsWith(".AspNetCore.Correlation.Google."));
} }
@ -132,11 +139,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task ChallengeWillSetDefaultScope() public async Task ChallengeWillSetDefaultScope()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge"); var transaction = await server.SendAsync("https://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var query = transaction.Response.Headers.Location.Query; var query = transaction.Response.Headers.Location.Query;
@ -147,7 +155,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ChallengeWillUseAuthenticationPropertiesParametersAsQueryArguments() public async Task ChallengeWillUseAuthenticationPropertiesParametersAsQueryArguments()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -172,6 +180,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
return Task.FromResult<object>(null); return Task.FromResult<object>(null);
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge2"); var transaction = await server.SendAsync("https://example.com/challenge2");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -198,7 +207,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ChallengeWillUseAuthenticationPropertiesItemsAsParameters() public async Task ChallengeWillUseAuthenticationPropertiesItemsAsParameters()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -223,6 +232,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
return Task.FromResult<object>(null); return Task.FromResult<object>(null);
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge2"); var transaction = await server.SendAsync("https://example.com/challenge2");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -249,7 +259,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ChallengeWillUseAuthenticationPropertiesItemsAsQueryArgumentsButParametersWillOverwrite() public async Task ChallengeWillUseAuthenticationPropertiesItemsAsQueryArgumentsButParametersWillOverwrite()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -278,6 +288,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
return Task.FromResult<object>(null); return Task.FromResult<object>(null);
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge2"); var transaction = await server.SendAsync("https://example.com/challenge2");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -303,7 +314,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent() public async Task ChallengeWillTriggerApplyRedirectEvent()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -316,6 +327,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
} }
}; };
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge"); var transaction = await server.SendAsync("https://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var query = transaction.Response.Headers.Location.Query; var query = transaction.Response.Headers.Location.Query;
@ -325,7 +337,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task AuthenticateWithoutCookieWillFail() public async Task AuthenticateWithoutCookieWillFail()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -340,6 +352,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
Assert.NotNull(result.Failure); Assert.NotNull(result.Failure);
} }
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/auth"); var transaction = await server.SendAsync("https://example.com/auth");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -347,11 +360,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task ReplyPathWithoutStateQueryStringWillBeRejected() public async Task ReplyPathWithoutStateQueryStringWillBeRejected()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var error = await Assert.ThrowsAnyAsync<Exception>(() => server.SendAsync("https://example.com/signin-google?code=TestCode")); var error = await Assert.ThrowsAnyAsync<Exception>(() => server.SendAsync("https://example.com/signin-google?code=TestCode"));
Assert.Equal("The oauth state was missing or invalid.", error.GetBaseException().Message); Assert.Equal("The oauth state was missing or invalid.", error.GetBaseException().Message);
} }
@ -361,7 +375,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[InlineData(false)] [InlineData(false)]
public async Task ReplyPathWithAccessDeniedErrorFails(bool redirect) public async Task ReplyPathWithAccessDeniedErrorFails(bool redirect)
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -376,6 +390,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
} }
} : new OAuthEvents(); } : new OAuthEvents();
}); });
using var server = host.GetTestServer();
var sendTask = server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=SoBad&error_uri=foobar&state=protected_state", var sendTask = server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=SoBad&error_uri=foobar&state=protected_state",
".AspNetCore.Correlation.Google.correlationId=N"); ".AspNetCore.Correlation.Google.correlationId=N");
if (redirect) if (redirect)
@ -394,7 +409,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task ReplyPathWithAccessDeniedError_AllowsCustomizingPath() public async Task ReplyPathWithAccessDeniedError_AllowsCustomizingPath()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -414,6 +429,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
} }
}; };
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=SoBad&error_uri=foobar&state=protected_state", var transaction = await server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=SoBad&error_uri=foobar&state=protected_state",
".AspNetCore.Correlation.Google.correlationId=N"); ".AspNetCore.Correlation.Google.correlationId=N");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -425,7 +441,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
{ {
var accessDeniedCalled = false; var accessDeniedCalled = false;
var remoteFailureCalled = false; var remoteFailureCalled = false;
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -456,6 +472,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
} }
}; };
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=whyitfailed&error_uri=https://example.com/fail&state=protected_state", var transaction = await server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=whyitfailed&error_uri=https://example.com/fail&state=protected_state",
".AspNetCore.Correlation.Google.correlationId=N"); ".AspNetCore.Correlation.Google.correlationId=N");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -469,7 +486,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[InlineData(false)] [InlineData(false)]
public async Task ReplyPathWithErrorFails(bool redirect) public async Task ReplyPathWithErrorFails(bool redirect)
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -491,6 +508,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
} }
} : new OAuthEvents(); } : new OAuthEvents();
}); });
using var server = host.GetTestServer();
var sendTask = server.SendAsync("https://example.com/signin-google?error=itfailed&error_description=whyitfailed&error_uri=https://example.com/fail&state=protected_state", var sendTask = server.SendAsync("https://example.com/signin-google?error=itfailed&error_description=whyitfailed&error_uri=https://example.com/fail&state=protected_state",
".AspNetCore.Correlation.Google.correlationId=N"); ".AspNetCore.Correlation.Google.correlationId=N");
if (redirect) if (redirect)
@ -512,7 +530,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string claimsIssuer) public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string claimsIssuer)
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -531,6 +549,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -567,7 +586,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ReplyPathWillThrowIfCodeIsInvalid(bool redirect) public async Task ReplyPathWillThrowIfCodeIsInvalid(bool redirect)
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -597,6 +616,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var sendTask = server.SendAsync( var sendTask = server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -620,7 +640,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ReplyPathWillRejectIfAccessTokenIsMissing(bool redirect) public async Task ReplyPathWillRejectIfAccessTokenIsMissing(bool redirect)
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -648,6 +668,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var sendTask = server.SendAsync( var sendTask = server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -669,7 +690,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task AuthenticatedEventCanGetRefreshToken() public async Task AuthenticatedEventCanGetRefreshToken()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -691,6 +712,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -710,7 +732,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task NullRedirectUriWillRedirectToSlash() public async Task NullRedirectUriWillRedirectToSlash()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -730,6 +752,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
var correlationValue = "TestCorrelationId"; var correlationValue = "TestCorrelationId";
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -744,7 +767,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ValidateAuthenticatedContext() public async Task ValidateAuthenticatedContext()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -776,6 +799,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
//Post a message to the Google middleware //Post a message to the Google middleware
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -787,13 +811,14 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact] [Fact]
public async Task NoStateCausesException() public async Task NoStateCausesException()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
//Post a message to the Google middleware //Post a message to the Google middleware
using var server = host.GetTestServer();
var error = await Assert.ThrowsAnyAsync<Exception>(() => server.SendAsync("https://example.com/signin-google?code=TestCode")); var error = await Assert.ThrowsAnyAsync<Exception>(() => server.SendAsync("https://example.com/signin-google?code=TestCode"));
Assert.Equal("The oauth state was missing or invalid.", error.GetBaseException().Message); Assert.Equal("The oauth state was missing or invalid.", error.GetBaseException().Message);
} }
@ -802,7 +827,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task CanRedirectOnError() public async Task CanRedirectOnError()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -818,6 +843,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
}); });
//Post a message to the Google middleware //Post a message to the Google middleware
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode"); "https://example.com/signin-google?code=TestCode");
@ -830,7 +856,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task AuthenticateAutomaticWhenAlreadySignedInSucceeds() public async Task AuthenticateAutomaticWhenAlreadySignedInSucceeds()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -847,6 +873,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -873,7 +900,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task AuthenticateGoogleWhenAlreadySignedInSucceeds() public async Task AuthenticateGoogleWhenAlreadySignedInSucceeds()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -890,6 +917,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -916,7 +944,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task AuthenticateFacebookWhenAlreadySignedWithGoogleReturnsNull() public async Task AuthenticateFacebookWhenAlreadySignedWithGoogleReturnsNull()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -933,6 +961,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -952,7 +981,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ChallengeFacebookWhenAlreadySignedWithGoogleSucceeds() public async Task ChallengeFacebookWhenAlreadySignedWithGoogleSucceeds()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -969,6 +998,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N"); $".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -1040,99 +1070,104 @@ namespace Microsoft.AspNetCore.Authentication.Google
} }
} }
private static TestServer CreateServer(Action<GoogleOptions> configureOptions, Func<HttpContext, Task> testpath = null) private static async Task<IHost> CreateHost(Action<GoogleOptions> configureOptions, Func<HttpContext, Task> testpath = null)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
app.UseAuthentication(); .Configure(app =>
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
if (req.Path == new PathString("/challenge"))
{ {
await context.ChallengeAsync(); app.UseAuthentication();
} app.Use(async (context, next) =>
else if (req.Path == new PathString("/challengeFacebook")) {
var req = context.Request;
var res = context.Response;
if (req.Path == new PathString("/challenge"))
{
await context.ChallengeAsync();
}
else if (req.Path == new PathString("/challengeFacebook"))
{
await context.ChallengeAsync("Facebook");
}
else if (req.Path == new PathString("/tokens"))
{
var result = await context.AuthenticateAsync(TestExtensions.CookieAuthenticationScheme);
var tokens = result.Properties.GetTokens();
await res.DescribeAsync(tokens);
}
else if (req.Path == new PathString("/me"))
{
await res.DescribeAsync(context.User);
}
else if (req.Path == new PathString("/authenticate"))
{
var result = await context.AuthenticateAsync(TestExtensions.CookieAuthenticationScheme);
await res.DescribeAsync(result.Principal);
}
else if (req.Path == new PathString("/authenticateGoogle"))
{
var result = await context.AuthenticateAsync("Google");
await res.DescribeAsync(result?.Principal);
}
else if (req.Path == new PathString("/authenticateFacebook"))
{
var result = await context.AuthenticateAsync("Facebook");
await res.DescribeAsync(result?.Principal);
}
else if (req.Path == new PathString("/unauthorized"))
{
// Simulate Authorization failure
var result = await context.AuthenticateAsync("Google");
await context.ChallengeAsync("Google");
}
else if (req.Path == new PathString("/unauthorizedAuto"))
{
var result = await context.AuthenticateAsync("Google");
await context.ChallengeAsync("Google");
}
else if (req.Path == new PathString("/401"))
{
res.StatusCode = 401;
}
else if (req.Path == new PathString("/signIn"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("Google", new ClaimsPrincipal()));
}
else if (req.Path == new PathString("/signOut"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync("Google"));
}
else if (req.Path == new PathString("/forbid"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.ForbidAsync("Google"));
}
else if (testpath != null)
{
await testpath(context);
}
else
{
await next();
}
});
})
.ConfigureServices(services =>
{ {
await context.ChallengeAsync("Facebook"); services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
} services.AddAuthentication(TestExtensions.CookieAuthenticationScheme)
else if (req.Path == new PathString("/tokens")) .AddCookie(TestExtensions.CookieAuthenticationScheme, o => o.ForwardChallenge = GoogleDefaults.AuthenticationScheme)
{ .AddGoogle(configureOptions)
var result = await context.AuthenticateAsync(TestExtensions.CookieAuthenticationScheme); .AddFacebook(o =>
var tokens = result.Properties.GetTokens(); {
await res.DescribeAsync(tokens); o.ClientId = "Test ClientId";
} o.ClientSecret = "Test AppSecrent";
else if (req.Path == new PathString("/me")) });
{ }))
await res.DescribeAsync(context.User); .Build();
}
else if (req.Path == new PathString("/authenticate")) await host.StartAsync();
{ return host;
var result = await context.AuthenticateAsync(TestExtensions.CookieAuthenticationScheme);
await res.DescribeAsync(result.Principal);
}
else if (req.Path == new PathString("/authenticateGoogle"))
{
var result = await context.AuthenticateAsync("Google");
await res.DescribeAsync(result?.Principal);
}
else if (req.Path == new PathString("/authenticateFacebook"))
{
var result = await context.AuthenticateAsync("Facebook");
await res.DescribeAsync(result?.Principal);
}
else if (req.Path == new PathString("/unauthorized"))
{
// Simulate Authorization failure
var result = await context.AuthenticateAsync("Google");
await context.ChallengeAsync("Google");
}
else if (req.Path == new PathString("/unauthorizedAuto"))
{
var result = await context.AuthenticateAsync("Google");
await context.ChallengeAsync("Google");
}
else if (req.Path == new PathString("/401"))
{
res.StatusCode = 401;
}
else if (req.Path == new PathString("/signIn"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("Google", new ClaimsPrincipal()));
}
else if (req.Path == new PathString("/signOut"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync("Google"));
}
else if (req.Path == new PathString("/forbid"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.ForbidAsync("Google"));
}
else if (testpath != null)
{
await testpath(context);
}
else
{
await next();
}
});
})
.ConfigureServices(services =>
{
services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
services.AddAuthentication(TestExtensions.CookieAuthenticationScheme)
.AddCookie(TestExtensions.CookieAuthenticationScheme, o => o.ForwardChallenge = GoogleDefaults.AuthenticationScheme)
.AddGoogle(configureOptions)
.AddFacebook(o =>
{
o.ClientId = "Test ClientId";
o.ClientSecret = "Test AppSecrent";
});
});
return new TestServer(builder);
} }
private class TestStateDataFormat : ISecureDataFormat<AuthenticationProperties> private class TestStateDataFormat : ISecureDataFormat<AuthenticationProperties>

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using System; using System;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
@ -61,7 +62,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
var tokenText = new JwtSecurityTokenHandler().WriteToken(token); var tokenText = new JwtSecurityTokenHandler().WriteToken(token);
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.TokenValidationParameters = new TokenValidationParameters() o.TokenValidationParameters = new TokenValidationParameters()
{ {
@ -72,6 +73,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}); });
var newBearerToken = "Bearer " + tokenText; var newBearerToken = "Bearer " + tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", newBearerToken); var response = await SendAsync(server, "http://example.com/oauth", newBearerToken);
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
} }
@ -96,7 +98,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
var tokenText = new JwtSecurityTokenHandler().WriteToken(token); var tokenText = new JwtSecurityTokenHandler().WriteToken(token);
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.SaveToken = true; o.SaveToken = true;
o.TokenValidationParameters = new TokenValidationParameters() o.TokenValidationParameters = new TokenValidationParameters()
@ -108,6 +110,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}); });
var newBearerToken = "Bearer " + tokenText; var newBearerToken = "Bearer " + tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/token", newBearerToken); var response = await SendAsync(server, "http://example.com/token", newBearerToken);
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal(tokenText, await response.Response.Content.ReadAsStringAsync()); Assert.Equal(tokenText, await response.Response.Content.ReadAsStringAsync());
@ -116,7 +119,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task SignInThrows() public async Task SignInThrows()
{ {
var server = CreateServer(); using var host = await CreateHost();
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signIn"); var transaction = await server.SendAsync("https://example.com/signIn");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -124,7 +128,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task SignOutThrows() public async Task SignOutThrows()
{ {
var server = CreateServer(); using var host = await CreateHost();
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut"); var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -132,7 +137,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task ThrowAtAuthenticationFailedEvent() public async Task ThrowAtAuthenticationFailedEvent()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.Events = new JwtBearerEvents o.Events = new JwtBearerEvents
{ {
@ -164,6 +169,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
} }
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signIn"); var transaction = await server.SendAsync("https://example.com/signIn");
Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode);
@ -172,7 +178,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task CustomHeaderReceived() public async Task CustomHeaderReceived()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.Events = new JwtBearerEvents() o.Events = new JwtBearerEvents()
{ {
@ -193,6 +199,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}; };
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "someHeader someblob"); var response = await SendAsync(server, "http://example.com/oauth", "someHeader someblob");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal("Bob le Magnifique", response.ResponseText); Assert.Equal("Bob le Magnifique", response.ResponseText);
@ -201,7 +208,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task NoHeaderReceived() public async Task NoHeaderReceived()
{ {
var server = CreateServer(); using var host = await CreateHost();
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth"); var response = await SendAsync(server, "http://example.com/oauth");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
} }
@ -209,7 +217,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task HeaderWithoutBearerReceived() public async Task HeaderWithoutBearerReceived()
{ {
var server = CreateServer(); using var host = await CreateHost();
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Token"); var response = await SendAsync(server, "http://example.com/oauth", "Token");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
} }
@ -217,7 +226,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task UnrecognizedTokenReceived() public async Task UnrecognizedTokenReceived()
{ {
var server = CreateServer(); using var host = await CreateHost();
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("", response.ResponseText); Assert.Equal("", response.ResponseText);
@ -226,12 +236,13 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task InvalidTokenReceived() public async Task InvalidTokenReceived()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new InvalidTokenValidator()); options.SecurityTokenValidators.Add(new InvalidTokenValidator());
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("Bearer error=\"invalid_token\"", response.Response.Headers.WwwAuthenticate.First().ToString()); Assert.Equal("Bearer error=\"invalid_token\"", response.Response.Headers.WwwAuthenticate.First().ToString());
@ -249,12 +260,13 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[InlineData(typeof(SecurityTokenSignatureKeyNotFoundException), "The signature key was not found")] [InlineData(typeof(SecurityTokenSignatureKeyNotFoundException), "The signature key was not found")]
public async Task ExceptionReportedInHeaderForAuthenticationFailures(Type errorType, string message) public async Task ExceptionReportedInHeaderForAuthenticationFailures(Type errorType, string message)
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType)); options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType));
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal($"Bearer error=\"invalid_token\", error_description=\"{message}\"", response.Response.Headers.WwwAuthenticate.First().ToString()); Assert.Equal($"Bearer error=\"invalid_token\", error_description=\"{message}\"", response.Response.Headers.WwwAuthenticate.First().ToString());
@ -269,12 +281,13 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[InlineData(typeof(SecurityTokenExpiredException), "The token expired at '02/20/2000 00:00:00'")] [InlineData(typeof(SecurityTokenExpiredException), "The token expired at '02/20/2000 00:00:00'")]
public async Task ExceptionReportedInHeaderWithDetailsForAuthenticationFailures(Type errorType, string message) public async Task ExceptionReportedInHeaderWithDetailsForAuthenticationFailures(Type errorType, string message)
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new DetailedInvalidTokenValidator(errorType)); options.SecurityTokenValidators.Add(new DetailedInvalidTokenValidator(errorType));
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal($"Bearer error=\"invalid_token\", error_description=\"{message}\"", response.Response.Headers.WwwAuthenticate.First().ToString()); Assert.Equal($"Bearer error=\"invalid_token\", error_description=\"{message}\"", response.Response.Headers.WwwAuthenticate.First().ToString());
@ -285,12 +298,13 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[InlineData(typeof(ArgumentException))] [InlineData(typeof(ArgumentException))]
public async Task ExceptionNotReportedInHeaderForOtherFailures(Type errorType) public async Task ExceptionNotReportedInHeaderForOtherFailures(Type errorType)
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType)); options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType));
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("Bearer error=\"invalid_token\"", response.Response.Headers.WwwAuthenticate.First().ToString()); Assert.Equal("Bearer error=\"invalid_token\"", response.Response.Headers.WwwAuthenticate.First().ToString());
@ -300,13 +314,14 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task ExceptionsReportedInHeaderForMultipleAuthenticationFailures() public async Task ExceptionsReportedInHeaderForMultipleAuthenticationFailures()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenInvalidAudienceException))); options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenInvalidAudienceException)));
options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenSignatureKeyNotFoundException))); options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenSignatureKeyNotFoundException)));
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("Bearer error=\"invalid_token\", error_description=\"The audience '(null)' is invalid; The signature key was not found\"", Assert.Equal("Bearer error=\"invalid_token\", error_description=\"The audience '(null)' is invalid; The signature key was not found\"",
@ -323,7 +338,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[InlineData(null, null, "custom_uri")] [InlineData(null, null, "custom_uri")]
public async Task ExceptionsReportedInHeaderExposesUserDefinedError(string error, string description, string uri) public async Task ExceptionsReportedInHeaderExposesUserDefinedError(string error, string description, string uri)
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.Events = new JwtBearerEvents options.Events = new JwtBearerEvents
{ {
@ -338,6 +353,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}; };
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("", response.ResponseText); Assert.Equal("", response.ResponseText);
@ -380,11 +396,12 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task ExceptionNotReportedInHeaderWhenIncludeErrorDetailsIsFalse() public async Task ExceptionNotReportedInHeaderWhenIncludeErrorDetailsIsFalse()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.IncludeErrorDetails = false; o.IncludeErrorDetails = false;
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("Bearer", response.Response.Headers.WwwAuthenticate.First().ToString()); Assert.Equal("Bearer", response.Response.Headers.WwwAuthenticate.First().ToString());
@ -394,8 +411,9 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task ExceptionNotReportedInHeaderWhenTokenWasMissing() public async Task ExceptionNotReportedInHeaderWhenTokenWasMissing()
{ {
var server = CreateServer(); using var host = await CreateHost();
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth"); var response = await SendAsync(server, "http://example.com/oauth");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("Bearer", response.Response.Headers.WwwAuthenticate.First().ToString()); Assert.Equal("Bearer", response.Response.Headers.WwwAuthenticate.First().ToString());
@ -405,7 +423,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task CustomTokenValidated() public async Task CustomTokenValidated()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.Events = new JwtBearerEvents() options.Events = new JwtBearerEvents()
{ {
@ -432,6 +450,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator(JwtBearerDefaults.AuthenticationScheme)); options.SecurityTokenValidators.Add(new BlobTokenValidator(JwtBearerDefaults.AuthenticationScheme));
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal("Bob le Magnifique", response.ResponseText); Assert.Equal("Bob le Magnifique", response.ResponseText);
@ -440,7 +459,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task RetrievingTokenFromAlternateLocation() public async Task RetrievingTokenFromAlternateLocation()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.Events = new JwtBearerEvents() options.Events = new JwtBearerEvents()
{ {
@ -457,6 +476,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
})); }));
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer Token"); var response = await SendAsync(server, "http://example.com/oauth", "Bearer Token");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal("Bob le Tout Puissant", response.ResponseText); Assert.Equal("Bob le Tout Puissant", response.ResponseText);
@ -465,7 +485,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task EventOnMessageReceivedSkip_NoMoreEventsExecuted() public async Task EventOnMessageReceivedSkip_NoMoreEventsExecuted()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.Events = new JwtBearerEvents() options.Events = new JwtBearerEvents()
{ {
@ -489,6 +509,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}; };
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal(string.Empty, response.ResponseText); Assert.Equal(string.Empty, response.ResponseText);
@ -497,7 +518,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task EventOnMessageReceivedReject_NoMoreEventsExecuted() public async Task EventOnMessageReceivedReject_NoMoreEventsExecuted()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.Events = new JwtBearerEvents() options.Events = new JwtBearerEvents()
{ {
@ -522,6 +543,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}; };
}); });
using var server = host.GetTestServer();
var exception = await Assert.ThrowsAsync<Exception>(delegate var exception = await Assert.ThrowsAsync<Exception>(delegate
{ {
return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
@ -533,7 +555,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task EventOnTokenValidatedSkip_NoMoreEventsExecuted() public async Task EventOnTokenValidatedSkip_NoMoreEventsExecuted()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.Events = new JwtBearerEvents() options.Events = new JwtBearerEvents()
{ {
@ -555,6 +577,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal(string.Empty, response.ResponseText); Assert.Equal(string.Empty, response.ResponseText);
@ -563,7 +586,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task EventOnTokenValidatedReject_NoMoreEventsExecuted() public async Task EventOnTokenValidatedReject_NoMoreEventsExecuted()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.Events = new JwtBearerEvents() options.Events = new JwtBearerEvents()
{ {
@ -586,6 +609,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
}); });
using var server = host.GetTestServer();
var exception = await Assert.ThrowsAsync<Exception>(delegate var exception = await Assert.ThrowsAsync<Exception>(delegate
{ {
return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
@ -597,7 +621,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task EventOnAuthenticationFailedSkip_NoMoreEventsExecuted() public async Task EventOnAuthenticationFailedSkip_NoMoreEventsExecuted()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.Events = new JwtBearerEvents() options.Events = new JwtBearerEvents()
{ {
@ -619,6 +643,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal(string.Empty, response.ResponseText); Assert.Equal(string.Empty, response.ResponseText);
@ -627,7 +652,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task EventOnAuthenticationFailedReject_NoMoreEventsExecuted() public async Task EventOnAuthenticationFailedReject_NoMoreEventsExecuted()
{ {
var server = CreateServer(options => using var host = await CreateHost(options =>
{ {
options.Events = new JwtBearerEvents() options.Events = new JwtBearerEvents()
{ {
@ -650,6 +675,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
}); });
using var server = host.GetTestServer();
var exception = await Assert.ThrowsAsync<Exception>(delegate var exception = await Assert.ThrowsAsync<Exception>(delegate
{ {
return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
@ -661,7 +687,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact] [Fact]
public async Task EventOnChallengeSkip_ResponseNotModified() public async Task EventOnChallengeSkip_ResponseNotModified()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.Events = new JwtBearerEvents() o.Events = new JwtBearerEvents()
{ {
@ -673,6 +699,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}; };
}); });
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/unauthorized", "Bearer Token"); var response = await SendAsync(server, "http://example.com/unauthorized", "Bearer Token");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Empty(response.Response.Headers.WwwAuthenticate); Assert.Empty(response.Response.Headers.WwwAuthenticate);
@ -684,7 +711,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
var tokenData = CreateStandardTokenAndKey(); var tokenData = CreateStandardTokenAndKey();
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.TokenValidationParameters = new TokenValidationParameters() o.TokenValidationParameters = new TokenValidationParameters()
{ {
@ -694,6 +721,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}; };
}); });
var newBearerToken = "Bearer " + tokenData.tokenText; var newBearerToken = "Bearer " + tokenData.tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken); var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken);
Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode);
} }
@ -702,7 +730,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
public async Task EventOnForbiddenSkip_ResponseNotModified() public async Task EventOnForbiddenSkip_ResponseNotModified()
{ {
var tokenData = CreateStandardTokenAndKey(); var tokenData = CreateStandardTokenAndKey();
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.TokenValidationParameters = new TokenValidationParameters() o.TokenValidationParameters = new TokenValidationParameters()
{ {
@ -719,6 +747,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}; };
}); });
var newBearerToken = "Bearer " + tokenData.tokenText; var newBearerToken = "Bearer " + tokenData.tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken); var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken);
Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode); Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode);
} }
@ -727,7 +756,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
public async Task EventOnForbidden_ResponseModified() public async Task EventOnForbidden_ResponseModified()
{ {
var tokenData = CreateStandardTokenAndKey(); var tokenData = CreateStandardTokenAndKey();
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.TokenValidationParameters = new TokenValidationParameters() o.TokenValidationParameters = new TokenValidationParameters()
{ {
@ -745,6 +774,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}; };
}); });
var newBearerToken = "Bearer " + tokenData.tokenText; var newBearerToken = "Bearer " + tokenData.tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken); var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken);
Assert.Equal(418, (int)response.Response.StatusCode); Assert.Equal(418, (int)response.Response.StatusCode);
Assert.Equal("You Shall Not Pass", await response.Response.Content.ReadAsStringAsync()); Assert.Equal("You Shall Not Pass", await response.Response.Content.ReadAsStringAsync());
@ -896,82 +926,86 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
} }
} }
private static TestServer CreateServer(Action<JwtBearerOptions> options = null, Func<HttpContext, Func<Task>, Task> handlerBeforeAuth = null) private static async Task<IHost> CreateHost(Action<JwtBearerOptions> options = null, Func<HttpContext, Func<Task>, Task> handlerBeforeAuth = null)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
if (handlerBeforeAuth != null) .Configure(app =>
{
app.Use(handlerBeforeAuth);
}
app.UseAuthentication();
app.Use(async (context, next) =>
{
if (context.Request.Path == new PathString("/checkforerrors"))
{ {
var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); // this used to be "Automatic" if (handlerBeforeAuth != null)
if (result.Failure != null)
{ {
throw new Exception("Failed to authenticate", result.Failure); app.Use(handlerBeforeAuth);
}
return;
}
else if (context.Request.Path == new PathString("/oauth"))
{
if (context.User == null ||
context.User.Identity == null ||
!context.User.Identity.IsAuthenticated)
{
context.Response.StatusCode = 401;
// REVIEW: no more automatic challenge
await context.ChallengeAsync(JwtBearerDefaults.AuthenticationScheme);
return;
} }
var identifier = context.User.FindFirst(ClaimTypes.NameIdentifier); app.UseAuthentication();
if (identifier == null) app.Use(async (context, next) =>
{ {
context.Response.StatusCode = 500; if (context.Request.Path == new PathString("/checkforerrors"))
return; {
} var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); // this used to be "Automatic"
if (result.Failure != null)
{
throw new Exception("Failed to authenticate", result.Failure);
}
return;
}
else if (context.Request.Path == new PathString("/oauth"))
{
if (context.User == null ||
context.User.Identity == null ||
!context.User.Identity.IsAuthenticated)
{
context.Response.StatusCode = 401;
// REVIEW: no more automatic challenge
await context.ChallengeAsync(JwtBearerDefaults.AuthenticationScheme);
return;
}
await context.Response.WriteAsync(identifier.Value); var identifier = context.User.FindFirst(ClaimTypes.NameIdentifier);
} if (identifier == null)
else if (context.Request.Path == new PathString("/token")) {
{ context.Response.StatusCode = 500;
var token = await context.GetTokenAsync("access_token"); return;
await context.Response.WriteAsync(token); }
}
else if (context.Request.Path == new PathString("/unauthorized"))
{
// Simulate Authorization failure
var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
await context.ChallengeAsync(JwtBearerDefaults.AuthenticationScheme);
}
else if (context.Request.Path == new PathString("/forbidden"))
{
// Simulate Forbidden
await context.ForbidAsync(JwtBearerDefaults.AuthenticationScheme);
}
else if (context.Request.Path == new PathString("/signIn"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(JwtBearerDefaults.AuthenticationScheme, new ClaimsPrincipal()));
}
else if (context.Request.Path == new PathString("/signOut"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync(JwtBearerDefaults.AuthenticationScheme));
}
else
{
await next();
}
});
})
.ConfigureServices(services => services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options));
return new TestServer(builder); await context.Response.WriteAsync(identifier.Value);
}
else if (context.Request.Path == new PathString("/token"))
{
var token = await context.GetTokenAsync("access_token");
await context.Response.WriteAsync(token);
}
else if (context.Request.Path == new PathString("/unauthorized"))
{
// Simulate Authorization failure
var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
await context.ChallengeAsync(JwtBearerDefaults.AuthenticationScheme);
}
else if (context.Request.Path == new PathString("/forbidden"))
{
// Simulate Forbidden
await context.ForbidAsync(JwtBearerDefaults.AuthenticationScheme);
}
else if (context.Request.Path == new PathString("/signIn"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(JwtBearerDefaults.AuthenticationScheme, new ClaimsPrincipal()));
}
else if (context.Request.Path == new PathString("/signOut"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync(JwtBearerDefaults.AuthenticationScheme));
}
else
{
await next();
}
});
})
.ConfigureServices(services => services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options)))
.Build();
await host.StartAsync();
return host;
} }
// TODO: see if we can share the TestExtensions SendAsync method (only diff is auth header) // TODO: see if we can share the TestExtensions SendAsync method (only diff is auth header)

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using System; using System;
using System.Linq; using System.Linq;
@ -48,7 +49,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
[Fact] [Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent() public async Task ChallengeWillTriggerApplyRedirectEvent()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Client Id"; o.ClientId = "Test Client Id";
o.ClientSecret = "Test Client Secret"; o.ClientSecret = "Test Client Secret";
@ -61,6 +62,8 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
} }
}; };
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var query = transaction.Response.Headers.Location.Query; var query = transaction.Response.Headers.Location.Query;
@ -70,11 +73,12 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
[Fact] [Fact]
public async Task SignInThrows() public async Task SignInThrows()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signIn"); var transaction = await server.SendAsync("https://example.com/signIn");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -82,11 +86,12 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
[Fact] [Fact]
public async Task SignOutThrows() public async Task SignOutThrows()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut"); var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -94,11 +99,12 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
[Fact] [Fact]
public async Task ForbidThrows() public async Task ForbidThrows()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut"); var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -106,11 +112,12 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
[Fact] [Fact]
public async Task ChallengeWillTriggerRedirection() public async Task ChallengeWillTriggerRedirection()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri; var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -127,7 +134,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
[Fact] [Fact]
public async Task ChallengeWillIncludeScopeAsConfigured() public async Task ChallengeWillIncludeScopeAsConfigured()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -135,6 +142,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
o.Scope.Add("foo"); o.Scope.Add("foo");
o.Scope.Add("bar"); o.Scope.Add("bar");
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
var res = transaction.Response; var res = transaction.Response;
Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); Assert.Equal(HttpStatusCode.Redirect, res.StatusCode);
@ -144,7 +152,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
[Fact] [Fact]
public async Task ChallengeWillIncludeScopeAsOverwritten() public async Task ChallengeWillIncludeScopeAsOverwritten()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -152,6 +160,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
o.Scope.Add("foo"); o.Scope.Add("foo");
o.Scope.Add("bar"); o.Scope.Add("bar");
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challengeWithOtherScope"); var transaction = await server.SendAsync("http://example.com/challengeWithOtherScope");
var res = transaction.Response; var res = transaction.Response;
Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); Assert.Equal(HttpStatusCode.Redirect, res.StatusCode);
@ -161,7 +170,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
[Fact] [Fact]
public async Task ChallengeWillIncludeScopeAsOverwrittenWithBaseAuthenticationProperties() public async Task ChallengeWillIncludeScopeAsOverwrittenWithBaseAuthenticationProperties()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
@ -169,6 +178,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
o.Scope.Add("foo"); o.Scope.Add("foo");
o.Scope.Add("bar"); o.Scope.Add("bar");
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challengeWithOtherScopeWithBaseAuthenticationProperties"); var transaction = await server.SendAsync("http://example.com/challengeWithOtherScopeWithBaseAuthenticationProperties");
var res = transaction.Response; var res = transaction.Response;
Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); Assert.Equal(HttpStatusCode.Redirect, res.StatusCode);
@ -179,7 +189,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
public async Task AuthenticatedEventCanGetRefreshToken() public async Task AuthenticatedEventCanGetRefreshToken()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("MsftTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("MsftTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Client Id"; o.ClientId = "Test Client Id";
o.ClientSecret = "Test Client Secret"; o.ClientSecret = "Test Client Secret";
@ -229,6 +239,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
properties.Items.Add(correlationKey, correlationValue); properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me"; properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties); var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync( var transaction = await server.SendAsync(
"https://example.com/signin-microsoft?code=TestCode&state=" + UrlEncoder.Default.Encode(state), "https://example.com/signin-microsoft?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Microsoft.{correlationValue}=N"); $".AspNetCore.Correlation.Microsoft.{correlationValue}=N");
@ -248,12 +259,13 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
public async Task ChallengeWillUseAuthenticationPropertiesParametersAsQueryArguments() public async Task ChallengeWillUseAuthenticationPropertiesParametersAsQueryArguments()
{ {
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("MicrosoftTest")); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("MicrosoftTest"));
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Id"; o.ClientId = "Test Id";
o.ClientSecret = "Test Secret"; o.ClientSecret = "Test Secret";
o.StateDataFormat = stateFormat; o.StateDataFormat = stateFormat;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge"); var transaction = await server.SendAsync("https://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -277,7 +289,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
[Fact] [Fact]
public async Task PkceSentToTokenEndpoint() public async Task PkceSentToTokenEndpoint()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ClientId = "Test Client Id"; o.ClientId = "Test Client Id";
o.ClientSecret = "Test Client Secret"; o.ClientSecret = "Test Client Secret";
@ -320,6 +332,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
} }
}; };
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge"); var transaction = await server.SendAsync("https://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var locationUri = transaction.Response.Headers.Location; var locationUri = transaction.Response.Headers.Location;
@ -342,68 +355,72 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
Assert.StartsWith(".AspNetCore." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); Assert.StartsWith(".AspNetCore." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]);
} }
private static TestServer CreateServer(Action<MicrosoftAccountOptions> configureOptions) private static async Task<IHost> CreateHost(Action<MicrosoftAccountOptions> configureOptions)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
app.UseAuthentication(); .Configure(app =>
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
if (req.Path == new PathString("/challenge"))
{ {
await context.ChallengeAsync("Microsoft", new MicrosoftChallengeProperties app.UseAuthentication();
app.Use(async (context, next) =>
{ {
Prompt = "select_account", var req = context.Request;
LoginHint = "username", var res = context.Response;
DomainHint = "consumers", if (req.Path == new PathString("/challenge"))
ResponseMode = "query", {
RedirectUri = "/me" await context.ChallengeAsync("Microsoft", new MicrosoftChallengeProperties
{
Prompt = "select_account",
LoginHint = "username",
DomainHint = "consumers",
ResponseMode = "query",
RedirectUri = "/me"
});
}
else if (req.Path == new PathString("/challengeWithOtherScope"))
{
var properties = new OAuthChallengeProperties();
properties.SetScope("baz", "qux");
await context.ChallengeAsync("Microsoft", properties);
}
else if (req.Path == new PathString("/challengeWithOtherScopeWithBaseAuthenticationProperties"))
{
var properties = new AuthenticationProperties();
properties.SetParameter(OAuthChallengeProperties.ScopeKey, new string[] { "baz", "qux" });
await context.ChallengeAsync("Microsoft", properties);
}
else if (req.Path == new PathString("/me"))
{
await res.DescribeAsync(context.User);
}
else if (req.Path == new PathString("/signIn"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("Microsoft", new ClaimsPrincipal()));
}
else if (req.Path == new PathString("/signOut"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync("Microsoft"));
}
else if (req.Path == new PathString("/forbid"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.ForbidAsync("Microsoft"));
}
else
{
await next();
}
}); });
} })
else if (req.Path == new PathString("/challengeWithOtherScope")) .ConfigureServices(services =>
{ {
var properties = new OAuthChallengeProperties(); services.AddAuthentication(TestExtensions.CookieAuthenticationScheme)
properties.SetScope("baz", "qux"); .AddCookie(TestExtensions.CookieAuthenticationScheme, o => { })
await context.ChallengeAsync("Microsoft", properties); .AddMicrosoftAccount(configureOptions);
} }))
else if (req.Path == new PathString("/challengeWithOtherScopeWithBaseAuthenticationProperties")) .Build();
{ await host.StartAsync();
var properties = new AuthenticationProperties(); return host;
properties.SetParameter(OAuthChallengeProperties.ScopeKey, new string[] { "baz", "qux" });
await context.ChallengeAsync("Microsoft", properties);
}
else if (req.Path == new PathString("/me"))
{
await res.DescribeAsync(context.User);
}
else if (req.Path == new PathString("/signIn"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("Microsoft", new ClaimsPrincipal()));
}
else if (req.Path == new PathString("/signOut"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync("Microsoft"));
}
else if (req.Path == new PathString("/forbid"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.ForbidAsync("Microsoft"));
}
else
{
await next();
}
});
})
.ConfigureServices(services =>
{
services.AddAuthentication(TestExtensions.CookieAuthenticationScheme)
.AddCookie(TestExtensions.CookieAuthenticationScheme, o => { })
.AddMicrosoftAccount(configureOptions);
});
return new TestServer(builder);
} }
private static HttpResponseMessage ReturnJsonResponse(object content) private static HttpResponseMessage ReturnJsonResponse(object content)

View File

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
[Fact] [Fact]
public async Task ThrowsIfClientIdMissing() public async Task ThrowsIfClientIdMissing()
{ {
var server = CreateServer( using var host = await CreateHost(
services => services.AddAuthentication().AddOAuth("weeblie", o => services => services.AddAuthentication().AddOAuth("weeblie", o =>
{ {
o.SignInScheme = "whatever"; o.SignInScheme = "whatever";
@ -43,13 +44,14 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
o.TokenEndpoint = "/"; o.TokenEndpoint = "/";
o.AuthorizationEndpoint = "/"; o.AuthorizationEndpoint = "/";
})); }));
using var server = host.GetTestServer();
await Assert.ThrowsAsync<ArgumentException>("ClientId", () => server.SendAsync("http://example.com/")); await Assert.ThrowsAsync<ArgumentException>("ClientId", () => server.SendAsync("http://example.com/"));
} }
[Fact] [Fact]
public async Task ThrowsIfClientSecretMissing() public async Task ThrowsIfClientSecretMissing()
{ {
var server = CreateServer( using var host = await CreateHost(
services => services.AddAuthentication().AddOAuth("weeblie", o => services => services.AddAuthentication().AddOAuth("weeblie", o =>
{ {
o.SignInScheme = "whatever"; o.SignInScheme = "whatever";
@ -58,13 +60,14 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
o.TokenEndpoint = "/"; o.TokenEndpoint = "/";
o.AuthorizationEndpoint = "/"; o.AuthorizationEndpoint = "/";
})); }));
using var server = host.GetTestServer();
await Assert.ThrowsAsync<ArgumentException>("ClientSecret", () => server.SendAsync("http://example.com/")); await Assert.ThrowsAsync<ArgumentException>("ClientSecret", () => server.SendAsync("http://example.com/"));
} }
[Fact] [Fact]
public async Task ThrowsIfCallbackPathMissing() public async Task ThrowsIfCallbackPathMissing()
{ {
var server = CreateServer( using var host = await CreateHost(
services => services.AddAuthentication().AddOAuth("weeblie", o => services => services.AddAuthentication().AddOAuth("weeblie", o =>
{ {
o.ClientId = "Whatever;"; o.ClientId = "Whatever;";
@ -73,13 +76,14 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
o.AuthorizationEndpoint = "/"; o.AuthorizationEndpoint = "/";
o.SignInScheme = "eh"; o.SignInScheme = "eh";
})); }));
using var server = host.GetTestServer();
await Assert.ThrowsAsync<ArgumentException>("CallbackPath", () => server.SendAsync("http://example.com/")); await Assert.ThrowsAsync<ArgumentException>("CallbackPath", () => server.SendAsync("http://example.com/"));
} }
[Fact] [Fact]
public async Task ThrowsIfTokenEndpointMissing() public async Task ThrowsIfTokenEndpointMissing()
{ {
var server = CreateServer( using var host = await CreateHost(
services => services.AddAuthentication().AddOAuth("weeblie", o => services => services.AddAuthentication().AddOAuth("weeblie", o =>
{ {
o.ClientId = "Whatever;"; o.ClientId = "Whatever;";
@ -88,13 +92,14 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
o.AuthorizationEndpoint = "/"; o.AuthorizationEndpoint = "/";
o.SignInScheme = "eh"; o.SignInScheme = "eh";
})); }));
using var server = host.GetTestServer();
await Assert.ThrowsAsync<ArgumentException>("TokenEndpoint", () => server.SendAsync("http://example.com/")); await Assert.ThrowsAsync<ArgumentException>("TokenEndpoint", () => server.SendAsync("http://example.com/"));
} }
[Fact] [Fact]
public async Task ThrowsIfAuthorizationEndpointMissing() public async Task ThrowsIfAuthorizationEndpointMissing()
{ {
var server = CreateServer( using var host = await CreateHost(
services => services.AddAuthentication().AddOAuth("weeblie", o => services => services.AddAuthentication().AddOAuth("weeblie", o =>
{ {
o.ClientId = "Whatever;"; o.ClientId = "Whatever;";
@ -103,13 +108,14 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
o.TokenEndpoint = "/"; o.TokenEndpoint = "/";
o.SignInScheme = "eh"; o.SignInScheme = "eh";
})); }));
using var server = host.GetTestServer();
await Assert.ThrowsAsync<ArgumentException>("AuthorizationEndpoint", () => server.SendAsync("http://example.com/")); await Assert.ThrowsAsync<ArgumentException>("AuthorizationEndpoint", () => server.SendAsync("http://example.com/"));
} }
[Fact] [Fact]
public async Task RedirectToIdentityProvider_SetsCorrelationIdCookiePath_ToCallBackPath() public async Task RedirectToIdentityProvider_SetsCorrelationIdCookiePath_ToCallBackPath()
{ {
var server = CreateServer( using var host = await CreateHost(
s => s.AddAuthentication().AddOAuth( s => s.AddAuthentication().AddOAuth(
"Weblie", "Weblie",
opt => opt =>
@ -122,6 +128,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://www.example.com/challenge"); var transaction = await server.SendAsync("https://www.example.com/challenge");
var res = transaction.Response; var res = transaction.Response;
@ -135,7 +142,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
[Fact] [Fact]
public async Task RedirectToAuthorizeEndpoint_CorrelationIdCookieOptions_CanBeOverriden() public async Task RedirectToAuthorizeEndpoint_CorrelationIdCookieOptions_CanBeOverriden()
{ {
var server = CreateServer( using var host = await CreateHost(
s => s.AddAuthentication().AddOAuth( s => s.AddAuthentication().AddOAuth(
"Weblie", "Weblie",
opt => opt =>
@ -149,6 +156,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://www.example.com/challenge"); var transaction = await server.SendAsync("https://www.example.com/challenge");
var res = transaction.Response; var res = transaction.Response;
@ -162,7 +170,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
[Fact] [Fact]
public async Task RedirectToAuthorizeEndpoint_HasScopeAsConfigured() public async Task RedirectToAuthorizeEndpoint_HasScopeAsConfigured()
{ {
var server = CreateServer( using var host = await CreateHost(
s => s.AddAuthentication().AddOAuth( s => s.AddAuthentication().AddOAuth(
"Weblie", "Weblie",
opt => opt =>
@ -178,6 +186,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://www.example.com/challenge"); var transaction = await server.SendAsync("https://www.example.com/challenge");
var res = transaction.Response; var res = transaction.Response;
@ -188,7 +197,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
[Fact] [Fact]
public async Task RedirectToAuthorizeEndpoint_HasScopeAsOverwritten() public async Task RedirectToAuthorizeEndpoint_HasScopeAsOverwritten()
{ {
var server = CreateServer( using var host = await CreateHost(
s => s.AddAuthentication().AddOAuth( s => s.AddAuthentication().AddOAuth(
"Weblie", "Weblie",
opt => opt =>
@ -206,6 +215,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://www.example.com/challenge"); var transaction = await server.SendAsync("https://www.example.com/challenge");
var res = transaction.Response; var res = transaction.Response;
@ -216,7 +226,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
[Fact] [Fact]
public async Task RedirectToAuthorizeEndpoint_HasScopeAsOverwrittenWithBaseAuthenticationProperties() public async Task RedirectToAuthorizeEndpoint_HasScopeAsOverwrittenWithBaseAuthenticationProperties()
{ {
var server = CreateServer( using var host = await CreateHost(
s => s.AddAuthentication().AddOAuth( s => s.AddAuthentication().AddOAuth(
"Weblie", "Weblie",
opt => opt =>
@ -234,6 +244,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://www.example.com/challenge"); var transaction = await server.SendAsync("https://www.example.com/challenge");
var res = transaction.Response; var res = transaction.Response;
@ -254,7 +265,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
[Fact] [Fact]
public async Task HandleRequestAsync_RedirectsToAccessDeniedPathWhenExplicitlySet() public async Task HandleRequestAsync_RedirectsToAccessDeniedPathWhenExplicitlySet()
{ {
var server = CreateServer( using var host = await CreateHost(
s => s.AddAuthentication().AddOAuth( s => s.AddAuthentication().AddOAuth(
"Weblie", "Weblie",
opt => opt =>
@ -270,6 +281,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
opt.Events.OnRemoteFailure = context => throw new InvalidOperationException("This event should not be called."); opt.Events.OnRemoteFailure = context => throw new InvalidOperationException("This event should not be called.");
})); }));
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state", var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state",
".AspNetCore.Correlation.Weblie.correlationId=N"); ".AspNetCore.Correlation.Weblie.correlationId=N");
@ -280,7 +292,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
[Fact] [Fact]
public async Task HandleRequestAsync_InvokesAccessDeniedEvent() public async Task HandleRequestAsync_InvokesAccessDeniedEvent()
{ {
var server = CreateServer( using var host = await CreateHost(
s => s.AddAuthentication().AddOAuth( s => s.AddAuthentication().AddOAuth(
"Weblie", "Weblie",
opt => opt =>
@ -304,6 +316,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
}; };
})); }));
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state", var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state",
".AspNetCore.Correlation.Weblie.correlationId=N"); ".AspNetCore.Correlation.Weblie.correlationId=N");
@ -314,7 +327,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
[Fact] [Fact]
public async Task HandleRequestAsync_InvokesRemoteFailureEventWhenAccessDeniedPathIsNotExplicitlySet() public async Task HandleRequestAsync_InvokesRemoteFailureEventWhenAccessDeniedPathIsNotExplicitlySet()
{ {
var server = CreateServer( using var host = await CreateHost(
s => s.AddAuthentication().AddOAuth( s => s.AddAuthentication().AddOAuth(
"Weblie", "Weblie",
opt => opt =>
@ -339,6 +352,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
}; };
})); }));
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state", var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state",
".AspNetCore.Correlation.Weblie.correlationId=N"); ".AspNetCore.Correlation.Weblie.correlationId=N");
@ -349,7 +363,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
[Fact] [Fact]
public async Task RemoteAuthenticationFailed_OAuthError_IncludesProperties() public async Task RemoteAuthenticationFailed_OAuthError_IncludesProperties()
{ {
var server = CreateServer( using var host = await CreateHost(
s => s.AddAuthentication().AddOAuth( s => s.AddAuthentication().AddOAuth(
"Weblie", "Weblie",
opt => opt =>
@ -374,6 +388,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
}; };
})); }));
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=custom_error&state=protected_state", var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=custom_error&state=protected_state",
".AspNetCore.Correlation.Weblie.correlationId=N"); ".AspNetCore.Correlation.Weblie.correlationId=N");
@ -381,22 +396,26 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
Assert.Null(transaction.Response.Headers.Location); Assert.Null(transaction.Response.Headers.Location);
} }
private static TestServer CreateServer(Action<IServiceCollection> configureServices, Func<HttpContext, Task<bool>> handler = null) private static async Task<IHost> CreateHost(Action<IServiceCollection> configureServices, Func<HttpContext, Task<bool>> handler = null)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
app.UseAuthentication(); .Configure(app =>
app.Use(async (context, next) =>
{
if (handler == null || ! await handler(context))
{ {
await next(); app.UseAuthentication();
} app.Use(async (context, next) =>
}); {
}) if (handler == null || ! await handler(context))
.ConfigureServices(configureServices); {
return new TestServer(builder); await next();
}
});
})
.ConfigureServices(configureServices))
.Build();
await host.StartAsync();
return host;
} }
private class TestStateDataFormat : ISecureDataFormat<AuthenticationProperties> private class TestStateDataFormat : ISecureDataFormat<AuthenticationProperties>

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
@ -550,16 +551,19 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
private TestServer BuildTestServer(Action<OpenIdConnectOptions> options) private TestServer BuildTestServer(Action<OpenIdConnectOptions> options)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.ConfigureServices(services => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
services.AddAuthentication() .ConfigureServices(services =>
.AddCookie() {
.AddOpenIdConnect(options); services.AddAuthentication()
}) .AddCookie()
.Configure(app => app.UseAuthentication()); .AddOpenIdConnect(options);
})
return new TestServer(builder); .Configure(app => app.UseAuthentication()))
.Build();
host.Start();
return host.GetTestServer();
} }
private async Task TestConfigurationException<T>( private async Task TestConfigurationException<T>(

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@ -1266,39 +1267,43 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
private TestServer CreateServer(OpenIdConnectEvents events, RequestDelegate appCode) private TestServer CreateServer(OpenIdConnectEvents events, RequestDelegate appCode)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.ConfigureServices(services => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
services.AddAuthentication(auth => .ConfigureServices(services =>
{ {
auth.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; services.AddAuthentication(auth =>
auth.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(o =>
{
o.Events = events;
o.ClientId = "ClientId";
o.GetClaimsFromUserInfoEndpoint = true;
o.Configuration = new OpenIdConnectConfiguration()
{ {
TokenEndpoint = "http://testhost/tokens", auth.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
UserInfoEndpoint = "http://testhost/user", auth.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
EndSessionEndpoint = "http://testhost/end" })
}; .AddCookie()
o.StateDataFormat = new TestStateDataFormat(); .AddOpenIdConnect(o =>
o.SecurityTokenValidator = new TestTokenValidator(); {
o.ProtocolValidator = new TestProtocolValidator(); o.Events = events;
o.BackchannelHttpHandler = new TestBackchannel(); o.ClientId = "ClientId";
}); o.GetClaimsFromUserInfoEndpoint = true;
}) o.Configuration = new OpenIdConnectConfiguration()
.Configure(app => {
{ TokenEndpoint = "http://testhost/tokens",
app.UseAuthentication(); UserInfoEndpoint = "http://testhost/user",
app.Run(appCode); EndSessionEndpoint = "http://testhost/end"
}); };
o.StateDataFormat = new TestStateDataFormat();
o.SecurityTokenValidator = new TestTokenValidator();
o.ProtocolValidator = new TestProtocolValidator();
o.BackchannelHttpHandler = new TestBackchannel();
});
})
.Configure(app =>
{
app.UseAuthentication();
app.Run(appCode);
}))
.Build();
return new TestServer(builder); host.Start();
return host.GetTestServer();
} }
private Task<HttpResponseMessage> PostAsync(TestServer server, string path, string form) private Task<HttpResponseMessage> PostAsync(TestServer server, string path, string form)

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
@ -62,59 +63,63 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
Func<HttpContext, Task> handler, Func<HttpContext, Task> handler,
AuthenticationProperties properties) AuthenticationProperties properties)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
app.UseAuthentication(); .Configure(app =>
app.Use(async (context, next) => {
{ app.UseAuthentication();
var req = context.Request; app.Use(async (context, next) =>
var res = context.Response; {
var req = context.Request;
var res = context.Response;
if (req.Path == new PathString(Challenge)) if (req.Path == new PathString(Challenge))
{
await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme);
}
else if (req.Path == new PathString(ChallengeWithProperties))
{
await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, properties);
}
else if (req.Path == new PathString(ChallengeWithOutContext))
{
res.StatusCode = 401;
}
else if (req.Path == new PathString(Signin))
{
await context.SignInAsync(OpenIdConnectDefaults.AuthenticationScheme, new ClaimsPrincipal());
}
else if (req.Path == new PathString(Signout))
{
await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
}
else if (req.Path == new PathString("/signout_with_specific_redirect_uri"))
{
await context.SignOutAsync(
OpenIdConnectDefaults.AuthenticationScheme,
new AuthenticationProperties() { RedirectUri = "http://www.example.com/specific_redirect_uri" });
}
else if (handler != null)
{
await handler(context);
}
else
{
await next();
}
});
})
.ConfigureServices(services =>
{ {
await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
} .AddCookie()
else if (req.Path == new PathString(ChallengeWithProperties)) .AddOpenIdConnect(options);
{ }))
await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, properties); .Build();
}
else if (req.Path == new PathString(ChallengeWithOutContext))
{
res.StatusCode = 401;
}
else if (req.Path == new PathString(Signin))
{
await context.SignInAsync(OpenIdConnectDefaults.AuthenticationScheme, new ClaimsPrincipal());
}
else if (req.Path == new PathString(Signout))
{
await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
}
else if (req.Path == new PathString("/signout_with_specific_redirect_uri"))
{
await context.SignOutAsync(
OpenIdConnectDefaults.AuthenticationScheme,
new AuthenticationProperties() { RedirectUri = "http://www.example.com/specific_redirect_uri" });
}
else if (handler != null)
{
await handler(context);
}
else
{
await next();
}
});
})
.ConfigureServices(services =>
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie()
.AddOpenIdConnect(options);
});
return new TestServer(builder); host.Start();
return host.GetTestServer();
} }
} }
} }

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xunit; using Xunit;
@ -16,8 +17,8 @@ namespace Microsoft.AspNetCore.Authentication
{ {
protected override string DisplayName => DefaultScheme; protected override string DisplayName => DefaultScheme;
private TestServer CreateServer(Action<TOptions> configureOptions, Func<HttpContext, Task> testpath = null, bool isDefault = true) private Task<IHost> CreateHost(Action<TOptions> configureOptions, Func<HttpContext, Task> testpath = null, bool isDefault = true)
=> CreateServerWithServices(s => => CreateHostWithServices(s =>
{ {
var builder = s.AddAuthentication(); var builder = s.AddAuthentication();
if (isDefault) if (isDefault)
@ -29,23 +30,26 @@ namespace Microsoft.AspNetCore.Authentication
}, testpath); }, testpath);
protected virtual TestServer CreateServerWithServices(Action<IServiceCollection> configureServices, Func<HttpContext, Task> testpath = null) protected virtual async Task<IHost> CreateHostWithServices(Action<IServiceCollection> configureServices, Func<HttpContext, Task> testpath = null)
{ {
//private static TestServer CreateServer(Action<IApplicationBuilder> configure, Action<IServiceCollection> configureServices, Func<HttpContext, Task<bool>> handler) var host = new HostBuilder()
var builder = new WebHostBuilder() .ConfigureWebHost(webHostBuilder =>
.Configure(app => webHostBuilder.UseTestServer()
{ .Configure(app =>
app.Use(async (context, next) =>
{
if (testpath != null)
{ {
await testpath(context); app.Use(async (context, next) =>
} {
await next(); if (testpath != null)
}); {
}) await testpath(context);
.ConfigureServices(configureServices); }
return new TestServer(builder); await next();
});
})
.ConfigureServices(configureServices))
.Build();
await host.StartAsync();
return host;
} }
protected abstract void ConfigureDefaults(TOptions o); protected abstract void ConfigureDefaults(TOptions o);
@ -53,13 +57,14 @@ namespace Microsoft.AspNetCore.Authentication
[Fact] [Fact]
public async Task VerifySignInSchemeCannotBeSetToSelf() public async Task VerifySignInSchemeCannotBeSetToSelf()
{ {
var server = CreateServer( using var host = await CreateHost(
o => o =>
{ {
ConfigureDefaults(o); ConfigureDefaults(o);
o.SignInScheme = DefaultScheme; o.SignInScheme = DefaultScheme;
}, },
context => context.ChallengeAsync(DefaultScheme)); context => context.ChallengeAsync(DefaultScheme));
using var server = host.GetTestServer();
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge")); var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message); Assert.Contains("cannot be set to itself", error.Message);
} }
@ -67,10 +72,12 @@ namespace Microsoft.AspNetCore.Authentication
[Fact] [Fact]
public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultScheme() public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultScheme()
{ {
var server = CreateServer(
using var host = await CreateHost(
o => o.SignInScheme = null, o => o.SignInScheme = null,
context => context.ChallengeAsync(DefaultScheme), context => context.ChallengeAsync(DefaultScheme),
isDefault: true); isDefault: true);
using var server = host.GetTestServer();
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge")); var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message); Assert.Contains("cannot be set to itself", error.Message);
} }
@ -78,13 +85,14 @@ namespace Microsoft.AspNetCore.Authentication
[Fact] [Fact]
public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultSignInScheme() public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultSignInScheme()
{ {
var server = CreateServerWithServices( using var host = await CreateHostWithServices(
services => services =>
{ {
var builder = services.AddAuthentication(o => o.DefaultSignInScheme = DefaultScheme); var builder = services.AddAuthentication(o => o.DefaultSignInScheme = DefaultScheme);
RegisterAuth(builder, o => o.SignInScheme = null); RegisterAuth(builder, o => o.SignInScheme = null);
}, },
context => context.ChallengeAsync(DefaultScheme)); context => context.ChallengeAsync(DefaultScheme));
using var server = host.GetTestServer();
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge")); var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message); Assert.Contains("cannot be set to itself", error.Message);
} }

View File

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using System; using System;
using System.Linq; using System.Linq;
@ -43,7 +44,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent() public async Task ChallengeWillTriggerApplyRedirectEvent()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
@ -65,6 +66,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter"); await context.ChallengeAsync("Twitter");
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var query = transaction.Response.Headers.Location.Query; var query = transaction.Response.Headers.Location.Query;
@ -78,11 +80,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task ThrowsIfClientIdMissing() public async Task ThrowsIfClientIdMissing()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
}); });
using var server = host.GetTestServer();
await Assert.ThrowsAsync<ArgumentException>("ConsumerKey", async () => await server.SendAsync("http://example.com/challenge")); await Assert.ThrowsAsync<ArgumentException>("ConsumerKey", async () => await server.SendAsync("http://example.com/challenge"));
} }
@ -93,24 +96,26 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task ThrowsIfClientSecretMissing() public async Task ThrowsIfClientSecretMissing()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
}); });
using var server = host.GetTestServer();
await Assert.ThrowsAsync<ArgumentException>("ConsumerSecret", async () => await server.SendAsync("http://example.com/challenge")); await Assert.ThrowsAsync<ArgumentException>("ConsumerSecret", async () => await server.SendAsync("http://example.com/challenge"));
} }
[Fact] [Fact]
public async Task BadSignInWillThrow() public async Task BadSignInWillThrow()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
}); });
// Send a bogus sign in // Send a bogus sign in
using var server = host.GetTestServer();
var error = await Assert.ThrowsAnyAsync<Exception>(() => server.SendAsync("https://example.com/signin-twitter")); var error = await Assert.ThrowsAnyAsync<Exception>(() => server.SendAsync("https://example.com/signin-twitter"));
Assert.Equal("Invalid state cookie.", error.GetBaseException().Message); Assert.Equal("Invalid state cookie.", error.GetBaseException().Message);
} }
@ -118,11 +123,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task SignInThrows() public async Task SignInThrows()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signIn"); var transaction = await server.SendAsync("https://example.com/signIn");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -130,11 +136,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task SignOutThrows() public async Task SignOutThrows()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut"); var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -142,11 +149,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task ForbidThrows() public async Task ForbidThrows()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut"); var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
} }
@ -154,7 +162,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task ChallengeWillTriggerRedirection() public async Task ChallengeWillTriggerRedirection()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
@ -168,6 +176,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter"); await context.ChallengeAsync("Twitter");
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri; var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -177,7 +186,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task HandleRequestAsync_RedirectsToAccessDeniedPathWhenExplicitlySet() public async Task HandleRequestAsync_RedirectsToAccessDeniedPathWhenExplicitlySet()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
@ -195,6 +204,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter", properties); await context.ChallengeAsync("Twitter", properties);
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri; var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -217,7 +227,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task BadCallbackCallsAccessDeniedWithState() public async Task BadCallbackCallsAccessDeniedWithState()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
@ -244,6 +254,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter", properties); await context.ChallengeAsync("Twitter", properties);
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri; var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -265,7 +276,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact] [Fact]
public async Task BadCallbackCallsRemoteAuthFailedWithState() public async Task BadCallbackCallsRemoteAuthFailedWithState()
{ {
var server = CreateServer(o => using var host = await CreateHost(o =>
{ {
o.ConsumerKey = "Test Consumer Key"; o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret"; o.ConsumerSecret = "Test Consumer Secret";
@ -294,6 +305,8 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter", properties); await context.ChallengeAsync("Twitter", properties);
return true; return true;
}); });
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge"); var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri; var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -312,46 +325,51 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
Assert.Equal(HttpStatusCode.NotAcceptable, response.StatusCode); Assert.Equal(HttpStatusCode.NotAcceptable, response.StatusCode);
} }
private static TestServer CreateServer(Action<TwitterOptions> options, Func<HttpContext, Task<bool>> handler = null) private static async Task<IHost> CreateHost(Action<TwitterOptions> options, Func<HttpContext, Task<bool>> handler = null)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(app => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
app.UseAuthentication(); .Configure(app =>
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
if (req.Path == new PathString("/signIn"))
{ {
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("Twitter", new ClaimsPrincipal())); app.UseAuthentication();
} app.Use(async (context, next) =>
else if (req.Path == new PathString("/signOut")) {
var req = context.Request;
var res = context.Response;
if (req.Path == new PathString("/signIn"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("Twitter", new ClaimsPrincipal()));
}
else if (req.Path == new PathString("/signOut"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync("Twitter"));
}
else if (req.Path == new PathString("/forbid"))
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.ForbidAsync("Twitter"));
}
else if (handler == null || !await handler(context))
{
await next();
}
});
})
.ConfigureServices(services =>
{ {
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync("Twitter")); Action<TwitterOptions> wrapOptions = o =>
} {
else if (req.Path == new PathString("/forbid")) o.SignInScheme = "External";
{ options(o);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.ForbidAsync("Twitter")); };
} services.AddAuthentication()
else if (handler == null || ! await handler(context)) .AddCookie("External", _ => { })
{ .AddTwitter(wrapOptions);
await next(); }))
} .Build();
});
}) await host.StartAsync();
.ConfigureServices(services => return host;
{
Action<TwitterOptions> wrapOptions = o =>
{
o.SignInScheme = "External";
options(o);
};
services.AddAuthentication()
.AddCookie("External", _ => { })
.AddTwitter(wrapOptions);
});
return new TestServer(builder);
} }
private HttpResponseMessage BackchannelRequestToken(HttpRequestMessage req) private HttpResponseMessage BackchannelRequestToken(HttpRequestMessage req)

View File

@ -19,6 +19,7 @@ using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Xunit; using Xunit;
@ -43,20 +44,25 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task MissingConfigurationThrows() public async Task MissingConfigurationThrows()
{ {
var builder = new WebHostBuilder() using var host = new HostBuilder()
.Configure(ConfigureApp) .ConfigureWebHost(builder =>
.ConfigureServices(services => builder.UseTestServer()
{ .Configure(ConfigureApp)
services.AddAuthentication(sharedOptions => .ConfigureServices(services =>
{ {
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; services.AddAuthentication(sharedOptions =>
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; {
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}) sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
.AddCookie() sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
.AddWsFederation(); })
}); .AddCookie()
var server = new TestServer(builder); .AddWsFederation();
}))
.Build();
await host.StartAsync();
using var server = host.GetTestServer();
var httpClient = server.CreateClient(); var httpClient = server.CreateClient();
// Verify if the request is redirected to STS with right parameters // Verify if the request is redirected to STS with right parameters
@ -67,7 +73,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task ChallengeRedirects() public async Task ChallengeRedirects()
{ {
var httpClient = CreateClient(); var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters // Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/"); var response = await httpClient.GetAsync("/");
@ -83,7 +89,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task MapWillNotAffectRedirect() public async Task MapWillNotAffectRedirect()
{ {
var httpClient = CreateClient(); var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters // Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/mapped-challenge"); var response = await httpClient.GetAsync("/mapped-challenge");
@ -99,7 +105,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task PreMappedWillAffectRedirect() public async Task PreMappedWillAffectRedirect()
{ {
var httpClient = CreateClient(); var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters // Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/premapped-challenge"); var response = await httpClient.GetAsync("/premapped-challenge");
@ -115,7 +121,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task ValidTokenIsAccepted() public async Task ValidTokenIsAccepted()
{ {
var httpClient = CreateClient(); var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters // Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/"); var response = await httpClient.GetAsync("/");
@ -139,7 +145,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task ValidUnsolicitedTokenIsRefused() public async Task ValidUnsolicitedTokenIsRefused()
{ {
var httpClient = CreateClient(); var httpClient = await CreateClient();
var form = CreateSignInContent("WsFederation/ValidToken.xml", suppressWctx: true); var form = CreateSignInContent("WsFederation/ValidToken.xml", suppressWctx: true);
var exception = await Assert.ThrowsAsync<Exception>(() => httpClient.PostAsync(httpClient.BaseAddress + "signin-wsfed", form)); var exception = await Assert.ThrowsAsync<Exception>(() => httpClient.PostAsync(httpClient.BaseAddress + "signin-wsfed", form));
Assert.Contains("Unsolicited logins are not allowed.", exception.InnerException.Message); Assert.Contains("Unsolicited logins are not allowed.", exception.InnerException.Message);
@ -148,7 +154,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task ValidUnsolicitedTokenIsAcceptedWhenAllowed() public async Task ValidUnsolicitedTokenIsAcceptedWhenAllowed()
{ {
var httpClient = CreateClient(allowUnsolicited: true); var httpClient = await CreateClient(allowUnsolicited: true);
var form = CreateSignInContent("WsFederation/ValidToken.xml", suppressWctx: true); var form = CreateSignInContent("WsFederation/ValidToken.xml", suppressWctx: true);
var response = await httpClient.PostAsync(httpClient.BaseAddress + "signin-wsfed", form); var response = await httpClient.PostAsync(httpClient.BaseAddress + "signin-wsfed", form);
@ -166,7 +172,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task InvalidTokenIsRejected() public async Task InvalidTokenIsRejected()
{ {
var httpClient = CreateClient(); var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters // Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/"); var response = await httpClient.GetAsync("/");
@ -184,7 +190,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task RemoteSignoutRequestTriggersSignout() public async Task RemoteSignoutRequestTriggersSignout()
{ {
var httpClient = CreateClient(); var httpClient = await CreateClient();
var response = await httpClient.GetAsync("/signin-wsfed?wa=wsignoutcleanup1.0"); var response = await httpClient.GetAsync("/signin-wsfed?wa=wsignoutcleanup1.0");
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
@ -198,30 +204,35 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact] [Fact]
public async Task EventsResolvedFromDI() public async Task EventsResolvedFromDI()
{ {
var builder = new WebHostBuilder() using var host = new HostBuilder()
.ConfigureServices(services => .ConfigureWebHost(builder =>
{ builder.UseTestServer()
services.AddSingleton<MyWsFedEvents>(); .ConfigureServices(services =>
services.AddAuthentication(sharedOptions => {
{ services.AddSingleton<MyWsFedEvents>();
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; services.AddAuthentication(sharedOptions =>
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; {
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}) sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
.AddCookie() sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
.AddWsFederation(options => })
{ .AddCookie()
options.Wtrealm = "http://Automation1"; .AddWsFederation(options =>
options.MetadataAddress = "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/federationmetadata/2007-06/federationmetadata.xml"; {
options.BackchannelHttpHandler = new WaadMetadataDocumentHandler(); options.Wtrealm = "http://Automation1";
options.EventsType = typeof(MyWsFedEvents); options.MetadataAddress = "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/federationmetadata/2007-06/federationmetadata.xml";
}); options.BackchannelHttpHandler = new WaadMetadataDocumentHandler();
}) options.EventsType = typeof(MyWsFedEvents);
.Configure(app => });
{ })
app.Run(context => context.ChallengeAsync()); .Configure(app =>
}); {
var server = new TestServer(builder); app.Run(context => context.ChallengeAsync());
}))
.Build();
await host.StartAsync();
using var server = host.GetTestServer();
var result = await server.CreateClient().GetAsync(""); var result = await server.CreateClient().GetAsync("");
Assert.Contains("CustomKey=CustomValue", result.Headers.Location.Query); Assert.Contains("CustomKey=CustomValue", result.Headers.Location.Query);
@ -264,86 +275,91 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
} }
} }
private HttpClient CreateClient(bool allowUnsolicited = false) private async Task<HttpClient> CreateClient(bool allowUnsolicited = false)
{ {
var builder = new WebHostBuilder() var host = new HostBuilder()
.Configure(ConfigureApp) .ConfigureWebHost(builder =>
.ConfigureServices(services => builder.UseTestServer()
{ .Configure(ConfigureApp)
services.AddAuthentication(sharedOptions => .ConfigureServices(services =>
{ {
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; services.AddAuthentication(sharedOptions =>
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddWsFederation(options =>
{
options.Wtrealm = "http://Automation1";
options.MetadataAddress = "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/federationmetadata/2007-06/federationmetadata.xml";
options.BackchannelHttpHandler = new WaadMetadataDocumentHandler();
options.StateDataFormat = new CustomStateDataFormat();
options.SecurityTokenHandlers = new List<ISecurityTokenValidator>() { new TestSecurityTokenValidator() };
options.UseTokenLifetime = false;
options.AllowUnsolicitedLogins = allowUnsolicited;
options.Events = new WsFederationEvents()
{ {
OnMessageReceived = context => sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddWsFederation(options =>
{
options.Wtrealm = "http://Automation1";
options.MetadataAddress = "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/federationmetadata/2007-06/federationmetadata.xml";
options.BackchannelHttpHandler = new WaadMetadataDocumentHandler();
options.StateDataFormat = new CustomStateDataFormat();
options.SecurityTokenHandlers = new List<ISecurityTokenValidator>() { new TestSecurityTokenValidator() };
options.UseTokenLifetime = false;
options.AllowUnsolicitedLogins = allowUnsolicited;
options.Events = new WsFederationEvents()
{ {
if (!context.ProtocolMessage.Parameters.TryGetValue("suppressWctx", out var suppress)) OnMessageReceived = context =>
{ {
Assert.True(context.ProtocolMessage.Wctx.Equals("customValue"), "wctx is not my custom value"); if (!context.ProtocolMessage.Parameters.TryGetValue("suppressWctx", out var suppress))
} {
context.HttpContext.Items["MessageReceived"] = true; Assert.True(context.ProtocolMessage.Wctx.Equals("customValue"), "wctx is not my custom value");
return Task.FromResult(0); }
}, context.HttpContext.Items["MessageReceived"] = true;
OnRedirectToIdentityProvider = context => return Task.FromResult(0);
{ },
if (context.ProtocolMessage.IsSignInMessage) OnRedirectToIdentityProvider = context =>
{ {
// Sign in message if (context.ProtocolMessage.IsSignInMessage)
context.ProtocolMessage.Wctx = "customValue"; {
} // Sign in message
context.ProtocolMessage.Wctx = "customValue";
}
return Task.FromResult(0); return Task.FromResult(0);
}, },
OnSecurityTokenReceived = context => OnSecurityTokenReceived = context =>
{
context.HttpContext.Items["SecurityTokenReceived"] = true;
return Task.FromResult(0);
},
OnSecurityTokenValidated = context =>
{
Assert.True((bool)context.HttpContext.Items["MessageReceived"], "MessageReceived notification not invoked");
Assert.True((bool)context.HttpContext.Items["SecurityTokenReceived"], "SecurityTokenReceived notification not invoked");
if (context.Principal != null)
{ {
var identity = context.Principal.Identities.Single(); context.HttpContext.Items["SecurityTokenReceived"] = true;
identity.AddClaim(new Claim("ReturnEndpoint", "true")); return Task.FromResult(0);
identity.AddClaim(new Claim("Authenticated", "true")); },
identity.AddClaim(new Claim(identity.RoleClaimType, "Guest", ClaimValueTypes.String)); OnSecurityTokenValidated = context =>
} {
Assert.True((bool)context.HttpContext.Items["MessageReceived"], "MessageReceived notification not invoked");
Assert.True((bool)context.HttpContext.Items["SecurityTokenReceived"], "SecurityTokenReceived notification not invoked");
return Task.FromResult(0); if (context.Principal != null)
}, {
OnAuthenticationFailed = context => var identity = context.Principal.Identities.Single();
{ identity.AddClaim(new Claim("ReturnEndpoint", "true"));
context.HttpContext.Items["AuthenticationFailed"] = true; identity.AddClaim(new Claim("Authenticated", "true"));
//Change the request url to something different and skip Wsfed. This new url will handle the request and let us know if this notification was invoked. identity.AddClaim(new Claim(identity.RoleClaimType, "Guest", ClaimValueTypes.String));
context.HttpContext.Request.Path = new PathString("/AuthenticationFailed"); }
context.SkipHandler();
return Task.FromResult(0); return Task.FromResult(0);
}, },
OnRemoteSignOut = context => OnAuthenticationFailed = context =>
{ {
context.Response.Headers["EventHeader"] = "OnRemoteSignOut"; context.HttpContext.Items["AuthenticationFailed"] = true;
return Task.FromResult(0); //Change the request url to something different and skip Wsfed. This new url will handle the request and let us know if this notification was invoked.
} context.HttpContext.Request.Path = new PathString("/AuthenticationFailed");
}; context.SkipHandler();
}); return Task.FromResult(0);
}); },
var server = new TestServer(builder); OnRemoteSignOut = context =>
{
context.Response.Headers["EventHeader"] = "OnRemoteSignOut";
return Task.FromResult(0);
}
};
});
}))
.Build();
await host.StartAsync();
var server = host.GetTestServer();
return server.CreateClient(); return server.CreateClient();
} }