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 Triplet deserializedObj = (Triplet)formatter.Deserialize(serializedToken);
\r
51 return new AntiForgeryData() {
\r
52 Salt = (string)deserializedObj.First,
\r
53 Value = (string)deserializedObj.Second,
\r
54 CreationDate = (DateTime)deserializedObj.Third
\r
57 catch (Exception ex) {
\r
58 throw CreateValidationException(ex);
\r
62 public virtual string Serialize(AntiForgeryData token) {
\r
63 if (token == null) {
\r
64 throw new ArgumentNullException("token");
\r
67 Triplet objToSerialize = new Triplet() {
\r
69 Second = token.Value,
\r
70 Third = token.CreationDate
\r
73 string serializedValue = Formatter.Serialize(objToSerialize);
\r
74 return serializedValue;
\r
77 // See http://www.yoda.arachsys.com/csharp/singleton.html (fifth version - fully lazy) for the singleton pattern
\r
78 // used here. We need to defer the call to TokenPersister.CreateFormatterGenerator() until we're actually
\r
79 // servicing a request, else HttpContext.Current might be invalid in TokenPersister.CreateFormatterGenerator().
\r
80 private static class FormatterGenerator {
\r
82 public static readonly Func<IStateFormatter> GetFormatter = TokenPersister.CreateFormatterGenerator();
\r
84 [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline",
\r
85 Justification = "This type must not be marked 'beforefieldinit'.")]
\r
86 static FormatterGenerator() {
\r
89 // This type is very difficult to unit-test because Page.ProcessRequest() requires mocking
\r
90 // much of the hosting environment. For now, we can perform functional tests of this feature.
\r
91 private sealed class TokenPersister : PageStatePersister {
\r
92 private TokenPersister(Page page)
\r
96 public static Func<IStateFormatter> CreateFormatterGenerator() {
\r
97 // This code instantiates a page and tricks it into thinking that it's servicing
\r
98 // a postback scenario with encrypted ViewState, which is required to make the
\r
99 // StateFormatter properly decrypt data. Specifically, this code sets the
\r
100 // internal Page.ContainsEncryptedViewState flag.
\r
101 TextWriter writer = TextWriter.Null;
\r
102 HttpResponse response = new HttpResponse(writer);
\r
103 HttpRequest request = new HttpRequest("DummyFile.aspx", HttpContext.Current.Request.Url.ToString(), "__EVENTTARGET=true&__VIEWSTATEENCRYPTED=true");
\r
104 HttpContext context = new HttpContext(request, response);
\r
106 Page page = new Page() {
\r
107 EnableViewStateMac = true,
\r
108 ViewStateEncryptionMode = ViewStateEncryptionMode.Always
\r
110 page.ProcessRequest(context);
\r
112 return () => new TokenPersister(page).StateFormatter;
\r
115 public override void Load() {
\r
116 throw new NotImplementedException();
\r
119 public override void Save() {
\r
120 throw new NotImplementedException();
\r