Fixes issue with resolving a scheme name since that is managed via IOptions but we were capturing it.

This commit is contained in:
Shannon
2021-07-27 16:12:23 -06:00
parent 29ebb42a01
commit 5cec6ab8f4
9 changed files with 90 additions and 50 deletions

View File

@@ -181,14 +181,14 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
}
else
{
var opt = _externalAuthenticationOptions.Get(authType.Name);
BackOfficeExternaLoginProviderScheme opt = await _externalAuthenticationOptions.GetAsync(authType.Name);
if (opt == null)
{
return BadRequest($"Could not find external authentication options registered for provider {unlinkLoginModel.LoginProvider}");
}
else
{
if (!opt.Options.AutoLinkOptions.AllowManualLinking)
if (!opt.ExternalLoginProvider.Options.AutoLinkOptions.AllowManualLinking)
{
// If AllowManualLinking is disabled for this provider we cannot unlink
return BadRequest();

View File

@@ -144,7 +144,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
/// Returns the server variables for authenticated users
/// </summary>
/// <returns></returns>
internal Task<Dictionary<string, object>> GetServerVariablesAsync()
internal async Task<Dictionary<string, object>> GetServerVariablesAsync()
{
var globalSettings = _globalSettings;
var backOfficeControllerName = ControllerExtensions.GetControllerName<BackOfficeController>();
@@ -432,12 +432,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
{
// TODO: It would be nicer to not have to manually translate these properties
// but then needs to be changed in quite a few places in angular
"providers", _externalLogins.GetBackOfficeProviders()
"providers", (await _externalLogins.GetBackOfficeProvidersAsync())
.Select(p => new
{
authType = p.AuthenticationType,
caption = p.Name,
properties = p.Options
authType = p.ExternalLoginProvider.AuthenticationType,
caption = p.AuthenticationScheme.DisplayName,
properties = p.ExternalLoginProvider.Options
})
.ToArray()
}
@@ -456,7 +456,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
}
}
};
return Task.FromResult(defaultVals);
return defaultVals;
}
[DataContract]

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -54,18 +54,18 @@ namespace Umbraco.Extensions
/// <param name="html"></param>
/// <param name="externalLogins"></param>
/// <returns></returns>
public static Task<IHtmlContent> AngularValueExternalLoginInfoScriptAsync(this IHtmlHelper html,
public static async Task<IHtmlContent> AngularValueExternalLoginInfoScriptAsync(this IHtmlHelper html,
IBackOfficeExternalLoginProviders externalLogins,
BackOfficeExternalLoginProviderErrors externalLoginErrors)
{
var providers = externalLogins.GetBackOfficeProviders();
var providers = await externalLogins.GetBackOfficeProvidersAsync();
var loginProviders = providers
.Select(p => new
{
authType = p.AuthenticationType,
caption = p.Name,
properties = p.Options
authType = p.ExternalLoginProvider.AuthenticationType,
caption = p.AuthenticationScheme.DisplayName,
properties = p.ExternalLoginProvider.Options
})
.ToArray();
@@ -89,7 +89,7 @@ namespace Umbraco.Extensions
sb.AppendLine(JsonConvert.SerializeObject(loginProviders));
sb.AppendLine(@"});");
return Task.FromResult(html.Raw(sb.ToString()));
return html.Raw(sb.ToString());
}
/// <summary>

View File

@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -45,7 +46,6 @@ namespace Umbraco.Cms.Web.BackOffice.Security
base.Services.AddSingleton(services =>
{
return new BackOfficeExternalLoginProvider(
displayName,
authenticationScheme,
services.GetRequiredService<IOptionsMonitor<BackOfficeExternalLoginProviderOptions>>());
});

View File

@@ -0,0 +1,20 @@
using System;
using Microsoft.AspNetCore.Authentication;
namespace Umbraco.Cms.Web.BackOffice.Security
{
public class BackOfficeExternaLoginProviderScheme
{
public BackOfficeExternaLoginProviderScheme(
BackOfficeExternalLoginProvider externalLoginProvider,
AuthenticationScheme authenticationScheme)
{
ExternalLoginProvider = externalLoginProvider ?? throw new ArgumentNullException(nameof(externalLoginProvider));
AuthenticationScheme = authenticationScheme ?? throw new ArgumentNullException(nameof(authenticationScheme));
}
public BackOfficeExternalLoginProvider ExternalLoginProvider { get; }
public AuthenticationScheme AuthenticationScheme { get; }
}
}

View File

@@ -9,7 +9,6 @@ namespace Umbraco.Cms.Web.BackOffice.Security
public class BackOfficeExternalLoginProvider : IEquatable<BackOfficeExternalLoginProvider>
{
public BackOfficeExternalLoginProvider(
string name,
string authenticationType,
IOptionsMonitor<BackOfficeExternalLoginProviderOptions> properties)
{
@@ -18,31 +17,20 @@ namespace Umbraco.Cms.Web.BackOffice.Security
throw new ArgumentNullException(nameof(properties));
}
Name = name ?? throw new ArgumentNullException(nameof(name));
AuthenticationType = authenticationType ?? throw new ArgumentNullException(nameof(authenticationType));
Options = properties.Get(authenticationType);
}
public string Name { get; }
/// <summary>
/// The authentication "Scheme"
/// </summary>
public string AuthenticationType { get; }
public BackOfficeExternalLoginProviderOptions Options { get; }
public override bool Equals(object obj)
{
return Equals(obj as BackOfficeExternalLoginProvider);
}
public bool Equals(BackOfficeExternalLoginProvider other)
{
return other != null &&
Name == other.Name &&
AuthenticationType == other.AuthenticationType;
}
public override int GetHashCode()
{
return HashCode.Combine(Name, AuthenticationType);
}
public override bool Equals(object obj) => Equals(obj as BackOfficeExternalLoginProvider);
public bool Equals(BackOfficeExternalLoginProvider other) => other != null && AuthenticationType == other.AuthenticationType;
public override int GetHashCode() => HashCode.Combine(AuthenticationType);
}
}

View File

@@ -1,41 +1,71 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
namespace Umbraco.Cms.Web.BackOffice.Security
{
/// <inheritdoc />
public class BackOfficeExternalLoginProviders : IBackOfficeExternalLoginProviders
{
public BackOfficeExternalLoginProviders(IEnumerable<BackOfficeExternalLoginProvider> externalLogins)
private readonly Dictionary<string, BackOfficeExternalLoginProvider> _externalLogins;
private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider;
public BackOfficeExternalLoginProviders(
IEnumerable<BackOfficeExternalLoginProvider> externalLogins,
IAuthenticationSchemeProvider authenticationSchemeProvider)
{
_externalLogins = externalLogins;
_externalLogins = externalLogins.ToDictionary(x => x.AuthenticationType);
_authenticationSchemeProvider = authenticationSchemeProvider;
}
private readonly IEnumerable<BackOfficeExternalLoginProvider> _externalLogins;
/// <inheritdoc />
public BackOfficeExternalLoginProvider Get(string authenticationType)
public async Task<BackOfficeExternaLoginProviderScheme> GetAsync(string authenticationType)
{
return _externalLogins.FirstOrDefault(x => x.AuthenticationType == authenticationType);
if (!_externalLogins.TryGetValue(authenticationType, out BackOfficeExternalLoginProvider provider))
{
return null;
}
// get the associated scheme
AuthenticationScheme associatedScheme = await _authenticationSchemeProvider.GetSchemeAsync(provider.AuthenticationType);
if (associatedScheme == null)
{
throw new InvalidOperationException("No authentication scheme registered for " + provider.AuthenticationType);
}
return new BackOfficeExternaLoginProviderScheme(provider, associatedScheme);
}
/// <inheritdoc />
public string GetAutoLoginProvider()
{
var found = _externalLogins.Where(x => x.Options.AutoRedirectLoginToExternalProvider).ToList();
var found = _externalLogins.Values.Where(x => x.Options.AutoRedirectLoginToExternalProvider).ToList();
return found.Count > 0 ? found[0].AuthenticationType : null;
}
/// <inheritdoc />
public IEnumerable<BackOfficeExternalLoginProvider> GetBackOfficeProviders()
public async Task<IEnumerable<BackOfficeExternaLoginProviderScheme>> GetBackOfficeProvidersAsync()
{
return _externalLogins;
var providersWithSchemes = new List<BackOfficeExternaLoginProviderScheme>();
foreach (BackOfficeExternalLoginProvider login in _externalLogins.Values)
{
// get the associated scheme
AuthenticationScheme associatedScheme = await _authenticationSchemeProvider.GetSchemeAsync(login.AuthenticationType);
providersWithSchemes.Add(new BackOfficeExternaLoginProviderScheme(login, associatedScheme));
}
return providersWithSchemes;
}
/// <inheritdoc />
public bool HasDenyLocalLogin()
{
var found = _externalLogins.Where(x => x.Options.DenyLocalLogin).ToList();
var found = _externalLogins.Values.Where(x => x.Options.DenyLocalLogin).ToList();
return found.Count > 0;
}
}

View File

@@ -64,7 +64,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
// borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs
// to be able to deal with auto-linking and reduce duplicate lookups
var autoLinkOptions = _externalLogins.Get(loginInfo.LoginProvider)?.Options?.AutoLinkOptions;
var autoLinkOptions = (await _externalLogins.GetAsync(loginInfo.LoginProvider))?.ExternalLoginProvider?.Options?.AutoLinkOptions;
var user = await UserManager.FindByLoginAsync(loginInfo.LoginProvider, loginInfo.ProviderKey);
if (user == null)
{

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Umbraco.Cms.Web.BackOffice.Security
{
@@ -13,13 +14,13 @@ namespace Umbraco.Cms.Web.BackOffice.Security
/// </summary>
/// <param name="authenticationType"></param>
/// <returns></returns>
BackOfficeExternalLoginProvider Get(string authenticationType);
Task<BackOfficeExternaLoginProviderScheme> GetAsync(string authenticationType);
/// <summary>
/// Get all registered <see cref="BackOfficeExternalLoginProvider"/>
/// </summary>
/// <returns></returns>
IEnumerable<BackOfficeExternalLoginProvider> GetBackOfficeProviders();
Task<IEnumerable<BackOfficeExternaLoginProviderScheme>> GetBackOfficeProvidersAsync();
/// <summary>
/// Returns the authentication type for the last registered external login (oauth) provider that specifies an auto-login redirect option