Initial Identity Core port, with Crypto/Claims #if net45 commented out

This commit is contained in:
Hao Kung 2014-02-19 15:36:18 -08:00
parent 79d615f41f
commit aa4787cc67
28 changed files with 3304 additions and 4 deletions

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.21126.0
VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0F647068-6602-4E24-B1DC-8ED91481A50A}"
EndProject
@ -46,11 +46,11 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{77CEDA6C-A833-455D-8357-649BFD944724} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{F6B0C0E9-C346-49D0-B583-95B6CE04BB1B} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{6211450F-FFB8-431F-84E2-9A7620875260} = {77CEDA6C-A833-455D-8357-649BFD944724}
{D32483A4-B617-480C-81E6-49CD596B9A34} = {77CEDA6C-A833-455D-8357-649BFD944724}
{77CEDA6C-A833-455D-8357-649BFD944724} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{B72401D7-47F6-4A98-89D5-CCBFEFC5B2B8} = {F6B0C0E9-C346-49D0-B583-95B6CE04BB1B}
{E52361C9-1F0B-4229-86A0-E5C7C12A5429} = {F6B0C0E9-C346-49D0-B583-95B6CE04BB1B}
{6211450F-FFB8-431F-84E2-9A7620875260} = {77CEDA6C-A833-455D-8357-649BFD944724}
{D32483A4-B617-480C-81E6-49CD596B9A34} = {77CEDA6C-A833-455D-8357-649BFD944724}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,29 @@
using System;
#if NET45
using System.Security.Claims;
#endif
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Interface for creating a ClaimsIdentity from an IUser
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IClaimsIdentityFactory<TUser, TKey>
where TUser : class, IUser<TKey>
where TKey : IEquatable<TKey>
{
#if NET45
/// <summary>
/// Create a ClaimsIdentity from an user using a UserManager
/// </summary>
/// <param name="manager"></param>
/// <param name="user"></param>
/// <param name="authenticationType"></param>
/// <returns></returns>
Task<ClaimsIdentity> Create(UserManager<TUser, TKey> manager, TUser user, string authenticationType);
#endif
}
}

View File

@ -0,0 +1,38 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Expose a way to send messages (email/txt)
/// </summary>
public interface IIdentityMessageService
{
/// <summary>
/// This method should send the message
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
Task Send(IdentityMessage message);
}
/// <summary>
/// Represents a message
/// </summary>
public class IdentityMessage
{
/// <summary>
/// Destination, i.e. To email, or SMS phone number
/// </summary>
public virtual string Destination { get; set; }
/// <summary>
/// Subject
/// </summary>
public virtual string Subject { get; set; }
/// <summary>
/// Message contents
/// </summary>
public virtual string Body { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Used to validate an item
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IIdentityValidator<in T>
{
/// <summary>
/// Validate the item
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
Task<IdentityResult> Validate(T item);
}
}

View File

@ -0,0 +1,23 @@
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Abstraction for password hashing methods
/// </summary>
public interface IPasswordHasher
{
/// <summary>
/// Hash a password
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
string HashPassword(string password);
/// <summary>
/// Verify that a password matches the hashed password
/// </summary>
/// <param name="hashedPassword"></param>
/// <param name="providedPassword"></param>
/// <returns></returns>
PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword);
}
}

View File

@ -0,0 +1,25 @@
using System.Linq;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Interface that exposes an IQueryable roles
/// </summary>
/// <typeparam name="TRole"></typeparam>
public interface IQueryableRoleStore<TRole> : IQueryableRoleStore<TRole, string> where TRole : IRole<string>
{
}
/// <summary>
/// Interface that exposes an IQueryable roles
/// </summary>
/// <typeparam name="TRole"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IQueryableRoleStore<TRole, in TKey> : IRoleStore<TRole, TKey> where TRole : IRole<TKey>
{
/// <summary>
/// IQueryable users
/// </summary>
IQueryable<TRole> Roles { get; }
}
}

View File

@ -0,0 +1,25 @@
using System.Linq;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Interface that exposes an IQueryable users
/// </summary>
/// <typeparam name="TUser"></typeparam>
public interface IQueryableUserStore<TUser> : IQueryableUserStore<TUser, string> where TUser : class, IUser<string>
{
}
/// <summary>
/// Interface that exposes an IQueryable users
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IQueryableUserStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// IQueryable users
/// </summary>
IQueryable<TUser> Users { get; }
}
}

View File

@ -0,0 +1,19 @@
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Mimimal set of data needed to persist role data
/// </summary>
/// <typeparam name="TKey"></typeparam>
public interface IRole<out TKey>
{
/// <summary>
/// Id of the role
/// </summary>
TKey Id { get; }
/// <summary>
/// Name of the role
/// </summary>
string Name { get; set; }
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Interface that exposes basic role management
/// </summary>
/// <typeparam name="TRole"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IRoleStore<TRole, in TKey> : IDisposable where TRole : IRole<TKey>
{
/// <summary>
/// Insert a new role
/// </summary>
/// <param name="role"></param>
/// <returns></returns>
Task Create(TRole role);
/// <summary>
/// Update a role
/// </summary>
/// <param name="role"></param>
/// <returns></returns>
Task Update(TRole role);
/// <summary>
/// Delete a role
/// </summary>
/// <param name="role"></param>
/// <returns></returns>
Task Delete(TRole role);
/// <summary>
/// Finds a role by id
/// </summary>
/// <param name="roleId"></param>
/// <returns></returns>
Task<TRole> FindById(TKey roleId);
/// <summary>
/// Find a role by name
/// </summary>
/// <param name="roleName"></param>
/// <returns></returns>
Task<TRole> FindByName(string roleName);
}
}

View File

@ -0,0 +1,19 @@
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Minimal interface for a user with id and username
/// </summary>
/// <typeparam name="TKey"></typeparam>
public interface IUser<out TKey>
{
/// <summary>
/// Unique key for the user
/// </summary>
TKey Id { get; }
/// <summary>
/// Unique username
/// </summary>
string UserName { get; set; }
}
}

View File

@ -0,0 +1,41 @@
#if NET45
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Stores user specific claims
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserClaimStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// Returns the claims for the user with the issuer set
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<IList<Claim>> GetClaims(TUser user);
/// <summary>
/// Add a new user claim
/// </summary>
/// <param name="user"></param>
/// <param name="claim"></param>
/// <returns></returns>
Task AddClaim(TUser user, Claim claim);
/// <summary>
/// Remove a user claim
/// </summary>
/// <param name="user"></param>
/// <param name="claim"></param>
/// <returns></returns>
Task RemoveClaim(TUser user, Claim claim);
}
}
#endif

View File

@ -0,0 +1,49 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Stores a user's email
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserEmailStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// Set the user email
/// </summary>
/// <param name="user"></param>
/// <param name="email"></param>
/// <returns></returns>
Task SetEmail(TUser user, string email);
/// <summary>
/// Get the user email
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<string> GetEmail(TUser user);
/// <summary>
/// Returns true if the user email is confirmed
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<bool> GetEmailConfirmed(TUser user);
/// <summary>
/// Sets whether the user email is confirmed
/// </summary>
/// <param name="user"></param>
/// <param name="confirmed"></param>
/// <returns></returns>
Task SetEmailConfirmed(TUser user, bool confirmed);
/// <summary>
/// Returns the user associated with this email
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
Task<TUser> FindByEmail(string email);
}
}

View File

@ -0,0 +1,66 @@
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Stores information which can be used to implement account lockout, including access failures and lockout status
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserLockoutStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// Returns the DateTimeOffset that represents the end of a user's lockout, any time in the past should be considered
/// not locked out.
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<DateTimeOffset> GetLockoutEndDate(TUser user);
/// <summary>
/// Locks a user out until the specified end date (set to a past date, to unlock a user)
/// </summary>
/// <param name="user"></param>
/// <param name="lockoutEnd"></param>
/// <returns></returns>
Task SetLockoutEndDate(TUser user, DateTimeOffset lockoutEnd);
/// <summary>
/// Used to record when an attempt to access the user has failed
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<int> IncrementAccessFailedCount(TUser user);
/// <summary>
/// Used to reset the account access count, typically after the account is successfully accessed
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task ResetAccessFailedCount(TUser user);
/// <summary>
/// Returns the current number of failed access attempts. This number usually will be reset whenever the password is
/// verified or the account is locked out.
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<int> GetAccessFailedCount(TUser user);
/// <summary>
/// Returns whether the user can be locked out.
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<bool> GetLockoutEnabled(TUser user);
/// <summary>
/// Sets whether the user can be locked out.
/// </summary>
/// <param name="user"></param>
/// <param name="enabled"></param>
/// <returns></returns>
Task SetLockoutEnabled(TUser user, bool enabled);
}
}

View File

@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Interface that maps users to login providers, i.e. Google, Facebook, Twitter, Microsoft
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserLoginStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// Adds a user login with the specified provider and key
/// </summary>
/// <param name="user"></param>
/// <param name="login"></param>
/// <returns></returns>
Task AddLogin(TUser user, UserLoginInfo login);
/// <summary>
/// Removes the user login with the specified combination if it exists, returns true if found and removed
/// </summary>
/// <param name="user"></param>
/// <param name="login"></param>
/// <returns></returns>
Task RemoveLogin(TUser user, UserLoginInfo login);
/// <summary>
/// Returns the linked accounts for this user
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<IList<UserLoginInfo>> GetLogins(TUser user);
/// <summary>
/// Returns the user associated with this login
/// </summary>
/// <returns></returns>
Task<TUser> Find(UserLoginInfo login);
}
}

View File

@ -0,0 +1,34 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Stores a user's password hash
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserPasswordStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// Set the user password hash
/// </summary>
/// <param name="user"></param>
/// <param name="passwordHash"></param>
/// <returns></returns>
Task SetPasswordHash(TUser user, string passwordHash);
/// <summary>
/// Get the user password hash
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<string> GetPasswordHash(TUser user);
/// <summary>
/// Returns true if a user has a password set
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<bool> HasPassword(TUser user);
}
}

View File

@ -0,0 +1,42 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Stores a user's phoneNumber
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserPhoneNumberStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// Set the user PhoneNumber
/// </summary>
/// <param name="user"></param>
/// <param name="phoneNumber"></param>
/// <returns></returns>
Task SetPhoneNumber(TUser user, string phoneNumber);
/// <summary>
/// Get the user phoneNumber
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<string> GetPhoneNumber(TUser user);
/// <summary>
/// Returns true if the user phone number is confirmed
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<bool> GetPhoneNumberConfirmed(TUser user);
/// <summary>
/// Sets whether the user phone number is confirmed
/// </summary>
/// <param name="user"></param>
/// <param name="confirmed"></param>
/// <returns></returns>
Task SetPhoneNumberConfirmed(TUser user, bool confirmed);
}
}

View File

@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Interface that maps users to their roles
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserRoleStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// Adds a user to role
/// </summary>
/// <param name="user"></param>
/// <param name="roleName"></param>
/// <returns></returns>
Task AddToRole(TUser user, string roleName);
/// <summary>
/// Removes the role for the user
/// </summary>
/// <param name="user"></param>
/// <param name="roleName"></param>
/// <returns></returns>
Task RemoveFromRole(TUser user, string roleName);
/// <summary>
/// Returns the roles for this user
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<IList<string>> GetRoles(TUser user);
/// <summary>
/// Returns true if a user is in a role
/// </summary>
/// <param name="user"></param>
/// <param name="roleName"></param>
/// <returns></returns>
Task<bool> IsInRole(TUser user, string roleName);
}
}

View File

@ -0,0 +1,27 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Stores a user's security stamp
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserSecurityStampStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// Set the security stamp for the user
/// </summary>
/// <param name="user"></param>
/// <param name="stamp"></param>
/// <returns></returns>
Task SetSecurityStamp(TUser user, string stamp);
/// <summary>
/// Get the user security stamp
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<string> GetSecurityStamp(TUser user);
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Interface that exposes basic user management apis
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserStore<TUser, in TKey> : IDisposable where TUser : class, IUser<TKey>
{
/// <summary>
/// Insert a new user
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task Create(TUser user);
/// <summary>
/// Update a user
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task Update(TUser user);
/// <summary>
/// Delete a user
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task Delete(TUser user);
/// <summary>
/// Finds a user
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
Task<TUser> FindById(TKey userId);
/// <summary>
/// Find a user by name
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
Task<TUser> FindByName(string userName);
}
}

View File

@ -0,0 +1,47 @@
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Interface to generate user tokens
/// </summary>
public interface IUserTokenProvider<TUser, TKey> where TUser : class, IUser<TKey> where TKey : IEquatable<TKey>
{
/// <summary>
/// Generate a token for a user
/// </summary>
/// <param name="purpose"></param>
/// <param name="manager"></param>
/// <param name="user"></param>
/// <returns></returns>
Task<string> Generate(string purpose, UserManager<TUser, TKey> manager, TUser user);
/// <summary>
/// Validate and unprotect a token, returns null if invalid
/// </summary>
/// <param name="purpose"></param>
/// <param name="token"></param>
/// <param name="manager"></param>
/// <param name="user"></param>
/// <returns></returns>
Task<bool> Validate(string purpose, string token, UserManager<TUser, TKey> manager, TUser user);
/// <summary>
/// Notifies the user that a token has been generated, i.e. via email or sms, or can no-op
/// </summary>
/// <param name="token"></param>
/// <param name="manager"></param>
/// <param name="user"></param>
/// <returns></returns>
Task Notify(string token, UserManager<TUser, TKey> manager, TUser user);
/// <summary>
/// Returns true if provider can be used for this user, i.e. could require a user to have an email
/// </summary>
/// <param name="manager"></param>
/// <param name="user"></param>
/// <returns></returns>
Task<bool> IsValidProviderForUser(UserManager<TUser, TKey> manager, TUser user);
}
}

View File

@ -0,0 +1,27 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Stores whether two factor is enabled for a user
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserTwoFactorStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
/// <summary>
/// Sets whether two factor is enabled for the user
/// </summary>
/// <param name="user"></param>
/// <param name="enabled"></param>
/// <returns></returns>
Task SetTwoFactorEnabled(TUser user, bool enabled);
/// <summary>
/// Returns whether two factor is enabled for the user
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<bool> GetTwoFactorEnabled(TUser user);
}
}

View File

@ -0,0 +1,69 @@
using System.Collections.Generic;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Represents the result of an identity operation
/// </summary>
public class IdentityResult
{
private static readonly IdentityResult _success = new IdentityResult(true);
/// <summary>
/// Failure constructor that takes error messages
/// </summary>
/// <param name="errors"></param>
public IdentityResult(params string[] errors) : this((IEnumerable<string>) errors)
{
}
/// <summary>
/// Failure constructor that takes error messages
/// </summary>
/// <param name="errors"></param>
public IdentityResult(IEnumerable<string> errors)
{
if (errors == null)
{
errors = new[] {"Resources.DefaultError"};
}
Succeeded = false;
Errors = errors;
}
private IdentityResult(bool success)
{
Succeeded = success;
Errors = new string[0];
}
/// <summary>
/// True if the operation was successful
/// </summary>
public bool Succeeded { get; private set; }
/// <summary>
/// List of errors
/// </summary>
public IEnumerable<string> Errors { get; private set; }
/// <summary>
/// Static success result
/// </summary>
/// <returns></returns>
public static IdentityResult Success
{
get { return _success; }
}
/// <summary>
/// Failed helper method
/// </summary>
/// <param name="errors"></param>
/// <returns></returns>
public static IdentityResult Failed(params string[] errors)
{
return new IdentityResult(errors);
}
}
}

View File

@ -0,0 +1,23 @@
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Return result for IPasswordHasher
/// </summary>
public enum PasswordVerificationResult
{
/// <summary>
/// Password verification failed
/// </summary>
Failed = 0,
/// <summary>
/// Success
/// </summary>
Success = 1,
/// <summary>
/// Success but should update and rehash the password
/// </summary>
SuccessRehashNeeded = 2
}
}

View File

@ -0,0 +1,382 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.AspNet.Identity {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
#if NET45
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNet.Identity.Resources", typeof(Resources).Assembly);
#else
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNet.Routing.Resources", System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(Resources)).Assembly);
#endif
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to An unknown failure has occured..
/// </summary>
internal static string DefaultError {
get {
return ResourceManager.GetString("DefaultError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Email &apos;{0}&apos; is already taken..
/// </summary>
internal static string DuplicateEmail {
get {
return ResourceManager.GetString("DuplicateEmail", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Name {0} is already taken..
/// </summary>
internal static string DuplicateName {
get {
return ResourceManager.GetString("DuplicateName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A user with that external login already exists..
/// </summary>
internal static string ExternalLoginExists {
get {
return ResourceManager.GetString("ExternalLoginExists", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Email &apos;{0}&apos; is invalid..
/// </summary>
internal static string InvalidEmail {
get {
return ResourceManager.GetString("InvalidEmail", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid token..
/// </summary>
internal static string InvalidToken {
get {
return ResourceManager.GetString("InvalidToken", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to User name {0} is invalid, can only contain letters or digits..
/// </summary>
internal static string InvalidUserName {
get {
return ResourceManager.GetString("InvalidUserName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Lockout is not enabled for this user..
/// </summary>
internal static string LockoutNotEnabled {
get {
return ResourceManager.GetString("LockoutNotEnabled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No IUserTokenProvider is registered..
/// </summary>
internal static string NoTokenProvider {
get {
return ResourceManager.GetString("NoTokenProvider", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No IUserTwoFactorProvider for &apos;{0}&apos; is registered..
/// </summary>
internal static string NoTwoFactorProvider {
get {
return ResourceManager.GetString("NoTwoFactorProvider", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Incorrect password..
/// </summary>
internal static string PasswordMismatch {
get {
return ResourceManager.GetString("PasswordMismatch", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Passwords must have at least one digit (&apos;0&apos;-&apos;9&apos;)..
/// </summary>
internal static string PasswordRequireDigit {
get {
return ResourceManager.GetString("PasswordRequireDigit", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Passwords must have at least one lowercase (&apos;a&apos;-&apos;z&apos;)..
/// </summary>
internal static string PasswordRequireLower {
get {
return ResourceManager.GetString("PasswordRequireLower", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Passwords must have at least one non letter or digit character..
/// </summary>
internal static string PasswordRequireNonLetterOrDigit {
get {
return ResourceManager.GetString("PasswordRequireNonLetterOrDigit", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Passwords must have at least one uppercase (&apos;A&apos;-&apos;Z&apos;)..
/// </summary>
internal static string PasswordRequireUpper {
get {
return ResourceManager.GetString("PasswordRequireUpper", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Passwords must be at least {0} characters..
/// </summary>
internal static string PasswordTooShort {
get {
return ResourceManager.GetString("PasswordTooShort", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} cannot be null or empty..
/// </summary>
internal static string PropertyTooShort {
get {
return ResourceManager.GetString("PropertyTooShort", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Role {0} does not exist..
/// </summary>
internal static string RoleNotFound {
get {
return ResourceManager.GetString("RoleNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IQueryableRoleStore&lt;TRole&gt;..
/// </summary>
internal static string StoreNotIQueryableRoleStore {
get {
return ResourceManager.GetString("StoreNotIQueryableRoleStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IQueryableUserStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIQueryableUserStore {
get {
return ResourceManager.GetString("StoreNotIQueryableUserStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserClaimStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserClaimStore {
get {
return ResourceManager.GetString("StoreNotIUserClaimStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserConfirmationStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserConfirmationStore {
get {
return ResourceManager.GetString("StoreNotIUserConfirmationStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserEmailStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserEmailStore {
get {
return ResourceManager.GetString("StoreNotIUserEmailStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserLockoutStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserLockoutStore {
get {
return ResourceManager.GetString("StoreNotIUserLockoutStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserLoginStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserLoginStore {
get {
return ResourceManager.GetString("StoreNotIUserLoginStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserPasswordStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserPasswordStore {
get {
return ResourceManager.GetString("StoreNotIUserPasswordStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserPhoneNumberStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserPhoneNumberStore {
get {
return ResourceManager.GetString("StoreNotIUserPhoneNumberStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserRoleStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserRoleStore {
get {
return ResourceManager.GetString("StoreNotIUserRoleStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserSecurityStampStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserSecurityStampStore {
get {
return ResourceManager.GetString("StoreNotIUserSecurityStampStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Store does not implement IUserTwoFactorStore&lt;TUser&gt;..
/// </summary>
internal static string StoreNotIUserTwoFactorStore {
get {
return ResourceManager.GetString("StoreNotIUserTwoFactorStore", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to User already has a password set..
/// </summary>
internal static string UserAlreadyHasPassword {
get {
return ResourceManager.GetString("UserAlreadyHasPassword", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to User already in role..
/// </summary>
internal static string UserAlreadyInRole {
get {
return ResourceManager.GetString("UserAlreadyInRole", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to UserId not found..
/// </summary>
internal static string UserIdNotFound {
get {
return ResourceManager.GetString("UserIdNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to User {0} does not exist..
/// </summary>
internal static string UserNameNotFound {
get {
return ResourceManager.GetString("UserNameNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to User is not in role..
/// </summary>
internal static string UserNotInRole {
get {
return ResourceManager.GetString("UserNotInRole", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,260 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="DefaultError" xml:space="preserve">
<value>An unknown failure has occured.</value>
<comment>Default identity result error message</comment>
</data>
<data name="DuplicateEmail" xml:space="preserve">
<value>Email '{0}' is already taken.</value>
<comment>error for duplicate emails</comment>
</data>
<data name="DuplicateName" xml:space="preserve">
<value>Name {0} is already taken.</value>
<comment>error for duplicate usernames</comment>
</data>
<data name="ExternalLoginExists" xml:space="preserve">
<value>A user with that external login already exists.</value>
<comment>Error when a login already linked</comment>
</data>
<data name="InvalidEmail" xml:space="preserve">
<value>Email '{0}' is invalid.</value>
<comment>invalid email</comment>
</data>
<data name="InvalidToken" xml:space="preserve">
<value>Invalid token.</value>
<comment>Error when a token is not recognized</comment>
</data>
<data name="InvalidUserName" xml:space="preserve">
<value>User name {0} is invalid, can only contain letters or digits.</value>
<comment>usernames can only contain letters or digits</comment>
</data>
<data name="LockoutNotEnabled" xml:space="preserve">
<value>Lockout is not enabled for this user.</value>
<comment>error when lockout is not enabled</comment>
</data>
<data name="NoTokenProvider" xml:space="preserve">
<value>No IUserTokenProvider is registered.</value>
<comment>Error when there is no IUserTokenProvider</comment>
</data>
<data name="NoTwoFactorProvider" xml:space="preserve">
<value>No IUserTwoFactorProvider for '{0}' is registered.</value>
<comment>Error when there is no provider found</comment>
</data>
<data name="PasswordMismatch" xml:space="preserve">
<value>Incorrect password.</value>
<comment>Error when a password doesn't match</comment>
</data>
<data name="PasswordRequireDigit" xml:space="preserve">
<value>Passwords must have at least one digit ('0'-'9').</value>
<comment>Error when passwords do not have a digit</comment>
</data>
<data name="PasswordRequireLower" xml:space="preserve">
<value>Passwords must have at least one lowercase ('a'-'z').</value>
<comment>Error when passwords do not have a lowercase letter</comment>
</data>
<data name="PasswordRequireNonLetterOrDigit" xml:space="preserve">
<value>Passwords must have at least one non letter or digit character.</value>
<comment>Error when password does not have enough letter or digit characters</comment>
</data>
<data name="PasswordRequireUpper" xml:space="preserve">
<value>Passwords must have at least one uppercase ('A'-'Z').</value>
<comment>Error when passwords do not have an uppercase letter</comment>
</data>
<data name="PasswordTooShort" xml:space="preserve">
<value>Passwords must be at least {0} characters.</value>
<comment>Error message for passwords that are too short</comment>
</data>
<data name="PropertyTooShort" xml:space="preserve">
<value>{0} cannot be null or empty.</value>
<comment>error for empty or null usernames</comment>
</data>
<data name="RoleNotFound" xml:space="preserve">
<value>Role {0} does not exist.</value>
<comment>error when a role does not exist</comment>
</data>
<data name="StoreNotIQueryableRoleStore" xml:space="preserve">
<value>Store does not implement IQueryableRoleStore&lt;TRole&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIQueryableUserStore" xml:space="preserve">
<value>Store does not implement IQueryableUserStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserClaimStore" xml:space="preserve">
<value>Store does not implement IUserClaimStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserConfirmationStore" xml:space="preserve">
<value>Store does not implement IUserConfirmationStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserEmailStore" xml:space="preserve">
<value>Store does not implement IUserEmailStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserLockoutStore" xml:space="preserve">
<value>Store does not implement IUserLockoutStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserLoginStore" xml:space="preserve">
<value>Store does not implement IUserLoginStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserPasswordStore" xml:space="preserve">
<value>Store does not implement IUserPasswordStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserPhoneNumberStore" xml:space="preserve">
<value>Store does not implement IUserPhoneNumberStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserRoleStore" xml:space="preserve">
<value>Store does not implement IUserRoleStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserSecurityStampStore" xml:space="preserve">
<value>Store does not implement IUserSecurityStampStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserTwoFactorStore" xml:space="preserve">
<value>Store does not implement IUserTwoFactorStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
</data>
<data name="UserAlreadyHasPassword" xml:space="preserve">
<value>User already has a password set.</value>
<comment>error when AddPassword called when a user already has a password</comment>
</data>
<data name="UserAlreadyInRole" xml:space="preserve">
<value>User already in role.</value>
<comment>Error when a user is already in a role</comment>
</data>
<data name="UserIdNotFound" xml:space="preserve">
<value>UserId not found.</value>
<comment>No user with this id found</comment>
</data>
<data name="UserNameNotFound" xml:space="preserve">
<value>User {0} does not exist.</value>
<comment>error when a user does not exist</comment>
</data>
<data name="UserNotInRole" xml:space="preserve">
<value>User is not in role.</value>
<comment>Error when a user is not in the role</comment>
</data>
</root>

View File

@ -0,0 +1,115 @@
#if NET45
using System;
using System.Diagnostics;
using System.Net;
using System.Security.Cryptography;
using System.Text;
namespace Microsoft.AspNet.Identity
{
internal sealed class SecurityToken
{
private readonly byte[] _data;
public SecurityToken(byte[] data)
{
_data = (byte[]) data.Clone();
}
internal byte[] GetDataNoClone()
{
return _data;
}
}
internal static class Rfc6238AuthenticationService
{
private static readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private static readonly TimeSpan _timestep = TimeSpan.FromMinutes(3);
private static readonly Encoding _encoding = new UTF8Encoding(false, true);
private static int ComputeTotp(HashAlgorithm hashAlgorithm, ulong timestepNumber, string modifier)
{
// # of 0's = length of pin
const int mod = 1000000;
// See https://tools.ietf.org/html/rfc4226
// We can add an optional modifier
var timestepAsBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((long) timestepNumber));
var hash = hashAlgorithm.ComputeHash(ApplyModifier(timestepAsBytes, modifier));
// Generate DT string
var offset = hash[hash.Length - 1] & 0xf;
Debug.Assert(offset + 4 < hash.Length);
var binaryCode = (hash[offset] & 0x7f) << 24
| (hash[offset + 1] & 0xff) << 16
| (hash[offset + 2] & 0xff) << 8
| (hash[offset + 3] & 0xff);
return binaryCode%mod;
}
private static byte[] ApplyModifier(byte[] input, string modifier)
{
if (String.IsNullOrEmpty(modifier))
{
return input;
}
var modifierBytes = _encoding.GetBytes(modifier);
var combined = new byte[checked(input.Length + modifierBytes.Length)];
Buffer.BlockCopy(input, 0, combined, 0, input.Length);
Buffer.BlockCopy(modifierBytes, 0, combined, input.Length, modifierBytes.Length);
return combined;
}
// More info: https://tools.ietf.org/html/rfc6238#section-4
private static ulong GetCurrentTimeStepNumber()
{
var delta = DateTime.UtcNow - _unixEpoch;
return (ulong) (delta.Ticks/_timestep.Ticks);
}
public static int GenerateCode(SecurityToken securityToken, string modifier = null)
{
if (securityToken == null)
{
throw new ArgumentNullException("securityToken");
}
// Allow a variance of no greater than 90 seconds in either direction
var currentTimeStep = GetCurrentTimeStepNumber();
using (var hashAlgorithm = new HMACSHA1(securityToken.GetDataNoClone()))
{
return ComputeTotp(hashAlgorithm, currentTimeStep, modifier);
}
}
public static bool ValidateCode(SecurityToken securityToken, int code, string modifier = null)
{
if (securityToken == null)
{
throw new ArgumentNullException("securityToken");
}
// Allow a variance of no greater than 90 seconds in either direction
var currentTimeStep = GetCurrentTimeStepNumber();
using (var hashAlgorithm = new HMACSHA1(securityToken.GetDataNoClone()))
{
for (var i = -2; i <= 2; i++)
{
var computedTotp = ComputeTotp(hashAlgorithm, (ulong) ((long) currentTimeStep + i), modifier);
if (computedTotp == code)
{
return true;
}
}
}
// No match
return false;
}
}
}
#endif

View File

@ -0,0 +1,29 @@
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Represents a linked login for a user (i.e. a local username/password or a facebook/google account
/// </summary>
public sealed class UserLoginInfo
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="loginProvider"></param>
/// <param name="providerKey"></param>
public UserLoginInfo(string loginProvider, string providerKey)
{
LoginProvider = loginProvider;
ProviderKey = providerKey;
}
/// <summary>
/// Provider for the linked login, i.e. Local, Facebook, Google, etc.
/// </summary>
public string LoginProvider { get; set; }
/// <summary>
/// Key for the linked login at the provider
/// </summary>
public string ProviderKey { get; set; }
}
}

File diff suppressed because it is too large Load Diff