Gets oauth working (with google) now need to test others and debug why the styles aren't working

This commit is contained in:
Shannon
2020-11-27 00:44:36 +11:00
parent e01abf2802
commit c08db7763e
10 changed files with 126 additions and 47 deletions

View File

@@ -180,7 +180,7 @@ namespace Umbraco.Web.BackOffice.Controllers
}
else
{
if (!opt.AutoLinkOptions.AllowManualLinking)
if (!opt.Options.AutoLinkOptions.AllowManualLinking)
{
// If AllowManualLinking is disabled for this provider we cannot unlink
return BadRequest();

View File

@@ -414,7 +414,7 @@ namespace Umbraco.Web.BackOffice.Controllers
}
else
{
autoLinkOptions = _externalLogins.Get(authType.Name)?.AutoLinkOptions;
autoLinkOptions = _externalLogins.Get(authType.Name)?.Options?.AutoLinkOptions;
}
// Sign in the user with this external login provider if the user already has a login
@@ -445,7 +445,7 @@ namespace Umbraco.Web.BackOffice.Controllers
ViewData.SetExternalSignInProviderErrors(
new BackOfficeExternalLoginProviderErrors(
loginInfo.LoginProvider,
new[] { "The requested provider (" + loginInfo.LoginProvider + ") has not been linked to an account" }));
new[] { "The requested provider (" + loginInfo.LoginProvider + ") has not been linked to an account, the provider must be linked from the back office." }));
}
//Remove the cookie otherwise this message will keep appearing
@@ -462,7 +462,7 @@ namespace Umbraco.Web.BackOffice.Controllers
if (autoLinkOptions.AutoLinkExternalAccount == false)
{
return true; // TODO: This seems weird to return true, but it was like that before so must be a reason?
return false;
}
var email = loginInfo.Principal.FindFirstValue(ClaimTypes.Email);

View File

@@ -135,7 +135,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// Returns the server variables for authenticated users
/// </summary>
/// <returns></returns>
internal async Task<Dictionary<string, object>> GetServerVariablesAsync()
internal Task<Dictionary<string, object>> GetServerVariablesAsync()
{
var globalSettings = _globalSettings;
var backOfficeControllerName = ControllerExtensions.GetControllerName<BackOfficeController>();
@@ -149,8 +149,8 @@ namespace Umbraco.Web.BackOffice.Controllers
// having each url defined here explicitly - we can do that in v8! for now
// for umbraco services we'll stick to explicitly defining the endpoints.
// {"externalLoginsUrl", _linkGenerator.GetPathByAction(nameof(BackOfficeController.ExternalLogin), backOfficeControllerName, new { area = Constants.Web.Mvc.BackOfficeArea })},
// {"externalLinkLoginsUrl", _linkGenerator.GetPathByAction(nameof(BackOfficeController.LinkLogin), backOfficeControllerName, new { area = Constants.Web.Mvc.BackOfficeArea })},
{"externalLoginsUrl", _linkGenerator.GetPathByAction(nameof(BackOfficeController.ExternalLogin), backOfficeControllerName, new { area = Constants.Web.Mvc.BackOfficeArea })},
{"externalLinkLoginsUrl", _linkGenerator.GetPathByAction(nameof(BackOfficeController.LinkLogin), backOfficeControllerName, new { area = Constants.Web.Mvc.BackOfficeArea })},
{"gridConfig", _linkGenerator.GetPathByAction(nameof(BackOfficeController.GetGridConfig), backOfficeControllerName, new { area = Constants.Web.Mvc.BackOfficeArea })},
// TODO: This is ultra confusing! this same key is used for different things, when returning the full app when authenticated it is this URL but when not auth'd it's actually the ServerVariables address
{"serverVarsJs", _linkGenerator.GetPathByAction(nameof(BackOfficeController.Application), backOfficeControllerName, new { area = Constants.Web.Mvc.BackOfficeArea })},
@@ -418,10 +418,13 @@ namespace Umbraco.Web.BackOffice.Controllers
"externalLogins", new Dictionary<string, object>
{
{
// 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()
.Select(p => new
{
authType = p.AuthenticationType, caption = p.Name,
authType = p.AuthenticationType,
caption = p.Name,
properties = p.Options
})
.ToArray()
@@ -441,7 +444,7 @@ namespace Umbraco.Web.BackOffice.Controllers
}
}
};
return defaultVals;
return Task.FromResult(defaultVals);
}
[DataContract]

View File

@@ -4,7 +4,6 @@ using System.Runtime.Serialization;
namespace Umbraco.Web.BackOffice.Security
{
// TODO: This is only for the back office, does it need to be in common?
/// <summary>
/// Options used to configure back office external login providers
@@ -12,13 +11,13 @@ namespace Umbraco.Web.BackOffice.Security
public class BackOfficeExternalLoginProviderOptions
{
public BackOfficeExternalLoginProviderOptions(
string style, string icon, string callbackPath,
string buttonStyle, string icon, string callbackPath,
ExternalSignInAutoLinkOptions autoLinkOptions = null,
bool denyLocalLogin = false,
bool autoRedirectLoginToExternalProvider = false,
string customBackOfficeView = null)
{
Style = style;
ButtonStyle = buttonStyle;
Icon = icon;
CallbackPath = callbackPath;
AutoLinkOptions = autoLinkOptions ?? new ExternalSignInAutoLinkOptions();
@@ -27,11 +26,10 @@ namespace Umbraco.Web.BackOffice.Security
CustomBackOfficeView = customBackOfficeView;
}
public string Style { get; }
public string ButtonStyle { get; }
public string Icon { get; }
public string CallbackPath { get; }
/// <summary>
/// Options used to control how users can be auto-linked/created/updated based on the external login provider
/// </summary>

View File

@@ -14,7 +14,6 @@ using Umbraco.Extensions;
namespace Umbraco.Web.Common.Security
{
// TODO: This is only for the back office, does it need to be in common?
using Constants = Umbraco.Core.Constants;

View File

@@ -7,8 +7,6 @@ using SecurityConstants = Umbraco.Core.Constants.Security;
namespace Umbraco.Web.BackOffice.Security
{
// TODO: This is only for the back office, does it need to be in common?
/// <summary>
/// Options used to configure auto-linking external OAuth providers
/// </summary>

View File

@@ -1,27 +1,109 @@
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Umbraco.Core;
using Umbraco.Core.Builder;
namespace Umbraco.Web.BackOffice.Security
{
// TODO: This is only for the back office, does it need to be in common?
/// <summary>
/// Custom <see cref="AuthenticationBuilder"/> used to associate external logins with umbraco external login options
/// </summary>
public class BackOfficeAuthenticationBuilder : AuthenticationBuilder
{
private readonly BackOfficeExternalLoginProviderOptions _loginProviderOptions;
public BackOfficeAuthenticationBuilder(IServiceCollection services, BackOfficeExternalLoginProviderOptions loginProviderOptions)
: base(services)
{
_loginProviderOptions = loginProviderOptions;
}
/// <summary>
/// Overridden to track the final authenticationScheme being registered for the external login
/// </summary>
/// <typeparam name="TOptions"></typeparam>
/// <typeparam name="THandler"></typeparam>
/// <param name="authenticationScheme"></param>
/// <param name="displayName"></param>
/// <param name="configureOptions"></param>
/// <returns></returns>
public override AuthenticationBuilder AddRemoteScheme<TOptions, THandler>(string authenticationScheme, string displayName, Action<TOptions> configureOptions)
{
//Ensure the prefix is set
if (!authenticationScheme.StartsWith(Constants.Security.BackOfficeExternalAuthenticationTypePrefix))
{
authenticationScheme = Constants.Security.BackOfficeExternalAuthenticationTypePrefix + authenticationScheme;
}
// add our login provider to the container along with a custom options configuration
Services.AddSingleton(x => new BackOfficeExternalLoginProvider(displayName, authenticationScheme, _loginProviderOptions));
Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<TOptions>, EnsureBackOfficeScheme<TOptions>>());
return base.AddRemoteScheme<TOptions, THandler>(authenticationScheme, displayName, configureOptions);
}
// TODO: We could override and throw NotImplementedException for other methods?
// Ensures that the sign in scheme is always the Umbraco back office external type
private class EnsureBackOfficeScheme<TOptions> : IPostConfigureOptions<TOptions> where TOptions : RemoteAuthenticationOptions
{
public void PostConfigure(string name, TOptions options)
{
options.SignInScheme = Constants.Security.BackOfficeExternalAuthenticationType;
}
}
}
/// <summary>
/// Used to add back office login providers
/// </summary>
public class BackOfficeExternalLoginsBuilder
{
public BackOfficeExternalLoginsBuilder(IServiceCollection services)
{
_services = services;
}
private readonly IServiceCollection _services;
/// <summary>
/// Add a back office login provider with options
/// </summary>
/// <param name="loginProviderOptions"></param>
/// <param name="build"></param>
/// <returns></returns>
public BackOfficeExternalLoginsBuilder AddBackOfficeLogin(
BackOfficeExternalLoginProviderOptions loginProviderOptions,
Action<BackOfficeAuthenticationBuilder> build)
{
build(new BackOfficeAuthenticationBuilder(_services, loginProviderOptions));
return this;
}
}
public static class AuthenticationBuilderExtensions
{
public static IUmbracoBuilder AddBackOfficeExternalLogins(this IUmbracoBuilder umbracoBuilder, Action<BackOfficeExternalLoginsBuilder> builder)
{
builder(new BackOfficeExternalLoginsBuilder(umbracoBuilder.Services));
return umbracoBuilder;
}
}
// TODO: We need to implement this and extend it to support the back office external login options
// basically migrate things from AuthenticationManagerExtensions & AuthenticationOptionsExtensions
// and use this to get the back office external login infos
public interface IBackOfficeExternalLoginProviders
{
/// <summary>
/// Register a login provider for the back office
/// </summary>
/// <param name="provider"></param>
void Register(BackOfficeExternalLoginProvider provider);
BackOfficeExternalLoginProviderOptions Get(string authenticationType);
BackOfficeExternalLoginProvider Get(string authenticationType);
IEnumerable<BackOfficeExternalLoginProvider> GetBackOfficeProviders();
@@ -32,42 +114,41 @@ namespace Umbraco.Web.BackOffice.Security
/// <returns></returns>
string GetAutoLoginProvider();
/// <summary>
/// Returns true if there is any external provider that has the Deny Local Login option configured
/// </summary>
/// <returns></returns>
bool HasDenyLocalLogin();
}
// TODO: This class is just a placeholder for later
public class BackOfficeExternalLoginProviders : IBackOfficeExternalLoginProviders
{
private ConcurrentDictionary<string, BackOfficeExternalLoginProvider> _providers = new ConcurrentDictionary<string, BackOfficeExternalLoginProvider>();
public void Register(BackOfficeExternalLoginProvider provider)
public BackOfficeExternalLoginProviders(IEnumerable<BackOfficeExternalLoginProvider> externalLogins)
{
_providers.TryAdd(provider.AuthenticationType, provider);
// TODO: we need to be able to set things like we were doing in ForUmbracoBackOffice.
// Ok, most is done but we'll also need to take into account the callback path to ignore when we
// do front-end routing
_externalLogins = externalLogins;
}
public BackOfficeExternalLoginProviderOptions Get(string authenticationType)
private readonly IEnumerable<BackOfficeExternalLoginProvider> _externalLogins;
public BackOfficeExternalLoginProvider Get(string authenticationType)
{
return _providers.TryGetValue(authenticationType, out var opt) ? opt.Options : null;
return _externalLogins.FirstOrDefault(x => x.AuthenticationType == authenticationType);
}
public string GetAutoLoginProvider()
{
var found = _providers.Where(x => x.Value.Options.AutoRedirectLoginToExternalProvider).ToList();
return found.Count > 0 ? found[0].Key : null;
var found = _externalLogins.Where(x => x.Options.AutoRedirectLoginToExternalProvider).ToList();
return found.Count > 0 ? found[0].AuthenticationType : null;
}
public IEnumerable<BackOfficeExternalLoginProvider> GetBackOfficeProviders()
{
return _providers.Values;
return _externalLogins;
}
public bool HasDenyLocalLogin()
{
var found = _providers.Where(x => x.Value.Options.DenyLocalLogin).ToList();
var found = _externalLogins.Where(x => x.Options.DenyLocalLogin).ToList();
return found.Count > 0;
}
}

View File

@@ -50,7 +50,7 @@ function externalLoginInfoService(externalLoginInfo, umbRequestHelper) {
return true;
}
else {
return x.properties.ExternalSignInAutoLinkOptions.AllowManualLinking;
return x.properties.AutoLinkOptions.AllowManualLinking;
}
});
return providers;

View File

@@ -52,11 +52,11 @@
<div ng-if="login.customView" ng-include="login.customView"></div>
<div ng-if="!login.customView && login.properties.ExternalSignInAutoLinkOptions.AllowManualLinking">
<div ng-if="!login.customView && login.properties.AutoLinkOptions.AllowManualLinking">
<form ng-submit="linkProvider($event)" ng-if="login.linkedProviderKey == undefined" method="POST" action="{{externalLinkLoginFormAction}}" name="oauthloginform" id="oauthloginform-{{login.authType}}">
<input type="hidden" name="provider" value="{{login.authType}}" />
<button class="btn btn-block btn-social"
ng-class="login.properties.SocialStyle"
ng-class="login.properties.ButtonStyle"
id="{{login.authType}}">
<i class="fa" ng-class="login.properties.SocialIcon"></i>
@@ -67,7 +67,7 @@
<button ng-if="login.linkedProviderKey != undefined"
ng-click="unlink($event, login.authType, login.linkedProviderKey)"
class="btn btn-block btn-social"
ng-class="login.properties.SocialStyle"
ng-class="login.properties.ButtonStyle"
id="{{login.authType}}"
name="provider"
value="{{login.authType}}">

View File

@@ -126,7 +126,7 @@
<form method="POST" action="{{vm.externalLoginFormAction}}">
<button type="submit"
class="btn btn-block btn-social"
ng-class="login.properties.SocialStyle"
ng-class="login.properties.ButtonStyle"
id="{{login.authType}}" name="provider" value="{{login.authType}}"
title="Log in using your {{login.caption}} account">
<i class="fa" ng-class="login.properties.SocialIcon"></i>