diff --git a/.gitignore b/.gitignore
index d8c3f27d5a..2a73537662 100644
--- a/.gitignore
+++ b/.gitignore
@@ -163,6 +163,13 @@ build/hooks/
build/temp/
+# Acceptance tests
+cypress.env.json
+/src/Umbraco.Tests.AcceptanceTest/cypress/support/chainable.ts
+/src/Umbraco.Tests.AcceptanceTest/package-lock.json
+/src/Umbraco.Tests.AcceptanceTest/cypress/videos/
+/src/Umbraco.Tests.AcceptanceTest/cypress/screenshots/
+
# eof
/src/Umbraco.Web.UI.Client/TESTS-*.xml
diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec
index 969ac5be3d..cfab130f0c 100644
--- a/build/NuSpecs/UmbracoCms.Web.nuspec
+++ b/build/NuSpecs/UmbracoCms.Web.nuspec
@@ -33,7 +33,7 @@
-
+
diff --git a/build/build.ps1 b/build/build.ps1
index 6e124d1508..3ba347a6dc 100644
--- a/build/build.ps1
+++ b/build/build.ps1
@@ -381,7 +381,7 @@
{
Write-Host "Restore NuGet"
Write-Host "Logging to $($this.BuildTemp)\nuget.restore.log"
- $params = "-Source", $nugetsourceUmbraco
+ $params = "-Source", $nugetsourceUmbraco
&$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" > "$($this.BuildTemp)\nuget.restore.log" @params
if (-not $?) { throw "Failed to restore NuGet packages." }
})
@@ -535,6 +535,7 @@
# run
if (-not $get)
{
+cd
if ($command.Length -eq 0)
{
$command = @( "Build" )
diff --git a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
index 7e3ff80690..dce3d85840 100644
--- a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
@@ -1,3 +1,4 @@
+using System.Net.Mail;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
@@ -8,5 +9,10 @@ namespace Umbraco.Configuration
public string Host { get; set; }
public int Port { get; set; }
public string PickupDirectoryLocation { get; set; }
+ public SmtpDeliveryMethod DeliveryMethod { get; set; }
+
+ public string Username { get; set; }
+
+ public string Password { get; set; }
}
}
diff --git a/src/Umbraco.Configuration/Models/GlobalSettings.cs b/src/Umbraco.Configuration/Models/GlobalSettings.cs
index 4b30813bd5..e4995cfb0b 100644
--- a/src/Umbraco.Configuration/Models/GlobalSettings.cs
+++ b/src/Umbraco.Configuration/Models/GlobalSettings.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using System.Net.Mail;
using Microsoft.Extensions.Configuration;
using Umbraco.Core;
using Umbraco.Core.Configuration;
@@ -72,10 +73,10 @@ namespace Umbraco.Configuration.Models
_configuration.GetValue(Prefix + "NoNodesViewPath", "~/config/splashes/NoNodes.cshtml");
public bool IsSmtpServerConfigured =>
- _configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp")?.GetChildren().Any() ?? false;
+ _configuration.GetSection(Constants.Configuration.ConfigGlobalPrefix + "Smtp")?.GetChildren().Any() ?? false;
public ISmtpSettings SmtpSettings =>
- new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp"));
+ new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigGlobalPrefix + "Smtp"));
private class SmtpSettingsImpl : ISmtpSettings
{
@@ -90,6 +91,11 @@ namespace Umbraco.Configuration.Models
public string Host => _configurationSection.GetValue("Host");
public int Port => _configurationSection.GetValue("Port");
public string PickupDirectoryLocation => _configurationSection.GetValue("PickupDirectoryLocation");
+ public SmtpDeliveryMethod DeliveryMethod => _configurationSection.GetValue("DeliveryMethod");
+
+ public string Username => _configurationSection.GetValue("Username");
+
+ public string Password => _configurationSection.GetValue("Password");
}
}
}
diff --git a/src/Umbraco.Core/ClaimsIdentityExtensions.cs b/src/Umbraco.Core/ClaimsIdentityExtensions.cs
new file mode 100644
index 0000000000..53fde97312
--- /dev/null
+++ b/src/Umbraco.Core/ClaimsIdentityExtensions.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Security.Claims;
+using System.Security.Principal;
+
+namespace Umbraco.Core
+{
+ public static class ClaimsIdentityExtensions
+ {
+ public static string GetUserId(this IIdentity identity)
+ {
+ if (identity == null) throw new ArgumentNullException(nameof(identity));
+
+ string userId = null;
+ if (identity is ClaimsIdentity claimsIdentity)
+ {
+ userId = claimsIdentity.FindFirstValue(ClaimTypes.NameIdentifier)
+ ?? claimsIdentity.FindFirstValue("sub");
+ }
+
+ return userId;
+ }
+
+ public static string GetUserName(this IIdentity identity)
+ {
+ if (identity == null) throw new ArgumentNullException(nameof(identity));
+
+ string username = null;
+ if (identity is ClaimsIdentity claimsIdentity)
+ {
+ username = claimsIdentity.FindFirstValue(ClaimTypes.Name)
+ ?? claimsIdentity.FindFirstValue("preferred_username");
+ }
+
+ return username;
+ }
+
+ public static string FindFirstValue(this ClaimsIdentity identity, string claimType)
+ {
+ if (identity == null) throw new ArgumentNullException(nameof(identity));
+
+ return identity.FindFirst(claimType)?.Value;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/ISmtpSettings.cs b/src/Umbraco.Core/Configuration/ISmtpSettings.cs
index c2fb4b2dbe..ea42ae5567 100644
--- a/src/Umbraco.Core/Configuration/ISmtpSettings.cs
+++ b/src/Umbraco.Core/Configuration/ISmtpSettings.cs
@@ -1,3 +1,5 @@
+using System.Net.Mail;
+
namespace Umbraco.Core.Configuration
{
public interface ISmtpSettings
@@ -6,5 +8,8 @@ namespace Umbraco.Core.Configuration
string Host { get; }
int Port{ get; }
string PickupDirectoryLocation { get; }
+ SmtpDeliveryMethod DeliveryMethod { get; }
+ string Username { get; }
+ string Password { get; }
}
}
diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs
index b1efd782fa..5602b99e2d 100644
--- a/src/Umbraco.Core/Constants-Web.cs
+++ b/src/Umbraco.Core/Constants-Web.cs
@@ -39,6 +39,16 @@
/// The route name of the page shown when Umbraco has no published content.
///
public const string NoContentRouteName = "umbraco-no-content";
+
+ ///
+ /// The claim type for the ASP.NET Identity security stamp
+ ///
+ public const string SecurityStampClaimType = "AspNet.Identity.SecurityStamp";
+
+ ///
+ /// The default authentication type used for remembering that 2FA is not needed on next login
+ ///
+ public const string TwoFactorRememberBrowserCookie = "TwoFactorRememberBrowser";
}
}
}
diff --git a/src/Umbraco.Core/FactoryExtensions.cs b/src/Umbraco.Core/FactoryExtensions.cs
index 8514525417..8ae2f76af3 100644
--- a/src/Umbraco.Core/FactoryExtensions.cs
+++ b/src/Umbraco.Core/FactoryExtensions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Umbraco.Core.Composing;
@@ -77,15 +78,28 @@ namespace Umbraco.Core
var ctorParameters = ctor.GetParameters();
var ctorArgs = new object[ctorParameters.Length];
+ var availableArgs = new List