//
// WSSecurityTokenSerializer.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// 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<Type> knownTypes)
: this (securityVersion, emitBspRequiredAttributes,
samlSerializer, securityStateEncoder,
knownTypes, defaultOffset, defaultLabelLength,
defaultNonceLength)
{
}
public WSSecurityTokenSerializer (
SecurityVersion securityVersion,
bool emitBspRequiredAttributes,
SamlSerializer samlSerializer,
SecurityStateEncoder securityStateEncoder,
IEnumerable<Type> knownTypes,
int maximumKeyDerivationOffset,
int maximumKeyDerivationLabelLength,
int maximumKeyDerivationNonceLength)
{
security_version = securityVersion;
emit_bsp = emitBspRequiredAttributes;
saml_serializer = samlSerializer;
encoder = securityStateEncoder;
known_types = new List<Type> (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<Type> 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 </Reference>
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 (); // </ds:KeyInfo>
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 ();
}
}
}
|