external login improvements
This commit is contained in:
		| @ -133,7 +133,7 @@ namespace Oqtane.Extensions | ||||
|                         output = "[" + output + "]"; // convert to json array | ||||
|                     } | ||||
|                     JsonNode items = JsonNode.Parse(output)!; | ||||
|                     foreach(var item in items.AsArray()) | ||||
|                     foreach (var item in items.AsArray()) | ||||
|                     { | ||||
|                         if (item[emailClaimType] != null) | ||||
|                         { | ||||
| @ -235,97 +235,112 @@ namespace Oqtane.Extensions | ||||
|             ClaimsIdentity identity = new ClaimsIdentity(Constants.AuthenticationScheme); | ||||
|             // use identity.Label as a temporary location to store validation status information | ||||
|  | ||||
|             if (EmailValid(email, httpContext.GetSiteSettings().GetValue("ExternalLogin:DomainFilter", ""))) | ||||
|             var providerType = httpContext.GetSiteSettings().GetValue("ExternalLogin:ProviderType", ""); | ||||
|             var providerName = httpContext.GetSiteSettings().GetValue("ExternalLogin:ProviderName", ""); | ||||
|             var alias = httpContext.GetAlias(); | ||||
|             var _users = httpContext.RequestServices.GetRequiredService<IUserRepository>(); | ||||
|             User user = null; | ||||
|  | ||||
|             // verify if external user is already registerd for this site | ||||
|             var _identityUserManager = httpContext.RequestServices.GetRequiredService<UserManager<IdentityUser>>(); | ||||
|             var identityuser = await _identityUserManager.FindByLoginAsync(providerType + ":" + alias.SiteId.ToString(), id); | ||||
|             if (identityuser != null) | ||||
|             { | ||||
|                 var _identityUserManager = httpContext.RequestServices.GetRequiredService<UserManager<IdentityUser>>(); | ||||
|                 var _users = httpContext.RequestServices.GetRequiredService<IUserRepository>(); | ||||
|                 var _userRoles = httpContext.RequestServices.GetRequiredService<IUserRoleRepository>(); | ||||
|                 var alias = httpContext.GetAlias(); | ||||
|                 var providerType = httpContext.GetSiteSettings().GetValue("ExternalLogin:ProviderType", ""); | ||||
|                 var providerName = httpContext.GetSiteSettings().GetValue("ExternalLogin:ProviderName", ""); | ||||
|                 User user = null; | ||||
|  | ||||
|                 bool duplicates = false; | ||||
|                 IdentityUser identityuser = null; | ||||
|                 try | ||||
|                 user = _users.GetUser(identityuser.UserName); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (EmailValid(email, httpContext.GetSiteSettings().GetValue("ExternalLogin:DomainFilter", ""))) | ||||
|                 { | ||||
|                     identityuser = await _identityUserManager.FindByEmailAsync(email); | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     // FindByEmailAsync will throw an error if the email matches multiple user accounts | ||||
|                     duplicates = true; | ||||
|                 } | ||||
|                 if (identityuser == null) | ||||
|                 { | ||||
|                     if (duplicates) | ||||
|                     bool duplicates = false; | ||||
|                     try | ||||
|                     { | ||||
|                         identity.Label = ExternalLoginStatus.DuplicateEmail; | ||||
|                         _logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "Multiple Users Exist With Email Address {Email}. Login Denied.", email); | ||||
|                         identityuser = await _identityUserManager.FindByEmailAsync(email); | ||||
|                     } | ||||
|                     else | ||||
|                     catch | ||||
|                     { | ||||
|                         if (bool.Parse(httpContext.GetSiteSettings().GetValue("ExternalLogin:CreateUsers", "true"))) | ||||
|                         // FindByEmailAsync will throw an error if the email matches multiple user accounts | ||||
|                         duplicates = true; | ||||
|                     } | ||||
|                     if (identityuser == null) | ||||
|                     { | ||||
|                         if (duplicates) | ||||
|                         { | ||||
|                             identityuser = new IdentityUser(); | ||||
|                             identityuser.UserName = email; | ||||
|                             identityuser.Email = email; | ||||
|                             identityuser.EmailConfirmed = true; | ||||
|                             var result = await _identityUserManager.CreateAsync(identityuser, DateTime.UtcNow.ToString("yyyy-MMM-dd-HH-mm-ss")); | ||||
|                             if (result.Succeeded) | ||||
|                             identity.Label = ExternalLoginStatus.DuplicateEmail; | ||||
|                             _logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "Multiple Users Exist With Email Address {Email}. Login Denied.", email); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             if (bool.Parse(httpContext.GetSiteSettings().GetValue("ExternalLogin:CreateUsers", "true"))) | ||||
|                             { | ||||
|                                 user = new User | ||||
|                                 identityuser = new IdentityUser(); | ||||
|                                 identityuser.UserName = email; | ||||
|                                 identityuser.Email = email; | ||||
|                                 identityuser.EmailConfirmed = true; | ||||
|                                 var result = await _identityUserManager.CreateAsync(identityuser, DateTime.UtcNow.ToString("yyyy-MMM-dd-HH-mm-ss")); | ||||
|                                 if (result.Succeeded) | ||||
|                                 { | ||||
|                                     SiteId = alias.SiteId, | ||||
|                                     Username = email, | ||||
|                                     DisplayName = email, | ||||
|                                     Email = email, | ||||
|                                     LastLoginOn = null, | ||||
|                                     LastIPAddress = "" | ||||
|                                 }; | ||||
|                                 user = _users.AddUser(user); | ||||
|                                     user = new User | ||||
|                                     { | ||||
|                                         SiteId = alias.SiteId, | ||||
|                                         Username = email, | ||||
|                                         DisplayName = email, | ||||
|                                         Email = email, | ||||
|                                         LastLoginOn = null, | ||||
|                                         LastIPAddress = "" | ||||
|                                     }; | ||||
|                                     user = _users.AddUser(user); | ||||
|  | ||||
|                                 if (user != null) | ||||
|                                 { | ||||
|                                     var _notifications = httpContext.RequestServices.GetRequiredService<INotificationRepository>(); | ||||
|                                     string url = httpContext.Request.Scheme + "://" + alias.Name; | ||||
|                                     string body = "You Recently Used An External Account To Sign In To Our Site.\n\n" + url + "\n\nThank You!"; | ||||
|                                     var notification = new Notification(user.SiteId, user, "User Account Notification", body); | ||||
|                                     _notifications.AddNotification(notification); | ||||
|                                     if (user != null) | ||||
|                                     { | ||||
|                                         var _notifications = httpContext.RequestServices.GetRequiredService<INotificationRepository>(); | ||||
|                                         string url = httpContext.Request.Scheme + "://" + alias.Name; | ||||
|                                         string body = "You Recently Used An External Account To Sign In To Our Site.\n\n" + url + "\n\nThank You!"; | ||||
|                                         var notification = new Notification(user.SiteId, user, "User Account Notification", body); | ||||
|                                         _notifications.AddNotification(notification); | ||||
|  | ||||
|                                     // add user login | ||||
|                                     await _identityUserManager.AddLoginAsync(identityuser, new UserLoginInfo(providerType, id, "")); | ||||
|                                         // add user login | ||||
|                                         await _identityUserManager.AddLoginAsync(identityuser, new UserLoginInfo(providerType + ":" + alias.SiteId.ToString(), id, providerName)); | ||||
|  | ||||
|                                     _logger.Log(user.SiteId, LogLevel.Information, "ExternalLogin", Enums.LogFunction.Create, "User Added {User}", user); | ||||
|                                         _logger.Log(user.SiteId, LogLevel.Information, "ExternalLogin", Enums.LogFunction.Create, "User Added {User}", user); | ||||
|                                     } | ||||
|                                     else | ||||
|                                     { | ||||
|                                         identity.Label = ExternalLoginStatus.UserNotCreated; | ||||
|                                         _logger.Log(user.SiteId, LogLevel.Error, "ExternalLogin", Enums.LogFunction.Create, "Unable To Add User {Email}", email); | ||||
|                                     } | ||||
|                                 } | ||||
|                                 else | ||||
|                                 { | ||||
|                                     identity.Label = ExternalLoginStatus.UserNotCreated; | ||||
|                                     _logger.Log(user.SiteId, LogLevel.Error, "ExternalLogin", Enums.LogFunction.Create, "Unable To Add User {Email}", email); | ||||
|                                     _logger.Log(user.SiteId, LogLevel.Error, "ExternalLogin", Enums.LogFunction.Create, "Unable To Add Identity User {Email} {Error}", email, result.Errors.ToString()); | ||||
|                                 } | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 identity.Label = ExternalLoginStatus.UserNotCreated; | ||||
|                                 _logger.Log(user.SiteId, LogLevel.Error, "ExternalLogin", Enums.LogFunction.Create, "Unable To Add Identity User {Email} {Error}", email, result.Errors.ToString()); | ||||
|                                 identity.Label = ExternalLoginStatus.UserDoesNotExist; | ||||
|                                 _logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "Creation Of New Users Is Disabled For This Site. User With Email Address {Email} Will First Need To Be Registered On The Site.", email); | ||||
|                             } | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             identity.Label = ExternalLoginStatus.UserDoesNotExist; | ||||
|                             _logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "Creation Of New Users Is Disabled For This Site. User With Email Address {Email} Will First Need To Be Registered On The Site.", email); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     var logins = await _identityUserManager.GetLoginsAsync(identityuser); | ||||
|                     var login = logins.FirstOrDefault(item => item.LoginProvider == (providerType + ":" + alias.SiteId.ToString())); | ||||
|                     if (login != null) | ||||
|                     else | ||||
|                     { | ||||
|                         if (login.ProviderKey == id) | ||||
|                         var logins = await _identityUserManager.GetLoginsAsync(identityuser); | ||||
|                         var login = logins.FirstOrDefault(item => item.LoginProvider == (providerType + ":" + alias.SiteId.ToString())); | ||||
|                         if (login == null) | ||||
|                         { | ||||
|                             user = _users.GetUser(identityuser.UserName); | ||||
|                             // new external login using existing user account - verification required | ||||
|                             var _notifications = httpContext.RequestServices.GetRequiredService<INotificationRepository>(); | ||||
|                             string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser); | ||||
|                             string url = httpContext.Request.Scheme + "://" + alias.Name; | ||||
|                             url += $"/login?name={identityuser.UserName}&token={WebUtility.UrlEncode(token)}&key={WebUtility.UrlEncode(id)}"; | ||||
|                             string body = $"You Recently Signed In To Our Site With {providerName} Using The Email Address {email}. "; | ||||
|                             body += "In Order To Complete The Linkage Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!"; | ||||
|                             var notification = new Notification(alias.SiteId, email, email, "External Login Linkage", body); | ||||
|                             _notifications.AddNotification(notification); | ||||
|  | ||||
|                             identity.Label = ExternalLoginStatus.VerificationRequired; | ||||
|                             _logger.Log(alias.SiteId, LogLevel.Information, "ExternalLogin", Enums.LogFunction.Create, "External Login Linkage Verification For Provider {Provider} Sent To {Email}", providerName, email); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
| @ -334,48 +349,36 @@ namespace Oqtane.Extensions | ||||
|                             _logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "Provider Key Does Not Match For User {Username}. Login Denied.", identityuser.UserName); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 else // email invalid | ||||
|                 { | ||||
|                     identity.Label = ExternalLoginStatus.InvalidEmail; | ||||
|                     if (!string.IsNullOrEmpty(email)) | ||||
|                     { | ||||
|                         _logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "The Email Address {Email} Is Invalid Or Does Not Match The Domain Filter Criteria. Login Denied.", email); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         // new external login using existing user account - verification required | ||||
|                         var _notifications = httpContext.RequestServices.GetRequiredService<INotificationRepository>(); | ||||
|                         string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser); | ||||
|                         string url = httpContext.Request.Scheme + "://" + alias.Name; | ||||
|                         url += $"/login?name={identityuser.UserName}&token={WebUtility.UrlEncode(token)}&key={WebUtility.UrlEncode(id)}"; | ||||
|                         string body = $"You Recently Signed In To Our Site With {providerName} Using The Email Address {email}. "; | ||||
|                         body += "In Order To Complete The Linkage Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!"; | ||||
|                         var notification = new Notification(alias.SiteId, email, email, "External Login Linkage", body); | ||||
|                         _notifications.AddNotification(notification); | ||||
|                         identity.Label = ExternalLoginStatus.VerificationRequired; | ||||
|                         _logger.Log(alias.SiteId, LogLevel.Information, "ExternalLogin", Enums.LogFunction.Create, "External Login Linkage Verification For Provider {Provider} Sent To {Email}", providerName, email); | ||||
|                         _logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "Provider Did Not Return An Email To Uniquely Identify The User."); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // manage user | ||||
|                 if (user != null) | ||||
|                 { | ||||
|                     // create claims identity | ||||
|                     identity = UserSecurity.CreateClaimsIdentity(alias, user, _userRoles.GetUserRoles(user.UserId, user.SiteId).ToList()); | ||||
|                     identity.Label = ExternalLoginStatus.Success; | ||||
|  | ||||
|                     // update user | ||||
|                     user.LastLoginOn = DateTime.UtcNow; | ||||
|                     user.LastIPAddress = httpContext.Connection.RemoteIpAddress.ToString(); | ||||
|                     _users.UpdateUser(user); | ||||
|                     _logger.Log(LogLevel.Information, "ExternalLogin", Enums.LogFunction.Security, "External User Login Successful For {Username} Using Provider {Provider}", user.Username, providerName); | ||||
|                 } | ||||
|             } | ||||
|             else // email invalid | ||||
|  | ||||
|             // manage user | ||||
|             if (user != null) | ||||
|             { | ||||
|                 identity.Label = ExternalLoginStatus.InvalidEmail; | ||||
|                 if (!string.IsNullOrEmpty(email)) | ||||
|                 { | ||||
|                     _logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "The Email Address {Email} Is Invalid Or Does Not Match The Domain Filter Criteria. Login Denied.", email); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     _logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "Provider Did Not Return An Email To Uniquely Identify The User."); | ||||
|                 } | ||||
|                 // create claims identity | ||||
|                 var _userRoles = httpContext.RequestServices.GetRequiredService<IUserRoleRepository>(); | ||||
|                 identity = UserSecurity.CreateClaimsIdentity(alias, user, _userRoles.GetUserRoles(user.UserId, user.SiteId).ToList()); | ||||
|                 identity.Label = ExternalLoginStatus.Success; | ||||
|  | ||||
|                 // update user | ||||
|                 user.LastLoginOn = DateTime.UtcNow; | ||||
|                 user.LastIPAddress = httpContext.Connection.RemoteIpAddress.ToString(); | ||||
|                 _users.UpdateUser(user); | ||||
|                 _logger.Log(LogLevel.Information, "ExternalLogin", Enums.LogFunction.Security, "External User Login Successful For {Username} Using Provider {Provider}", user.Username, providerName); | ||||
|             } | ||||
|              | ||||
|             return identity; | ||||
|         } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Shaun Walker
					Shaun Walker