From 56a73d03953c917d3f32141fba8201f202ee3b59 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 4 Sep 2020 14:32:34 +1000 Subject: [PATCH] More options for external providers with a toggle to not allow manual linking --- .../services/externallogininfo.service.js | 8 ++++---- .../Editors/AuthenticationController.cs | 19 +++++++++++++++++-- src/Umbraco.Web/Editors/UsersController.cs | 4 ++-- .../BackOfficeExternalLoginProviderOptions.cs | 2 +- .../Security/ExternalSignInAutoLinkOptions.cs | 6 ++++++ 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/externallogininfo.service.js b/src/Umbraco.Web.UI.Client/src/common/services/externallogininfo.service.js index 90b559b9ea..47d23f75cc 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/externallogininfo.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/externallogininfo.service.js @@ -36,11 +36,11 @@ function externalLoginInfoService(externalLoginInfo, umbRequestHelper) { /** * Returns all login providers - * @param {any} excludeDenyLocalLogin true to exclude providers the deny local login + * @param {any} excludeUnlinkable true to exclude providers that are not manually linkable */ - function getLoginProviders(excludeDenyLocalLogin) { - if (excludeDenyLocalLogin) { - return _.filter(externalLoginInfo.providers, x => !x.properties.UmbracoBackOfficeExternalLoginOptions.DenyLocalLogin); + function getLoginProviders(excludeUnlinkable) { + if (excludeUnlinkable) { + return _.filter(externalLoginInfo.providers, x => !x.properties.UmbracoBackOfficeExternalLoginOptions.AutoLinkOptions.AllowManualLinking); } else { return externalLoginInfo.providers; diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 38c18268da..e2ab829427 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -27,6 +27,7 @@ using Umbraco.Core.Persistence; using Umbraco.Web.Composing; using IUser = Umbraco.Core.Models.Membership.IUser; using Umbraco.Web.Editors.Filters; +using Microsoft.Owin.Security; namespace Umbraco.Web.Editors { @@ -113,7 +114,22 @@ namespace Umbraco.Web.Editors [ValidateAngularAntiForgeryToken] public async Task PostUnLinkLogin(UnLinkLoginModel unlinkLoginModel) { - // TODO: If DenyLocalLogin is enabled for this provider we cannot unlink + var owinContext = TryGetOwinContext().Result; + ExternalSignInAutoLinkOptions autoLinkOptions = null; + var authType = owinContext.Authentication.GetExternalAuthenticationTypes().FirstOrDefault(x => x.AuthenticationType == unlinkLoginModel.LoginProvider); + if (authType == null) + { + Logger.Warn("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(), @@ -183,7 +199,6 @@ namespace Umbraco.Web.Editors /// [WebApi.UmbracoAuthorize(requireApproval: false)] [SetAngularAntiForgeryTokens] - [DenyLocalLoginAuthorization] public UserDetail GetCurrentInvitedUser() { var user = UmbracoContext.Security.CurrentUser; diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index d98cfd47f7..84709fd620 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -505,9 +505,9 @@ namespace Umbraco.Web.Editors /// /// [OutgoingEditorModelEvent] - public async Task PostSaveUser(UserSave userSave) + public UserDisplay PostSaveUser(UserSave userSave) { - if (userSave == null) throw new ArgumentNullException("userSave"); + if (userSave == null) throw new ArgumentNullException(nameof(userSave)); if (ModelState.IsValid == false) { diff --git a/src/Umbraco.Web/Security/BackOfficeExternalLoginProviderOptions.cs b/src/Umbraco.Web/Security/BackOfficeExternalLoginProviderOptions.cs index ecff31e2ca..1c27742bba 100644 --- a/src/Umbraco.Web/Security/BackOfficeExternalLoginProviderOptions.cs +++ b/src/Umbraco.Web/Security/BackOfficeExternalLoginProviderOptions.cs @@ -27,7 +27,7 @@ namespace Umbraco.Web.Security /// Options used to control how users can be auto-linked/created/updated based on the external login provider /// [IgnoreDataMember] // we are ignoring this one from serialization for backwards compat since these options are manually incuded in the response separately - public ExternalSignInAutoLinkOptions AutoLinkOptions { get; set; } + public ExternalSignInAutoLinkOptions AutoLinkOptions { get; set; } = new ExternalSignInAutoLinkOptions(); /// /// When set to true will disable all local user login functionality diff --git a/src/Umbraco.Web/Security/ExternalSignInAutoLinkOptions.cs b/src/Umbraco.Web/Security/ExternalSignInAutoLinkOptions.cs index b6c9d699d1..52f758aa74 100644 --- a/src/Umbraco.Web/Security/ExternalSignInAutoLinkOptions.cs +++ b/src/Umbraco.Web/Security/ExternalSignInAutoLinkOptions.cs @@ -32,6 +32,12 @@ namespace Umbraco.Web.Security private readonly string[] _defaultUserGroups; + /// + /// By default this is true which allows the user to manually link and unlink the external provider, if set to false the back office user + /// will not see and cannot perform manual linking or unlinking of the external provider. + /// + public bool AllowManualLinking { get; set; } = true; + /// /// A callback executed during account auto-linking and before the user is persisted ///