private async Task CreateNewUserReleaseInvite(Guid releaseId, string email) { var hasExistingInvite = await _context .UserReleaseInvites .Where( i => i.ReleaseId == releaseId && i.Email.ToLower() == email.ToLower() && i.Role == ReleaseRole.PrereleaseViewer ) .AnyAsync(); if (hasExistingInvite) { return; } _context.Add( new UserReleaseInvite { Email = email.ToLower(), ReleaseId = releaseId, Role = ReleaseRole.PrereleaseViewer, Created = UtcNow, CreatedById = _userService.GetUserId() } ); await _context.SaveChangesAsync(); var hasExistingSystemInvite = await _usersAndRolesDbContext .UserInvites .Where(i => i.Email.ToLower() == email.ToLower()) .AnyAsync(); // TODO EES-1181 - allow multiple invites per email address to allow people to // be assigned multiple roles upon first login if (!hasExistingSystemInvite) { var role = await GetPreReleaseUserRole(); _usersAndRolesDbContext.Add( new UserInvite { Email = email.ToLower(), Role = role, Created = UtcNow, // TODO CreatedBy = "" } ); await _usersAndRolesDbContext.SaveChangesAsync(); } }
public async Task <UserInvite> Create(string email, string roleId, Guid createdById) { var existingInvite = await _usersAndRolesDbContext .UserInvites .AsQueryable() .SingleOrDefaultAsync(i => i.Email.ToLower().Equals(email.ToLower())); if (existingInvite != null) { return(existingInvite); } var newInvite = new UserInvite { Email = email.ToLower(), RoleId = roleId, Created = DateTime.UtcNow, CreatedById = createdById.ToString(), }; _usersAndRolesDbContext.Add(newInvite); await _usersAndRolesDbContext.SaveChangesAsync(); return(newInvite); }
public async Task <Either <ActionResult, UserInvite> > InviteUser(string email, string inviteCreatedByUser, string roleId) { return(await _userService .CheckCanManageAllUsers() .OnSuccess <ActionResult, Unit, UserInvite>(async() => { if (string.IsNullOrWhiteSpace(email)) { return ValidationActionResult(InvalidEmailAddress); } if (_usersAndRolesDbContext.Users.Any(u => u.Email.ToLower() == email.ToLower())) { return ValidationActionResult(UserAlreadyExists); } var role = await _usersAndRolesDbContext.Roles.FirstOrDefaultAsync(r => r.Id == roleId); if (role == null) { return ValidationActionResult(InvalidUserRole); } var invite = new UserInvite { Email = email.ToLower(), Created = DateTime.UtcNow, CreatedBy = inviteCreatedByUser, Role = role }; await _usersAndRolesDbContext.UserInvites.AddAsync(invite); await _usersAndRolesDbContext.SaveChangesAsync(); SendInviteEmail(email); return invite; })); }
public async Task <Either <ActionResult, Unit> > CancelInvite(string email) { return(await _userService .CheckCanManageAllUsers() .OnSuccess <ActionResult, Unit, Unit>(async() => { var invite = await _usersAndRolesDbContext.UserInvites .AsQueryable() .FirstOrDefaultAsync(i => i.Email == email); if (invite == null) { return ValidationActionResult(InviteNotFound); } _usersAndRolesDbContext.UserInvites.Remove(invite); await _usersAndRolesDbContext.SaveChangesAsync(); return Unit.Instance; })); }
public async Task <Either <ActionResult, Unit> > RemovePreReleaseUser(Guid releaseId, string email) { if (!new EmailAddressAttribute().IsValid(email)) { return(ValidationActionResult(InvalidEmailAddress)); } return(await _persistenceHelper .CheckEntityExists <Release>(releaseId) .OnSuccess(_userService.CheckCanAssignPrereleaseContactsToRelease) .OnSuccessVoid( async() => { var userReleaseRolesToRemove = await _context .UserReleaseRoles .Include(r => r.User) .Where( r => r.ReleaseId == releaseId && r.User.Email.ToLower().Equals(email.ToLower()) && r.Role == PrereleaseViewer ).ToListAsync(); await _userReleaseRoleRepository.RemoveMany(userReleaseRolesToRemove, _userService.GetUserId()); _context.RemoveRange( _context .UserReleaseInvites .AsQueryable() .Where( i => i.ReleaseId == releaseId && i.Email.ToLower().Equals(email.ToLower()) && i.Role == PrereleaseViewer ) ); await _context.SaveChangesAsync(); // NOTE: UserInvites only stores whether a user has a particular role - not which release // that role may be against. So we only wanted to remove the user's prerelease role from // UserInvites if they no longer have any PrereleaseView roles. var remainingReleaseInvites = await _context .UserReleaseInvites .AsQueryable() .Where( i => i.Email.ToLower().Equals(email.ToLower()) && i.Role == PrereleaseViewer ) .CountAsync(); if (remainingReleaseInvites == 0) { _usersAndRolesDbContext.UserInvites.RemoveRange( _usersAndRolesDbContext.UserInvites .AsQueryable() .Where( i => i.Email.ToLower().Equals(email.ToLower()) && i.RoleId == Role.PrereleaseUser.GetEnumValue() && !i.Accepted ) ); await _usersAndRolesDbContext.SaveChangesAsync(); } } )); }
public async Task <IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null) { returnUrl = returnUrl ?? Url.Content("~/"); if (remoteError != null) { ErrorMessage = $"Error from external provider: {remoteError}"; return(RedirectToPage("./Login", new { ReturnUrl = returnUrl })); } var info = await _signInManager.GetExternalLoginInfoAsync(); if (info == null) { ErrorMessage = "Error loading external login information."; return(RedirectToPage("./Login", new { ReturnUrl = returnUrl })); } // Sign in the user with this external login provider if the user already has a login. var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent : false, bypassTwoFactor : true); if (result.Succeeded) { _logger.LogInformation("{Name} logged in with {LoginProvider} provider.", info.Principal.Identity.Name, info.LoginProvider); return(LocalRedirect(returnUrl)); } if (result.IsLockedOut) { return(RedirectToPage("./Lockout")); } var firstName = info.Principal.FindFirstValue(ClaimTypes.GivenName); var lastName = info.Principal.FindFirstValue(ClaimTypes.Surname); var email = info.Principal.FindFirstValue(ClaimTypes.Email) != null ? info.Principal.FindFirstValue(ClaimTypes.Email) : info.Principal.FindFirstValue(ClaimTypes.Name); // Ensure names are set if (firstName == null && lastName == null) { var nameClaim = info.Principal.FindFirstValue(JwtClaimTypes.Name); if (nameClaim.IndexOf(' ') > 0) { firstName = nameClaim.Substring(0, nameClaim.IndexOf(' ')); lastName = nameClaim.Substring(nameClaim.IndexOf(' ') + 1); } else { firstName = nameClaim; lastName = ""; } } if (email == null) { ErrorMessage = "Email address not returned from Azure Active Directory"; return(RedirectToPage("./Login", new { ReturnUrl = returnUrl })); } // Check if the user is invited var inviteToSystem = await _usersAndRolesDbContext .UserInvites .Include(i => i.Role) .FirstOrDefaultAsync(i => i.Email.ToLower() == email.ToLower() && i.Accepted == false); // If the user has an invite register them automatically if (inviteToSystem != null) { var user = new ApplicationUser { UserName = email, Email = email, FirstName = firstName, LastName = lastName }; var createdUserResult = await _userManager.CreateAsync(user); var addedUserRoles = await _userManager.AddToRoleAsync(user, inviteToSystem.Role.Name); if (createdUserResult.Succeeded && addedUserRoles.Succeeded) { var newUser = new User { Id = new Guid(user.Id), FirstName = user.FirstName, LastName = user.LastName, Email = user.Email }; _contentDbContext.Users.Add(newUser); await _contentDbContext.SaveChangesAsync(); createdUserResult = await _userManager.AddLoginAsync(user, info); if (createdUserResult.Succeeded) { await _signInManager.SignInAsync(user, isPersistent : false); _logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider); inviteToSystem.Accepted = true; _usersAndRolesDbContext.UserInvites.Update(inviteToSystem); await _usersAndRolesDbContext.SaveChangesAsync(); var releaseInvites = _contentDbContext .UserReleaseInvites .Where(i => i.Email.ToLower() == user.Email.ToLower()); await releaseInvites.ForEachAsync(invite => { _contentDbContext.Add(new UserReleaseRole { ReleaseId = invite.ReleaseId, Role = invite.Role, UserId = newUser.Id, }); invite.Accepted = true; }); await _contentDbContext.SaveChangesAsync(); await _usersAndRolesDbContext.SaveChangesAsync(); return(LocalRedirect(returnUrl)); } } foreach (var error in createdUserResult.Errors) { ModelState.AddModelError(string.Empty, error.Description); } foreach (var error in addedUserRoles.Errors) { ModelState.AddModelError(string.Empty, error.Description); } } ReturnUrl = returnUrl; return(Page()); }
private async Task <IActionResult> HandleNewInvitedUser( UserInvite inviteToSystem, string email, string firstName, string lastName, ExternalLoginInfo info, string returnUrl) { // Mark the invite as accepted. inviteToSystem.Accepted = true; _usersAndRolesDbContext.UserInvites.Update(inviteToSystem); // See if we have an "internal" User record in existence yet that has a matching email address to the // new user logging in. If we do, create this new AspNetUser record with a matching one-to-one id. // Otherwise, later on we'll create a new "internal" Users record with an id matching this AspNetUser's // id, continuing to establish the one-to-one relationship. var existingInternalUser = await _contentDbContext .Users .AsQueryable() .SingleOrDefaultAsync(u => u.Email.ToLower() == email.ToLower()); // Create a new set of AspNetUser records for the Identity Framework. var newAspNetUser = new ApplicationUser { Id = existingInternalUser?.Id.ToString() ?? Guid.NewGuid().ToString(), UserName = email, Email = email, FirstName = firstName, LastName = lastName }; var createdIdentityUserResult = await _userManager.CreateAsync(newAspNetUser); if (!createdIdentityUserResult.Succeeded) { return(HandleCreateIdentityFailure(returnUrl, createdIdentityUserResult)); } var addedIdentityUserRoles = await _userManager.AddToRoleAsync(newAspNetUser, inviteToSystem.Role.Name); if (!addedIdentityUserRoles.Succeeded) { _logger.LogError("Error adding role to invited User - unable to log in"); return(HandleIdentityResultFailure(returnUrl, addedIdentityUserRoles)); } var recordIdpLoginDetailsResult = await _userManager.AddLoginAsync(newAspNetUser, info); if (!recordIdpLoginDetailsResult.Succeeded) { return(HandleAddingLoginIdentityFailure(returnUrl, newAspNetUser, recordIdpLoginDetailsResult)); } // If adding the new Identity Framework user records succeeded, continue on to create internal User // and Role records for the application itself and sign the user in. // If we didn't yet have an existing "internal" User record matching this new login in the Users // table, create one now, being sure to establish the one-to-one id relationship between the // AspNetUsers record and the Users record. if (existingInternalUser == null) { var newInternalUser = new User { Id = Guid.Parse(newAspNetUser.Id), FirstName = newAspNetUser.FirstName, LastName = newAspNetUser.LastName, Email = newAspNetUser.Email }; await _contentDbContext.Users.AddAsync(newInternalUser); var releaseInvites = _contentDbContext .UserReleaseInvites .AsQueryable() .Where(i => i.Email.ToLower() == newAspNetUser.Email.ToLower()); await releaseInvites.ForEachAsync(invite => { _contentDbContext.AddAsync(new UserReleaseRole { ReleaseId = invite.ReleaseId, Role = invite.Role, UserId = newInternalUser.Id, Created = DateTime.UtcNow, CreatedById = invite.CreatedById, }); invite.Accepted = true; }); } await _contentDbContext.SaveChangesAsync(); await _usersAndRolesDbContext.SaveChangesAsync(); await _signInManager.ExternalLoginSignInAsync( info.LoginProvider, info.ProviderKey, isPersistent : false, bypassTwoFactor : true); return(LocalRedirect(returnUrl)); }