From 9ea5a939cf52575cd42942b4baf1db982e34fda4 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 3 Feb 2016 16:32:37 -0800 Subject: [PATCH] Move Antiforgery.GetHtml() to MVC as an extension --- .../ViewFeatures/AntiforgeryExtensions.cs | 81 +++++++++++++++++++ .../ViewFeatures/AntiforgeryExtensionsTest.cs | 37 +++++++++ 2 files changed, 118 insertions(+) create mode 100644 src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/AntiforgeryExtensions.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/AntiforgeryExtensionsTest.cs diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/AntiforgeryExtensions.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/AntiforgeryExtensions.cs new file mode 100644 index 0000000000..630316e182 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/AntiforgeryExtensions.cs @@ -0,0 +1,81 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Antiforgery; +using Microsoft.AspNetCore.Html; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Mvc.ViewFeatures +{ + public static class AntiforgeryExtensions + { + /// + /// Generates an <input type="hidden"> element for an antiforgery token. + /// + /// The instance. + /// The associated with the current request. + /// + /// A containing an <input type="hidden"> element. This element should be put + /// inside a <form>. + /// + /// + /// This method has a side effect: + /// A response cookie is set if there is no valid cookie associated with the request. + /// + public static IHtmlContent GetHtml(this IAntiforgery antiforgery, HttpContext httpContext) + { + if (antiforgery == null) + { + throw new ArgumentNullException(nameof(antiforgery)); + } + + if (httpContext == null) + { + throw new ArgumentNullException(nameof(httpContext)); + } + + var tokenSet = antiforgery.GetAndStoreTokens(httpContext); + return new InputContent(tokenSet); + } + + private class InputContent : IHtmlContent + { + private readonly string _fieldName; + private readonly string _requestToken; + + public InputContent(AntiforgeryTokenSet tokenSet) + { + _fieldName = tokenSet.FormFieldName; + _requestToken = tokenSet.RequestToken; + } + + // Though _requestToken normally contains only US-ASCII letters, numbers, '-', and '_', must assume the + // IAntiforgeryTokenSerializer implementation has been overridden. Similarly, users may choose a + // _fieldName containing almost any character. + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + var builder = writer as IHtmlContentBuilder; + if (builder != null) + { + // If possible, defer encoding until we're writing to the response. + // But there's little reason to keep this IHtmlContent instance around. + builder + .AppendHtml(""); + } + + writer.Write(""); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/AntiforgeryExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/AntiforgeryExtensionsTest.cs new file mode 100644 index 0000000000..33a2f370bf --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/AntiforgeryExtensionsTest.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Antiforgery; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Internal; +using Microsoft.AspNetCore.Mvc.TestCommon; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.ViewFeatures +{ + /// + /// Extension methods for . + /// + public class AntiforgeryExtensionsTest + { + [Fact] + public void GetHtml_RendersInputField() + { + // Arrange + var antiforgery = new Mock(MockBehavior.Strict); + var tokenSet = new AntiforgeryTokenSet("request-token", "cookie-token", "form-field", "header"); + antiforgery + .Setup(a => a.GetAndStoreTokens(It.IsAny())) + .Returns(tokenSet); + + // Act + var inputElement = AntiforgeryExtensions.GetHtml(antiforgery.Object, new DefaultHttpContext()); + + // Assert + Assert.Equal( + @"", + HtmlContentUtilities.HtmlContentToString(inputElement)); + } + } +}