1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 
5 namespace System.IdentityModel.Tokens
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.Collections.ObjectModel;
10     using System.IdentityModel;
11     using System.IdentityModel.Selectors;
12     using System.Runtime.Serialization;
13     using System.Security;
14     using System.Security.Cryptography;
15     using System.Security.Cryptography.X509Certificates;
16     using System.Text;
17     using System.Xml;
18 
19     public class SamlSerializer
20     {
21         DictionaryManager dictionaryManager;
22 
SamlSerializer()23         public SamlSerializer()
24         {
25         }
26 
27         // Interface to plug in external Dictionaries. The external
28         // dictionary should already be populated with all strings
29         // required by this assembly.
PopulateDictionary(IXmlDictionary dictionary)30         public void PopulateDictionary(IXmlDictionary dictionary)
31         {
32             if (dictionary == null)
33                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
34 
35             this.dictionaryManager = new DictionaryManager(dictionary);
36         }
37 
38         internal DictionaryManager DictionaryManager
39         {
40             get
41             {
42                 if (this.dictionaryManager == null)
43                     this.dictionaryManager = new DictionaryManager();
44 
45                 return this.dictionaryManager;
46             }
47         }
48 
ReadToken(XmlReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)49         public virtual SamlSecurityToken ReadToken(XmlReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
50         {
51             if (reader == null)
52                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
53 
54             XmlDictionaryReader dictionaryReader = XmlDictionaryReader.CreateDictionaryReader(reader);
55             WrappedReader wrappedReader = new WrappedReader(dictionaryReader);
56 
57             SamlAssertion assertion = LoadAssertion(wrappedReader, keyInfoSerializer, outOfBandTokenResolver);
58             if (assertion == null)
59                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLUnableToLoadAssertion)));
60 
61             //if (assertion.Signature == null)
62             //    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SamlTokenMissingSignature)));
63 
64             return new SamlSecurityToken(assertion);
65         }
66 
WriteToken(SamlSecurityToken token, XmlWriter writer, SecurityTokenSerializer keyInfoSerializer)67         public virtual void WriteToken(SamlSecurityToken token, XmlWriter writer, SecurityTokenSerializer keyInfoSerializer)
68         {
69             if (token == null)
70                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("token");
71 
72 #pragma warning suppress 56506 // token.Assertion is never null.
73             token.Assertion.WriteTo(writer, this, keyInfoSerializer);
74         }
75 
LoadAssertion(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)76         public virtual SamlAssertion LoadAssertion(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
77         {
78             if (reader == null)
79                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
80 
81             SamlAssertion assertion = new SamlAssertion();
82             assertion.ReadXml(reader, this, keyInfoSerializer, outOfBandTokenResolver);
83 
84             return assertion;
85         }
86 
LoadCondition(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)87         public virtual SamlCondition LoadCondition(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
88         {
89             if (reader == null)
90                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
91 
92             if (reader.IsStartElement(DictionaryManager.SamlDictionary.AudienceRestrictionCondition, DictionaryManager.SamlDictionary.Namespace))
93             {
94                 SamlAudienceRestrictionCondition audienceRestriction = new SamlAudienceRestrictionCondition();
95                 audienceRestriction.ReadXml(reader, this, keyInfoSerializer, outOfBandTokenResolver);
96                 return audienceRestriction;
97             }
98             else if (reader.IsStartElement(DictionaryManager.SamlDictionary.DoNotCacheCondition, DictionaryManager.SamlDictionary.Namespace))
99             {
100                 SamlDoNotCacheCondition doNotCacheCondition = new SamlDoNotCacheCondition();
101                 doNotCacheCondition.ReadXml(reader, this, keyInfoSerializer, outOfBandTokenResolver);
102                 return doNotCacheCondition;
103             }
104             else
105                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.SAMLUnableToLoadUnknownElement, reader.LocalName)));
106         }
107 
LoadConditions(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)108         public virtual SamlConditions LoadConditions(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
109         {
110             if (reader == null)
111                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
112 
113             SamlConditions conditions = new SamlConditions();
114             conditions.ReadXml(reader, this, keyInfoSerializer, outOfBandTokenResolver);
115 
116             return conditions;
117         }
118 
LoadAdvice(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)119         public virtual SamlAdvice LoadAdvice(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
120         {
121             if (reader == null)
122                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
123 
124             SamlAdvice advice = new SamlAdvice();
125             advice.ReadXml(reader, this, keyInfoSerializer, outOfBandTokenResolver);
126 
127             return advice;
128         }
129 
LoadStatement(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)130         public virtual SamlStatement LoadStatement(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
131         {
132             if (reader == null)
133                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
134 
135             if (reader.IsStartElement(DictionaryManager.SamlDictionary.AuthenticationStatement, DictionaryManager.SamlDictionary.Namespace))
136             {
137                 SamlAuthenticationStatement authStatement = new SamlAuthenticationStatement();
138                 authStatement.ReadXml(reader, this, keyInfoSerializer, outOfBandTokenResolver);
139                 return authStatement;
140             }
141             else if (reader.IsStartElement(DictionaryManager.SamlDictionary.AttributeStatement, DictionaryManager.SamlDictionary.Namespace))
142             {
143                 SamlAttributeStatement attrStatement = new SamlAttributeStatement();
144                 attrStatement.ReadXml(reader, this, keyInfoSerializer, outOfBandTokenResolver);
145                 return attrStatement;
146             }
147             else if (reader.IsStartElement(DictionaryManager.SamlDictionary.AuthorizationDecisionStatement, DictionaryManager.SamlDictionary.Namespace))
148             {
149                 SamlAuthorizationDecisionStatement authDecisionStatement = new SamlAuthorizationDecisionStatement();
150                 authDecisionStatement.ReadXml(reader, this, keyInfoSerializer, outOfBandTokenResolver);
151                 return authDecisionStatement;
152             }
153             else
154                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.SAMLUnableToLoadUnknownElement, reader.LocalName)));
155         }
156 
LoadAttribute(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)157         public virtual SamlAttribute LoadAttribute(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
158         {
159             // We will load all attributes as string values.
160             SamlAttribute attribute = new SamlAttribute();
161             attribute.ReadXml(reader, this, keyInfoSerializer, outOfBandTokenResolver);
162 
163             return attribute;
164         }
165 
166 
167         // Helper metods to read and write SecurityKeyIdentifiers.
ReadSecurityKeyIdentifier(XmlReader reader, SecurityTokenSerializer tokenSerializer)168         internal static SecurityKeyIdentifier ReadSecurityKeyIdentifier(XmlReader reader, SecurityTokenSerializer tokenSerializer)
169         {
170             if (tokenSerializer == null)
171                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenSerializer", SR.GetString(SR.SamlSerializerRequiresExternalSerializers));
172 
173             if (tokenSerializer.CanReadKeyIdentifier(reader))
174             {
175                 return tokenSerializer.ReadKeyIdentifier(reader);
176             }
177 
178             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SamlSerializerUnableToReadSecurityKeyIdentifier)));
179         }
180 
WriteSecurityKeyIdentifier(XmlWriter writer, SecurityKeyIdentifier ski, SecurityTokenSerializer tokenSerializer)181         internal static void WriteSecurityKeyIdentifier(XmlWriter writer, SecurityKeyIdentifier ski, SecurityTokenSerializer tokenSerializer)
182         {
183             if (tokenSerializer == null)
184                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenSerializer", SR.GetString(SR.SamlSerializerRequiresExternalSerializers));
185 
186             bool keyWritten = false;
187             if (tokenSerializer.CanWriteKeyIdentifier(ski))
188             {
189                 tokenSerializer.WriteKeyIdentifier(writer, ski);
190                 keyWritten = true;
191             }
192 
193             if (!keyWritten)
194                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SamlSerializerUnableToWriteSecurityKeyIdentifier, ski.ToString())));
195         }
196 
ResolveSecurityKey(SecurityKeyIdentifier ski, SecurityTokenResolver tokenResolver)197         internal static SecurityKey ResolveSecurityKey(SecurityKeyIdentifier ski, SecurityTokenResolver tokenResolver)
198         {
199             if (ski == null)
200                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ski");
201 
202             if (tokenResolver != null)
203             {
204                 for (int i = 0; i < ski.Count; ++i)
205                 {
206                     SecurityKey key = null;
207                     if (tokenResolver.TryResolveSecurityKey(ski[i], out key))
208                         return key;
209                 }
210             }
211 
212             if (ski.CanCreateKey)
213                 return ski.CreateKey();
214 
215             return null;
216         }
217 
ResolveSecurityToken(SecurityKeyIdentifier ski, SecurityTokenResolver tokenResolver)218         internal static SecurityToken ResolveSecurityToken(SecurityKeyIdentifier ski, SecurityTokenResolver tokenResolver)
219         {
220             SecurityToken token = null;
221 
222             if (tokenResolver != null)
223             {
224                 tokenResolver.TryResolveToken(ski, out token);
225             }
226 
227             if (token == null)
228             {
229                 // Check if this is a RSA key.
230                 RsaKeyIdentifierClause rsaClause;
231                 if (ski.TryFind<RsaKeyIdentifierClause>(out rsaClause))
232                     token = new RsaSecurityToken(rsaClause.Rsa);
233             }
234 
235             if (token == null)
236             {
237                 // Check if this is a X509RawDataKeyIdentifier Clause.
238                 X509RawDataKeyIdentifierClause rawDataKeyIdentifierClause;
239                 if (ski.TryFind<X509RawDataKeyIdentifierClause>(out rawDataKeyIdentifierClause))
240                     token = new X509SecurityToken(new X509Certificate2(rawDataKeyIdentifierClause.GetX509RawData()));
241             }
242 
243             return token;
244         }
245 
246     }
247 
248 }
249