using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Oqtane.Repository; using Oqtane.Models; using Microsoft.AspNetCore.Identity; using System.Threading.Tasks; using System.Linq; using System.Security.Claims; using Oqtane.Shared; using Oqtane.Infrastructure; using System; using Microsoft.AspNetCore.Http; using System.Net; namespace Oqtane.Controllers { [Route("{site}/api/[controller]")] public class UserController : Controller { private readonly IUserRepository Users; private readonly IRoleRepository Roles; private readonly IUserRoleRepository UserRoles; private readonly UserManager IdentityUserManager; private readonly SignInManager IdentitySignInManager; private readonly ITenantResolver Tenants; private readonly INotificationRepository Notifications; private readonly ILogManager logger; public UserController(IUserRepository Users, IRoleRepository Roles, IUserRoleRepository UserRoles, UserManager IdentityUserManager, SignInManager IdentitySignInManager, ITenantResolver Tenants, INotificationRepository Notifications, ILogManager logger) { this.Users = Users; this.Roles = Roles; this.UserRoles = UserRoles; this.IdentityUserManager = IdentityUserManager; this.IdentitySignInManager = IdentitySignInManager; this.Tenants = Tenants; this.Notifications = Notifications; this.logger = logger; } // GET: api/?siteid=x [HttpGet] public IEnumerable Get() { return Users.GetUsers(); } // GET api//5?siteid=x [HttpGet("{id}")] public User Get(int id, string siteid) { User user = Users.GetUser(id); if (user != null) { user.SiteId = int.Parse(siteid); user.Roles = GetUserRoles(user.UserId, user.SiteId); } return user; } // GET api//name/x?siteid=x [HttpGet("name/{name}")] public User Get(string name, string siteid) { User user = Users.GetUser(name); if (user != null) { user.SiteId = int.Parse(siteid); user.Roles = GetUserRoles(user.UserId, user.SiteId); } return user; } // POST api/ [HttpPost] public async Task Post([FromBody] User User) { User user = null; if (ModelState.IsValid) { bool verified = true; // users created by non-administrators must be verified if (!base.User.IsInRole(Constants.AdminRole) && User.Username != Constants.HostUser) { verified = false; } IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(User.Username); if (identityuser == null) { identityuser = new IdentityUser(); identityuser.UserName = User.Username; identityuser.Email = User.Email; identityuser.EmailConfirmed = verified; var result = await IdentityUserManager.CreateAsync(identityuser, User.Password); if (result.Succeeded) { user = Users.AddUser(User); if (!verified) { Notification notification = new Notification(); notification.SiteId = User.SiteId; notification.FromUserId = null; notification.ToUserId = user.UserId; notification.ToEmail = ""; notification.Subject = "User Account Verification"; string token = await IdentityUserManager.GenerateEmailConfirmationTokenAsync(identityuser); string url = HttpContext.Request.Scheme + "://" + Tenants.GetAlias().Name + "/login?name=" + User.Username + "&token=" + WebUtility.UrlEncode(token); notification.Body = "Dear " + User.DisplayName + ",\n\nIn Order To Complete The Registration Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!"; notification.ParentId = null; notification.CreatedOn = DateTime.Now; notification.IsDelivered = false; notification.DeliveredOn = null; Notifications.AddNotification(notification); } // assign to host role if this is the host user ( initial installation ) if (User.Username == Constants.HostUser) { int hostroleid = Roles.GetRoles(User.SiteId, true).Where(item => item.Name == Constants.HostRole).FirstOrDefault().RoleId; UserRole userrole = new UserRole(); userrole.UserId = user.UserId; userrole.RoleId = hostroleid; userrole.EffectiveDate = null; userrole.ExpiryDate = null; UserRoles.AddUserRole(userrole); } } } else { var result = await IdentitySignInManager.CheckPasswordSignInAsync(identityuser, User.Password, false); if (result.Succeeded) { user = Users.GetUser(User.Username); } } if (user != null && User.Username != Constants.HostUser) { // add auto assigned roles to user for site List roles = Roles.GetRoles(User.SiteId).Where(item => item.IsAutoAssigned == true).ToList(); foreach (Role role in roles) { UserRole userrole = new UserRole(); userrole.UserId = user.UserId; userrole.RoleId = role.RoleId; userrole.EffectiveDate = null; userrole.ExpiryDate = null; UserRoles.AddUserRole(userrole); } } user.Password = ""; // remove sensitive information logger.Log(LogLevel.Information, this, LogFunction.Create, "User Added {User}", user); } return user; } // PUT api//5 [HttpPut("{id}")] [Authorize] public async Task Put(int id, [FromBody] User User) { if (ModelState.IsValid) { if (User.Password != "") { IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(User.Username); if (identityuser != null) { identityuser.PasswordHash = IdentityUserManager.PasswordHasher.HashPassword(identityuser, User.Password); await IdentityUserManager.UpdateAsync(identityuser); } } User = Users.UpdateUser(User); User.Password = ""; // remove sensitive information logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", User); } return User; } // DELETE api//5?siteid=x [HttpDelete("{id}")] [Authorize(Roles = Constants.AdminRole)] public async Task Delete(int id) { IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(Users.GetUser(id).Username); if (identityuser != null) { var result = await IdentityUserManager.DeleteAsync(identityuser); if (result != null) { Users.DeleteUser(id); logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", id); } } } // POST api//login [HttpPost("login")] public async Task Login([FromBody] User User, bool SetCookie, bool IsPersistent) { User user = new Models.User { Username = User.Username, IsAuthenticated = false }; if (ModelState.IsValid) { IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(User.Username); if (identityuser != null) { var result = await IdentitySignInManager.CheckPasswordSignInAsync(identityuser, User.Password, false); if (result.Succeeded) { user = Users.GetUser(identityuser.UserName); if (user != null) { if (identityuser.EmailConfirmed) { user.IsAuthenticated = true; logger.Log(LogLevel.Information, this, LogFunction.Security, "User Login Successful {Username}", User.Username); if (SetCookie) { await IdentitySignInManager.SignInAsync(identityuser, IsPersistent); } } else { logger.Log(LogLevel.Information, this, LogFunction.Security, "User Not Verified {Username}", User.Username); } } } else { logger.Log(LogLevel.Error, this, LogFunction.Security, "User Login Failed {Username}", User.Username); } } } return user; } // POST api//logout [HttpPost("logout")] [Authorize] public async Task Logout([FromBody] User User) { await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme); logger.Log(LogLevel.Information, this, LogFunction.Security, "User Logout {Username}", User.Username); } // POST api//verify [HttpPost("verify")] public async Task Verify([FromBody] User User, string token) { if (ModelState.IsValid) { IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(User.Username); if (identityuser != null) { var result = await IdentityUserManager.ConfirmEmailAsync(identityuser, token); if (result.Succeeded) { logger.Log(LogLevel.Information, this, LogFunction.Security, "Email Verified For {Username}", User.Username); } else { logger.Log(LogLevel.Error, this, LogFunction.Security, "Email Verification Failed For {Username}", User.Username); User = null; } } else { logger.Log(LogLevel.Error, this, LogFunction.Security, "Email Verification Failed For {Username}", User.Username); User = null; } } return User; } // POST api//forgot [HttpPost("forgot")] public async Task Forgot([FromBody] User User) { if (ModelState.IsValid) { IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(User.Username); if (identityuser != null) { Notification notification = new Notification(); notification.SiteId = User.SiteId; notification.FromUserId = null; notification.ToUserId = User.UserId; notification.ToEmail = ""; notification.Subject = "User Password Reset"; string token = await IdentityUserManager.GeneratePasswordResetTokenAsync(identityuser); string url = HttpContext.Request.Scheme + "://" + Tenants.GetAlias().Name + "/reset?name=" + User.Username + "&token=" + WebUtility.UrlEncode(token); notification.Body = "Dear " + User.DisplayName + ",\n\nPlease Click The Link Displayed Below To Reset Your Password:\n\n" + url + "\n\nThank You!"; notification.ParentId = null; notification.CreatedOn = DateTime.Now; notification.IsDelivered = false; notification.DeliveredOn = null; Notifications.AddNotification(notification); logger.Log(LogLevel.Information, this, LogFunction.Security, "Password Reset Notification Sent For {Username}", User.Username); } else { logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Notification Failed For {Username}", User.Username); } } } // POST api//reset [HttpPost("reset")] public async Task Reset([FromBody] User User, string token) { if (ModelState.IsValid) { IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(User.Username); if (identityuser != null && !string.IsNullOrEmpty(token)) { var result = await IdentityUserManager.ResetPasswordAsync(identityuser, token, User.Password); if (result.Succeeded) { logger.Log(LogLevel.Information, this, LogFunction.Security, "Password Reset For {Username}", User.Username); User.Password = ""; } else { logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Failed For {Username}", User.Username); User = null; } } else { logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Failed For {Username}", User.Username); User = null; } } return User; } // GET api//current [HttpGet("authenticate")] public User Authenticate() { User user = new User(); user.Username = User.Identity.Name; user.IsAuthenticated = User.Identity.IsAuthenticated; string roles = ""; foreach (var claim in User.Claims.Where(item => item.Type == ClaimTypes.Role)) { roles += claim.Value + ";"; } if (roles != "") roles = ";" + roles; user.Roles = roles; return user; } private string GetUserRoles(int UserId, int SiteId) { string roles = ""; List userroles = UserRoles.GetUserRoles(UserId, SiteId).ToList(); foreach (UserRole userrole in userroles) { roles += userrole.Role.Name + ";"; if (userrole.Role.Name == Constants.HostRole && userroles.Where(item => item.Role.Name == Constants.AdminRole).FirstOrDefault() == null) { roles += Constants.AdminRole + ";"; } } if (roles != "") roles = ";" + roles; return roles; } } }