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