// // WSSecurityTokenSerializer.cs // // Author: // Atsushi Enomoto // // Copyright (C) 2006-2007 Novell, Inc. http://www.novell.com // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.Xml; using System.ServiceModel.Security.Tokens; using System.Text; using System.Xml; namespace System.ServiceModel.Security { public class WSSecurityTokenSerializer : SecurityTokenSerializer { static WSSecurityTokenSerializer default_instance = new WSSecurityTokenSerializer (); public static WSSecurityTokenSerializer DefaultInstance { get { return default_instance; } } const int defaultOffset = 64, defaultLabelLength = 128, defaultNonceLength = 128; public WSSecurityTokenSerializer () : this (false) { } public WSSecurityTokenSerializer (bool emitBspRequiredAttributes) : this (SecurityVersion.WSSecurity11, emitBspRequiredAttributes) { } public WSSecurityTokenSerializer (SecurityVersion securityVersion) : this (securityVersion, false) { } public WSSecurityTokenSerializer (SecurityVersion securityVersion, bool emitBspRequiredAttributes) : this (securityVersion, emitBspRequiredAttributes, new SamlSerializer ()) { } public WSSecurityTokenSerializer ( SecurityVersion securityVersion, bool emitBspRequiredAttributes, SamlSerializer samlSerializer) : this (securityVersion, emitBspRequiredAttributes, samlSerializer, null, null) { } public WSSecurityTokenSerializer ( SecurityVersion securityVersion, bool emitBspRequiredAttributes, SamlSerializer samlSerializer, SecurityStateEncoder securityStateEncoder, IEnumerable knownTypes) : this (securityVersion, emitBspRequiredAttributes, samlSerializer, securityStateEncoder, knownTypes, defaultOffset, defaultLabelLength, defaultNonceLength) { } public WSSecurityTokenSerializer ( SecurityVersion securityVersion, bool emitBspRequiredAttributes, SamlSerializer samlSerializer, SecurityStateEncoder securityStateEncoder, IEnumerable knownTypes, int maximumKeyDerivationOffset, int maximumKeyDerivationLabelLength, int maximumKeyDerivationNonceLength) { security_version = securityVersion; emit_bsp = emitBspRequiredAttributes; saml_serializer = samlSerializer; encoder = securityStateEncoder; known_types = new List (knownTypes ?? Type.EmptyTypes); max_offset = maximumKeyDerivationOffset; max_label_length = maximumKeyDerivationLabelLength; max_nonce_length = maximumKeyDerivationNonceLength; if (encoder == null) encoder = new DataProtectionSecurityStateEncoder (); } SecurityVersion security_version; bool emit_bsp; SamlSerializer saml_serializer; SecurityStateEncoder encoder; List known_types; int max_offset, max_label_length, max_nonce_length; bool WSS1_0 { get { return SecurityVersion == SecurityVersion.WSSecurity10; } } public bool EmitBspRequiredAttributes { get { return emit_bsp; } } public SecurityVersion SecurityVersion { get { return security_version; } } [MonoTODO] public int MaximumKeyDerivationOffset { get { return max_offset; } } [MonoTODO] public int MaximumKeyDerivationLabelLength { get { return max_label_length; } } [MonoTODO] public int MaximumKeyDerivationNonceLength { get { return max_nonce_length; } } protected virtual string GetTokenTypeUri (Type tokenType) { if (tokenType == typeof (WrappedKeySecurityToken)) return Constants.WSSEncryptedKeyToken; if (tokenType == typeof (X509SecurityToken)) return Constants.WSSX509Token; // if (tokenType == typeof (RsaSecurityToken)) // return null; if (tokenType == typeof (SamlSecurityToken)) return Constants.WSSSamlToken; if (tokenType == typeof (SecurityContextSecurityToken)) return Constants.WsscContextToken; // if (tokenType == typeof (huh)) // return ServiceModelSecurityTokenTypes.SecureConversation; // if (tokenType == typeof (hah)) // return ServiceModelSecurityTokenTypes.MutualSslnego; // if (tokenType == typeof (whoa)) // return ServiceModelSecurityTokenTypes.AnonymousSslnego; if (tokenType == typeof (UserNameSecurityToken)) return Constants.WSSUserNameToken; // if (tokenType == typeof (uhoh)) // return ServiceModelSecurityTokenTypes.Spnego; // if (tokenType == typeof (SspiSecurityToken)) // return ServiceModelSecurityTokenTypes.SspiCredential; if (tokenType == typeof (KerberosRequestorSecurityToken)) return Constants.WSSKerberosToken; return null; } [MonoTODO] protected override bool CanReadKeyIdentifierClauseCore (XmlReader reader) { reader.MoveToContent (); switch (reader.NamespaceURI) { case EncryptedXml.XmlEncNamespaceUrl: switch (reader.LocalName) { case "EncryptedKey": return true; } break; case Constants.WssNamespace: switch (reader.LocalName) { case "SecurityTokenReference": return true; } break; } return false; } [MonoTODO] protected override bool CanReadKeyIdentifierCore (XmlReader reader) { throw new NotImplementedException (); } [MonoTODO] protected override bool CanReadTokenCore (XmlReader reader) { reader.MoveToContent (); switch (reader.NamespaceURI) { case Constants.WssNamespace: switch (reader.LocalName) { case "BinarySecurityToken": case "BinarySecret": case "UsernameToken": return true; } break; case Constants.WsscNamespace: switch (reader.LocalName) { case "DerivedKeyToken": case "SecurityContextToken": return true; } break; case EncryptedXml.XmlEncNamespaceUrl: switch (reader.LocalName) { case "EncryptedKey": return true; } break; } return false; } [MonoTODO] public virtual SecurityKeyIdentifierClause CreateKeyIdentifierClauseFromTokenXml ( XmlElement tokenXml, SecurityTokenReferenceStyle referenceStyle) { throw new NotImplementedException (); } [MonoTODO] protected override SecurityKeyIdentifier ReadKeyIdentifierCore ( XmlReader reader) { throw new NotImplementedException (); } [MonoTODO] protected override SecurityKeyIdentifierClause ReadKeyIdentifierClauseCore (XmlReader reader) { reader.MoveToContent (); switch (reader.NamespaceURI) { case EncryptedXml.XmlEncNamespaceUrl: switch (reader.LocalName) { case "EncryptedKey": return ReadEncryptedKeyIdentifierClause (reader); } break; case Constants.WssNamespace: switch (reader.LocalName) { case "SecurityTokenReference": return ReadSecurityTokenReference (reader); } break; } throw new NotImplementedException (String.Format ("Security key identifier clause element '{0}' in namespace '{1}' is either not implemented or not supported.", reader.LocalName, reader.NamespaceURI)); } SecurityKeyIdentifierClause ReadSecurityTokenReference (XmlReader reader) { reader.ReadStartElement (); reader.MoveToContent (); if (reader.NamespaceURI == SignedXml.XmlDsigNamespaceUrl) { KeyInfoX509Data x509 = new KeyInfoX509Data (); x509.LoadXml (new XmlDocument ().ReadNode (reader) as XmlElement); if (x509.IssuerSerials.Count == 0) throw new XmlException ("'X509IssuerSerial' element is expected inside 'X509Data' element"); X509IssuerSerial s = (X509IssuerSerial) x509.IssuerSerials [0]; reader.MoveToContent (); reader.ReadEndElement (); return new X509IssuerSerialKeyIdentifierClause (s.IssuerName, s.SerialNumber); } if (reader.NamespaceURI != Constants.WssNamespace) throw new XmlException (String.Format ("Unexpected SecurityTokenReference content: expected local name 'Reference' and namespace URI '{0}' but found local name '{1}' and namespace '{2}'.", Constants.WssNamespace, reader.LocalName, reader.NamespaceURI)); switch (reader.LocalName) { case "Reference": Type ownerType = null; // FIXME: there could be more token types. if (reader.MoveToAttribute ("ValueType")) { switch (reader.Value) { case Constants.WSSEncryptedKeyToken: ownerType = typeof (WrappedKeySecurityToken); break; case Constants.WSSX509Token: ownerType = typeof (X509SecurityToken); break; case Constants.WsscContextToken: ownerType = typeof (SecurityContextSecurityToken); break; default: throw new XmlException (String.Format ("Unexpected ValueType in 'Reference' element: '{0}'", reader.Value)); } } reader.MoveToElement (); string uri = reader.GetAttribute ("URI"); if (String.IsNullOrEmpty (uri)) uri = "#"; SecurityKeyIdentifierClause ic = null; if (ownerType == typeof (SecurityContextSecurityToken) && uri [0] != '#') // FIXME: Generation? ic = new SecurityContextKeyIdentifierClause (new UniqueId (uri)); else ic = new LocalIdKeyIdentifierClause (uri.Substring (1), ownerType); reader.Skip (); reader.MoveToContent (); reader.ReadEndElement (); return ic; case "KeyIdentifier": string valueType = reader.GetAttribute ("ValueType"); string value = reader.ReadElementContentAsString (); reader.MoveToContent (); reader.ReadEndElement (); // consume switch (valueType) { case Constants.WssKeyIdentifierX509Thumbptint: return new X509ThumbprintKeyIdentifierClause (Convert.FromBase64String (value)); case Constants.WssKeyIdentifierEncryptedKey: return new InternalEncryptedKeyIdentifierClause (Convert.FromBase64String (value)); case Constants.WssKeyIdentifierSamlAssertion: return new SamlAssertionKeyIdentifierClause (value); default: // It is kinda weird but it throws XmlException here ... throw new XmlException (String.Format ("KeyIdentifier type '{0}' is not supported in WSSecurityTokenSerializer.", valueType)); } default: throw new XmlException (String.Format ("Unexpected SecurityTokenReference content: expected local name 'Reference' and namespace URI '{0}' but found local name '{1}' and namespace '{2}'.", Constants.WssNamespace, reader.LocalName, reader.NamespaceURI)); } } EncryptedKeyIdentifierClause ReadEncryptedKeyIdentifierClause ( XmlReader reader) { string encNS = EncryptedXml.XmlEncNamespaceUrl; string id = reader.GetAttribute ("Id", Constants.WsuNamespace); reader.Read (); reader.MoveToContent (); string encMethod = reader.GetAttribute ("Algorithm"); bool isEmpty = reader.IsEmptyElement; reader.ReadStartElement ("EncryptionMethod", encNS); string digMethod = null; if (!isEmpty) { reader.MoveToContent (); if (reader.LocalName == "DigestMethod" && reader.NamespaceURI == SignedXml.XmlDsigNamespaceUrl) digMethod = reader.GetAttribute ("Algorithm"); while (reader.NodeType != XmlNodeType.EndElement) { reader.Skip (); reader.MoveToContent (); } reader.ReadEndElement (); } reader.MoveToContent (); SecurityKeyIdentifier ki = null; if (!reader.IsEmptyElement) { reader.ReadStartElement ("KeyInfo", SignedXml.XmlDsigNamespaceUrl); reader.MoveToContent (); SecurityKeyIdentifierClause kic = ReadKeyIdentifierClauseCore (reader); ki = new SecurityKeyIdentifier (); ki.Add (kic); reader.MoveToContent (); reader.ReadEndElement (); // reader.MoveToContent (); } byte [] keyValue = null; if (!reader.IsEmptyElement) { reader.ReadStartElement ("CipherData", encNS); reader.MoveToContent (); keyValue = Convert.FromBase64String (reader.ReadElementContentAsString ("CipherValue", encNS)); reader.MoveToContent (); reader.ReadEndElement (); // CipherData } string carriedKeyName = null; if (!reader.IsEmptyElement && reader.LocalName == "CarriedKeyName" && reader.NamespaceURI == encNS) { carriedKeyName = reader.ReadElementContentAsString (); reader.MoveToContent (); } // FIXME: handle derived keys?? return new EncryptedKeyIdentifierClause (keyValue, encMethod, ki, carriedKeyName); } [MonoTODO] protected override SecurityToken ReadTokenCore ( XmlReader reader, SecurityTokenResolver tokenResolver) { if (!CanReadToken (reader)) throw new XmlException (String.Format ("Cannot read security token from {0} node of name '{1}' and namespace URI '{2}'", reader.NodeType, reader.LocalName, reader.NamespaceURI)); switch (reader.NamespaceURI) { case Constants.WssNamespace: switch (reader.LocalName) { case "BinarySecurityToken": return ReadX509TokenCore (reader, tokenResolver); case "BinarySecret": return ReadBinarySecretTokenCore (reader, tokenResolver); case "UsernameToken": return ReadUserNameTokenCore (reader, tokenResolver); } break; case Constants.WsscNamespace: if (reader.LocalName == "DerivedKeyToken") return ReadDerivedKeyToken (reader, tokenResolver); if (reader.LocalName == "SecurityContextToken") return ReadSecurityContextToken (reader, tokenResolver); break; case EncryptedXml.XmlEncNamespaceUrl: switch (reader.LocalName) { case "EncryptedKey": return ReadWrappedKeySecurityTokenCore (reader, tokenResolver); } break; } throw new NotImplementedException (); } DerivedKeySecurityToken ReadDerivedKeyToken ( XmlReader reader, SecurityTokenResolver tokenResolver) { try { return ReadDerivedKeyTokenCore (reader, tokenResolver); } catch (XmlException) { throw; } catch (Exception ex) { throw new XmlException ("Cannot read DerivedKeyToken", ex); } } DerivedKeySecurityToken ReadDerivedKeyTokenCore ( XmlReader reader, SecurityTokenResolver tokenResolver) { if (tokenResolver == null) throw new ArgumentNullException ("tokenResolver"); string id = reader.GetAttribute ("Id", Constants.WsuNamespace); string algorithm = reader.MoveToAttribute ("Algorithm") ? reader.Value : null; reader.MoveToElement (); reader.ReadStartElement (); reader.MoveToContent (); SecurityKeyIdentifierClause kic = ReadKeyIdentifierClause (reader); int? generation = null, offset = null, length = null; byte [] nonce = null; string name = null, label = null; for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) switch (reader.LocalName) { case "Properties": reader.ReadStartElement ("Properties", Constants.WsscNamespace); for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) switch (reader.LocalName) { case "Name": name = reader.ReadElementContentAsString ("Name", Constants.WsscNamespace); break; case "Label": label = reader.ReadElementContentAsString ("Label", Constants.WsscNamespace); break; case "Nonce": nonce = Convert.FromBase64String (reader.ReadElementContentAsString ("Nonce", Constants.WsscNamespace)); break; } reader.ReadEndElement (); break; case "Offset": offset = reader.ReadElementContentAsInt ("Offset", Constants.WsscNamespace); break; case "Length": length = reader.ReadElementContentAsInt ("Length", Constants.WsscNamespace); break; case "Nonce": nonce = Convert.FromBase64String (reader.ReadElementContentAsString ("Nonce", Constants.WsscNamespace)); break; case "Label": label = reader.ReadElementContentAsString ("Label", Constants.WsscNamespace); break; } reader.ReadEndElement (); // resolve key reference SymmetricSecurityKey key = tokenResolver.ResolveSecurityKey (kic) as SymmetricSecurityKey; if (key == null) throw new XmlException ("Cannot resolve the security key referenced by the DerivedKeyToken as a symmetric key"); return new DerivedKeySecurityToken (id, algorithm, kic, key, name, generation, offset, length, label, nonce); } // since it cannot consume RequestSecurityTokenResponse, // the token information cannot be complete. SecurityContextSecurityToken ReadSecurityContextToken ( XmlReader reader, SecurityTokenResolver tokenResolver) { string id = reader.GetAttribute ("Id", Constants.WsuNamespace); reader.Read (); // The input dnse:Cookie value is encrypted by the // server's SecurityStateEncoder // (setting error-raising encoder to ServiceCredentials. // SecureConversationAuthentication.SecurityStateEncoder // shows it). UniqueId cid = null; byte [] cookie = null; while (true) { reader.MoveToContent (); if (reader.NodeType != XmlNodeType.Element) break; switch (reader.NamespaceURI) { case Constants.WsscNamespace: switch (reader.LocalName) { case "Identifier": cid = new UniqueId (reader.ReadElementContentAsString ()); continue; } break; case Constants.MSTlsnegoTokenContent: switch (reader.LocalName) { case "Cookie": cookie = Convert.FromBase64String (reader.ReadElementContentAsString ()); continue; } break; } throw new XmlException (String.Format ("Unexpected element {0} in namespace {1}", reader.LocalName, reader.NamespaceURI)); } reader.ReadEndElement (); // LAMESPEC: at client side there is no way to specify // SecurityStateEncoder, so it must be guessed from // its cookie content itself. if (encoder == null) throw new Exception (); byte [] decoded = cookie != null && cookie.Length > 154 ? encoder.DecodeSecurityState (cookie) : cookie; return SslnegoCookieResolver.ResolveCookie (decoded, cookie); } WrappedKeySecurityToken ReadWrappedKeySecurityTokenCore ( XmlReader reader, SecurityTokenResolver tokenResolver) { if (tokenResolver == null) throw new ArgumentNullException ("tokenResolver"); EncryptedKey ek = new EncryptedKey (); ek.LoadXml (new XmlDocument ().ReadNode (reader) as XmlElement); SecurityKeyIdentifier ki = new SecurityKeyIdentifier (); foreach (KeyInfoClause kic in ek.KeyInfo) ki.Add (ReadKeyIdentifierClause (new XmlNodeReader (kic.GetXml ()))); SecurityToken token = tokenResolver.ResolveToken (ki); string alg = ek.EncryptionMethod.KeyAlgorithm; foreach (SecurityKey skey in token.SecurityKeys) if (skey.IsSupportedAlgorithm (alg)) { byte [] key = skey.DecryptKey (alg, ek.CipherData.CipherValue); WrappedKeySecurityToken wk = new WrappedKeySecurityToken (ek.Id, key, alg, token, ki); // FIXME: This should not be required. wk.SetWrappedKey (ek.CipherData.CipherValue); wk.ReferenceList = ek.ReferenceList; return wk; } throw new InvalidOperationException (String.Format ("Cannot resolve security key with the resolved SecurityToken specified by the key identifier in the EncryptedKey XML. The key identifier is: {0}", ki)); } X509SecurityToken ReadX509TokenCore ( XmlReader reader, SecurityTokenResolver resolver) { string id = reader.GetAttribute ("Id", Constants.WsuNamespace); byte [] raw = Convert.FromBase64String (reader.ReadElementContentAsString ()); return new X509SecurityToken (new X509Certificate2 (raw), id); } UserNameSecurityToken ReadUserNameTokenCore ( XmlReader reader, SecurityTokenResolver resolver) { string id = reader.GetAttribute ("Id", Constants.WsuNamespace); if (reader.IsEmptyElement) throw new XmlException ("At least UsernameToken must contain Username"); reader.Read (); reader.MoveToContent (); string user = reader.ReadElementContentAsString ("Username", Constants.WssNamespace); reader.MoveToContent (); string pass = null; if (reader.LocalName == "Password" && reader.NamespaceURI == Constants.WssNamespace) { pass = reader.ReadElementContentAsString ("Password", Constants.WssNamespace); reader.MoveToContent (); } reader.ReadEndElement (); return id != null ? new UserNameSecurityToken (user, pass, id) : new UserNameSecurityToken (user, pass); } BinarySecretSecurityToken ReadBinarySecretTokenCore ( XmlReader reader, SecurityTokenResolver resolver) { string id = reader.GetAttribute ("Id", Constants.WsuNamespace); byte [] data = Convert.FromBase64String (reader.ReadElementContentAsString ()); return new BinarySecretSecurityToken (id, data); } [MonoTODO] protected override bool CanWriteKeyIdentifierCore ( SecurityKeyIdentifier keyIdentifier) { throw new NotImplementedException (); } [MonoTODO] protected override bool CanWriteKeyIdentifierClauseCore ( SecurityKeyIdentifierClause keyIdentifierClause) { if (keyIdentifierClause == null) throw new ArgumentNullException ("keyIdentifierClause"); if (keyIdentifierClause is LocalIdKeyIdentifierClause || keyIdentifierClause is SecurityContextKeyIdentifierClause || keyIdentifierClause is X509IssuerSerialKeyIdentifierClause || (keyIdentifierClause is X509ThumbprintKeyIdentifierClause && !WSS1_0) || keyIdentifierClause is EncryptedKeyIdentifierClause || keyIdentifierClause is BinarySecretKeyIdentifierClause || keyIdentifierClause is InternalEncryptedKeyIdentifierClause || keyIdentifierClause is SamlAssertionKeyIdentifierClause) return true; else return false; } [MonoTODO] protected override bool CanWriteTokenCore (SecurityToken token) { throw new NotImplementedException (); } [MonoTODO] protected override void WriteKeyIdentifierCore ( XmlWriter writer, SecurityKeyIdentifier keyIdentifier) { throw new NotImplementedException (); } [MonoTODO] protected override void WriteKeyIdentifierClauseCore ( XmlWriter writer, SecurityKeyIdentifierClause keyIdentifierClause) { string errorReason = null; if (keyIdentifierClause == null) throw new ArgumentNullException ("keyIdentifierClause"); if (keyIdentifierClause is LocalIdKeyIdentifierClause) WriteLocalIdKeyIdentifierClause (writer, (LocalIdKeyIdentifierClause) keyIdentifierClause); else if (keyIdentifierClause is SecurityContextKeyIdentifierClause) WriteSecurityContextKeyIdentifierClause (writer, (SecurityContextKeyIdentifierClause) keyIdentifierClause); else if (keyIdentifierClause is X509IssuerSerialKeyIdentifierClause) WriteX509IssuerSerialKeyIdentifierClause (writer, (X509IssuerSerialKeyIdentifierClause) keyIdentifierClause); else if (keyIdentifierClause is X509ThumbprintKeyIdentifierClause) { if (WSS1_0) errorReason = String.Format ("Security key identifier clause '{0}' is not supported in this serializer.", keyIdentifierClause.GetType ()); else WriteX509ThumbprintKeyIdentifierClause (writer, (X509ThumbprintKeyIdentifierClause) keyIdentifierClause); } else if (keyIdentifierClause is EncryptedKeyIdentifierClause) WriteEncryptedKeyIdentifierClause (writer, (EncryptedKeyIdentifierClause) keyIdentifierClause); else if (keyIdentifierClause is BinarySecretKeyIdentifierClause) WriteBinarySecretKeyIdentifierClause (writer, (BinarySecretKeyIdentifierClause) keyIdentifierClause); else if (keyIdentifierClause is InternalEncryptedKeyIdentifierClause) WriteInternalEncryptedKeyIdentifierClause (writer, (InternalEncryptedKeyIdentifierClause) keyIdentifierClause); else if (keyIdentifierClause is SamlAssertionKeyIdentifierClause) WriteSamlAssertionKeyIdentifierClause (writer, (SamlAssertionKeyIdentifierClause) keyIdentifierClause); else throw new NotImplementedException (String.Format ("Security key identifier clause '{0}' is not either implemented or supported.", keyIdentifierClause.GetType ())); if (errorReason != null) throw new InvalidOperationException (errorReason); } void WriteX509IssuerSerialKeyIdentifierClause ( XmlWriter w, X509IssuerSerialKeyIdentifierClause ic) { w.WriteStartElement ("o", "SecurityTokenReference", Constants.WssNamespace); w.WriteStartElement ("X509Data", Constants.XmlDsig); w.WriteStartElement ("X509IssuerSerial", Constants.XmlDsig); w.WriteStartElement ("X509IssuerName", Constants.XmlDsig); w.WriteString (ic.IssuerName); w.WriteEndElement (); w.WriteStartElement ("X509SerialNumber", Constants.XmlDsig); w.WriteString (ic.IssuerSerialNumber); w.WriteEndElement (); w.WriteEndElement (); w.WriteEndElement (); w.WriteEndElement (); } void WriteX509ThumbprintKeyIdentifierClause ( XmlWriter w, X509ThumbprintKeyIdentifierClause ic) { w.WriteStartElement ("o", "SecurityTokenReference", Constants.WssNamespace); w.WriteStartElement ("o", "KeyIdentifier", Constants.WssNamespace); w.WriteAttributeString ("ValueType", Constants.WssKeyIdentifierX509Thumbptint); if (EmitBspRequiredAttributes) w.WriteAttributeString ("EncodingType", Constants.WssBase64BinaryEncodingType); w.WriteString (Convert.ToBase64String (ic.GetX509Thumbprint ())); w.WriteEndElement (); w.WriteEndElement (); } void WriteLocalIdKeyIdentifierClause ( XmlWriter w, LocalIdKeyIdentifierClause ic) { w.WriteStartElement ("o", "SecurityTokenReference", Constants.WssNamespace); w.WriteStartElement ("o", "Reference", Constants.WssNamespace); if (EmitBspRequiredAttributes && ic.OwnerType != null) { string vt = GetTokenTypeUri (ic.OwnerType); if (vt != null) w.WriteAttributeString ("ValueType", vt); } w.WriteAttributeString ("URI", "#" + ic.LocalId); w.WriteEndElement (); w.WriteEndElement (); } void WriteSecurityContextKeyIdentifierClause ( XmlWriter w, SecurityContextKeyIdentifierClause ic) { w.WriteStartElement ("o", "SecurityTokenReference", Constants.WssNamespace); w.WriteStartElement ("o", "Reference", Constants.WssNamespace); w.WriteAttributeString ("URI", ic.ContextId.ToString ()); string vt = GetTokenTypeUri (typeof (SecurityContextSecurityToken)); w.WriteAttributeString ("ValueType", vt); w.WriteEndElement (); w.WriteEndElement (); } void WriteEncryptedKeyIdentifierClause ( XmlWriter w, EncryptedKeyIdentifierClause ic) { w.WriteStartElement ("e", "EncryptedKey", EncryptedXml.XmlEncNamespaceUrl); w.WriteStartElement ("EncryptionMethod", EncryptedXml.XmlEncNamespaceUrl); w.WriteAttributeString ("Algorithm", ic.EncryptionMethod); w.WriteEndElement (); if (ic.EncryptingKeyIdentifier != null) { w.WriteStartElement ("KeyInfo", SignedXml.XmlDsigNamespaceUrl); foreach (SecurityKeyIdentifierClause ckic in ic.EncryptingKeyIdentifier) WriteKeyIdentifierClause (w, ckic); w.WriteEndElement (); } w.WriteStartElement ("CipherData", EncryptedXml.XmlEncNamespaceUrl); w.WriteStartElement ("CipherValue", EncryptedXml.XmlEncNamespaceUrl); w.WriteString (Convert.ToBase64String (ic.GetEncryptedKey ())); w.WriteEndElement (); w.WriteEndElement (); if (ic.CarriedKeyName != null) w.WriteElementString ("CarriedKeyName", EncryptedXml.XmlEncNamespaceUrl, ic.CarriedKeyName); w.WriteEndElement (); } void WriteBinarySecretKeyIdentifierClause ( XmlWriter w, BinarySecretKeyIdentifierClause ic) { w.WriteStartElement ("t", "BinarySecret", Constants.WstNamespace); w.WriteString (Convert.ToBase64String (ic.GetBuffer ())); w.WriteEndElement (); } void WriteInternalEncryptedKeyIdentifierClause ( XmlWriter w, InternalEncryptedKeyIdentifierClause ic) { w.WriteStartElement ("o", "SecurityTokenReference", Constants.WssNamespace); w.WriteStartElement ("o", "KeyIdentifier", Constants.WssNamespace); w.WriteAttributeString ("ValueType", Constants.WssKeyIdentifierEncryptedKey); w.WriteString (Convert.ToBase64String (ic.GetBuffer ())); w.WriteEndElement (); w.WriteEndElement (); } void WriteSamlAssertionKeyIdentifierClause (XmlWriter w, SamlAssertionKeyIdentifierClause ic) { w.WriteStartElement ("o", "SecurityTokenReference", Constants.WssNamespace); w.WriteStartElement ("o", "KeyIdentifier", Constants.WssNamespace); w.WriteAttributeString ("ValueType", Constants.WssKeyIdentifierSamlAssertion); w.WriteString (ic.AssertionId); w.WriteEndElement (); w.WriteEndElement (); } [MonoTODO] protected override void WriteTokenCore ( XmlWriter writer, SecurityToken token) { // WSSecurity supports: // - UsernameToken : S.IM.T.UserNameSecurityToken // - X509SecurityToken : S.IM.T.X509SecurityToken // - SAML Assertion : S.IM.T.SamlSecurityToken // - Kerberos : S.IM.T.KerberosRequestorSecurityToken // - Rights Expression Language (REL) : N/A // - SOAP with Attachments : N/A // they are part of standards support: // - WrappedKey (EncryptedKey) // - BinarySecret (WS-Trust) // - SecurityContext (WS-SecureConversation) // additionally there are extra token types in WCF: // - GenericXml // - Windows // - Sspi // not supported in this class: // - Rsa if (token is UserNameSecurityToken) WriteUserNameSecurityToken (writer, ((UserNameSecurityToken) token)); else if (token is X509SecurityToken) WriteX509SecurityToken (writer, ((X509SecurityToken) token)); else if (token is BinarySecretSecurityToken) WriteBinarySecretSecurityToken (writer, ((BinarySecretSecurityToken) token)); else if (token is SamlSecurityToken) throw new NotImplementedException ("WriteTokenCore() is not implemented for " + token); else if (token is GenericXmlSecurityToken) ((GenericXmlSecurityToken) token).TokenXml.WriteTo (writer); else if (token is WrappedKeySecurityToken) WriteWrappedKeySecurityToken (writer, (WrappedKeySecurityToken) token); else if (token is DerivedKeySecurityToken) WriteDerivedKeySecurityToken (writer, (DerivedKeySecurityToken) token); else if (token is SecurityContextSecurityToken) WriteSecurityContextSecurityToken (writer, (SecurityContextSecurityToken) token); else if (token is SspiSecurityToken) throw new NotImplementedException ("WriteTokenCore() is not implemented for " + token); else if (token is KerberosRequestorSecurityToken) throw new NotImplementedException ("WriteTokenCore() is not implemented for " + token); else if (token is WindowsSecurityToken) throw new NotImplementedException ("WriteTokenCore() is not implemented for " + token); else throw new InvalidOperationException (String.Format ("This SecurityTokenSerializer does not support security token '{0}'.", token)); } void WriteUserNameSecurityToken (XmlWriter w, UserNameSecurityToken token) { w.WriteStartElement ("o", "UsernameToken", Constants.WssNamespace); w.WriteAttributeString ("u", "Id", Constants.WsuNamespace, token.Id); w.WriteStartElement ("o", "Username", Constants.WssNamespace); w.WriteString (token.UserName); w.WriteEndElement (); w.WriteStartElement ("o", "Password", Constants.WssNamespace); w.WriteString (token.Password); w.WriteEndElement (); w.WriteEndElement (); } void WriteX509SecurityToken (XmlWriter w, X509SecurityToken token) { w.WriteStartElement ("o", "BinarySecurityToken", Constants.WssNamespace); w.WriteAttributeString ("u", "Id", Constants.WsuNamespace, token.Id); w.WriteAttributeString ("ValueType", Constants.WSSX509Token); w.WriteString (Convert.ToBase64String (token.Certificate.RawData)); w.WriteEndElement (); } void WriteBinarySecretSecurityToken (XmlWriter w, BinarySecretSecurityToken token) { w.WriteStartElement ("t", "BinarySecret", Constants.WstNamespace); w.WriteAttributeString ("u", "Id", Constants.WsuNamespace, token.Id); w.WriteString (Convert.ToBase64String (token.GetKeyBytes ())); w.WriteEndElement (); } void WriteDerivedKeySecurityToken (XmlWriter w, DerivedKeySecurityToken token) { string ns = Constants.WsscNamespace; w.WriteStartElement ("c", "DerivedKeyToken", ns); w.WriteAttributeString ("u", "Id", Constants.WsuNamespace, token.Id); WriteKeyIdentifierClause (w, token.TokenReference); if (token.Name != null) { w.WriteStartElement ("Properties", ns); w.WriteElementString ("Name", ns, token.Name); w.WriteEndElement (); } if (token.Offset != null) w.WriteElementString ("Offset", ns, Convert.ToString (token.Offset)); if (token.Length != null) w.WriteElementString ("Length", ns, Convert.ToString (token.Length)); if (token.Label != null) w.WriteElementString ("Label", ns, token.Label); w.WriteElementString ("Nonce", ns, Convert.ToBase64String (token.Nonce)); w.WriteEndElement (); } void WriteWrappedKeySecurityToken (XmlWriter w, WrappedKeySecurityToken token) { string encNS = EncryptedXml.XmlEncNamespaceUrl; w.WriteStartElement ("e", "EncryptedKey", encNS); w.WriteAttributeString ("Id", token.Id); w.WriteStartElement ("EncryptionMethod", encNS); w.WriteAttributeString ("Algorithm", token.WrappingAlgorithm); w.WriteStartElement ("DigestMethod", SignedXml.XmlDsigNamespaceUrl); w.WriteAttributeString ("Algorithm", SignedXml.XmlDsigSHA1Url); w.WriteEndElement (); w.WriteEndElement (); w.WriteStartElement ("KeyInfo", SignedXml.XmlDsigNamespaceUrl); if (token.WrappingTokenReference != null) foreach (SecurityKeyIdentifierClause kic in token.WrappingTokenReference) WriteKeyIdentifierClause (w, kic); w.WriteEndElement (); w.WriteStartElement ("CipherData", encNS); w.WriteStartElement ("CipherValue", encNS); w.WriteString (Convert.ToBase64String (token.GetWrappedKey ())); w.WriteEndElement (); w.WriteEndElement (); if (token.ReferenceList != null) { w.WriteStartElement ("e", "ReferenceList", encNS); foreach (DataReference er in token.ReferenceList) { w.WriteStartElement ("DataReference", encNS); w.WriteAttributeString ("URI", er.Uri); w.WriteEndElement (); } w.WriteEndElement (); } w.WriteEndElement (); } void WriteSecurityContextSecurityToken (XmlWriter w, SecurityContextSecurityToken token) { string ns = Constants.WsscNamespace; w.WriteStartElement ("c", "SecurityContextToken", ns); w.WriteAttributeString ("u", "Id", Constants.WsuNamespace, token.Id); w.WriteElementString ("Identifier", ns, token.ContextId.ToString ()); // FIXME: add Cookie output (from CreateCookieSecurityContextToken() method) if (token.Cookie != null) w.WriteElementString ("dnse", "Cookie", Constants.MSTlsnegoTokenContent, Convert.ToBase64String (token.Cookie)); w.WriteEndElement (); } } }