forked from ServiceStack/ServiceStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAntiForgeryTokenSerializer.cs
More file actions
120 lines (103 loc) · 4.56 KB
/
Copy pathAntiForgeryTokenSerializer.cs
File metadata and controls
120 lines (103 loc) · 4.56 KB
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
#if !NETSTANDARD2_0
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ServiceStack.Text;
namespace ServiceStack.Html.AntiXsrf
{
internal sealed class AntiForgeryTokenSerializer : IAntiForgeryTokenSerializer
{
private const byte TokenVersion = 0x01;
private readonly ICryptoSystem _cryptoSystem;
internal AntiForgeryTokenSerializer(ICryptoSystem cryptoSystem)
{
_cryptoSystem = cryptoSystem;
}
public AntiForgeryToken Deserialize(string serializedToken)
{
try {
using (MemoryStream stream = MemoryStreamFactory.GetStream(_cryptoSystem.Unprotect(serializedToken))) {
using (BinaryReader reader = new BinaryReader(stream)) {
AntiForgeryToken token = DeserializeImpl(reader);
if (token != null) {
return token;
}
}
}
} catch {
// swallow all exceptions - homogenize error if something went wrong
}
// if we reached this point, something went wrong deserializing
throw HttpAntiForgeryException.CreateDeserializationFailedException();
}
/* The serialized format of the anti-XSRF token is as follows:
* Version: 1 byte integer
* SecurityToken: 16 byte binary blob
* IsSessionToken: 1 byte Boolean
* [if IsSessionToken = true]
* +- IsClaimsBased: 1 byte Boolean
* | [if IsClaimsBased = true]
* | `- ClaimUid: 32 byte binary blob
* | [if IsClaimsBased = false]
* | `- Username: UTF-8 string with 7-bit integer length prefix
* `- AdditionalData: UTF-8 string with 7-bit integer length prefix
*/
private static AntiForgeryToken DeserializeImpl(BinaryReader reader)
{
// we can only consume tokens of the same serialized version that we generate
byte embeddedVersion = reader.ReadByte();
if (embeddedVersion != TokenVersion) {
return null;
}
AntiForgeryToken deserializedToken = new AntiForgeryToken();
byte[] securityTokenBytes = reader.ReadBytes(AntiForgeryToken.SecurityTokenBitLength / 8);
deserializedToken.SecurityToken = new BinaryBlob(AntiForgeryToken.SecurityTokenBitLength, securityTokenBytes);
deserializedToken.IsSessionToken = reader.ReadBoolean();
if (!deserializedToken.IsSessionToken) {
bool isClaimsBased = reader.ReadBoolean();
if (isClaimsBased) {
byte[] claimUidBytes = reader.ReadBytes(AntiForgeryToken.ClaimUidBitLength / 8);
deserializedToken.ClaimUid = new BinaryBlob(AntiForgeryToken.ClaimUidBitLength, claimUidBytes);
} else {
deserializedToken.Username = reader.ReadString();
}
deserializedToken.AdditionalData = reader.ReadString();
}
// if there's still unconsumed data in the stream, fail
if (reader.BaseStream.ReadByte() != -1) {
return null;
}
// success
return deserializedToken;
}
public string Serialize(AntiForgeryToken token)
{
#if NET_4_0
Contract.Assert(token != null);
#endif
using (MemoryStream stream = MemoryStreamFactory.GetStream()) {
using (BinaryWriter writer = new BinaryWriter(stream)) {
writer.Write(TokenVersion);
writer.Write(token.SecurityToken.GetData());
writer.Write(token.IsSessionToken);
if (!token.IsSessionToken) {
if (token.ClaimUid != null) {
writer.Write(true /* isClaimsBased */);
writer.Write(token.ClaimUid.GetData());
} else {
writer.Write(false /* isClaimsBased */);
writer.Write(token.Username);
}
writer.Write(token.AdditionalData);
}
writer.Flush();
return _cryptoSystem.Protect(stream.ToArray());
}
}
}
}
}
#endif