Add functional tests

+ cleanup
Fixes https://github.com/aspnet/Identity/issues/395
Fixes https://github.com/aspnet/Identity/issues/231
This commit is contained in:
Hao Kung 2015-03-12 16:30:32 -07:00
parent 99f5a9cfed
commit 2246a41978
8 changed files with 348 additions and 196 deletions

View File

@ -23,6 +23,11 @@ namespace Microsoft.Framework.DependencyInjection
return services.Configure<IdentityOptions>(config);
}
public static IServiceCollection ConfigureIdentityApplicationCookie(this IServiceCollection services, Action<CookieAuthenticationOptions> configureOptions)
{
return services.Configure<CookieAuthenticationOptions>(configureOptions, IdentityOptions.ApplicationCookieAuthenticationScheme);
}
public static IdentityBuilder AddIdentity(this IServiceCollection services)
{
return services.AddIdentity<IdentityUser, IdentityRole>(configureOptions: null);
@ -72,7 +77,7 @@ namespace Microsoft.Framework.DependencyInjection
});
// Configure all of the cookie middlewares
services.Configure<CookieAuthenticationOptions>(options =>
services.ConfigureIdentityApplicationCookie(options =>
{
options.AuthenticationScheme = IdentityOptions.ApplicationCookieAuthenticationScheme;
options.LoginPath = new PathString("/Account/Login");
@ -80,7 +85,7 @@ namespace Microsoft.Framework.DependencyInjection
{
OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
};
}, IdentityOptions.ApplicationCookieAuthenticationScheme);
});
services.Configure<CookieAuthenticationOptions>(options =>
{
options.AuthenticationScheme = IdentityOptions.ExternalCookieAuthenticationScheme;

View File

@ -18,14 +18,13 @@ namespace System.Security.Principal
/// <param name="principal">The <see cref="IPrincipal"/> instance this method extends.</param>
/// <returns>The Name claim value, or null if the claim is not present.</returns>
/// <remarks>The name claim is identified by <see cref="ClaimsIdentity.DefaultNameClaimType"/>.</remarks>
public static string GetUserName(this IPrincipal principal)
public static string GetUserName(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
var cp = principal as ClaimsPrincipal;
return cp != null ? cp.FindFirstValue(ClaimsIdentity.DefaultNameClaimType) : null;
return principal.FindFirstValue(ClaimsIdentity.DefaultNameClaimType);
}
/// <summary>
@ -34,14 +33,13 @@ namespace System.Security.Principal
/// <param name="principal">The <see cref="IPrincipal"/> instance this method extends.</param>
/// <returns>The User ID claim value, or null if the claim is not present.</returns>
/// <remarks>The name claim is identified by <see cref="ClaimTypes.NameIdentifier"/>.</remarks>
public static string GetUserId(this IPrincipal principal)
public static string GetUserId(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
var ci = principal as ClaimsPrincipal;
return ci != null ? ci.FindFirstValue(ClaimTypes.NameIdentifier) : null;
return principal.FindFirstValue(ClaimTypes.NameIdentifier);
}
/// <summary>
@ -49,15 +47,14 @@ namespace System.Security.Principal
/// </summary>
/// <param name="principal">The <see cref="IPrincipal"/> instance this method extends.</param>
/// <returns>True if the user is logged in with identity.</returns>
public static bool IsSignedIn(this IPrincipal principal)
public static bool IsSignedIn(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
var p = principal as ClaimsPrincipal;
return p?.Identities != null &&
p.Identities.Any(i => i.AuthenticationType == IdentityOptions.ApplicationCookieAuthenticationType);
return principal.Identities != null &&
principal.Identities.Any(i => i.AuthenticationType == IdentityOptions.ApplicationCookieAuthenticationType);
}
/// <summary>

View File

@ -1,130 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30408.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.net45", "..\src\Microsoft.AspNet.Identity\Microsoft.AspNet.Identity.net45.csproj", "{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{31019886-9CDA-4072-B3D9-E513122CECD0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Entity.net45", "..\src\Microsoft.AspNet.Identity.Entity\Microsoft.AspNet.Identity.Entity.net45.csproj", "{B00CB809-C040-42A4-8AB2-4CFB924DD038}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.InMemory.net45", "..\src\Microsoft.AspNet.Identity.InMemory\Microsoft.AspNet.Identity.InMemory.net45.csproj", "{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Security.net45", "..\src\Microsoft.AspNet.Identity.Security\Microsoft.AspNet.Identity.Security.net45.csproj", "{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{394C0E59-7E24-453E-993C-7B914C62110A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Test.net45", "..\test\Microsoft.AspNet.Identity.Test\Microsoft.AspNet.Identity.Test.net45.csproj", "{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Security.Test.net45", "..\test\Microsoft.AspNet.Identity.Security.Test\Microsoft.AspNet.Identity.Security.Test.net45.csproj", "{13883A27-8710-421A-86CE-298E34CE82DD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.InMemory.Test.net45", "..\test\Microsoft.AspNet.Identity.InMemory.Test\Microsoft.AspNet.Identity.InMemory.Test.net45.csproj", "{47F00656-3F63-45CD-BBE5-1505CE7938D3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Entity.Test.net45", "..\test\Microsoft.AspNet.Identity.Entity.Test\Microsoft.AspNet.Identity.Entity.Test.net45.csproj", "{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Debug|x86.ActiveCfg = Debug|Any CPU
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Release|Any CPU.Build.0 = Release|Any CPU
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A}.Release|x86.ActiveCfg = Release|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Debug|x86.ActiveCfg = Debug|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Release|Any CPU.Build.0 = Release|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{B00CB809-C040-42A4-8AB2-4CFB924DD038}.Release|x86.ActiveCfg = Release|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Debug|x86.ActiveCfg = Debug|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Release|Any CPU.Build.0 = Release|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F}.Release|x86.ActiveCfg = Release|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Debug|x86.ActiveCfg = Debug|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Release|Any CPU.Build.0 = Release|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8}.Release|x86.ActiveCfg = Release|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Debug|x86.ActiveCfg = Debug|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Release|Any CPU.Build.0 = Release|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486}.Release|x86.ActiveCfg = Release|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Debug|x86.ActiveCfg = Debug|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Release|Any CPU.Build.0 = Release|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{13883A27-8710-421A-86CE-298E34CE82DD}.Release|x86.ActiveCfg = Release|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Debug|x86.ActiveCfg = Debug|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Release|Any CPU.Build.0 = Release|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{47F00656-3F63-45CD-BBE5-1505CE7938D3}.Release|x86.ActiveCfg = Release|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Debug|x86.ActiveCfg = Debug|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Release|Any CPU.Build.0 = Release|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{91C0C8AC-F889-4EB9-B4C7-1EB951FC428A} = {31019886-9CDA-4072-B3D9-E513122CECD0}
{B00CB809-C040-42A4-8AB2-4CFB924DD038} = {31019886-9CDA-4072-B3D9-E513122CECD0}
{13A0C423-FD34-41B7-AB46-2BB16CF5DC1F} = {31019886-9CDA-4072-B3D9-E513122CECD0}
{ADE2B479-1D29-4D63-9B8B-D5E05943C4A8} = {31019886-9CDA-4072-B3D9-E513122CECD0}
{CD364B81-5435-4EF7-ADE7-B6E02E0B4486} = {394C0E59-7E24-453E-993C-7B914C62110A}
{13883A27-8710-421A-86CE-298E34CE82DD} = {394C0E59-7E24-453E-993C-7B914C62110A}
{47F00656-3F63-45CD-BBE5-1505CE7938D3} = {394C0E59-7E24-453E-993C-7B914C62110A}
{9CDAEF16-DD10-4307-9186-EC70BF8A5AD8} = {394C0E59-7E24-453E-993C-7B914C62110A}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,304 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Diagnostics;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
using Microsoft.AspNet.TestHost;
using Microsoft.Framework.DependencyInjection;
using Microsoft.AspNet.Authentication.Cookies;
using Shouldly;
using Xunit;
namespace Microsoft.AspNet.Identity.InMemory
{
public class FunctionalTest
{
const string TestPassword = "1qaz!QAZ";
[Fact]
public async Task CanCreateMeLoginAndCookieStopsWorkingAfterExpiration()
{
var clock = new TestClock();
TestServer server = CreateServer(appCookieOptions =>
{
appCookieOptions.SystemClock = clock;
appCookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(10);
appCookieOptions.SlidingExpiration = false;
});
Transaction transaction1 = await SendAsync(server, "http://example.com/createMe");
transaction1.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
Assert.Null(transaction1.SetCookie);
Transaction transaction2 = await SendAsync(server, "http://example.com/pwdLogin/false");
transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
Assert.NotNull(transaction2.SetCookie);
transaction2.SetCookie.ShouldNotContain("; expires=");
Transaction transaction3 = await SendAsync(server, "http://example.com/me", transaction2.CookieNameValue);
FindClaimValue(transaction3, ClaimTypes.Name).ShouldBe("hao");
Assert.Null(transaction3.SetCookie);
clock.Add(TimeSpan.FromMinutes(7));
Transaction transaction4 = await SendAsync(server, "http://example.com/me", transaction2.CookieNameValue);
FindClaimValue(transaction4, ClaimTypes.Name).ShouldBe("hao");
Assert.Null(transaction4.SetCookie);
clock.Add(TimeSpan.FromMinutes(7));
Transaction transaction5 = await SendAsync(server, "http://example.com/me", transaction2.CookieNameValue);
FindClaimValue(transaction5, ClaimTypes.Name).ShouldBe(null);
Assert.Null(transaction5.SetCookie);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task CanCreateMeLoginAndSecurityStampExtendsExpiration(bool rememberMe)
{
var clock = new TestClock();
TestServer server = CreateServer(appCookieOptions =>
{
appCookieOptions.SystemClock = clock;
});
Transaction transaction1 = await SendAsync(server, "http://example.com/createMe");
transaction1.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
Assert.Null(transaction1.SetCookie);
Transaction transaction2 = await SendAsync(server, "http://example.com/pwdLogin/" + rememberMe);
transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
Assert.NotNull(transaction2.SetCookie);
if (rememberMe)
{
transaction2.SetCookie.ShouldContain("; expires=");
}
else
{
transaction2.SetCookie.ShouldNotContain("; expires=");
}
Transaction transaction3 = await SendAsync(server, "http://example.com/me", transaction2.CookieNameValue);
FindClaimValue(transaction3, ClaimTypes.Name).ShouldBe("hao");
Assert.Null(transaction3.SetCookie);
// Make sure we don't get a new cookie yet
clock.Add(TimeSpan.FromMinutes(10));
Transaction transaction4 = await SendAsync(server, "http://example.com/me", transaction2.CookieNameValue);
FindClaimValue(transaction4, ClaimTypes.Name).ShouldBe("hao");
Assert.Null(transaction4.SetCookie);
// Go past SecurityStampValidation interval and ensure we get a new cookie
clock.Add(TimeSpan.FromMinutes(21));
Transaction transaction5 = await SendAsync(server, "http://example.com/me", transaction2.CookieNameValue);
Assert.NotNull(transaction5.SetCookie);
FindClaimValue(transaction5, ClaimTypes.Name).ShouldBe("hao");
// Make sure new cookie is valid
Transaction transaction6 = await SendAsync(server, "http://example.com/me", transaction5.CookieNameValue);
FindClaimValue(transaction6, ClaimTypes.Name).ShouldBe("hao");
}
[Fact]
public async Task TwoFactorRememberCookieVerification()
{
TestServer server = CreateServer(appCookieOptions => { });
Transaction transaction1 = await SendAsync(server, "http://example.com/createMe");
transaction1.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
Assert.Null(transaction1.SetCookie);
Transaction transaction2 = await SendAsync(server, "http://example.com/twofactorRememeber");
transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
string setCookie = transaction2.SetCookie;
setCookie.ShouldContain(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme+"=");
setCookie.ShouldContain("; expires=");
Transaction transaction3 = await SendAsync(server, "http://example.com/isTwoFactorRememebered", transaction2.CookieNameValue);
transaction3.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
}
private static string FindClaimValue(Transaction transaction, string claimType)
{
XElement claim = transaction.ResponseElement.Elements("claim").SingleOrDefault(elt => elt.Attribute("type").Value == claimType);
if (claim == null)
{
return null;
}
return claim.Attribute("value").Value;
}
private static async Task<XElement> GetAuthData(TestServer server, string url, string cookie)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("Cookie", cookie);
HttpResponseMessage response2 = await server.CreateClient().SendAsync(request);
string text = await response2.Content.ReadAsStringAsync();
XElement me = XElement.Parse(text);
return me;
}
private static TestServer CreateServer(Action<CookieAuthenticationOptions> configureAppCookie, Func<HttpContext, Task> testpath = null, Uri baseAddress = null)
{
var server = TestServer.Create(app =>
{
app.UseServices(services =>
{
services.AddIdentity<InMemoryUser, IdentityRole>();
services.AddSingleton<IUserStore<InMemoryUser>, InMemoryUserStore<InMemoryUser>>();
services.AddSingleton<IRoleStore<IdentityRole>, InMemoryRoleStore<IdentityRole>>();
services.ConfigureIdentityApplicationCookie(configureAppCookie);
});
app.UseIdentity();
app.Use(async (context, next) =>
{
var req = context.Request;
var res = context.Response;
var userManager = context.RequestServices.GetRequiredService<UserManager<InMemoryUser>>();
var signInManager = context.RequestServices.GetRequiredService<SignInManager<InMemoryUser>>();
PathString remainder;
if (req.Path == new PathString("/normal"))
{
res.StatusCode = 200;
}
else if (req.Path == new PathString("/createMe"))
{
var result = await userManager.CreateAsync(new InMemoryUser("hao"), TestPassword);
res.StatusCode = result.Succeeded ? 200 : 500;
}
else if (req.Path == new PathString("/protected"))
{
res.StatusCode = 401;
}
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("/twofactorSignIn"))
{
}
else if (req.Path == new PathString("/me"))
{
Describe(res, new AuthenticationResult(context.User, new AuthenticationProperties(), new AuthenticationDescription()));
}
else if (req.Path.StartsWithSegments(new PathString("/me"), out remainder))
{
var result = await context.AuthenticateAsync(remainder.Value.Substring(1));
Describe(res, result);
}
else if (req.Path == new PathString("/testpath") && testpath != null)
{
await testpath(context);
}
else
{
await next();
}
});
});
server.BaseAddress = baseAddress;
return server;
}
private static void Describe(HttpResponse res, AuthenticationResult result)
{
res.StatusCode = 200;
res.ContentType = "text/xml";
var xml = new XElement("xml");
if (result != null && result.Principal != null)
{
xml.Add(result.Principal.Claims.Select(claim => new XElement("claim", new XAttribute("type", claim.Type), new XAttribute("value", claim.Value))));
}
if (result != null && result.Properties != null)
{
xml.Add(result.Properties.Dictionary.Select(extra => new XElement("extra", new XAttribute("type", extra.Key), new XAttribute("value", extra.Value))));
}
using (var memory = new MemoryStream())
{
using (var writer = new XmlTextWriter(memory, Encoding.UTF8))
{
xml.WriteTo(writer);
}
res.Body.Write(memory.ToArray(), 0, memory.ToArray().Length);
}
}
private static async Task<Transaction> SendAsync(TestServer server, string uri, string cookieHeader = null, bool ajaxRequest = false)
{
var request = new HttpRequestMessage(HttpMethod.Get, uri);
if (!string.IsNullOrEmpty(cookieHeader))
{
request.Headers.Add("Cookie", cookieHeader);
}
if (ajaxRequest)
{
request.Headers.Add("X-Requested-With", "XMLHttpRequest");
}
var transaction = new Transaction
{
Request = request,
Response = await server.CreateClient().SendAsync(request),
};
if (transaction.Response.Headers.Contains("Set-Cookie"))
{
transaction.SetCookie = transaction.Response.Headers.GetValues("Set-Cookie").SingleOrDefault();
}
if (!string.IsNullOrEmpty(transaction.SetCookie))
{
transaction.CookieNameValue = transaction.SetCookie.Split(new[] { ';' }, 2).First();
}
transaction.ResponseText = await transaction.Response.Content.ReadAsStringAsync();
if (transaction.Response.Content != null &&
transaction.Response.Content.Headers.ContentType != null &&
transaction.Response.Content.Headers.ContentType.MediaType == "text/xml")
{
transaction.ResponseElement = XElement.Parse(transaction.ResponseText);
}
return transaction;
}
private class Transaction
{
public HttpRequestMessage Request { get; set; }
public HttpResponseMessage Response { get; set; }
public string SetCookie { get; set; }
public string CookieNameValue { get; set; }
public string ResponseText { get; set; }
public XElement ResponseElement { get; set; }
}
}
}

View File

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Authentication;
namespace Microsoft.AspNet.Identity.InMemory
{
public class TestClock : ISystemClock
{
public TestClock()
{
UtcNow = new DateTimeOffset(2013, 6, 11, 12, 34, 56, 789, TimeSpan.Zero);
}
public DateTimeOffset UtcNow { get; set; }
public void Add(TimeSpan timeSpan)
{
UtcNow = UtcNow + timeSpan;
}
}
}

View File

@ -1,22 +1,24 @@
{
"dependencies": {
"Microsoft.AspNet.Authentication" : "1.0.0-*",
"Microsoft.AspNet.Authentication.Cookies" : "1.0.0-*",
"Microsoft.AspNet.Hosting": "1.0.0-*",
"Microsoft.AspNet.Http" : "1.0.0-*",
"Microsoft.AspNet.Identity" : "3.0.0-*",
"Microsoft.AspNet.RequestContainer" : "1.0.0-*",
"Microsoft.AspNet.Authentication" : "1.0.0-*",
"Microsoft.AspNet.Authentication.Cookies" : "1.0.0-*",
"Microsoft.AspNet.TestHost": "1.0.0-*",
"Microsoft.AspNet.Testing" : "1.0.0-*",
"Microsoft.Framework.ConfigurationModel": "1.0.0-*",
"Microsoft.Framework.DependencyInjection" : "1.0.0-*",
"Microsoft.Framework.OptionsModel" : "1.0.0-*",
"Moq": "4.2.1312.1622",
"xunit.runner.kre": "1.0.0-*"
},
"code": "**\\*.cs;..\\Shared\\*.cs",
"frameworks": {
"dnx451": {
"dependencies": {
"Moq" : "4.2.1312.1622"
"Shouldly": "1.1.1.1"
}
}
},

View File

@ -1,6 +0,0 @@
namespace Microsoft.AspNet.Identity.Test
{
internal interface IHttpContextAccessor<T>
{
}
}

View File

@ -15,21 +15,12 @@ namespace Microsoft.AspNet.Identity.Test
[Fact]
public void IdentityNullCheckTest()
{
IPrincipal p = null;
Assert.Throws<ArgumentNullException>("principal", () => p.GetUserId());
Assert.Throws<ArgumentNullException>("principal", () => p.GetUserName());
ClaimsPrincipal cp = null;
Assert.Throws<ArgumentNullException>("principal", () => cp.GetUserId());
Assert.Throws<ArgumentNullException>("principal", () => cp.GetUserName());
Assert.Throws<ArgumentNullException>("principal", () => cp.FindFirstValue(null));
}
[Fact]
public void IdentityNullIfNotClaimsIdentityTest()
{
IPrincipal identity = new TestPrincipal();
Assert.Null(identity.GetUserId());
Assert.Null(identity.GetUserName());
}
[Fact]
public void UserNameAndIdTest()
{
@ -82,39 +73,5 @@ namespace Microsoft.AspNet.Identity.Test
},
ExternalAuthenticationScheme));
}
private class TestPrincipal : IPrincipal
{
public IIdentity Identity
{
get
{
throw new NotImplementedException();
}
}
public bool IsInRole(string role)
{
throw new NotImplementedException();
}
}
private class TestIdentity : IIdentity
{
public string AuthenticationType
{
get { throw new NotImplementedException(); }
}
public bool IsAuthenticated
{
get { throw new NotImplementedException(); }
}
public string Name
{
get { throw new NotImplementedException(); }
}
}
}
}