Skip to content

Commit

Permalink
Shell configuration for Smtp, Https & Reverse proxy settings (#287)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean-Philippe Tissot authored Jun 22, 2021
1 parent 3ca48f1 commit 70820ac
Show file tree
Hide file tree
Showing 12 changed files with 730 additions and 2 deletions.
15 changes: 15 additions & 0 deletions StatCan.OrchardCore.sln
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{E8DD6EC8-A
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatCan.OrchardCore.Scheduling", "src\Apps\StatCan.OrchardCore.Scheduling\StatCan.OrchardCore.Scheduling.csproj", "{56F32388-650F-433C-919F-8C265F99411D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatCan.OrchardCore.Configuration", "src\Modules\StatCan.OrchardCore.Configuration\StatCan.OrchardCore.Configuration.csproj", "{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -452,6 +454,18 @@ Global
{56F32388-650F-433C-919F-8C265F99411D}.Release|x64.Build.0 = Release|Any CPU
{56F32388-650F-433C-919F-8C265F99411D}.Release|x86.ActiveCfg = Release|Any CPU
{56F32388-650F-433C-919F-8C265F99411D}.Release|x86.Build.0 = Release|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Debug|x64.ActiveCfg = Debug|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Debug|x64.Build.0 = Debug|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Debug|x86.ActiveCfg = Debug|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Debug|x86.Build.0 = Debug|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Release|Any CPU.Build.0 = Release|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Release|x64.ActiveCfg = Release|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Release|x64.Build.0 = Release|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Release|x86.ActiveCfg = Release|Any CPU
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -491,6 +505,7 @@ Global
{B6EAD8A3-58BE-4E21-93EF-D6322A69D63E} = {8BEC45F6-4F23-4994-9959-50C1DB93ABC3}
{E8DD6EC8-AA09-440F-937A-1901293389E1} = {8EA5EBF0-41C6-11EA-890A-ED68CBADDC1F}
{56F32388-650F-433C-919F-8C265F99411D} = {E8DD6EC8-AA09-440F-937A-1901293389E1}
{DEA6A849-3230-43DE-A9A0-3C22DA8E316E} = {5E638520-41E8-11EA-885A-BDD3BB7B4F92}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8FF197F3-C3E2-4D83-80AC-D59BE36DD4AF}
Expand Down
119 changes: 119 additions & 0 deletions docs/en/reference/modules/Configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Deployment configuration

The `StatCan.OrchardCore.Configuration` library adds support for configuring persistent modules, smtp settings, reverse proxy setting and https settings with orchard's [configuration](https://docs.orchardcore.net/en/dev/docs/reference/core/Configuration/).

## Example appsettings.json

```json
{
"OrchardCore": {
"Features": [
"StatCan.OrchardCore.Configuration",
"OrchardCore.Email",
"OrchardCore.ReverseProxy",
"OrchardCore.Https"
],
"StatCan_Configuration": {
"OverwriteSmtpSettings": true,
"OverwriteReverseProxySettings": true,
"OverwriteHttpsSettings": true
},
"StatCan_Smtp": {
"DefaultSender": "no-reply@cloud.statcan.ca",
"DeliveryMethod": 0,
"Host": "smtp.cloud.statcan.ca",
"PickupDirectoryLocation": null,
"AutoSelectEncryption": false,
"EncryptionMethod": 2,
"Port": 25,
"RequireCredentials": true,
"UseDefaultCredentials": false,
"UserName": "test",
"Password": "mysmtppassword"
},
"StatCan_Https": {
"RequireHttps": true,
"EnableStrictTransportSecurity": false,
"RequireHttpsPermanent": false,
"SslPort": null
},
"StatCan_ReverseProxy": {
"EnableXForwardedFor": true,
"EnableXForwardedHost": true,
"EnableXForwardedProto": true
},
}
}
```

## Sections

### StatCan_Configuration

The variables in this section define if the related settings will be overwritten when the tenant activates. For example, if someone modifies the smtp settings from the Admin interface and the `OverwriteSmtpSettings` is set to true, the settings will be reset to those specified via configuration the next time the tenant activates.

### StatCan_Smtp
This section will update Orchard's [email module configuration](https://docs.orchardcore.net/en/dev/docs/reference/modules/Email).

### StatCan_Https
This section will update Orchard's [https module configuration](https://docs.orchardcore.net/en/dev/docs/reference/modules/Https).

### StatCan_ReverseProxy
This section will update Orchard's [reverse proxy module configuration](https://docs.orchardcore.net/en/dev/docs/reference/modules/ReverseProxy).


## Environment variables

It is recommended to use [environment variables](https://docs.orchardcore.net/en/dev/docs/reference/core/Configuration/index.html#ishellconfiguration-via-environment-variables) to configure these settings in a production environment.

```shell
# Configuration
OrchardCore__StatCan_Configuration__OverwriteSmtpSettings: bool
OrchardCore__StatCan_Configuration__OverwriteReverseProxySettings: bool
OrchardCore__StatCan_Configuration__OverwriteHttpsSettings: bool

# Smtp
OrchardCore__StatCan_Smtp__DefaultSender: string
OrchardCore__StatCan_Smtp__DeliveryMethod: 0=Network;1=SpecifiedPickupDirectory
OrchardCore__StatCan_Smtp__Host: string
OrchardCore__StatCan_Smtp__PickupDirectoryLocation: string
OrchardCore__StatCan_Smtp__AutoSelectEncryption: bool
OrchardCore__StatCan_Smtp__EncryptionMethod: 0=none;1=SSLTLS;2=STARTTLS
OrchardCore__StatCan_Smtp__Port: int
OrchardCore__StatCan_Smtp__RequireCredentials: bool
OrchardCore__StatCan_Smtp__UseDefaultCredentials: bool
OrchardCore__StatCan_Smtp__UserName: string
OrchardCore__StatCan_Smtp__Password: string (unencrypted)

# Https
OrchardCore__StatCan_Https__RequireHttps: bool
OrchardCore__StatCan_Https__EnableStrictTransportSecurity: bool
OrchardCore__StatCan_Https__RequireHttpsPermanent: bool
OrchardCore__StatCan_Https__SslPort: int

# ReverseProxy
OrchardCore__StatCan_ReverseProxy__EnableXForwardedFor: bool
OrchardCore__StatCan_ReverseProxy__EnableXForwardedHost: bool
OrchardCore__StatCan_ReverseProxy__EnableXForwardedProto: bool

# Features
OrchardCore__Features__0: string
OrchardCore__Features__1: string

```

Here is an example on how to set these environment variables with powershell
```powershell
$env:OrchardCore__Features__0="StatCan.OrchardCore.Configuration"
$env:OrchardCore__Features__1="OrchardCore.ReverseProxy"
$env:OrchardCore__Features__2="OrchardCore.Https"
$env:OrchardCore__StatCan_Configuration__OverwriteReverseProxySettings="true"
$env:OrchardCore__StatCan_ReverseProxy__EnableXForwardedFor="true"
$env:OrchardCore__StatCan_ReverseProxy__EnableXForwardedHost="true"
$env:OrchardCore__StatCan_ReverseProxy__EnableXForwardedProto="true"
$env:OrchardCore__StatCan_Configuration__OverwriteHttpsSettings="true"
$env:OrchardCore__StatCan_Https__RequireHttps="true"
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ nav:
- Scripting: reference/Scripting.md
- Workflows: reference/Workflows.md
- Modules:
- Configuration: reference/modules/Configuration.md
- ContentFields: reference/modules/ContentFields.md
- EmailTemplates: reference/modules/EmailTemplates.md
- GCCollab: reference/modules/GCCollab.md
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace StatCan.OrchardCore.Configuration
{
public class ConfigurationSettings
{
public string HttpsSettingsHash { get; set; }
public string ReverseProxySettingsHash { get; set; }
public string SmtpSettingsHash { get; set; }
}
}
130 changes: 130 additions & 0 deletions src/Modules/StatCan.OrchardCore.Configuration/HttpsSettingsUpdater.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
using System.Threading.Tasks;
using OrchardCore.Entities;
using OrchardCore.Environment.Extensions.Features;
using OrchardCore.Environment.Shell;
using OrchardCore.Settings;
using OrchardCore.Environment.Shell.Configuration;
using Microsoft.Extensions.Configuration;
using OrchardCore.Modules;
using OrchardCore.Https.Settings;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.WebUtilities;

namespace StatCan.OrchardCore.Configuration
{
/// <summary>
/// Updates the Https settings based on a configuration
/// </summary>
public class HttpsSettingsUpdater : ModularTenantEvents, IFeatureEventHandler
{
private readonly ShellSettings _shellSettings;
private readonly IShellHost _shellHost;
private readonly ISiteService _siteService;
private readonly IShellConfiguration _shellConfiguration;

public HttpsSettingsUpdater(
ISiteService siteService,
IShellConfiguration shellConfiguration,
IShellHost shellHost,
ShellSettings shellSettings)
{
_siteService = siteService;
_shellConfiguration = shellConfiguration;
_shellHost = shellHost;
_shellSettings = shellSettings;
}

// for existing sites, update settings from configuration when tenant activates
public async override Task ActivatedAsync()
{
var section = _shellConfiguration.GetSection("StatCan_Configuration");

if(section.GetValue<bool>("OverwriteHttpsSettings"))
{
await UpdateConfiguration();
}
}

Task IFeatureEventHandler.InstallingAsync(IFeatureInfo feature) => Task.CompletedTask;

Task IFeatureEventHandler.InstalledAsync(IFeatureInfo feature) => Task.CompletedTask;

Task IFeatureEventHandler.EnablingAsync(IFeatureInfo feature) => Task.CompletedTask;

Task IFeatureEventHandler.EnabledAsync(IFeatureInfo feature) => SetConfiguredHttpsSettings(feature);

Task IFeatureEventHandler.DisablingAsync(IFeatureInfo feature) => Task.CompletedTask;

Task IFeatureEventHandler.DisabledAsync(IFeatureInfo feature) => Task.CompletedTask;

Task IFeatureEventHandler.UninstallingAsync(IFeatureInfo feature) => Task.CompletedTask;

Task IFeatureEventHandler.UninstalledAsync(IFeatureInfo feature) => Task.CompletedTask;

private async Task SetConfiguredHttpsSettings(IFeatureInfo feature)
{
if (feature.Id != "OrchardCore.Https")
{
return;
}
await UpdateConfiguration();
}

private async Task UpdateConfiguration()
{
var siteSettings = await _siteService.LoadSiteSettingsAsync();
if(NeedsUpdate(siteSettings))
{
SetConfiguration(siteSettings);
SetHash(siteSettings);
await _siteService.UpdateSiteSettingsAsync(siteSettings);
await _shellHost.ReleaseShellContextAsync(_shellSettings);
}
}

private void SetConfiguration(ISite siteSettings)
{
var httpsSettings = siteSettings.As<HttpsSettings>();
var section = _shellConfiguration.GetSection("StatCan_Https");

httpsSettings.RequireHttps = section.GetValue("RequireHttps", false);
httpsSettings.EnableStrictTransportSecurity = section.GetValue("EnableStrictTransportSecurity", false);
httpsSettings.RequireHttpsPermanent = section.GetValue("RequireHttpsPermanent", false);
httpsSettings.SslPort = section.GetValue<int?>("SslPort", null);

siteSettings.Put(httpsSettings);
}

private static bool NeedsUpdate(ISite settings)
{
var configSettings = settings.As<ConfigurationSettings>();
if(!string.IsNullOrEmpty(configSettings.HttpsSettingsHash))
{
var encValue = EncryptSettings(settings);
if(configSettings.HttpsSettingsHash == encValue)
{
return false;
}
}
return true;
}

private static void SetHash(ISite settings)
{
var configSettings = settings.As<ConfigurationSettings>();
configSettings.HttpsSettingsHash = EncryptSettings(settings);
settings.Put(configSettings);
}

private static string EncryptSettings(ISite settings)
{
using var sha256 = SHA256.Create();
if (settings.Properties.TryGetValue(nameof(HttpsSettings), out var value))
{
return WebEncoders.Base64UrlEncode(sha256.ComputeHash(Encoding.UTF8.GetBytes(value.ToString())));
}
return string.Empty;
}
}
}
23 changes: 23 additions & 0 deletions src/Modules/StatCan.OrchardCore.Configuration/Manifest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using OrchardCore.Modules.Manifest;
using static StatCan.OrchardCore.Manifest.StatCanManifestConstants;

[assembly: Module(
Name = "StatCan Configuration",
Author = DigitalInnovationTeam,
Website = DigitalInnovationWebsite,
Version = Version,
Description = "Deployment configuration",
Category = "Configuration"
)]

[assembly: Feature(
Id = "StatCan.OrchardCore.Configuration",
Name = "StatCan Configuration",
Description = "Deployment configuration",
Category = "Configuration",
Dependencies = new[]
{
"OrchardCore.Features",
"OrchardCore.Settings",
}
)]
Loading

0 comments on commit 70820ac

Please sign in to comment.