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