public async Task <IHttpActionResult> Logout() { string currentUserId = User.Identity.GetUserId(); await UserManager.UpdateSecurityStampAsync(currentUserId); //audit var _userActivityRepository = new UserActivityRepository(); var userActivity = new UserActivity() { ActionId = UserActionIds.Logout, ActionType = ActionTypes.NonAdmin, UserName = UserManager.FindById(currentUserId).Email }; try { await _userActivityRepository.AddAsync(userActivity); } catch { //TODO - send email here } return(Ok()); }
/// <summary> /// /// </summary> /// <param name="context"></param> /// <returns></returns> public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { LogEventInfo eventInfo = new LogEventInfo(); try { var userManager = context.OwinContext.GetUserManager <ApplicationUserManager>(); var roleManager = context.OwinContext.Get <ApplicationRoleManager>(); eventInfo.Properties["CorrelationId"] = Guid.NewGuid().ToString(); eventInfo.LoggerName = "LoginAttempts"; eventInfo.Properties["IsServiceSideLog"] = 1; // Ensure User Email is not case sensitive var userName = context.UserName.TrimAndToLowerCase(); // Handle LINQ to Entities TrimAndToLowerCase() method cannot be translated into a store expression byr using ToLower() and Trim() directly var user = await userManager.Users.Include("Roles.Role").Include("Organizations").FirstOrDefaultAsync(x => x.UserName.ToLower().Trim() == userName && x.Deleted != true && x.Disabled != true); if (user != null) { eventInfo.Properties["UserId"] = user.Id; eventInfo.Properties["UserName"] = user.UserName; var passwordExpired = false; var passwordExpirationDays = AppSettings.Get <int>("PasswordExpirationDays"); if (passwordExpirationDays > 0) { passwordExpired = user.LastPasswordChangedDate.AddDays(passwordExpirationDays) < DateTime.Now; } var validCredentials = await userManager.FindAsync(context.UserName, context.Password); if (await userManager.IsLockedOutAsync(user.Id)) { // account locked // use invalid user name or password message to avoid disclosing that a valid username was input var message = string.Format(App_GlobalResources.LocalizedText.LoginFailureMessageAccountLockedOut, AppSettings.Get <int>("DefaultAccountLockoutTimeSpan")); context.SetError("locked_out", message); // Get locked out email template var accountLockedOutEmailTemplatePath = System.Web.Hosting.HostingEnvironment.MapPath(@"~/App_Data/AccountLockedOutEmailTemplate.txt"); var accountLockedOutEmailTemplateString = File.ReadAllText(accountLockedOutEmailTemplatePath); //Send Account Lock Out Email await userManager.SendEmailAsync(user.Id, AppSettings.Get <string>("AccountLockedoutEmailSubject"), accountLockedOutEmailTemplateString); throw new UnauthorizedAccessException(string.Format("{0}: {1}", App_GlobalResources.LocalizedText.LoginFailureMessage, message)); } if (!user.EmailConfirmed) { // email not confirmed // use invalid user name or password message to avoid disclosing that a valid username was input context.SetError("invalid_grant", App_GlobalResources.LocalizedText.LoginFailureMessageEmailNotConfirmed); var message = string.Format("{0}: {1}", App_GlobalResources.LocalizedText.LoginFailureMessage, App_GlobalResources.LocalizedText.LoginFailureMessageEmailNotConfirmed); eventInfo.Message = message; throw new UnauthorizedAccessException(message); } if (validCredentials == null) { // invalid credentials // increment failed login count int loginAttempted = 0; if (await userManager.GetLockoutEnabledAsync(user.Id)) { loginAttempted = await userManager.GetAccessFailedCountAsync(user.Id); await userManager.AccessFailedAsync(user.Id); } context.SetError("invalid_grant", App_GlobalResources.LocalizedText.InvalidUserNameorPassword); throw new UnauthorizedAccessException(string.Format("{0}: {1} Login Attempted: {2}", App_GlobalResources.LocalizedText.LoginFailureMessage, App_GlobalResources.LocalizedText.InvalidUserNameorPassword, loginAttempted + 1)); } if (passwordExpired) { // password expired context.SetError("invalid_grant", App_GlobalResources.LocalizedText.LoginFailureMessagePasswordExpired); var message = string.Format("{0}: {1}", App_GlobalResources.LocalizedText.LoginFailureMessage, App_GlobalResources.LocalizedText.LoginFailureMessagePasswordExpired); eventInfo.Message = message; throw new UnauthorizedAccessException(message); } var data = await context.Request.ReadFormAsync(); var code = data.Get("code"); // Send authentication code if code is empty if (await userManager.GetTwoFactorEnabledAsync(user.Id) && string.IsNullOrEmpty(code)) { await userManager.UpdateSecurityStampAsync(user.Id); var token = await userManager.GenerateTwoFactorTokenAsync(user.Id, "EmailCode"); await userManager.NotifyTwoFactorTokenAsync(user.Id, "EmailCode", token); context.SetError("need_code", App_GlobalResources.LocalizedText.MissingUser2FACode); var message = string.Format("{0}: {1}", "Send 2FA Code", App_GlobalResources.LocalizedText.MissingUser2FACode); eventInfo.Level = LogLevel.Info; eventInfo.Message = message; return; } // Verify authentication code if (await userManager.GetTwoFactorEnabledAsync(user.Id) && !await userManager.VerifyTwoFactorTokenAsync(user.Id, "EmailCode", code)) { context.SetError("invalid_code", App_GlobalResources.LocalizedText.LoginFailureEmailCodeIncorrect); var message = string.Format("{0}: {1}", App_GlobalResources.LocalizedText.LoginFailureMessage, App_GlobalResources.LocalizedText.LoginFailureEmailCodeIncorrect); eventInfo.Message = message; throw new UnauthorizedAccessException(App_GlobalResources.LocalizedText.LoginFailureEmailCodeIncorrect); } else { // successful login ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, roleManager, OAuthDefaults.AuthenticationType); ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager, roleManager, CookieAuthenticationDefaults.AuthenticationType); AuthenticationProperties properties = CreateProperties(user.Email); AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties); context.Validated(ticket); context.Request.Context.Authentication.SignIn(cookiesIdentity); // reset failed attempts count await userManager.ResetAccessFailedCountAsync(user.Id); // logging of successful attempts eventInfo.Level = LogLevel.Info; eventInfo.Message = App_GlobalResources.LocalizedText.LoginSuccessMessage; //audit var _userActivityRepository = new UserActivityRepository(); var userActivity = new UserActivity() { ActionId = UserActionIds.Login, ActionType = ActionTypes.NonAdmin, UserName = user.Email }; try { await _userActivityRepository.AddAsync(userActivity); } catch { //TODO - send email here } } } else { // invalid username context.SetError("invalid_grant", App_GlobalResources.LocalizedText.InvalidUserNameorPassword); throw new UnauthorizedAccessException(App_GlobalResources.LocalizedText.InvalidUserNameorPassword); } } catch (Exception ex) { // logging of unsuccessful attempts eventInfo.Message = ex.Message; eventInfo.Exception = ex; eventInfo.Level = LogLevel.Error; } finally { // Write log to database _logger.Log(eventInfo); } }
public async Task <IHttpActionResult> Register(RegisterViewModel model) { try { if (!ModelState.IsValid) { BadRequest("Model state is not valid"); } // Add User var now = DateTime.UtcNow; var user = new ApplicationUser() { UserName = model.Email, Email = model.Email, EmailConfirmed = false, TwoFactorEnabled = AppSettings.Get <bool>("UserTwoFactorEnabledByDefault"), FirstName = model.FirstName, LastName = model.LastName, CreatedAt = now, LastModifiedAt = now, Disabled = false, Deleted = false }; IdentityResult result = await UserManager.CreateAsync(user, model.Password); if (!result.Succeeded) { return(GetErrorResult(result)); } else { //audit var userActivity = new UserActivity() { ActionId = UserActionIds.NewRegistration, ActionType = ActionTypes.NonAdmin, UserName = model.Email }; await _userActivityRepository.AddAsync(userActivity); } // Add to application role try { result = await UserManager.AddToRoleAsync(user.Id, Roles.Applicant); if (!result.Succeeded) { //soft delete the user try { var currentUser = UserManager.FindById(user.Id); currentUser.Deleted = true; UserManager.Update(currentUser); //audit var userActivity = new UserActivity() { ActionId = UserActionIds.Delete, ActionType = ActionTypes.NonAdmin, UserName = model.Email }; try { await _userActivityRepository.AddAsync(userActivity); } catch { //TODO - send email here } } catch { // } return(GetErrorResult(result)); } } catch { //soft delete the user try { var currentUser = UserManager.FindById(user.Id); currentUser.Deleted = true; UserManager.Update(currentUser); } catch { // } return(GetErrorResult(result)); } // Send Verification Email var nounce = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); var queryString = HttpUtility.ParseQueryString(string.Empty); queryString["userId"] = user.Id; queryString["code"] = nounce; // Support Urls with existing querystring var callbackUrl = $@"{model.EmailVerificationUrl}?{queryString}"; try { await UserManager.SendEmailAsync(user.Id, "Confirm your account for the Department of Labor Section 14(c) Online Certificate Application", "Thank you for registering for the Department of Labor Section 14( c ) Certificate Application. Please confirm your account by clicking this link or copying and pasting it into your browser: " + callbackUrl); } catch (Exception e) //PT135 { IdentityResult err = new IdentityResult("Error sending the email."); return(GetErrorResult(err)); //BadRequest(e.Message); } } catch (Exception e) { // Log Error message to database BadRequest(e.Message); } return(Ok()); }