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.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Net.Http.Headers;
using Xunit;
@ -31,7 +32,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CanChangePasswordOptions()
{
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.RequireNonAlphanumeric = false;
@ -49,7 +50,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CookieContainsRoleClaim()
{
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");
Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode);
@ -70,7 +71,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CanCreateMeLoginAndCookieStopsWorkingAfterExpiration()
{
var clock = new TestClock();
var server = CreateServer(services =>
var server = await CreateServer(services =>
{
services.ConfigureApplicationCookie(options =>
{
@ -112,7 +113,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CanCreateMeLoginAndSecurityStampExtendsExpiration(bool rememberMe)
{
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");
Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode);
@ -156,7 +157,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task CanAccessOldPrincipalDuringSecurityStampReplacement()
{
var clock = new TestClock();
var server = CreateServer(services =>
var server = await CreateServer(services =>
{
services.Configure<SecurityStampValidatorOptions>(options =>
{
@ -207,7 +208,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task TwoFactorRememberCookieVerification()
{
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");
Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode);
@ -234,7 +235,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
public async Task TwoFactorRememberCookieClearedBySecurityStampChange()
{
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");
Assert.Equal(HttpStatusCode.OK, transaction1.Response.StatusCode);
@ -285,111 +286,115 @@ namespace Microsoft.AspNetCore.Identity.InMemory
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()
.Configure(app =>
{
app.UseAuthentication();
app.Use(async (context, next) =>
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.Configure(app =>
{
var req = context.Request;
var res = context.Response;
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"))
app.UseAuthentication();
app.Use(async (context, next) =>
{
res.StatusCode = 200;
}
else if (req.Path == new PathString("/createMe"))
{
var user = new PocoUser("hao");
var result = await userManager.CreateAsync(user, TestPassword);
if (result.Succeeded)
var req = context.Request;
var res = context.Response;
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"))
{
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");
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);
services.AddIdentityCore<PocoUser>()
.AddRoles<PocoRole>()
.AddSignInManager()
.AddDefaultTokenProviders();
services.AddAuthentication(IdentityConstants.ApplicationScheme).AddIdentityCookies();
}
else
{
await next();
services.AddIdentity<PocoUser, PocoRole>().AddDefaultTokenProviders();
}
});
})
.ConfigureServices(services =>
{
if (testCore)
{
services.AddIdentityCore<PocoUser>()
.AddRoles<PocoRole>()
.AddSignInManager()
.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);
var store = new InMemoryStore<PocoUser, PocoRole>();
services.AddSingleton<IUserStore<PocoUser>>(store);
services.AddSingleton<IRoleStore<PocoRole>>(store);
configureServices?.Invoke(services);
})
.UseTestServer())
.Build();
await host.StartAsync();
var server = host.GetTestServer();
server.BaseAddress = baseAddress;
return server;
}

View File

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

View File

@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.Certificate.Test
@ -44,7 +45,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyValidSelfSignedWithClientEkuAuthenticates()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -52,6 +53,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithClientEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
@ -59,7 +61,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyValidSelfSignedWithNoEkuAuthenticates()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -67,6 +69,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithNoEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
@ -74,13 +77,14 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyValidSelfSignedWithClientEkuFailsWhenSelfSignedCertsNotAllowed()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.Chained
},
Certificates.SelfSignedValidWithClientEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -88,7 +92,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyValidSelfSignedWithNoEkuFailsWhenSelfSignedCertsNotAllowed()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.Chained,
@ -96,6 +100,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithNoEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -103,7 +108,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyValidSelfSignedWithServerFailsEvenIfSelfSignedCertsAreAllowed()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -111,6 +116,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -118,7 +124,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyValidSelfSignedWithServerPassesWhenSelfSignedCertsAreAllowedAndPurposeValidationIsOff()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -127,6 +133,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
@ -134,7 +141,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyValidSelfSignedWithServerFailsPurposeValidationIsOffButSelfSignedCertsAreNotAllowed()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.Chained,
@ -143,6 +150,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -150,7 +158,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyExpiredSelfSignedFails()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -159,6 +167,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedExpired);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -166,7 +175,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyExpiredSelfSignedPassesIfDateRangeValidationIsDisabled()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -175,6 +184,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedExpired);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
@ -182,7 +192,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyNotYetValidSelfSignedFails()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -191,6 +201,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedNotYetValid);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -198,7 +209,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyNotYetValidSelfSignedPassesIfDateRangeValidationIsDisabled()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -207,6 +218,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedNotYetValid);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
@ -214,7 +226,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyFailingInTheValidationEventReturnsForbidden()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
ValidateCertificateUse = false,
@ -222,6 +234,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -229,7 +242,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task DoingNothingInTheValidationEventReturnsOK()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -238,6 +251,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithServerEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
@ -245,12 +259,13 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyNotSendingACertificateEndsUpInForbidden()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
Events = successfulValidationEvents
});
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -258,12 +273,13 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyUntrustedClientCertEndsUpInForbidden()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
Events = successfulValidationEvents
}, Certificates.SignedClient);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -271,7 +287,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyClientCertWithUntrustedRootAndTrustedChainEndsUpInForbidden()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
Events = successfulValidationEvents,
@ -280,6 +296,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
RevocationMode = X509RevocationMode.NoCheck
}, Certificates.SignedClient);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
@ -287,7 +304,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyValidClientCertWithTrustedChainAuthenticates()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
Events = successfulValidationEvents,
@ -296,6 +313,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
RevocationMode = X509RevocationMode.NoCheck
}, Certificates.SignedClient);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
@ -303,7 +321,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyHeaderIsUsedIfCertIsNotPresent()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -311,6 +329,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
wireUpHeaderMiddleware: true);
using var server = host.GetTestServer();
var client = server.CreateClient();
client.DefaultRequestHeaders.Add("X-Client-Cert", Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData));
var response = await client.GetAsync("https://example.com/");
@ -320,13 +339,14 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyHeaderEncodedCertFailsOnBadEncoding()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
Events = successfulValidationEvents
},
wireUpHeaderMiddleware: true);
using var server = host.GetTestServer();
var client = server.CreateClient();
client.DefaultRequestHeaders.Add("X-Client-Cert", "OOPS" + Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData));
var response = await client.GetAsync("https://example.com/");
@ -336,7 +356,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifySettingTheAzureHeaderOnTheForwarderOptionsWorks()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -345,6 +365,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
wireUpHeaderMiddleware: true,
headerName: "X-ARR-ClientCert");
using var server = host.GetTestServer();
var client = server.CreateClient();
client.DefaultRequestHeaders.Add("X-ARR-ClientCert", Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData));
var response = await client.GetAsync("https://example.com/");
@ -354,7 +375,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyACustomHeaderFailsIfTheHeaderIsNotPresent()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
Events = successfulValidationEvents
@ -362,6 +383,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
wireUpHeaderMiddleware: true,
headerName: "X-ARR-ClientCert");
using var server = host.GetTestServer();
var client = server.CreateClient();
client.DefaultRequestHeaders.Add("random-Weird-header", Convert.ToBase64String(Certificates.SelfSignedValidWithNoEku.RawData));
var response = await client.GetAsync("https://example.com/");
@ -371,13 +393,14 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
[Fact]
public async Task VerifyNoEventWireupWithAValidCertificateCreatesADefaultUser()
{
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned
},
Certificates.SelfSignedValidWithNoEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -481,7 +504,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
const string Expected = "John Doe";
var validationCount = 0;
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -508,6 +531,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithNoEku, null, null, false, "", cache);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -554,7 +578,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
{
const string Expected = "John Doe";
var server = CreateServer(
using var host = await CreateHost(
new CertificateAuthenticationOptions
{
AllowedCertificateTypes = CertificateTypes.SelfSigned,
@ -577,6 +601,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
},
Certificates.SelfSignedValidWithNoEku);
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("https://example.com/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -596,7 +621,7 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
Assert.Single(responseAsXml.Elements("claim"));
}
private static TestServer CreateServer(
private static async Task<IHost> CreateHost(
CertificateAuthenticationOptions configureOptions,
X509Certificate2 clientCertificate = null,
Func<HttpContext, bool> handler = null,
@ -605,92 +630,95 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test
string headerName = "",
bool useCache = false)
{
var builder = new WebHostBuilder()
.Configure(app =>
{
app.Use((context, next) =>
{
if (clientCertificate != null)
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.Configure(app =>
{
context.Connection.ClientCertificate = clientCertificate;
}
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)
app.Use((context, next) =>
{
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
{
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))
{
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = headerName;
});
}
});
if (wireUpHeaderMiddleware && !string.IsNullOrEmpty(headerName))
{
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = headerName;
});
}
}))
.Build();
var server = new TestServer(builder)
{
BaseAddress = baseAddress
};
await host.StartAsync();
return server;
var server = host.GetTestServer();
server.BaseAddress = baseAddress;
return host;
}
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.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Xunit;
@ -21,12 +22,13 @@ namespace Microsoft.AspNetCore.Authentication
[Fact]
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>("Two", o => o.Instance = new Singleton());
});
// Add One scheme
using var server = host.GetTestServer();
var response = await server.CreateClient().GetAsync("http://example.com/add/One");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var transaction = await server.SendAsync("http://example.com/auth/One");
@ -57,7 +59,8 @@ namespace Microsoft.AspNetCore.Authentication
[Fact]
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"));
// 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()
.Configure(app =>
{
app.UseAuthentication();
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
if (req.Path.StartsWithSegments(new PathString("/add"), out var remainder))
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.Configure(app =>
{
app.UseAuthentication();
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
if (req.Path.StartsWithSegments(new PathString("/add"), out var remainder))
{
var name = remainder.Value.Substring(1);
var auth = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = new AuthenticationScheme(name, name, typeof(TestHandler));
auth.AddScheme(scheme);
}
else if (req.Path.StartsWithSegments(new PathString("/auth"), out remainder))
{
var name = (remainder.Value.Length > 0) ? remainder.Value.Substring(1) : null;
var result = await context.AuthenticateAsync(name);
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);
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 =>
{
configureServices?.Invoke(services);
services.AddAuthentication();
});
return new TestServer(builder);
configureServices?.Invoke(services);
services.AddAuthentication();
}))
.Build();
await host.StartAsync();
return host;
}
}
}

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Linq;
@ -47,7 +48,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact]
public async Task ThrowsIfAppIdMissing()
{
var server = CreateServer(
using var host = await CreateHost(
app => { },
services => services.AddAuthentication().AddFacebook(o => o.SignInScheme = "Whatever"),
async context =>
@ -55,6 +56,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
await Assert.ThrowsAsync<ArgumentException>("AppId", () => context.ChallengeAsync("Facebook"));
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -62,7 +64,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact]
public async Task ThrowsIfAppSecretMissing()
{
var server = CreateServer(
using var host = await CreateHost(
app => { },
services => services.AddAuthentication().AddFacebook(o => o.AppId = "Whatever"),
async context =>
@ -70,6 +72,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
await Assert.ThrowsAsync<ArgumentException>("AppSecret", () => context.ChallengeAsync("Facebook"));
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -77,7 +80,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent()
{
var server = CreateServer(
using var host = await CreateHost(
app =>
{
app.UseAuthentication();
@ -105,6 +108,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
await context.ChallengeAsync("Facebook");
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var query = transaction.Response.Headers.Location.Query;
@ -114,7 +118,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact]
public async Task ChallengeWillIncludeScopeAsConfigured()
{
var server = CreateServer(
using var host = await CreateHost(
app => app.UseAuthentication(),
services =>
{
@ -133,6 +137,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
var res = transaction.Response;
@ -143,7 +148,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact]
public async Task ChallengeWillIncludeScopeAsOverwritten()
{
var server = CreateServer(
using var host = await CreateHost(
app => app.UseAuthentication(),
services =>
{
@ -164,6 +169,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
var res = transaction.Response;
@ -174,7 +180,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact]
public async Task ChallengeWillIncludeScopeAsOverwrittenWithBaseAuthenticationProperties()
{
var server = CreateServer(
using var host = await CreateHost(
app => app.UseAuthentication(),
services =>
{
@ -195,6 +201,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
var res = transaction.Response;
@ -205,7 +212,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact]
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.Map("/login", signoutApp => signoutApp.Run(context => context.ChallengeAsync("Facebook", new AuthenticationProperties() { RedirectUri = "/" })));
@ -222,6 +229,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
},
handler: null);
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/base/login");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -236,7 +244,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact]
public async Task MapWillNotAffectRedirect()
{
var server = CreateServer(
using var host = await CreateHost(
app =>
{
app.UseAuthentication();
@ -254,6 +262,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
});
},
handler: null);
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/login");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -268,7 +277,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
[Fact]
public async Task ChallengeWillTriggerRedirection()
{
var server = CreateServer(
using var host = await CreateHost(
app => app.UseAuthentication(),
services =>
{
@ -288,6 +297,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
await context.ChallengeAsync("Facebook");
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
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 finalUserInfoEndpoint = string.Empty;
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("FacebookTest"));
var server = CreateServer(
using var host = await CreateHost(
app => app.UseAuthentication(),
services =>
{
@ -350,6 +360,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-facebook?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Facebook.{correlationValue}=N");
@ -360,22 +371,27 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
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()
.Configure(app =>
{
configure?.Invoke(app);
app.Use(async (context, next) =>
{
if (handler == null || !await handler(context))
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.Configure(app =>
{
await next();
}
});
})
.ConfigureServices(configureServices);
return new TestServer(builder);
configure?.Invoke(app);
app.Use(async (context, next) =>
{
if (handler == null || !await handler(context))
{
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.WebUtilities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
@ -48,11 +49,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task ChallengeWillTriggerRedirection()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.ToString();
@ -72,11 +74,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task SignInThrows()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signIn");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -84,11 +87,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task SignOutThrows()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -96,11 +100,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task ForbidThrows()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -108,11 +113,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task Challenge401WillNotTriggerRedirection()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/401");
Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode);
}
@ -120,11 +126,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task ChallengeWillSetCorrelationCookie()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge");
Assert.Contains(transaction.SetCookie, cookie => cookie.StartsWith(".AspNetCore.Correlation.Google."));
}
@ -132,11 +139,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task ChallengeWillSetDefaultScope()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var query = transaction.Response.Headers.Location.Query;
@ -147,7 +155,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ChallengeWillUseAuthenticationPropertiesParametersAsQueryArguments()
{
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.ClientSecret = "Test Secret";
@ -172,6 +180,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
return Task.FromResult<object>(null);
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge2");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -198,7 +207,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ChallengeWillUseAuthenticationPropertiesItemsAsParameters()
{
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.ClientSecret = "Test Secret";
@ -223,6 +232,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
return Task.FromResult<object>(null);
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge2");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -249,7 +259,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ChallengeWillUseAuthenticationPropertiesItemsAsQueryArgumentsButParametersWillOverwrite()
{
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.ClientSecret = "Test Secret";
@ -278,6 +288,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
return Task.FromResult<object>(null);
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/challenge2");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -303,7 +314,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
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");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var query = transaction.Response.Headers.Location.Query;
@ -325,7 +337,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task AuthenticateWithoutCookieWillFail()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
@ -340,6 +352,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
Assert.NotNull(result.Failure);
}
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/auth");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -347,11 +360,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task ReplyPathWithoutStateQueryStringWillBeRejected()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
});
using var server = host.GetTestServer();
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);
}
@ -361,7 +375,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[InlineData(false)]
public async Task ReplyPathWithAccessDeniedErrorFails(bool redirect)
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
@ -376,6 +390,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
}
} : 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",
".AspNetCore.Correlation.Google.correlationId=N");
if (redirect)
@ -394,7 +409,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task ReplyPathWithAccessDeniedError_AllowsCustomizingPath()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
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",
".AspNetCore.Correlation.Google.correlationId=N");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -425,7 +441,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
{
var accessDeniedCalled = false;
var remoteFailureCalled = false;
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
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",
".AspNetCore.Correlation.Google.correlationId=N");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
@ -469,7 +486,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
[InlineData(false)]
public async Task ReplyPathWithErrorFails(bool redirect)
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
@ -491,6 +508,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
}
} : 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",
".AspNetCore.Correlation.Google.correlationId=N");
if (redirect)
@ -512,7 +530,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string claimsIssuer)
{
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.ClientSecret = "Test Secret";
@ -531,6 +549,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -567,7 +586,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ReplyPathWillThrowIfCodeIsInvalid(bool redirect)
{
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.ClientSecret = "Test Secret";
@ -597,6 +616,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var sendTask = server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -620,7 +640,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ReplyPathWillRejectIfAccessTokenIsMissing(bool redirect)
{
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.ClientSecret = "Test Secret";
@ -648,6 +668,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var sendTask = server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -669,7 +690,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task AuthenticatedEventCanGetRefreshToken()
{
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.ClientSecret = "Test Secret";
@ -691,6 +712,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -710,7 +732,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task NullRedirectUriWillRedirectToSlash()
{
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.ClientSecret = "Test Secret";
@ -730,6 +752,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
var correlationValue = "TestCorrelationId";
properties.Items.Add(correlationKey, correlationValue);
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -744,7 +767,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ValidateAuthenticatedContext()
{
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.ClientSecret = "Test Secret";
@ -776,6 +799,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
var state = stateFormat.Protect(properties);
//Post a message to the Google middleware
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -787,13 +811,14 @@ namespace Microsoft.AspNetCore.Authentication.Google
[Fact]
public async Task NoStateCausesException()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
});
//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"));
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()
{
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.ClientSecret = "Test Secret";
@ -818,6 +843,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
});
//Post a message to the Google middleware
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode");
@ -830,7 +856,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task AuthenticateAutomaticWhenAlreadySignedInSucceeds()
{
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.ClientSecret = "Test Secret";
@ -847,6 +873,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -873,7 +900,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task AuthenticateGoogleWhenAlreadySignedInSucceeds()
{
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.ClientSecret = "Test Secret";
@ -890,6 +917,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -916,7 +944,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task AuthenticateFacebookWhenAlreadySignedWithGoogleReturnsNull()
{
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.ClientSecret = "Test Secret";
@ -933,6 +961,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
@ -952,7 +981,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
public async Task ChallengeFacebookWhenAlreadySignedWithGoogleSucceeds()
{
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.ClientSecret = "Test Secret";
@ -969,6 +998,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
using var server = host.GetTestServer();
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".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()
.Configure(app =>
{
app.UseAuthentication();
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
if (req.Path == new PathString("/challenge"))
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.Configure(app =>
{
await context.ChallengeAsync();
}
else if (req.Path == new PathString("/challengeFacebook"))
app.UseAuthentication();
app.Use(async (context, next) =>
{
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");
}
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 =>
{
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);
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";
});
}))
.Build();
await host.StartAsync();
return host;
}
private class TestStateDataFormat : ISecureDataFormat<AuthenticationProperties>

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
@ -61,7 +62,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
var tokenText = new JwtSecurityTokenHandler().WriteToken(token);
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.TokenValidationParameters = new TokenValidationParameters()
{
@ -72,6 +73,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
});
var newBearerToken = "Bearer " + tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", newBearerToken);
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
}
@ -96,7 +98,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
var tokenText = new JwtSecurityTokenHandler().WriteToken(token);
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.SaveToken = true;
o.TokenValidationParameters = new TokenValidationParameters()
@ -108,6 +110,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
});
var newBearerToken = "Bearer " + tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/token", newBearerToken);
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal(tokenText, await response.Response.Content.ReadAsStringAsync());
@ -116,7 +119,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
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");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -124,7 +128,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
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");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -132,7 +137,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task ThrowAtAuthenticationFailedEvent()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
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");
Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode);
@ -172,7 +178,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task CustomHeaderReceived()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
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");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal("Bob le Magnifique", response.ResponseText);
@ -201,7 +208,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
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");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
}
@ -209,7 +217,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
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");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
}
@ -217,7 +226,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
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");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("", response.ResponseText);
@ -226,12 +236,13 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task InvalidTokenReceived()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new InvalidTokenValidator());
});
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
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")]
public async Task ExceptionReportedInHeaderForAuthenticationFailures(Type errorType, string message)
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType));
});
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
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'")]
public async Task ExceptionReportedInHeaderWithDetailsForAuthenticationFailures(Type errorType, string message)
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new DetailedInvalidTokenValidator(errorType));
});
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
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))]
public async Task ExceptionNotReportedInHeaderForOtherFailures(Type errorType)
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType));
});
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("Bearer error=\"invalid_token\"", response.Response.Headers.WwwAuthenticate.First().ToString());
@ -300,13 +314,14 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task ExceptionsReportedInHeaderForMultipleAuthenticationFailures()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenInvalidAudienceException)));
options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenSignatureKeyNotFoundException)));
});
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
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\"",
@ -323,7 +338,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[InlineData(null, null, "custom_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
{
@ -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");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("", response.ResponseText);
@ -380,11 +396,12 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task ExceptionNotReportedInHeaderWhenIncludeErrorDetailsIsFalse()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.IncludeErrorDetails = false;
});
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("Bearer", response.Response.Headers.WwwAuthenticate.First().ToString());
@ -394,8 +411,9 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
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");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
Assert.Equal("Bearer", response.Response.Headers.WwwAuthenticate.First().ToString());
@ -405,7 +423,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task CustomTokenValidated()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.Events = new JwtBearerEvents()
{
@ -432,6 +450,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator(JwtBearerDefaults.AuthenticationScheme));
});
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal("Bob le Magnifique", response.ResponseText);
@ -440,7 +459,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task RetrievingTokenFromAlternateLocation()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
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");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal("Bob le Tout Puissant", response.ResponseText);
@ -465,7 +485,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task EventOnMessageReceivedSkip_NoMoreEventsExecuted()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
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");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal(string.Empty, response.ResponseText);
@ -497,7 +518,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task EventOnMessageReceivedReject_NoMoreEventsExecuted()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
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
{
return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
@ -533,7 +555,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task EventOnTokenValidatedSkip_NoMoreEventsExecuted()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.Events = new JwtBearerEvents()
{
@ -555,6 +577,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
});
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal(string.Empty, response.ResponseText);
@ -563,7 +586,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task EventOnTokenValidatedReject_NoMoreEventsExecuted()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.Events = new JwtBearerEvents()
{
@ -586,6 +609,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
});
using var server = host.GetTestServer();
var exception = await Assert.ThrowsAsync<Exception>(delegate
{
return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
@ -597,7 +621,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task EventOnAuthenticationFailedSkip_NoMoreEventsExecuted()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.Events = new JwtBearerEvents()
{
@ -619,6 +643,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
});
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Equal(string.Empty, response.ResponseText);
@ -627,7 +652,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task EventOnAuthenticationFailedReject_NoMoreEventsExecuted()
{
var server = CreateServer(options =>
using var host = await CreateHost(options =>
{
options.Events = new JwtBearerEvents()
{
@ -650,6 +675,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
});
using var server = host.GetTestServer();
var exception = await Assert.ThrowsAsync<Exception>(delegate
{
return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token");
@ -661,7 +687,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
[Fact]
public async Task EventOnChallengeSkip_ResponseNotModified()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
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");
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
Assert.Empty(response.Response.Headers.WwwAuthenticate);
@ -684,7 +711,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
var tokenData = CreateStandardTokenAndKey();
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.TokenValidationParameters = new TokenValidationParameters()
{
@ -694,6 +721,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
};
});
var newBearerToken = "Bearer " + tokenData.tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken);
Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode);
}
@ -702,7 +730,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
public async Task EventOnForbiddenSkip_ResponseNotModified()
{
var tokenData = CreateStandardTokenAndKey();
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.TokenValidationParameters = new TokenValidationParameters()
{
@ -719,6 +747,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
};
});
var newBearerToken = "Bearer " + tokenData.tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken);
Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode);
}
@ -727,7 +756,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
public async Task EventOnForbidden_ResponseModified()
{
var tokenData = CreateStandardTokenAndKey();
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.TokenValidationParameters = new TokenValidationParameters()
{
@ -745,6 +774,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
};
});
var newBearerToken = "Bearer " + tokenData.tokenText;
using var server = host.GetTestServer();
var response = await SendAsync(server, "http://example.com/forbidden", newBearerToken);
Assert.Equal(418, (int)response.Response.StatusCode);
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()
.Configure(app =>
{
if (handlerBeforeAuth != null)
{
app.Use(handlerBeforeAuth);
}
app.UseAuthentication();
app.Use(async (context, next) =>
{
if (context.Request.Path == new PathString("/checkforerrors"))
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.Configure(app =>
{
var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); // this used to be "Automatic"
if (result.Failure != null)
if (handlerBeforeAuth != 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;
app.Use(handlerBeforeAuth);
}
var identifier = context.User.FindFirst(ClaimTypes.NameIdentifier);
if (identifier == null)
app.UseAuthentication();
app.Use(async (context, next) =>
{
context.Response.StatusCode = 500;
return;
}
if (context.Request.Path == new PathString("/checkforerrors"))
{
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);
}
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));
var identifier = context.User.FindFirst(ClaimTypes.NameIdentifier);
if (identifier == null)
{
context.Response.StatusCode = 500;
return;
}
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)

View File

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

View File

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

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
@ -550,16 +551,19 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
private TestServer BuildTestServer(Action<OpenIdConnectOptions> options)
{
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddAuthentication()
.AddCookie()
.AddOpenIdConnect(options);
})
.Configure(app => app.UseAuthentication());
return new TestServer(builder);
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.ConfigureServices(services =>
{
services.AddAuthentication()
.AddCookie()
.AddOpenIdConnect(options);
})
.Configure(app => app.UseAuthentication()))
.Build();
host.Start();
return host.GetTestServer();
}
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.
using System;
@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
@ -1266,39 +1267,43 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
private TestServer CreateServer(OpenIdConnectEvents events, RequestDelegate appCode)
{
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddAuthentication(auth =>
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.ConfigureServices(services =>
{
auth.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
auth.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(o =>
{
o.Events = events;
o.ClientId = "ClientId";
o.GetClaimsFromUserInfoEndpoint = true;
o.Configuration = new OpenIdConnectConfiguration()
services.AddAuthentication(auth =>
{
TokenEndpoint = "http://testhost/tokens",
UserInfoEndpoint = "http://testhost/user",
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);
});
auth.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
auth.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(o =>
{
o.Events = events;
o.ClientId = "ClientId";
o.GetClaimsFromUserInfoEndpoint = true;
o.Configuration = new OpenIdConnectConfiguration()
{
TokenEndpoint = "http://testhost/tokens",
UserInfoEndpoint = "http://testhost/user",
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)

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
@ -62,59 +63,63 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
Func<HttpContext, Task> handler,
AuthenticationProperties properties)
{
var builder = new WebHostBuilder()
.Configure(app =>
{
app.UseAuthentication();
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.Configure(app =>
{
app.UseAuthentication();
app.Use(async (context, next) =>
{
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);
}
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 =>
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie()
.AddOpenIdConnect(options);
});
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie()
.AddOpenIdConnect(options);
}))
.Build();
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.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Threading.Tasks;
using Xunit;
@ -16,8 +17,8 @@ namespace Microsoft.AspNetCore.Authentication
{
protected override string DisplayName => DefaultScheme;
private TestServer CreateServer(Action<TOptions> configureOptions, Func<HttpContext, Task> testpath = null, bool isDefault = true)
=> CreateServerWithServices(s =>
private Task<IHost> CreateHost(Action<TOptions> configureOptions, Func<HttpContext, Task> testpath = null, bool isDefault = true)
=> CreateHostWithServices(s =>
{
var builder = s.AddAuthentication();
if (isDefault)
@ -29,23 +30,26 @@ namespace Microsoft.AspNetCore.Authentication
}, 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 builder = new WebHostBuilder()
.Configure(app =>
{
app.Use(async (context, next) =>
{
if (testpath != null)
var host = new HostBuilder()
.ConfigureWebHost(webHostBuilder =>
webHostBuilder.UseTestServer()
.Configure(app =>
{
await testpath(context);
}
await next();
});
})
.ConfigureServices(configureServices);
return new TestServer(builder);
app.Use(async (context, next) =>
{
if (testpath != null)
{
await testpath(context);
}
await next();
});
})
.ConfigureServices(configureServices))
.Build();
await host.StartAsync();
return host;
}
protected abstract void ConfigureDefaults(TOptions o);
@ -53,13 +57,14 @@ namespace Microsoft.AspNetCore.Authentication
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelf()
{
var server = CreateServer(
using var host = await CreateHost(
o =>
{
ConfigureDefaults(o);
o.SignInScheme = DefaultScheme;
},
context => context.ChallengeAsync(DefaultScheme));
using var server = host.GetTestServer();
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
@ -67,10 +72,12 @@ namespace Microsoft.AspNetCore.Authentication
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultScheme()
{
var server = CreateServer(
using var host = await CreateHost(
o => o.SignInScheme = null,
context => context.ChallengeAsync(DefaultScheme),
isDefault: true);
using var server = host.GetTestServer();
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
@ -78,13 +85,14 @@ namespace Microsoft.AspNetCore.Authentication
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultSignInScheme()
{
var server = CreateServerWithServices(
using var host = await CreateHostWithServices(
services =>
{
var builder = services.AddAuthentication(o => o.DefaultSignInScheme = DefaultScheme);
RegisterAuth(builder, o => o.SignInScheme = null);
},
context => context.ChallengeAsync(DefaultScheme));
using var server = host.GetTestServer();
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
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.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Net.Http.Headers;
using System;
using System.Linq;
@ -43,7 +44,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
@ -65,6 +66,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter");
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var query = transaction.Response.Headers.Location.Query;
@ -78,11 +80,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task ThrowsIfClientIdMissing()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerSecret = "Test Consumer Secret";
});
using var server = host.GetTestServer();
await Assert.ThrowsAsync<ArgumentException>("ConsumerKey", async () => await server.SendAsync("http://example.com/challenge"));
}
@ -93,24 +96,26 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task ThrowsIfClientSecretMissing()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
});
using var server = host.GetTestServer();
await Assert.ThrowsAsync<ArgumentException>("ConsumerSecret", async () => await server.SendAsync("http://example.com/challenge"));
}
[Fact]
public async Task BadSignInWillThrow()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
});
// Send a bogus sign in
using var server = host.GetTestServer();
var error = await Assert.ThrowsAnyAsync<Exception>(() => server.SendAsync("https://example.com/signin-twitter"));
Assert.Equal("Invalid state cookie.", error.GetBaseException().Message);
}
@ -118,11 +123,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task SignInThrows()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signIn");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -130,11 +136,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task SignOutThrows()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -142,11 +149,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task ForbidThrows()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("https://example.com/signOut");
Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode);
}
@ -154,7 +162,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task ChallengeWillTriggerRedirection()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
@ -168,6 +176,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter");
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -177,7 +186,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task HandleRequestAsync_RedirectsToAccessDeniedPathWhenExplicitlySet()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
@ -195,6 +204,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter", properties);
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -217,7 +227,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task BadCallbackCallsAccessDeniedWithState()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
@ -244,6 +254,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter", properties);
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -265,7 +276,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
[Fact]
public async Task BadCallbackCallsRemoteAuthFailedWithState()
{
var server = CreateServer(o =>
using var host = await CreateHost(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
@ -294,6 +305,8 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await context.ChallengeAsync("Twitter", properties);
return true;
});
using var server = host.GetTestServer();
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri;
@ -312,46 +325,51 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
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()
.Configure(app =>
{
app.UseAuthentication();
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
if (req.Path == new PathString("/signIn"))
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.Configure(app =>
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("Twitter", new ClaimsPrincipal()));
}
else if (req.Path == new PathString("/signOut"))
app.UseAuthentication();
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()));
}
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"));
}
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 =>
{
Action<TwitterOptions> wrapOptions = o =>
{
o.SignInScheme = "External";
options(o);
};
services.AddAuthentication()
.AddCookie("External", _ => { })
.AddTwitter(wrapOptions);
});
return new TestServer(builder);
Action<TwitterOptions> wrapOptions = o =>
{
o.SignInScheme = "External";
options(o);
};
services.AddAuthentication()
.AddCookie("External", _ => { })
.AddTwitter(wrapOptions);
}))
.Build();
await host.StartAsync();
return host;
}
private HttpResponseMessage BackchannelRequestToken(HttpRequestMessage req)

View File

@ -19,6 +19,7 @@ using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Net.Http.Headers;
using Xunit;
@ -43,20 +44,25 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task MissingConfigurationThrows()
{
var builder = new WebHostBuilder()
.Configure(ConfigureApp)
.ConfigureServices(services =>
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddWsFederation();
});
var server = new TestServer(builder);
using var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.Configure(ConfigureApp)
.ConfigureServices(services =>
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddWsFederation();
}))
.Build();
await host.StartAsync();
using var server = host.GetTestServer();
var httpClient = server.CreateClient();
// Verify if the request is redirected to STS with right parameters
@ -67,7 +73,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task ChallengeRedirects()
{
var httpClient = CreateClient();
var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/");
@ -83,7 +89,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task MapWillNotAffectRedirect()
{
var httpClient = CreateClient();
var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/mapped-challenge");
@ -99,7 +105,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task PreMappedWillAffectRedirect()
{
var httpClient = CreateClient();
var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/premapped-challenge");
@ -115,7 +121,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task ValidTokenIsAccepted()
{
var httpClient = CreateClient();
var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/");
@ -139,7 +145,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task ValidUnsolicitedTokenIsRefused()
{
var httpClient = CreateClient();
var httpClient = await CreateClient();
var form = CreateSignInContent("WsFederation/ValidToken.xml", suppressWctx: true);
var exception = await Assert.ThrowsAsync<Exception>(() => httpClient.PostAsync(httpClient.BaseAddress + "signin-wsfed", form));
Assert.Contains("Unsolicited logins are not allowed.", exception.InnerException.Message);
@ -148,7 +154,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task ValidUnsolicitedTokenIsAcceptedWhenAllowed()
{
var httpClient = CreateClient(allowUnsolicited: true);
var httpClient = await CreateClient(allowUnsolicited: true);
var form = CreateSignInContent("WsFederation/ValidToken.xml", suppressWctx: true);
var response = await httpClient.PostAsync(httpClient.BaseAddress + "signin-wsfed", form);
@ -166,7 +172,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task InvalidTokenIsRejected()
{
var httpClient = CreateClient();
var httpClient = await CreateClient();
// Verify if the request is redirected to STS with right parameters
var response = await httpClient.GetAsync("/");
@ -184,7 +190,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task RemoteSignoutRequestTriggersSignout()
{
var httpClient = CreateClient();
var httpClient = await CreateClient();
var response = await httpClient.GetAsync("/signin-wsfed?wa=wsignoutcleanup1.0");
response.EnsureSuccessStatusCode();
@ -198,30 +204,35 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
[Fact]
public async Task EventsResolvedFromDI()
{
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddSingleton<MyWsFedEvents>();
services.AddAuthentication(sharedOptions =>
{
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.EventsType = typeof(MyWsFedEvents);
});
})
.Configure(app =>
{
app.Run(context => context.ChallengeAsync());
});
var server = new TestServer(builder);
using var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.ConfigureServices(services =>
{
services.AddSingleton<MyWsFedEvents>();
services.AddAuthentication(sharedOptions =>
{
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.EventsType = typeof(MyWsFedEvents);
});
})
.Configure(app =>
{
app.Run(context => context.ChallengeAsync());
}))
.Build();
await host.StartAsync();
using var server = host.GetTestServer();
var result = await server.CreateClient().GetAsync("");
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()
.Configure(ConfigureApp)
.ConfigureServices(services =>
{
services.AddAuthentication(sharedOptions =>
var host = new HostBuilder()
.ConfigureWebHost(builder =>
builder.UseTestServer()
.Configure(ConfigureApp)
.ConfigureServices(services =>
{
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()
services.AddAuthentication(sharedOptions =>
{
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");
}
context.HttpContext.Items["MessageReceived"] = true;
return Task.FromResult(0);
},
OnRedirectToIdentityProvider = context =>
{
if (context.ProtocolMessage.IsSignInMessage)
if (!context.ProtocolMessage.Parameters.TryGetValue("suppressWctx", out var suppress))
{
Assert.True(context.ProtocolMessage.Wctx.Equals("customValue"), "wctx is not my custom value");
}
context.HttpContext.Items["MessageReceived"] = true;
return Task.FromResult(0);
},
OnRedirectToIdentityProvider = context =>
{
// Sign in message
context.ProtocolMessage.Wctx = "customValue";
}
if (context.ProtocolMessage.IsSignInMessage)
{
// Sign in message
context.ProtocolMessage.Wctx = "customValue";
}
return Task.FromResult(0);
},
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)
return Task.FromResult(0);
},
OnSecurityTokenReceived = context =>
{
var identity = context.Principal.Identities.Single();
identity.AddClaim(new Claim("ReturnEndpoint", "true"));
identity.AddClaim(new Claim("Authenticated", "true"));
identity.AddClaim(new Claim(identity.RoleClaimType, "Guest", ClaimValueTypes.String));
}
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");
return Task.FromResult(0);
},
OnAuthenticationFailed = context =>
{
context.HttpContext.Items["AuthenticationFailed"] = 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.
context.HttpContext.Request.Path = new PathString("/AuthenticationFailed");
context.SkipHandler();
return Task.FromResult(0);
},
OnRemoteSignOut = context =>
{
context.Response.Headers["EventHeader"] = "OnRemoteSignOut";
return Task.FromResult(0);
}
};
});
});
var server = new TestServer(builder);
if (context.Principal != null)
{
var identity = context.Principal.Identities.Single();
identity.AddClaim(new Claim("ReturnEndpoint", "true"));
identity.AddClaim(new Claim("Authenticated", "true"));
identity.AddClaim(new Claim(identity.RoleClaimType, "Guest", ClaimValueTypes.String));
}
return Task.FromResult(0);
},
OnAuthenticationFailed = context =>
{
context.HttpContext.Items["AuthenticationFailed"] = 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.
context.HttpContext.Request.Path = new PathString("/AuthenticationFailed");
context.SkipHandler();
return Task.FromResult(0);
},
OnRemoteSignOut = context =>
{
context.Response.Headers["EventHeader"] = "OnRemoteSignOut";
return Task.FromResult(0);
}
};
});
}))
.Build();
await host.StartAsync();
var server = host.GetTestServer();
return server.CreateClient();
}