Migrated AppendUserModifiedHeaderAttribute into netcore

This commit is contained in:
Andy Butland
2020-05-17 08:52:28 +02:00
parent 60c5c15fdf
commit ed8f65b74e
4 changed files with 203 additions and 3 deletions

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Models.Membership;
using Umbraco.Web.BackOffice.Filters;
using Umbraco.Web.Security;
namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters
{
[TestFixture]
public class AppendUserModifiedHeaderAttributeTests
{
[Test]
public void Appends_Header_When_No_User_Parameter_Provider()
{
// Arrange
var context = CreateContext();
var attribute = new AppendUserModifiedHeaderAttribute();
// Act
attribute.OnActionExecuting(context);
// Assert
context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out var headerValue);
Assert.AreEqual("1", headerValue[0]);
}
[Test]
public void Does_Not_Append_Header_If_Already_Exists()
{
// Arrange
var context = CreateContext(headerValue: "0");
var attribute = new AppendUserModifiedHeaderAttribute();
// Act
attribute.OnActionExecuting(context);
// Assert
context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out var headerValue);
Assert.AreEqual("0", headerValue[0]);
}
[Test]
public void Does_Not_Append_Header_When_User_Id_Parameter_Provided_And_Does_Not_Match_Current_User()
{
// Arrange
var context = CreateContext(actionArgument: new KeyValuePair<string, object>("UserId", 99));
var userIdParameter = "UserId";
var attribute = new AppendUserModifiedHeaderAttribute(userIdParameter);
// Act
attribute.OnActionExecuting(context);
// Assert
Assert.IsFalse(context.HttpContext.Response.Headers.ContainsKey("X-Umb-User-Modified"));
}
[Test]
public void Appends_Header_When_User_Id_Parameter_Provided_And_Does_Not_Match_Current_User()
{
// Arrange
var context = CreateContext(actionArgument: new KeyValuePair<string, object>("UserId", 100));
var userIdParameter = "UserId";
var attribute = new AppendUserModifiedHeaderAttribute(userIdParameter);
// Act
attribute.OnActionExecuting(context);
// Assert
context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out var headerValue);
Assert.AreEqual("1", headerValue[0]);
}
private static ActionExecutingContext CreateContext(string headerValue = null, KeyValuePair<string, object> actionArgument = default)
{
var httpContext = new DefaultHttpContext();
if (!string.IsNullOrEmpty(headerValue))
{
httpContext.Response.Headers.Add("X-Umb-User-Modified", headerValue);
}
var currentUserMock = new Mock<IUser>();
currentUserMock
.SetupGet(x => x.Id)
.Returns(100);
var webSecurityMock = new Mock<IWebSecurity>();
webSecurityMock
.SetupGet(x => x.CurrentUser)
.Returns(currentUserMock.Object);
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock
.Setup(x => x.GetService(typeof(IWebSecurity)))
.Returns(webSecurityMock.Object);
httpContext.RequestServices = serviceProviderMock.Object;
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var context = new ActionExecutingContext(
actionContext,
new List<IFilterMetadata>(),
new Dictionary<string, object>(),
new Mock<Controller>().Object);
if (!EqualityComparer<KeyValuePair<string, object>>.Default.Equals(actionArgument, default))
{
context.ActionArguments.Add(actionArgument);
}
return context;
}
}
}

View File

@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Moq;
using NUnit.Framework;

View File

@@ -0,0 +1,80 @@
using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Core;
using Umbraco.Web.Security;
namespace Umbraco.Web.BackOffice.Filters
{
/// <summary>
/// Appends a custom response header to notify the UI that the current user data has been modified
/// </summary>
public sealed class AppendUserModifiedHeaderAttribute : ActionFilterAttribute
{
private readonly string _userIdParameter;
/// <summary>
/// An empty constructor which will always set the header.
/// </summary>
public AppendUserModifiedHeaderAttribute()
{
}
/// <summary>
/// A constructor specifying the action parameter name containing the user id to match against the
/// current user and if they match the header will be appended.
/// </summary>
/// <param name="userIdParameter"></param>
public AppendUserModifiedHeaderAttribute(string userIdParameter)
{
_userIdParameter = userIdParameter ?? throw new ArgumentNullException(nameof(userIdParameter));
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (_userIdParameter.IsNullOrWhiteSpace())
{
AppendHeader(context);
}
else
{
if (!context.ActionArguments.ContainsKey(_userIdParameter))
{
throw new InvalidOperationException($"No argument found for the current action with the name: {_userIdParameter}");
}
var webSecurityService = context.HttpContext.RequestServices.GetService<IWebSecurity>();
var user = webSecurityService.CurrentUser;
if (user == null)
{
return;
}
var userId = GetUserIdFromParameter(context.ActionArguments[_userIdParameter]);
if (userId == user.Id)
{
AppendHeader(context);
}
}
}
public static void AppendHeader(ActionExecutingContext context)
{
const string HeaderName = "X-Umb-User-Modified";
if (context.HttpContext.Response.Headers.ContainsKey(HeaderName) == false)
{
context.HttpContext.Response.Headers.Add(HeaderName, "1");
}
}
private int GetUserIdFromParameter(object parameterValue)
{
if (parameterValue is int)
{
return (int)parameterValue;
}
throw new InvalidOperationException($"The id type: {parameterValue.GetType()} is not a supported id.");
}
}
}

View File

@@ -9,6 +9,7 @@ namespace Umbraco.Web.WebApi.Filters
/// <summary>
/// Appends a custom response header to notify the UI that the current user data has been modified
/// </summary>
/// Migrated to NET core
public sealed class AppendUserModifiedHeaderAttribute : ActionFilterAttribute
{
private readonly string _userIdParameter;