#21237: Moved IClientIpAddressProvider into Orchard.Framework.

This changeset also renames the service to IClientAddressAccessor and refactors the settings into being configurable from HostComponents instead of through a site settings part.

Work Item: 21237
This commit is contained in:
Sipke Schoorstra
2015-03-06 19:59:52 +01:00
parent 439046c298
commit ce23bb5a3e
15 changed files with 80 additions and 145 deletions

View File

@@ -94,5 +94,16 @@
</Properties>
</Component>
<Component Type="Orchard.Services.ClientAddressAccessor">
<Properties>
<!-- Set Value="true" to read the client host address from the specified HTTP header. -->
<Property Name="EnableClientAddressHeader" Value="false"/>
<!-- Set Value to the HTTP header name from which to read the client host address. Only used when EnableClientAddressHeader="true".
If the specified header was not found, the system will fall back to the user host address as provided by the Request object.-->
<Property Name="ClientAddressHeaderName" Value="X-Forwarded-For"/>
</Properties>
</Component>
</Components>
</HostComponents>

View File

@@ -1,31 +0,0 @@
using Orchard.AuditTrail.Models;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Security;
namespace Orchard.AuditTrail.Drivers {
public class ClientIpAddressSettingsPartDriver : ContentPartDriver<ClientIpAddressSettingsPart> {
private readonly IAuthorizer _authorizer;
public ClientIpAddressSettingsPartDriver(IAuthorizer authorizer) {
_authorizer = authorizer;
}
protected override DriverResult Editor(ClientIpAddressSettingsPart part, dynamic shapeHelper) {
return Editor(part, null, shapeHelper);
}
protected override DriverResult Editor(ClientIpAddressSettingsPart part, IUpdateModel updater, dynamic shapeHelper) {
if (!_authorizer.Authorize(Permissions.ManageClientIpAddressSettings))
return null;
return ContentShape("Parts_ClientIpAddressSettings_Edit", () => {
if (updater != null) {
updater.TryUpdateModel(part, Prefix, null, null);
}
return shapeHelper.EditorTemplate(TemplateName: "Parts.ClientIpAddressSettings", Model: part, Prefix: Prefix);
}).OnGroup("Audit Trail");
}
}
}

View File

@@ -1,17 +0,0 @@
using Orchard.AuditTrail.Models;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Localization;
namespace Orchard.AuditTrail.Handlers {
public class ClientIpAddressSettingsPartHandler : ContentHandler {
public ClientIpAddressSettingsPartHandler() {
Filters.Add(new ActivatingFilter<ClientIpAddressSettingsPart>("Site"));
OnGetContentItemMetadata<ClientIpAddressSettingsPart>((context, part) => context.Metadata.EditorGroupInfo.Add(new GroupInfo(T("Audit Trail"))));
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
}
}

View File

@@ -1,16 +0,0 @@
using Orchard.ContentManagement;
namespace Orchard.AuditTrail.Models {
public class ClientIpAddressSettingsPart : ContentPart {
public bool EnableClientIpAddressHeader {
get { return this.Retrieve(x => x.EnableClientIpAddressHeader); }
set { this.Store(x => x.EnableClientIpAddressHeader, value); }
}
public string ClientIpAddressHeaderName {
get { return this.Retrieve(x => x.ClientIpAddressHeaderName, "X-Forwarded-For"); }
set { this.Store(x => x.ClientIpAddressHeaderName, value); }
}
}
}

View File

@@ -200,10 +200,8 @@
<Compile Include="Services\IRecycleBin.cs" />
<Compile Include="Services\RecycleBin.cs" />
<Compile Include="ViewModels\RecycleBinViewModel.cs" />
<Compile Include="Drivers\ClientIpAddressSettingsPartDriver.cs" />
<Compile Include="Drivers\AuditTrailTrimmingSettingsPartDriver.cs" />
<Compile Include="Drivers\AuditTrailSettingsPartDriver.cs" />
<Compile Include="Handlers\ClientIpAddressSettingsPartHandler.cs" />
<Compile Include="Handlers\AuditTrailTrimmingSettingsPartHandler.cs" />
<Compile Include="Helpers\FiltersExtensions.cs" />
<Compile Include="Helpers\DateTimeExtensions.cs" />
@@ -215,14 +213,11 @@
<Compile Include="ImportExport\AuditTrailExportHandler.cs" />
<Compile Include="ImportExport\AuditTrailImportHandler.cs" />
<Compile Include="Models\AuditTrailEventRecordResult.cs" />
<Compile Include="Models\ClientIpAddressSettingsPart.cs" />
<Compile Include="Models\AuditTrailTrimmingSettingsPart.cs" />
<Compile Include="Providers\AuditTrail\AuditTrailTrimmingSettingsEventProvider.cs" />
<Compile Include="Providers\AuditTrail\AuditTrailSettingsEventProvider.cs" />
<Compile Include="Providers\ContentDefinition\Shapes\ContentPartImportedEventShape.cs" />
<Compile Include="Providers\ContentDefinition\Shapes\ContentTypeImportedEventShape.cs" />
<Compile Include="Services\DefaultClientIpAddressProvider.cs" />
<Compile Include="Services\IClientIpAddressProvider.cs" />
<Compile Include="Services\Models\AuditTrailSettingsContext.cs" />
<Compile Include="Services\CommonAuditTrailEventHandler.cs" />
<Compile Include="Services\AuditTrailEventHandlerBase.cs" />
@@ -316,9 +311,6 @@
<ItemGroup>
<Content Include="Views\EditorTemplates\Parts.AuditTrail.Comment.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\EditorTemplates\Parts.ClientIpAddressSettings.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\AuditTrailEventActions.cshtml" />
</ItemGroup>

View File

@@ -26,7 +26,7 @@ namespace Orchard.AuditTrail.Services {
private readonly ISiteService _siteService;
private readonly ISignals _signals;
private readonly IShapeFactory _shapeFactory;
private readonly IClientIpAddressProvider _clientIpAddressProvider;
private readonly IClientAddressAccessor _clientAddressAccessor;
public AuditTrailManager(
IRepository<AuditTrailEventRecord> auditTrailRepository,
@@ -38,7 +38,7 @@ namespace Orchard.AuditTrail.Services {
ISiteService siteService,
ISignals signals,
IShapeFactory shapeFactory,
IClientIpAddressProvider clientIpAddressProvider) {
IClientAddressAccessor clientAddressAccessor) {
_auditTrailRepository = auditTrailRepository;
_providers = providers;
@@ -49,7 +49,7 @@ namespace Orchard.AuditTrail.Services {
_siteService = siteService;
_signals = signals;
_shapeFactory = shapeFactory;
_clientIpAddressProvider = clientIpAddressProvider;
_clientAddressAccessor = clientAddressAccessor;
}
public IPageOfItems<AuditTrailEventRecord> GetRecords(
@@ -155,7 +155,7 @@ namespace Orchard.AuditTrail.Services {
EventFilterKey = context.EventFilterKey,
EventFilterData = context.EventFilterData,
Comment = context.Comment,
ClientIpAddress = GetClientIpAddress()
ClientIpAddress = GetClientAddress()
};
_auditTrailRepository.Create(record);
@@ -238,13 +238,13 @@ namespace Orchard.AuditTrail.Services {
return Enumerable.Empty<AuditTrailEventSetting>();
}
private string GetClientIpAddress() {
private string GetClientAddress() {
var settings = _siteService.GetSiteSettings().As<AuditTrailSettingsPart>();
if (!settings.EnableClientIpAddressLogging)
return null;
return _clientIpAddressProvider.GetClientIpAddress();
return _clientAddressAccessor.GetClientAddress();
}
private bool IsEventEnabled(AuditTrailEventDescriptor eventDescriptor) {

View File

@@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.AuditTrail.Models;
using Orchard.ContentManagement;
namespace Orchard.AuditTrail.Services {
public class DefaultClientIpAddressProvider : IClientIpAddressProvider {
private readonly IWorkContextAccessor _wca;
public DefaultClientIpAddressProvider(IWorkContextAccessor wca) {
_wca = wca;
}
public string GetClientIpAddress() {
var workContext = _wca.GetContext();
var settings = workContext.CurrentSite.As<ClientIpAddressSettingsPart>();
var address = workContext.HttpContext.Request.UserHostAddress;
if (settings.EnableClientIpAddressHeader && !String.IsNullOrWhiteSpace(settings.ClientIpAddressHeaderName)) {
var headerName = settings.ClientIpAddressHeaderName.Trim();
var customAddresses = ParseAddresses(workContext.HttpContext.Request.Headers[headerName]).ToArray();
if (customAddresses.Any())
address = customAddresses.First();
}
return address;
}
private static IEnumerable<string> ParseAddresses(string value) {
return !String.IsNullOrWhiteSpace(value)
? value.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim())
: Enumerable.Empty<string>();
}
}
}

View File

@@ -1,5 +0,0 @@
namespace Orchard.AuditTrail.Services {
public interface IClientIpAddressProvider : IDependency {
string GetClientIpAddress();
}
}

View File

@@ -1,16 +0,0 @@
@model Orchard.AuditTrail.Models.ClientIpAddressSettingsPart
@{
Script.Require("ShapesBase");
}
<section class="clientipaddress-settings-section">
<fieldset>
@Html.CheckBoxFor(m => m.EnableClientIpAddressHeader)
@Html.LabelFor(m => m.EnableClientIpAddressHeader, T("Read client IP address from HTTP header instead of network source IP").Text, new { @class = "forcheckbox" })
<span class="hint">@T("This can be useful when the site is behind a reverse proxy server.")</span>
</fieldset>
<fieldset data-controllerid="@Html.FieldIdFor(m => m.EnableClientIpAddressHeader)">
@Html.LabelFor(m => m.ClientIpAddressHeaderName, T("Client IP address HTTP header name"))
@Html.TextBoxFor(m => m.ClientIpAddressHeaderName, new { @class = "text medium" })
<span class="hint">@T("The name of the HTTP header from which to read the client IP address. For most reverse proxy servers this should be <strong>X-Forwarded-For</strong>.")</span>
</fieldset>
</section>

View File

@@ -1,13 +1,13 @@
using Orchard.AuditTrail.Services;
using Orchard.DynamicForms.Elements;
using Orchard.DynamicForms.Services;
using Orchard.Services;
namespace Orchard.DynamicForms.Handlers {
public class IpAddressFieldHandler : FormElementEventHandlerBase {
private readonly IClientIpAddressProvider _clientIpAddressProvider;
private readonly IClientAddressAccessor _clientAddressAccessor;
public IpAddressFieldHandler(IClientIpAddressProvider clientIpAddressProvider) {
_clientIpAddressProvider = clientIpAddressProvider;
public IpAddressFieldHandler(IClientAddressAccessor clientAddressAccessor) {
_clientAddressAccessor = clientAddressAccessor;
}
public override void GetElementValue(FormElement element, ReadElementValuesContext context) {
@@ -17,7 +17,7 @@ namespace Orchard.DynamicForms.Handlers {
return;
var key = ipAddressField.Name;
context.Output[key] = _clientIpAddressProvider.GetClientIpAddress();
context.Output[key] = _clientAddressAccessor.GetClientAddress();
}
}
}

View File

@@ -10,7 +10,7 @@ Features:
Name: Dynamic Forms
Description: Create custom forms like contact forms using layouts.
Category: Forms
Dependencies: Orchard.Layouts, Orchard.Scripting.CSharp, Orchard.Tokens, Orchard.Workflows, Orchard.Users, Orchard.AuditTrail, Orchard.Fields, Common
Dependencies: Orchard.Layouts, Orchard.Scripting.CSharp, Orchard.Tokens, Orchard.Workflows, Orchard.Users, Orchard.Fields, Common
Orchard.DynamicForms.AntiSpam:
Name: Anti-Spam Elements
Description: Provides anti-spam elements to protect your content from malicious submissions.

View File

@@ -118,10 +118,6 @@
<Project>{91bc2e7f-da04-421c-98ef-76d37cec130c}</Project>
<Name>Orchard.AntiSpam</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.AuditTrail\Orchard.AuditTrail.csproj">
<Project>{3dd574cd-9c5d-4a45-85e1-ebba64c22b5f}</Project>
<Name>Orchard.AuditTrail</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.Fields\Orchard.Fields.csproj">
<Project>{3787dde5-e5c8-4841-bda7-dcb325388064}</Project>
<Name>Orchard.Fields</Name>

View File

@@ -349,7 +349,9 @@
<Compile Include="Security\CurrentUserWorkContext.cs" />
<Compile Include="Security\Providers\DefaultEncryptionService.cs" />
<Compile Include="Services\Clock.cs" />
<Compile Include="Services\ClientAddressAccessor.cs" />
<Compile Include="Services\DefaultJsonConverter.cs" />
<Compile Include="Services\IClientAddressAccessor.cs" />
<Compile Include="Services\IJsonConverter.cs" />
<Compile Include="Settings\CurrentSiteWorkContext.cs" />
<Compile Include="Settings\ResourceDebugMode.cs" />

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
namespace Orchard.Services {
/// <summary>
/// Provides access to the client host address.
/// </summary>
public class ClientAddressAccessor : IClientAddressAccessor {
private readonly IWorkContextAccessor _wca;
public ClientAddressAccessor(IWorkContextAccessor wca) {
_wca = wca;
}
/// <summary>
/// Indicates whether the client host address should be read from an HTTP header, specified via <see cref="ClientAddressHeaderName"/>
/// </summary>
public bool EnableClientAddressHeader { get; set; }
/// <summary>
/// The HTTP header name to read the client host address from if <see cref="EnableClientAddressHeader"/> is set to true.
/// If the specified header was not found, the system will fall back to the user host address as provided by the Request object.
/// </summary>
public string ClientAddressHeaderName { get; set; }
public string GetClientAddress() {
var request = _wca.GetContext().HttpContext.Request;
if (EnableClientAddressHeader && !String.IsNullOrWhiteSpace(ClientAddressHeaderName)) {
var headerName = ClientAddressHeaderName.Trim();
var customAddresses = ParseAddresses(request.Headers[headerName]).ToArray();
if (customAddresses.Any())
return customAddresses.First();
}
return request.UserHostAddress;
}
private static IEnumerable<string> ParseAddresses(string value) {
return !String.IsNullOrWhiteSpace(value)
? value.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim())
: Enumerable.Empty<string>();
}
}
}

View File

@@ -0,0 +1,8 @@
namespace Orchard.Services {
/// <summary>
/// Provides access to the user host address.
/// </summary>
public interface IClientAddressAccessor : IDependency {
string GetClientAddress();
}
}