File: AntiForgeryDataSerializer.cs

package info (click to toggle)
mono 2.6.7-5.1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 327,344 kB
  • ctags: 413,649
  • sloc: cs: 2,471,883; xml: 1,768,594; ansic: 350,665; sh: 13,644; makefile: 8,640; perl: 1,784; asm: 717; cpp: 209; python: 146; sql: 81; sed: 16
file content (128 lines) | stat: -rw-r--r-- 5,330 bytes parent folder | download | duplicates (2)
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();
                }
            }
        }

    }
}