1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This software is subject to the Microsoft Public License (Ms-PL).
* A copy of the license can be found in the license.htm file included
* in this distribution.
*
* You must not remove this notice, or any other, from this software.
*
* ***************************************************************************/
namespace System.Web.Mvc {
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Web;
using System.Web.Mvc.Resources;
using System.Web.UI;
internal class AntiForgeryDataSerializer {
private IStateFormatter _formatter;
protected internal IStateFormatter Formatter {
get {
if (_formatter == null) {
_formatter = FormatterGenerator.GetFormatter();
}
return _formatter;
}
set {
_formatter = value;
}
}
private static HttpAntiForgeryException CreateValidationException(Exception innerException) {
return new HttpAntiForgeryException(MvcResources.AntiForgeryToken_ValidationFailed, innerException);
}
public virtual AntiForgeryData Deserialize(string serializedToken) {
if (String.IsNullOrEmpty(serializedToken)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "serializedToken");
}
// call property getter outside try { } block so that exceptions bubble up for debugging
IStateFormatter formatter = Formatter;
try {
object[] deserializedObj = (object[])formatter.Deserialize(serializedToken);
return new AntiForgeryData() {
Salt = (string)deserializedObj[0],
Value = (string)deserializedObj[1],
CreationDate = (DateTime)deserializedObj[2],
Username = (string)deserializedObj[3]
};
}
catch (Exception ex) {
throw CreateValidationException(ex);
}
}
public virtual string Serialize(AntiForgeryData token) {
if (token == null) {
throw new ArgumentNullException("token");
}
object[] objToSerialize = new object[] {
token.Salt,
token.Value,
token.CreationDate,
token.Username
};
string serializedValue = Formatter.Serialize(objToSerialize);
return serializedValue;
}
// See http://www.yoda.arachsys.com/csharp/singleton.html (fifth version - fully lazy) for the singleton pattern
// used here. We need to defer the call to TokenPersister.CreateFormatterGenerator() until we're actually
// servicing a request, else HttpContext.Current might be invalid in TokenPersister.CreateFormatterGenerator().
private static class FormatterGenerator {
public static readonly Func<IStateFormatter> GetFormatter = TokenPersister.CreateFormatterGenerator();
[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline",
Justification = "This type must not be marked 'beforefieldinit'.")]
static FormatterGenerator() {
}
// This type is very difficult to unit-test because Page.ProcessRequest() requires mocking
// much of the hosting environment. For now, we can perform functional tests of this feature.
private sealed class TokenPersister : PageStatePersister {
private TokenPersister(Page page)
: base(page) {
}
public static Func<IStateFormatter> CreateFormatterGenerator() {
// This code instantiates a page and tricks it into thinking that it's servicing
// a postback scenario with encrypted ViewState, which is required to make the
// StateFormatter properly decrypt data. Specifically, this code sets the
// internal Page.ContainsEncryptedViewState flag.
TextWriter writer = TextWriter.Null;
HttpResponse response = new HttpResponse(writer);
HttpRequest request = new HttpRequest("DummyFile.aspx", HttpContext.Current.Request.Url.ToString(), "__EVENTTARGET=true&__VIEWSTATEENCRYPTED=true");
HttpContext context = new HttpContext(request, response);
Page page = new Page() {
EnableViewStateMac = true,
ViewStateEncryptionMode = ViewStateEncryptionMode.Always
};
page.ProcessRequest(context);
return () => new TokenPersister(page).StateFormatter;
}
public override void Load() {
throw new NotImplementedException();
}
public override void Save() {
throw new NotImplementedException();
}
}
}
}
}
|