// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING // WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF // TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR // NON-INFRINGEMENT. // See the Apache 2 License for the specific language governing // permissions and limitations under the License. using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using Microsoft.Data.Entity; namespace Microsoft.AspNet.Identity.Entity { // Real Sql implementation public class SqlUserStore : UserStore { public SqlUserStore(DbContext context) : base(context) { } } public class UserStore : //IUserRoleStore, IUserPasswordStore, IQueryableUserStore, IUserClaimStore where TUser : User { private bool _disposed; public UserStore(DbContext context) { if (context == null) { throw new ArgumentNullException("context"); } Context = context; AutoSaveChanges = true; } public DbContext Context { get; private set; } /// /// If true will call SaveChanges after CreateAsync/UpdateAsync/DeleteAsync /// public bool AutoSaveChanges { get; set; } private Task SaveChanges(CancellationToken cancellationToken) { return AutoSaveChanges ? Context.SaveChangesAsync(cancellationToken) : Task.FromResult(0); } protected virtual Task GetUserAggregate(Expression> filter, CancellationToken cancellationToken = default(CancellationToken)) { return Task.FromResult(Users.SingleOrDefault(filter)); // TODO: return Users.SingleOrDefaultAsync(filter, cancellationToken); //Include(u => u.Roles) //.Include(u => u.Claims) //.Include(u => u.Logins) } public Task GetUserIdAsync(TUser user, CancellationToken cancellationToken = new CancellationToken()) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } return Task.FromResult(Convert.ToString(user.Id, CultureInfo.InvariantCulture)); } public Task GetUserNameAsync(TUser user, CancellationToken cancellationToken = new CancellationToken()) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } return Task.FromResult(user.UserName); } public Task SetUserNameAsync(TUser user, string userName, CancellationToken cancellationToken = new CancellationToken()) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } user.UserName = userName; return Task.FromResult(0); } public async virtual Task CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } await Context.AddAsync(user, cancellationToken); await SaveChanges(cancellationToken); } public async virtual Task UpdateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } await Context.UpdateAsync(user, cancellationToken); await SaveChanges(cancellationToken); } public async virtual Task DeleteAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } Context.Delete(user); await SaveChanges(cancellationToken); } /// /// Find a user by id /// /// /// /// public virtual Task FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); return GetUserAggregate(u => u.Id.Equals(userId), cancellationToken); } /// /// Find a user by name /// /// /// /// public virtual Task FindByNameAsync(string userName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); return GetUserAggregate(u => u.UserName.ToUpper() == userName.ToUpper(), cancellationToken); } public IQueryable Users { get { return Context.Set(); } } /// /// Set the password hash for a user /// /// /// /// /// public virtual Task SetPasswordHashAsync(TUser user, string passwordHash, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } user.PasswordHash = passwordHash; return Task.FromResult(0); } /// /// Get the password hash for a user /// /// /// /// public virtual Task GetPasswordHashAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } return Task.FromResult(user.PasswordHash); } /// /// Returns true if the user has a password set /// /// /// /// public virtual Task HasPasswordAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); return Task.FromResult(user.PasswordHash != null); } ///// ///// Add a user to a role ///// ///// ///// ///// ///// //public virtual Task AddToRoleAsync(TUser user, string roleName, CancellationToken cancellationToken = default(CancellationToken)) //{ // cancellationToken.ThrowIfCancellationRequested(); // ThrowIfDisposed(); // if (user == null) // { // throw new ArgumentNullException("user"); // } // // TODO: // //if (String.IsNullOrWhiteSpace(roleName)) // //{ // // throw new ArgumentException(IdentityResources.ValueCannotBeNullOrEmpty, "roleName"); // //} // var roleEntity = Context.Set().SingleOrDefault(r => r.Name.ToUpper() == roleName.ToUpper()); // if (roleEntity == null) // { // throw new InvalidOperationException("Role Not Found"); // //TODO: String.Format(CultureInfo.CurrentCulture, IdentityResources.RoleNotFound, roleName)); // } // var ur = new TUserRole { UserId = user.Id, RoleId = roleEntity.Id }; // user.Roles.Add(ur); // roleEntity.Users.Add(ur); // return Task.FromResult(0); //} ///// ///// Remove a user from a role ///// ///// ///// ///// ///// //public virtual Task RemoveFromRoleAsync(TUser user, string roleName, CancellationToken cancellationToken = default(CancellationToken)) //{ // cancellationToken.ThrowIfCancellationRequested(); // ThrowIfDisposed(); // if (user == null) // { // throw new ArgumentNullException("user"); // } // //if (String.IsNullOrWhiteSpace(roleName)) // //{ // // throw new ArgumentException(IdentityResources.ValueCannotBeNullOrEmpty, "roleName"); // //} // var roleEntity = Context.Set().SingleOrDefault(r => r.Name.ToUpper() == roleName.ToUpper()); // if (roleEntity != null) // { // var userRole = user.Roles.FirstOrDefault(r => roleEntity.Id.Equals(r.RoleId)); // if (userRole != null) // { // user.Roles.Remove(userRole); // roleEntity.Users.Remove(userRole); // } // } // return Task.FromResult(0); //} ///// ///// Get the names of the roles a user is a member of ///// ///// ///// ///// //public virtual Task> GetRolesAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) //{ // cancellationToken.ThrowIfCancellationRequested(); // ThrowIfDisposed(); // if (user == null) // { // throw new ArgumentNullException("user"); // } // var query = from userRoles in user.Roles // join roles in Context.Set() // on userRoles.RoleId equals roles.Id // select roles.Name; // return Task.FromResult>(query.ToList()); //} ///// ///// Returns true if the user is in the named role ///// ///// ///// ///// ///// //public virtual Task IsInRoleAsync(TUser user, string roleName, CancellationToken cancellationToken = default(CancellationToken)) //{ // cancellationToken.ThrowIfCancellationRequested(); // ThrowIfDisposed(); // if (user == null) // { // throw new ArgumentNullException("user"); // } // //if (String.IsNullOrWhiteSpace(roleName)) // //{ // // throw new ArgumentException(IdentityResources.ValueCannotBeNullOrEmpty, "roleName"); // //} // var any = // Context.Set().Where(r => r.Name.ToUpper() == roleName.ToUpper()) // .Where(r => r.Users.Any(ur => ur.UserId.Equals(user.Id))) // .Count() > 0; // return Task.FromResult(any); //} private void ThrowIfDisposed() { if (_disposed) { throw new ObjectDisposedException(GetType().Name); } } /// /// Dispose the store /// public void Dispose() { _disposed = true; } private DbSet UserClaims { get { return Context.Set(); } } public Task> GetClaimsAsync(TUser user, CancellationToken cancellationToken = new CancellationToken()) { ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } IList result = UserClaims.Where(uc => uc.UserId == user.Id).Select(c => new Claim(c.ClaimType, c.ClaimValue)).ToList(); return Task.FromResult(result); } public Task AddClaimAsync(TUser user, Claim claim, CancellationToken cancellationToken = new CancellationToken()) { ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } if (claim == null) { throw new ArgumentNullException("claim"); } UserClaims.Add(new IdentityUserClaim { UserId = user.Id, ClaimType = claim.Type, ClaimValue = claim.Value }); return Task.FromResult(0); } public Task RemoveClaimAsync(TUser user, Claim claim, CancellationToken cancellationToken = new CancellationToken()) { ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } if (claim == null) { throw new ArgumentNullException("claim"); } var claims = UserClaims.Where(uc => uc.ClaimValue == claim.Value && uc.ClaimType == claim.Type).ToList(); foreach (var c in claims) { UserClaims.Remove(c); } return Task.FromResult(0); } } }