Merge branch 'netcore/dev' into netcore/netcore

# Conflicts:
#	src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs
#	src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
#	src/Umbraco.Web.UI.NetCore/appsettings.json
#	src/Umbraco.Web/Editors/AuthenticationController.cs
#	src/Umbraco.Web/Editors/UsersController.cs
This commit is contained in:
Bjarke Berg
2020-05-20 12:43:13 +02:00
12 changed files with 146 additions and 34 deletions

View File

@@ -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; }
}
}

View File

@@ -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<string>("Host");
public int Port => _configurationSection.GetValue<int>("Port");
public string PickupDirectoryLocation => _configurationSection.GetValue<string>("PickupDirectoryLocation");
public SmtpDeliveryMethod DeliveryMethod => _configurationSection.GetValue<SmtpDeliveryMethod>("DeliveryMethod");
public string Username => _configurationSection.GetValue<string>("Username");
public string Password => _configurationSection.GetValue<string>("Password");
}
}
}

View File

@@ -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; }
}
}

View File

@@ -321,6 +321,7 @@ namespace Umbraco.Core.Runtime
composition.RegisterUnique<IEventMessagesAccessor, HybridEventMessagesAccessor>();
composition.RegisterUnique<ITreeService, TreeService>();
composition.RegisterUnique<ISectionService, SectionService>();
composition.RegisterUnique<IEmailSender, EmailSender>();
composition.RegisterUnique<IExamineManager, ExamineManager>();

View File

@@ -11,6 +11,7 @@
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
<PackageReference Include="LightInject.Microsoft.DependencyInjection" Version="3.3.0" />
<PackageReference Include="LightInject.Microsoft.Hosting" Version="1.2.0" />
<PackageReference Include="MailKit" Version="2.6.0" />
<PackageReference Include="Markdown" Version="2.2.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.2" />

View File

@@ -1,9 +1,12 @@
using System;
using System.Linq;
using System.Net.Mail;
using System.Threading.Tasks;
using Umbraco.Core.Composing;
using MimeKit;
using MimeKit.Text;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using SmtpClient = MailKit.Net.Smtp.SmtpClient;
namespace Umbraco.Core
{
@@ -21,7 +24,7 @@ namespace Umbraco.Core
{
}
internal EmailSender(IGlobalSettings globalSettings, bool enableEvents)
public EmailSender(IGlobalSettings globalSettings, bool enableEvents)
{
_globalSettings = globalSettings;
_enableEvents = enableEvents;
@@ -45,7 +48,17 @@ namespace Umbraco.Core
{
using (var client = new SmtpClient())
{
client.Send(message);
client.Connect(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
if (!(_globalSettings.SmtpSettings.Username is null &&
_globalSettings.SmtpSettings.Password is null))
{
client.Authenticate(_globalSettings.SmtpSettings.Username, _globalSettings.SmtpSettings.Password);
}
client.Send(ConstructEmailMessage(message));
client.Disconnect(true);
}
}
}
@@ -65,14 +78,25 @@ namespace Umbraco.Core
{
using (var client = new SmtpClient())
{
if (client.DeliveryMethod == SmtpDeliveryMethod.Network)
await client.ConnectAsync(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
if (!(_globalSettings.SmtpSettings.Username is null &&
_globalSettings.SmtpSettings.Password is null))
{
await client.SendMailAsync(message);
await client.AuthenticateAsync(_globalSettings.SmtpSettings.Username, _globalSettings.SmtpSettings.Password);
}
var mailMessage = ConstructEmailMessage(message);
if (_globalSettings.SmtpSettings.DeliveryMethod == SmtpDeliveryMethod.Network)
{
await client.SendAsync(mailMessage);
}
else
{
client.Send(message);
client.Send(mailMessage);
}
await client.DisconnectAsync(true);
}
}
}
@@ -83,7 +107,7 @@ namespace Umbraco.Core
/// <remarks>
/// We assume this is possible if either an event handler is registered or an smtp server is configured
/// </remarks>
internal static bool CanSendRequiredEmail(IGlobalSettings globalSettings) => EventHandlerRegistered || globalSettings.IsSmtpServerConfigured;
public static bool CanSendRequiredEmail(IGlobalSettings globalSettings) => EventHandlerRegistered || globalSettings.IsSmtpServerConfigured;
/// <summary>
/// returns true if an event handler has been registered
@@ -103,5 +127,22 @@ namespace Umbraco.Core
var handler = SendEmail;
if (handler != null) handler(null, e);
}
private MimeMessage ConstructEmailMessage(MailMessage mailMessage)
{
var fromEmail = mailMessage.From?.Address;
if(string.IsNullOrEmpty(fromEmail))
fromEmail = _globalSettings.SmtpSettings.From;
var messageToSend = new MimeMessage
{
Subject = mailMessage.Subject,
From = { new MailboxAddress(fromEmail)},
Body = new TextPart(mailMessage.IsBodyHtml ? TextFormat.Html : TextFormat.Plain) { Text = mailMessage.Body }
};
messageToSend.To.AddRange(mailMessage.To.Select(x=>new MailboxAddress(x.Address)));
return messageToSend;
}
}
}

View File

@@ -1,4 +1,6 @@
using Umbraco.Core.Configuration;
using System.Net.Mail;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Tests.Common.Builders
{
@@ -16,6 +18,9 @@ namespace Umbraco.Tests.Common.Builders
private string _host;
private int? _port;
private string _pickupDirectoryLocation;
private SmtpDeliveryMethod? _deliveryMethod;
private string _username;
private string _password;
public SmtpSettingsBuilder(TParent parentBuilder) : base(parentBuilder)
{
@@ -33,24 +38,45 @@ namespace Umbraco.Tests.Common.Builders
return this;
}
public SmtpSettingsBuilder<TParent> WithUsername(string username)
{
_username = username;
return this;
}
public SmtpSettingsBuilder<TParent> WithPost(int port)
{
_port = port;
return this;
}
public SmtpSettingsBuilder<TParent> WithPassword(string password)
{
_password = password;
return this;
}
public SmtpSettingsBuilder<TParent> WithPickupDirectoryLocation(string pickupDirectoryLocation)
{
_pickupDirectoryLocation = pickupDirectoryLocation;
return this;
}
public SmtpSettingsBuilder<TParent> WithDeliveryMethod(SmtpDeliveryMethod deliveryMethod)
{
_deliveryMethod = deliveryMethod;
return this;
}
public override ISmtpSettings Build()
{
var from = _from ?? null;
var host = _host ?? null;
var port = _port ?? 25;
var pickupDirectoryLocation = _pickupDirectoryLocation ?? null;
var deliveryMethod = _deliveryMethod ?? SmtpDeliveryMethod.Network;
var username = _username ?? null;
var password = _password ?? null;
return new TestSmtpSettings()
{
@@ -58,6 +84,9 @@ namespace Umbraco.Tests.Common.Builders
Host = host,
Port = port,
PickupDirectoryLocation = pickupDirectoryLocation,
DeliveryMethod = deliveryMethod,
Username = username,
Password = password,
};
}
@@ -67,6 +96,9 @@ namespace Umbraco.Tests.Common.Builders
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; }
}
}
}

View File

@@ -313,6 +313,7 @@ namespace Umbraco.Tests.Testing
Composition.RegisterUnique<ISectionService, SectionService>();
Composition.RegisterUnique<HtmlLocalLinkParser>();
Composition.RegisterUnique<IEmailSender, EmailSender>();
Composition.RegisterUnique<HtmlUrlParser>();
Composition.RegisterUnique<HtmlImageSourceParser>();
Composition.RegisterUnique<RichTextEditorPastedImages>();

View File

@@ -93,7 +93,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance<UmbracoMapper>(),
Factory.GetInstance<ISecuritySettings>(),
Factory.GetInstance<IPublishedUrlProvider>(),
Factory.GetInstance<IRequestAccessor>()
Factory.GetInstance<IRequestAccessor>(),
Factory.GetInstance<IEmailSender>()
);
return usersController;
}

View File

@@ -105,7 +105,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance<IImageUrlGenerator>(),
Factory.GetInstance<IPublishedUrlProvider>(),
Factory.GetInstance<ISecuritySettings>(),
Factory.GetInstance<IRequestAccessor>()
Factory.GetInstance<IRequestAccessor>(),
Factory.GetInstance<IEmailSender>()
);
return usersController;
@@ -179,7 +180,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance<IImageUrlGenerator>(),
Factory.GetInstance<IPublishedUrlProvider>(),
Factory.GetInstance<ISecuritySettings>(),
Factory.GetInstance<IRequestAccessor>()
Factory.GetInstance<IRequestAccessor>(),
Factory.GetInstance<IEmailSender>()
);
return usersController;
}
@@ -223,7 +225,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance<IImageUrlGenerator>(),
Factory.GetInstance<IPublishedUrlProvider>(),
Factory.GetInstance<ISecuritySettings>(),
Factory.GetInstance<IRequestAccessor>()
Factory.GetInstance<IRequestAccessor>(),
Factory.GetInstance<IEmailSender>()
);
return usersController;
}
@@ -302,7 +305,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance<IImageUrlGenerator>(),
Factory.GetInstance<IPublishedUrlProvider>(),
Factory.GetInstance<ISecuritySettings>(),
Factory.GetInstance<IRequestAccessor>()
Factory.GetInstance<IRequestAccessor>(),
Factory.GetInstance<IEmailSender>()
);
return usersController;
}
@@ -493,7 +497,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance<IImageUrlGenerator>(),
Factory.GetInstance<IPublishedUrlProvider>(),
Factory.GetInstance<ISecuritySettings>(),
Factory.GetInstance<IRequestAccessor>());
Factory.GetInstance<IRequestAccessor>(),
Factory.GetInstance<IEmailSender>());
var mockOwinContext = new Mock<IOwinContext>();
var mockUserManagerMarker = new Mock<IBackOfficeUserManagerMarker>();

View File

@@ -3,6 +3,7 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Collections.Generic;
using System.Net.Mail;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Web;
@@ -48,6 +49,7 @@ namespace Umbraco.Web.Editors
private readonly IRuntimeState _runtimeState;
private readonly ISecuritySettings _securitySettings;
private readonly IRequestAccessor _requestAccessor;
private readonly IEmailSender _emailSender;
public AuthenticationController(
IUserPasswordConfiguration passwordConfiguration,
@@ -62,7 +64,8 @@ namespace Umbraco.Web.Editors
UmbracoMapper umbracoMapper,
ISecuritySettings securitySettings,
IPublishedUrlProvider publishedUrlProvider,
IRequestAccessor requestAccessor)
IRequestAccessor requestAccessor,
IEmailSender emailSender)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider)
{
_passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration));
@@ -70,6 +73,7 @@ namespace Umbraco.Web.Editors
_runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState));
_securitySettings = securitySettings ?? throw new ArgumentNullException(nameof(securitySettings));
_requestAccessor = requestAccessor ?? throw new ArgumentNullException(nameof(securitySettings));
_emailSender = emailSender;
}
protected BackOfficeUserManager<BackOfficeIdentityUser> UserManager => _userManager
@@ -331,12 +335,19 @@ namespace Umbraco.Web.Editors
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings),
new[] { identityUser.UserName, callbackUrl });
// TODO: Port email service to ASP.NET Core
/*await UserManager.SendEmailAsync(identityUser.Id,
Services.TextService.Localize("login/resetPasswordEmailCopySubject",
// Ensure the culture of the found user is used for the email!
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings)),
message);*/
var subject = Services.TextService.Localize("login/resetPasswordEmailCopySubject",
// Ensure the culture of the found user is used for the email!
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings));
var mailMessage = new MailMessage()
{
Subject = subject,
Body = message,
IsBodyHtml = true,
To = { user.Email}
};
await _emailSender.SendAsync(mailMessage);
UserManager.RaiseForgotPasswordRequestedEvent(user.Id);
}

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Mail;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Threading.Tasks;
@@ -53,6 +54,7 @@ namespace Umbraco.Web.Editors
private readonly IImageUrlGenerator _imageUrlGenerator;
private readonly ISecuritySettings _securitySettings;
private readonly IRequestAccessor _requestAccessor;
private readonly IEmailSender _emailSender;
public UsersController(
IGlobalSettings globalSettings,
@@ -70,7 +72,8 @@ namespace Umbraco.Web.Editors
IImageUrlGenerator imageUrlGenerator,
IPublishedUrlProvider publishedUrlProvider,
ISecuritySettings securitySettings,
IRequestAccessor requestAccessor)
IRequestAccessor requestAccessor,
IEmailSender emailSender)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
{
_mediaFileSystem = mediaFileSystem;
@@ -80,6 +83,7 @@ namespace Umbraco.Web.Editors
_imageUrlGenerator = imageUrlGenerator;
_securitySettings = securitySettings;
_requestAccessor = requestAccessor;
_emailSender = emailSender;
}
/// <summary>
@@ -503,17 +507,15 @@ namespace Umbraco.Web.Editors
UmbracoUserExtensions.GetUserCulture(to.Language, Services.TextService, GlobalSettings),
new[] { userDisplay.Name, from, message, inviteUri.ToString(), fromEmail });
// TODO: Port email service to ASP.NET Core
/*await UserManager.EmailService.SendAsync(
//send the special UmbracoEmailMessage which configures it's own sender
//to allow for events to handle sending the message if no smtp is configured
new UmbracoEmailMessage(new EmailSender(GlobalSettings, true))
{
Body = emailBody,
Destination = userDisplay.Email,
Subject = emailSubject
});*/
var mailMessage = new MailMessage()
{
Subject = emailSubject,
Body = emailBody,
IsBodyHtml = true,
To = { to.Email}
};
await _emailSender.SendAsync(mailMessage);
}
/// <summary>