966bba02bb
Former-commit-id: bb0468d0f257ff100aa895eb5fe583fb5dfbf900
948 lines
35 KiB
C#
948 lines
35 KiB
C#
//
|
|
// 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 element, SecurityTokenReferenceStyle tokenReferenceStyle)
|
|
{
|
|
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 ();
|
|
}
|
|
}
|
|
}
|