public static IAppBuilder UseUmbracoBackOfficeAdfsAuthentication( this IAppBuilder app, string caption = "AD FS", string style = "btn-microsoft", string icon = "fa-windows", string[] defaultUserGroups = null, string defaultCulture = "en-GB", Action <BackOfficeIdentityUser, ExternalLoginInfo> onAutoLinking = null, Func <SecurityTokenValidatedNotification <WsFederationMessage, WsFederationAuthenticationOptions>, Task> onSecurityTokenValidated = null ) { var adfsMetadataEndpoint = ConfigurationManager.AppSettings["AdfsMetadataEndpoint"]; var adfsRelyingParty = ConfigurationManager.AppSettings["AdfsRelyingParty"]; var adfsFederationServerIdentifier = ConfigurationManager.AppSettings["AdfsFederationServerIdentifier"]; app.SetDefaultSignInAsAuthenticationType(Constants.Security.BackOfficeExternalAuthenticationType); var wsFedOptions = new WsFederationAuthenticationOptions { Wtrealm = adfsRelyingParty, MetadataAddress = adfsMetadataEndpoint, SignInAsAuthenticationType = Constants.Security.BackOfficeExternalAuthenticationType, Caption = caption }; wsFedOptions.ForUmbracoBackOffice(style, icon); wsFedOptions.AuthenticationType = adfsFederationServerIdentifier; var autoLinking = new ExternalSignInAutoLinkOptions( autoLinkExternalAccount: true, defaultUserGroups: defaultUserGroups ?? new[] { "writer" }, defaultCulture: defaultCulture) { OnAutoLinking = onAutoLinking }; if (onSecurityTokenValidated != null) { wsFedOptions.Notifications = new WsFederationAuthenticationNotifications { SecurityTokenValidated = onSecurityTokenValidated }; } wsFedOptions.SetExternalSignInAutoLinkOptions(autoLinking); app.UseWsFederationAuthentication(wsFedOptions); return(app); }
public BackOfficeExternalLoginProviderOptions( string buttonStyle, string icon, ExternalSignInAutoLinkOptions autoLinkOptions = null, bool denyLocalLogin = false, bool autoRedirectLoginToExternalProvider = false, string customBackOfficeView = null) { ButtonStyle = buttonStyle; Icon = icon; AutoLinkOptions = autoLinkOptions ?? new ExternalSignInAutoLinkOptions(); DenyLocalLogin = denyLocalLogin; AutoRedirectLoginToExternalProvider = autoRedirectLoginToExternalProvider; CustomBackOfficeView = customBackOfficeView; }
public async Task <HttpResponseMessage> PostUnLinkLogin(UnLinkLoginModel unlinkLoginModel) { var owinContext = TryGetOwinContext().Result; ExternalSignInAutoLinkOptions autoLinkOptions = null; var authType = owinContext.Authentication.GetExternalAuthenticationTypes().FirstOrDefault(x => x.AuthenticationType == unlinkLoginModel.LoginProvider); if (authType == null) { Logger.Warn <BackOfficeController>("Could not find external authentication provider registered: {LoginProvider}", unlinkLoginModel.LoginProvider); } else { autoLinkOptions = authType.GetExternalSignInAutoLinkOptions(); if (!autoLinkOptions.AllowManualLinking) { // If AllowManualLinking is disabled for this provider we cannot unlink return(Request.CreateResponse(HttpStatusCode.BadRequest)); } } var result = await UserManager.RemoveLoginAsync( User.Identity.GetUserId <int>(), new UserLoginInfo(unlinkLoginModel.LoginProvider, unlinkLoginModel.ProviderKey)); if (result.Succeeded) { var user = await UserManager.FindByIdAsync(User.Identity.GetUserId <int>()); await SignInManager.SignInAsync(user, isPersistent : true, rememberBrowser : false); return(Request.CreateResponse(HttpStatusCode.OK)); } else { AddModelErrors(result); return(Request.CreateValidationErrorResponse(ModelState)); } }
private async Task <bool> AutoLinkAndSignInExternalAccount(ExternalLoginInfo loginInfo, ExternalSignInAutoLinkOptions autoLinkOptions) { if (autoLinkOptions == null) { return(false); } if (autoLinkOptions.ShouldAutoLinkExternalAccount(UmbracoContext, loginInfo) == false) { return(true); } //we are allowing auto-linking/creating of local accounts if (loginInfo.Email.IsNullOrWhiteSpace()) { ViewData.SetExternalSignInProviderErrors( new BackOfficeExternalLoginProviderErrors( loginInfo.Login.LoginProvider, new[] { "The requested provider (" + loginInfo.Login.LoginProvider + ") has not provided an email address, the account cannot be linked." })); } else { //Now we need to perform the auto-link, so first we need to lookup/create a user with the email address var autoLinkUser = UserManager.FindByEmail(loginInfo.Email); if (autoLinkUser != null) { try { //call the callback if one is assigned autoLinkOptions.OnAutoLinking?.Invoke(autoLinkUser, loginInfo); } catch (Exception ex) { var msg = "Could not link login provider " + loginInfo.Login.LoginProvider + "."; Logger.Error <BackOfficeController>(ex, msg); ViewData.SetExternalSignInProviderErrors( new BackOfficeExternalLoginProviderErrors( loginInfo.Login.LoginProvider, new[] { msg + " " + ex.Message })); return(true); } await LinkUser(autoLinkUser, loginInfo); } else { if (loginInfo.Email.IsNullOrWhiteSpace()) { throw new InvalidOperationException("The Email value cannot be null"); } if (loginInfo.ExternalIdentity.Name.IsNullOrWhiteSpace()) { throw new InvalidOperationException("The Name value cannot be null"); } var groups = Services.UserService.GetUserGroupsByAlias(autoLinkOptions.GetDefaultUserGroups(UmbracoContext, loginInfo)); autoLinkUser = BackOfficeIdentityUser.CreateNew( loginInfo.Email, loginInfo.Email, autoLinkOptions.GetDefaultCulture(UmbracoContext, loginInfo)); autoLinkUser.Name = loginInfo.ExternalIdentity.Name; foreach (var userGroup in groups) { autoLinkUser.AddRole(userGroup.Alias); } //call the callback if one is assigned try { autoLinkOptions.OnAutoLinking?.Invoke(autoLinkUser, loginInfo); } catch (Exception ex) { var msg = "Could not link login provider " + loginInfo.Login.LoginProvider + "."; Logger.Error <BackOfficeController>(ex, msg); ViewData.SetExternalSignInProviderErrors( new BackOfficeExternalLoginProviderErrors( loginInfo.Login.LoginProvider, new[] { msg + " " + ex.Message })); return(true); } var userCreationResult = await UserManager.CreateAsync(autoLinkUser); if (userCreationResult.Succeeded == false) { ViewData.SetExternalSignInProviderErrors( new BackOfficeExternalLoginProviderErrors( loginInfo.Login.LoginProvider, userCreationResult.Errors)); } else { await LinkUser(autoLinkUser, loginInfo); } } } return(true); }
private async Task <ActionResult> ExternalSignInAsync(ExternalLoginInfo loginInfo, Func <ActionResult> response) { if (loginInfo == null) { throw new ArgumentNullException("loginInfo"); } if (response == null) { throw new ArgumentNullException("response"); } ExternalSignInAutoLinkOptions autoLinkOptions = null; // Here we can check if the provider associated with the request has been configured to allow // new users (auto-linked external accounts). This would never be used with public providers such as // Google, unless you for some reason wanted anybody to be able to access the backend if they have a Google account // .... not likely! var authType = OwinContext.Authentication.GetExternalAuthenticationTypes().FirstOrDefault(x => x.AuthenticationType == loginInfo.Login.LoginProvider); if (authType == null) { Logger.Warn <BackOfficeController, string>("Could not find external authentication provider registered: {LoginProvider}", loginInfo.Login.LoginProvider); } else { autoLinkOptions = authType.GetExternalSignInAutoLinkOptions(); } // Sign in the user with this external login provider if the user already has a login var user = await UserManager.FindAsync(loginInfo.Login); if (user != null) { var shouldSignIn = true; if (autoLinkOptions != null && autoLinkOptions.OnExternalLogin != null) { shouldSignIn = autoLinkOptions.OnExternalLogin(user, loginInfo); if (shouldSignIn == false) { Logger.Warn <BackOfficeController, string, int>("The AutoLinkOptions of the external authentication provider '{LoginProvider}' have refused the login based on the OnExternalLogin method. Affected user id: '{UserId}'", loginInfo.Login.LoginProvider, user.Id); } } if (shouldSignIn) { //sign in await SignInManager.SignInAsync(user, isPersistent : false, rememberBrowser : false); } } else { if (await AutoLinkAndSignInExternalAccount(loginInfo, autoLinkOptions) == false) { ViewData.SetExternalSignInProviderErrors( new BackOfficeExternalLoginProviderErrors( loginInfo.Login.LoginProvider, new[] { "The requested provider (" + loginInfo.Login.LoginProvider + ") has not been linked to an account" })); } //Remove the cookie otherwise this message will keep appearing if (Response.Cookies[Constants.Security.BackOfficeExternalCookieName] != null) { Response.Cookies[Constants.Security.BackOfficeExternalCookieName].Expires = DateTime.MinValue; } } return(response()); }
private async Task<bool> AutoLinkAndSignInExternalAccount(ExternalLoginInfo loginInfo, ExternalSignInAutoLinkOptions autoLinkOptions) { if (autoLinkOptions == null) return false; if (autoLinkOptions.ShouldAutoLinkExternalAccount(UmbracoContext, loginInfo) == false) return true; //we are allowing auto-linking/creating of local accounts if (loginInfo.Email.IsNullOrWhiteSpace()) { ViewData.SetExternalSignInError(new[] { "The requested provider (" + loginInfo.Login.LoginProvider + ") has not provided an email address, the account cannot be linked." }); } else { //Now we need to perform the auto-link, so first we need to lookup/create a user with the email address var foundByEmail = Services.UserService.GetByEmail(loginInfo.Email); if (foundByEmail != null) { ViewData.SetExternalSignInError(new[] { "A user with this email address already exists locally. You will need to login locally to Umbraco and link this external provider: " + loginInfo.Login.LoginProvider }); } else { if (loginInfo.Email.IsNullOrWhiteSpace()) throw new InvalidOperationException("The Email value cannot be null"); if (loginInfo.ExternalIdentity.Name.IsNullOrWhiteSpace()) throw new InvalidOperationException("The Name value cannot be null"); var groups = Services.UserService.GetUserGroupsByAlias(autoLinkOptions.GetDefaultUserGroups(UmbracoContext, loginInfo)); var autoLinkUser = BackOfficeIdentityUser.CreateNew( loginInfo.Email, loginInfo.Email, autoLinkOptions.GetDefaultCulture(UmbracoContext, loginInfo)); autoLinkUser.Name = loginInfo.ExternalIdentity.Name; foreach (var userGroup in groups) { autoLinkUser.AddRole(userGroup.Alias); } //call the callback if one is assigned if (autoLinkOptions.OnAutoLinking != null) { autoLinkOptions.OnAutoLinking(autoLinkUser, loginInfo); } var userCreationResult = await UserManager.CreateAsync(autoLinkUser); if (userCreationResult.Succeeded == false) { ViewData.SetExternalSignInError(userCreationResult.Errors); } else { var linkResult = await UserManager.AddLoginAsync(autoLinkUser.Id, loginInfo.Login); if (linkResult.Succeeded == false) { ViewData.SetExternalSignInError(linkResult.Errors); //If this fails, we should really delete the user since it will be in an inconsistent state! var deleteResult = await UserManager.DeleteAsync(autoLinkUser); if (deleteResult.Succeeded == false) { //DOH! ... this isn't good, combine all errors to be shown ViewData.SetExternalSignInError(linkResult.Errors.Concat(deleteResult.Errors)); } } else { //sign in await SignInManager.SignInAsync(autoLinkUser, isPersistent: false, rememberBrowser: false); } } } } return true; }
private async Task<ActionResult> ExternalSignInAsync(ExternalLoginInfo loginInfo, Func<ActionResult> response) { if (loginInfo == null) throw new ArgumentNullException("loginInfo"); if (response == null) throw new ArgumentNullException("response"); ExternalSignInAutoLinkOptions autoLinkOptions = null; //Here we can check if the provider associated with the request has been configured to allow // new users (auto-linked external accounts). This would never be used with public providers such as // Google, unless you for some reason wanted anybody to be able to access the backend if they have a Google account // .... not likely! var authType = OwinContext.Authentication.GetExternalAuthenticationTypes().FirstOrDefault(x => x.AuthenticationType == loginInfo.Login.LoginProvider); if (authType == null) { Logger.Warn<BackOfficeController>("Could not find external authentication provider registered: {LoginProvider}", loginInfo.Login.LoginProvider); } else { autoLinkOptions = authType.GetExternalAuthenticationOptions(); } // Sign in the user with this external login provider if the user already has a login var user = await UserManager.FindAsync(loginInfo.Login); if (user != null) { // TODO: It might be worth keeping some of the claims associated with the ExternalLoginInfo, in which case we // wouldn't necessarily sign the user in here with the standard login, instead we'd update the // UseUmbracoBackOfficeExternalCookieAuthentication extension method to have the correct provider and claims factory, // ticket format, etc.. to create our back office user including the claims assigned and in this method we'd just ensure // that the ticket is created and stored and that the user is logged in. var shouldSignIn = true; if (autoLinkOptions != null && autoLinkOptions.OnExternalLogin != null) { shouldSignIn = autoLinkOptions.OnExternalLogin(user, loginInfo); if (shouldSignIn == false) { Logger.Warn<BackOfficeController>("The AutoLinkOptions of the external authentication provider '{LoginProvider}' have refused the login based on the OnExternalLogin method. Affected user id: '{UserId}'", loginInfo.Login.LoginProvider, user.Id); } } if (shouldSignIn) { //sign in await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); } } else { if (await AutoLinkAndSignInExternalAccount(loginInfo, autoLinkOptions) == false) { ViewData.SetExternalSignInError(new[] { "The requested provider (" + loginInfo.Login.LoginProvider + ") has not been linked to an account" }); } //Remove the cookie otherwise this message will keep appearing if (Response.Cookies[Constants.Security.BackOfficeExternalCookieName] != null) { Response.Cookies[Constants.Security.BackOfficeExternalCookieName].Expires = DateTime.MinValue; } } return response(); }