parent
3a2d09b066
commit
33e3001d53
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Antiforgery
|
||||
|
|
@ -13,20 +12,6 @@ namespace Microsoft.AspNetCore.Antiforgery
|
|||
/// </summary>
|
||||
public interface IAntiforgery
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates an <input type="hidden"> element for an antiforgery token.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="IHtmlContent"/> containing an <input type="hidden"> element. This element should be put
|
||||
/// inside a <form>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method has a side effect:
|
||||
/// A response cookie is set if there is no valid cookie associated with the request.
|
||||
/// </remarks>
|
||||
IHtmlContent GetHtml(HttpContext httpContext);
|
||||
|
||||
/// <summary>
|
||||
/// Generates an <see cref="AntiforgeryTokenSet"/> for this request and stores the cookie token
|
||||
/// in the response.
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
@ -35,20 +32,6 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
_tokenStore = tokenStore;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IHtmlContent GetHtml(HttpContext httpContext)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
CheckSSLConfig(httpContext);
|
||||
|
||||
var tokenSet = GetAndStoreTokens(httpContext);
|
||||
return new InputContent(_options.FormFieldName, tokenSet.RequestToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public AntiforgeryTokenSet GetAndStoreTokens(HttpContext httpContext)
|
||||
{
|
||||
|
|
@ -307,42 +290,5 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
public bool IsNewCookieToken { get; set; }
|
||||
}
|
||||
|
||||
private class InputContent : IHtmlContent
|
||||
{
|
||||
private readonly string _fieldName;
|
||||
private readonly string _requestToken;
|
||||
|
||||
public InputContent(string fieldName, string requestToken)
|
||||
{
|
||||
_fieldName = fieldName;
|
||||
_requestToken = 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("<input name=\"")
|
||||
.Append(_fieldName)
|
||||
.AppendHtml("\" type=\"hidden\" value=\"")
|
||||
.Append(_requestToken)
|
||||
.AppendHtml("\" />");
|
||||
}
|
||||
|
||||
writer.Write("<input name=\"");
|
||||
encoder.Encode(writer, _fieldName);
|
||||
writer.Write("\" type=\"hidden\" value=\"");
|
||||
encoder.Encode(writer, _requestToken);
|
||||
writer.Write("\" />");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.DataProtection": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.Html.Abstractions": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.WebUtilities": "1.0.0-*",
|
||||
"Microsoft.Extensions.ObjectPool": "1.0.0-*"
|
||||
|
|
|
|||
|
|
@ -2,14 +2,12 @@
|
|||
// 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.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Internal;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -81,26 +79,6 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ChecksSSL_GetHtml_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var options = new AntiforgeryOptions()
|
||||
{
|
||||
RequireSsl = true
|
||||
};
|
||||
|
||||
var antiforgery = GetAntiforgery(options);
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => antiforgery.GetHtml(httpContext));
|
||||
Assert.Equal(
|
||||
@"The antiforgery system has the configuration value AntiforgeryOptions.RequireSsl = true, " +
|
||||
"but the current request is not an SSL request.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ChecksSSL_GetAndStoreTokens_Throws()
|
||||
{
|
||||
|
|
@ -164,136 +142,6 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHtml_ExistingInvalidCookieToken_GeneratesANewCookieAndAnAntiforgeryToken()
|
||||
{
|
||||
// Arrange
|
||||
var options = new AntiforgeryOptions()
|
||||
{
|
||||
FormFieldName = "form-field-name"
|
||||
};
|
||||
|
||||
// Make sure the existing cookie is invalid.
|
||||
var context = CreateMockContext(options, isOldCookieValid: false);
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
var encoder = new HtmlTestEncoder();
|
||||
|
||||
// Setup so that the null cookie token returned is treated as invalid.
|
||||
context.TokenGenerator
|
||||
.Setup(o => o.IsCookieTokenValid(null))
|
||||
.Returns(false);
|
||||
|
||||
// Act
|
||||
var inputElement = antiforgery.GetHtml(context.HttpContext);
|
||||
|
||||
// Assert
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
inputElement.WriteTo(writer, encoder);
|
||||
|
||||
Assert.Equal(
|
||||
@"<input name=""HtmlEncode[[form-field-name]]"" type=""hidden"" " +
|
||||
@"value=""HtmlEncode[[serialized-form-token]]"" />",
|
||||
writer.ToString());
|
||||
}
|
||||
|
||||
context.TokenStore.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHtml_ExistingInvalidCookieToken_SwallowsExceptions()
|
||||
{
|
||||
// Arrange
|
||||
var options = new AntiforgeryOptions()
|
||||
{
|
||||
FormFieldName = "form-field-name"
|
||||
};
|
||||
|
||||
// Make sure the existing cookie is invalid.
|
||||
var context = CreateMockContext(options, isOldCookieValid: false);
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
|
||||
// This will cause the cookieToken to be null.
|
||||
context.TokenStore
|
||||
.Setup(o => o.GetCookieToken(context.HttpContext))
|
||||
.Throws(new Exception("should be swallowed"));
|
||||
|
||||
// Setup so that the null cookie token returned is treated as invalid.
|
||||
context.TokenGenerator
|
||||
.Setup(o => o.IsCookieTokenValid(null))
|
||||
.Returns(false);
|
||||
|
||||
var encoder = new HtmlTestEncoder();
|
||||
|
||||
// Act
|
||||
var inputElement = antiforgery.GetHtml(context.HttpContext);
|
||||
|
||||
// Assert
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
inputElement.WriteTo(writer, encoder);
|
||||
|
||||
Assert.Equal(
|
||||
@"<input name=""HtmlEncode[[form-field-name]]"" type=""hidden"" " +
|
||||
@"value=""HtmlEncode[[serialized-form-token]]"" />",
|
||||
writer.ToString());
|
||||
}
|
||||
|
||||
context.TokenStore.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHtml_ExistingValidCookieToken_GeneratesAnAntiforgeryToken()
|
||||
{
|
||||
// Arrange
|
||||
var options = new AntiforgeryOptions()
|
||||
{
|
||||
FormFieldName = "form-field-name"
|
||||
};
|
||||
|
||||
// Make sure the existing cookie is valid and use the same cookie for the mock Token Provider.
|
||||
var context = CreateMockContext(options, useOldCookie: true, isOldCookieValid: true);
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
var encoder = new HtmlTestEncoder();
|
||||
|
||||
// Act
|
||||
var inputElement = antiforgery.GetHtml(context.HttpContext);
|
||||
|
||||
// Assert
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
inputElement.WriteTo(writer, encoder);
|
||||
|
||||
Assert.Equal(
|
||||
@"<input name=""HtmlEncode[[form-field-name]]"" type=""hidden"" " +
|
||||
@"value=""HtmlEncode[[serialized-form-token]]"" />",
|
||||
writer.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, "SAMEORIGIN")]
|
||||
[InlineData(true, null)]
|
||||
public void GetHtml_AddsXFrameOptionsHeader(bool suppressXFrameOptions, string expectedHeaderValue)
|
||||
{
|
||||
// Arrange
|
||||
var options = new AntiforgeryOptions()
|
||||
{
|
||||
SuppressXFrameOptionsHeader = suppressXFrameOptions
|
||||
};
|
||||
|
||||
// Generate a new cookie.
|
||||
var context = CreateMockContext(options, useOldCookie: false, isOldCookieValid: false);
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
|
||||
// Act
|
||||
antiforgery.GetHtml(context.HttpContext);
|
||||
|
||||
// Assert
|
||||
string xFrameOptions = context.HttpContext.Response.Headers["X-Frame-Options"];
|
||||
Assert.Equal(expectedHeaderValue, xFrameOptions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTokens_ExistingInvalidCookieToken_GeneratesANewCookieTokenAndANewFormToken()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue