1 namespace System.Web.Mvc {
\r
3 using System.Diagnostics.CodeAnalysis;
\r
6 using System.Web.Mvc.Resources;
\r
9 internal class AntiForgeryTokenSerializer {
\r
11 private IStateFormatter _formatter;
\r
13 protected internal IStateFormatter Formatter {
\r
15 if (_formatter == null) {
\r
16 _formatter = FormatterGenerator.GetFormatter();
\r
25 private static HttpAntiForgeryException CreateValidationException(Exception innerException) {
\r
26 return new HttpAntiForgeryException(MvcResources.AntiForgeryToken_ValidationFailed, innerException);
\r
29 public virtual AntiForgeryToken Deserialize(string serializedToken) {
\r
30 if (String.IsNullOrEmpty(serializedToken)) {
\r
31 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "serializedToken");
\r
34 // call property getter outside try { } block so that exceptions bubble up for debugging
\r
35 IStateFormatter formatter = Formatter;
\r
38 Triplet deserializedObj = (Triplet)formatter.Deserialize(serializedToken);
\r
39 return new AntiForgeryToken() {
\r
40 Salt = (string)deserializedObj.First,
\r
41 Value = (string)deserializedObj.Second,
\r
42 CreationDate = (DateTime)deserializedObj.Third
\r
45 catch (Exception ex) {
\r
46 throw CreateValidationException(ex);
\r
50 public virtual string Serialize(AntiForgeryToken token) {
\r
51 if (token == null) {
\r
52 throw new ArgumentNullException("token");
\r
55 Triplet objToSerialize = new Triplet() {
\r
57 Second = token.Value,
\r
58 Third = token.CreationDate
\r
61 string serializedValue = Formatter.Serialize(objToSerialize);
\r
62 return serializedValue;
\r
65 // See http://www.yoda.arachsys.com/csharp/singleton.html (fifth version - fully lazy) for the singleton pattern
\r
66 // used here. We need to defer the call to TokenPersister.CreateFormatterGenerator() until we're actually
\r
67 // servicing a request, else HttpContext.Current might be invalid in TokenPersister.CreateFormatterGenerator().
\r
68 private static class FormatterGenerator {
\r
70 public static readonly Func<IStateFormatter> GetFormatter = TokenPersister.CreateFormatterGenerator();
\r
72 [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline",
\r
73 Justification = "This type must not be marked 'beforefieldinit'.")]
\r
74 static FormatterGenerator() {
\r
77 // This type is very difficult to unit-test because Page.ProcessRequest() requires mocking
\r
78 // much of the hosting environment. For now, we can perform functional tests of this feature.
\r
79 private sealed class TokenPersister : PageStatePersister {
\r
80 private TokenPersister(Page page)
\r
84 public static Func<IStateFormatter> CreateFormatterGenerator() {
\r
85 // This code instantiates a page and tricks it into thinking that it's servicing
\r
86 // a postback scenario with encrypted ViewState, which is required to make the
\r
87 // StateFormatter properly decrypt data. Specifically, this code sets the
\r
88 // internal Page.ContainsEncryptedViewState flag.
\r
89 TextWriter writer = TextWriter.Null;
\r
90 HttpResponse response = new HttpResponse(writer);
\r
91 HttpRequest request = new HttpRequest("DummyFile.aspx", HttpContext.Current.Request.Url.ToString(), "__EVENTTARGET=true&__VIEWSTATEENCRYPTED=true");
\r
92 HttpContext context = new HttpContext(request, response);
\r
94 Page page = new Page() {
\r
95 EnableViewStateMac = true,
\r
96 ViewStateEncryptionMode = ViewStateEncryptionMode.Always
\r
98 page.ProcessRequest(context);
\r
100 return () => new TokenPersister(page).StateFormatter;
\r
103 public override void Load() {
\r
104 throw new NotImplementedException();
\r
107 public override void Save() {
\r
108 throw new NotImplementedException();
\r