324 lines
10 KiB
C#
324 lines
10 KiB
C#
|
//
|
||
|
// WSTrustSTSContract.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.Collections.ObjectModel;
|
||
|
using System.IdentityModel.Claims;
|
||
|
using System.IdentityModel.Selectors;
|
||
|
using System.IdentityModel.Tokens;
|
||
|
using System.Net.Security;
|
||
|
using System.Runtime.Serialization;
|
||
|
using System.Security.Cryptography.Xml;
|
||
|
using System.ServiceModel.Channels;
|
||
|
using System.ServiceModel.Description;
|
||
|
using System.ServiceModel.Security;
|
||
|
using System.ServiceModel.Security.Tokens;
|
||
|
using System.Xml;
|
||
|
|
||
|
namespace System.ServiceModel.Description
|
||
|
{
|
||
|
internal class WSTrustSecurityTokenServiceProxy
|
||
|
: ClientBase<IWSTrustSecurityTokenService>, IWSTrustSecurityTokenService
|
||
|
{
|
||
|
public WSTrustSecurityTokenServiceProxy (Binding binding, EndpointAddress address)
|
||
|
: base (binding, address)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public Message Issue (Message request)
|
||
|
{
|
||
|
return Channel.Issue (request);
|
||
|
}
|
||
|
|
||
|
public Message IssueReply (Message request)
|
||
|
{
|
||
|
return Channel.IssueReply (request);
|
||
|
}
|
||
|
|
||
|
public Message Renew (Message request)
|
||
|
{
|
||
|
return Channel.Issue (request);
|
||
|
}
|
||
|
|
||
|
public Message Cancel (Message request)
|
||
|
{
|
||
|
return Channel.Issue (request);
|
||
|
}
|
||
|
|
||
|
public Message Validate (Message request)
|
||
|
{
|
||
|
return Channel.Issue (request);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[ServiceContract]
|
||
|
internal interface IWSTrustSecurityTokenService
|
||
|
{
|
||
|
[OperationContract (Action = Constants.WstIssueAction, ReplyAction = Constants.WstIssueReplyAction, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
|
||
|
Message Issue (Message request);
|
||
|
|
||
|
[OperationContract (Action = Constants.WstIssueReplyAction, ReplyAction = Constants.WstIssueReplyAction, ProtectionLevel = ProtectionLevel.EncryptAndSign)] // needed for token negotiation reply
|
||
|
Message IssueReply (Message request);
|
||
|
|
||
|
[OperationContract (Action = Constants.WstRenewAction, ReplyAction = Constants.WstRenewReplyAction, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
|
||
|
Message Renew (Message request);
|
||
|
|
||
|
[OperationContract (Action = Constants.WstCancelAction, ReplyAction = Constants.WstCancelReplyAction, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
|
||
|
Message Cancel (Message request);
|
||
|
|
||
|
[OperationContract (Action = Constants.WstValidateAction, ReplyAction = Constants.WstValidateReplyAction, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
|
||
|
Message Validate (Message request);
|
||
|
|
||
|
// FIXME: do we need KET here?
|
||
|
}
|
||
|
|
||
|
class WstRequestSecurityToken : WstRequestSecurityTokenBase
|
||
|
{
|
||
|
protected override void OnWriteBodyContents (XmlDictionaryWriter w)
|
||
|
{
|
||
|
w.WriteStartElement ("t", "RequestSecurityToken", Constants.WstNamespace);
|
||
|
WriteBodyContentsCore (w);
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class WstRequestSecurityTokenResponse : WstRequestSecurityTokenBase
|
||
|
{
|
||
|
SecurityTokenSerializer serializer;
|
||
|
|
||
|
public WstRequestSecurityTokenResponse (SecurityTokenSerializer serializer)
|
||
|
{
|
||
|
this.serializer = serializer;
|
||
|
}
|
||
|
|
||
|
public string TokenType;
|
||
|
|
||
|
public SecurityContextSecurityToken RequestedSecurityToken;
|
||
|
|
||
|
public SecurityKeyIdentifierClause RequestedAttachedReference;
|
||
|
|
||
|
public SecurityKeyIdentifierClause RequestedUnattachedReference;
|
||
|
|
||
|
public object RequestedProofToken;
|
||
|
|
||
|
public WstLifetime Lifetime;
|
||
|
|
||
|
public byte [] Authenticator;
|
||
|
|
||
|
// it only supports negotiation so far ...
|
||
|
protected override void OnWriteBodyContents (XmlDictionaryWriter w)
|
||
|
{
|
||
|
string ns = Constants.WstNamespace;
|
||
|
string nsu = Constants.WsuNamespace;
|
||
|
w.WriteStartElement ("t", "RequestSecurityTokenResponse", ns);
|
||
|
w.WriteXmlnsAttribute ("u", nsu);
|
||
|
w.WriteAttributeString ("Context", Context);
|
||
|
if (Authenticator != null) {
|
||
|
w.WriteStartElement ("t", "Authenticator", ns);
|
||
|
w.WriteStartElement ("t", "CombinedHash", ns);
|
||
|
w.WriteBase64 (Authenticator, 0, Authenticator.Length);
|
||
|
w.WriteEndElement ();
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
if (TokenType != null)
|
||
|
w.WriteElementString ("t", "TokenType", ns, TokenType);
|
||
|
if (RequestedSecurityToken != null) {
|
||
|
w.WriteStartElement ("t", "RequestedSecurityToken", ns);
|
||
|
serializer.WriteToken (w, RequestedSecurityToken);
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
if (RequestedAttachedReference != null) {
|
||
|
w.WriteStartElement ("t", "RequestedAttachedReference", ns);
|
||
|
serializer.WriteKeyIdentifierClause (w, RequestedAttachedReference);
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
if (RequestedUnattachedReference != null) {
|
||
|
w.WriteStartElement ("t", "RequestedUnattachedReference", ns);
|
||
|
serializer.WriteKeyIdentifierClause (w, RequestedUnattachedReference);
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
if (RequestedProofToken != null) {
|
||
|
w.WriteStartElement ("t", "RequestedProofToken", ns);
|
||
|
if (RequestedProofToken is SecurityToken)
|
||
|
serializer.WriteToken (w, (SecurityToken) RequestedProofToken);
|
||
|
else if (RequestedProofToken is SecurityKeyIdentifierClause)
|
||
|
serializer.WriteKeyIdentifierClause (w, (SecurityKeyIdentifierClause) RequestedProofToken);
|
||
|
else {
|
||
|
string ens = EncryptedXml.XmlEncNamespaceUrl;
|
||
|
w.WriteStartElement ("e", "EncryptedKey", ens);
|
||
|
w.WriteStartElement ("EncryptionMethod", ens);
|
||
|
w.WriteAttributeString ("Algorithm", Constants.WstTlsnegoProofTokenType);
|
||
|
w.WriteEndElement ();
|
||
|
w.WriteStartElement ("CipherData", ens);
|
||
|
w.WriteStartElement ("CipherValue", ens);
|
||
|
byte [] base64 = (byte []) RequestedProofToken;
|
||
|
w.WriteBase64 (base64, 0, base64.Length);
|
||
|
w.WriteEndElement ();
|
||
|
w.WriteEndElement ();
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
if (Lifetime != null) {
|
||
|
w.WriteStartElement ("t", "Lifetime", ns);
|
||
|
if (Lifetime.Created != DateTime.MinValue)
|
||
|
w.WriteElementString ("Created", nsu, XmlConvert.ToString (Lifetime.Created.ToUniversalTime (), Constants.LifetimeFormat));
|
||
|
if (Lifetime.Expires != DateTime.MaxValue)
|
||
|
w.WriteElementString ("Expires", nsu, XmlConvert.ToString (Lifetime.Expires.ToUniversalTime (), Constants.LifetimeFormat));
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
//w.WriteElementString ("t", "KeySize", ns, XmlConvert.ToString (KeySize));
|
||
|
if (BinaryExchange != null)
|
||
|
BinaryExchange.WriteTo (w);
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
abstract class WstRequestSecurityTokenBase : BodyWriter
|
||
|
{
|
||
|
protected WstRequestSecurityTokenBase ()
|
||
|
: base (true)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
protected void WriteBodyContentsCore (XmlDictionaryWriter w)
|
||
|
{
|
||
|
string ns = Constants.WstNamespace;
|
||
|
w.WriteAttributeString ("Context", Context);
|
||
|
w.WriteElementString ("t", "TokenType", ns, Constants.WsscContextToken);
|
||
|
w.WriteElementString ("t", "RequestType", ns, Constants.WstIssueRequest);
|
||
|
w.WriteElementString ("t", "KeySize", ns, XmlConvert.ToString (KeySize));
|
||
|
if (BinaryExchange != null)
|
||
|
BinaryExchange.WriteTo (w);
|
||
|
}
|
||
|
|
||
|
public string Context = "uuid-" + Guid.NewGuid (); // UniqueId()-"urn:"
|
||
|
public string RequestType;
|
||
|
public WspAppliesTo AppliesTo;
|
||
|
|
||
|
public SecurityToken Entropy;
|
||
|
|
||
|
public int KeySize = 256;
|
||
|
public string KeyType;
|
||
|
public string ComputedKeyAlgorithm;
|
||
|
|
||
|
public WstBinaryExchange BinaryExchange;
|
||
|
}
|
||
|
|
||
|
class WstRequestSecurityTokenResponseCollection : BodyWriter
|
||
|
{
|
||
|
public WstRequestSecurityTokenResponseCollection ()
|
||
|
: base (true)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
Collection<WstRequestSecurityTokenResponse> responses =
|
||
|
new Collection<WstRequestSecurityTokenResponse> ();
|
||
|
|
||
|
public Collection<WstRequestSecurityTokenResponse> Responses {
|
||
|
get { return responses; }
|
||
|
}
|
||
|
|
||
|
protected override void OnWriteBodyContents (XmlDictionaryWriter w)
|
||
|
{
|
||
|
w.WriteStartElement ("t", "RequestSecurityTokenResponseCollection", Constants.WstNamespace);
|
||
|
foreach (WstRequestSecurityTokenResponse r in Responses)
|
||
|
r.WriteBodyContents (w);
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
|
||
|
public void Read (string negotiationType, XmlDictionaryReader r, SecurityTokenSerializer serializer, SecurityTokenResolver resolver)
|
||
|
{
|
||
|
r.MoveToContent ();
|
||
|
r.ReadStartElement ("RequestSecurityTokenResponseCollection", Constants.WstNamespace);
|
||
|
while (true) {
|
||
|
r.MoveToContent ();
|
||
|
if (r.NodeType != XmlNodeType.Element)
|
||
|
break;
|
||
|
WSTrustRequestSecurityTokenResponseReader rstrr = new WSTrustRequestSecurityTokenResponseReader (negotiationType, r, serializer, resolver);
|
||
|
rstrr.Read ();
|
||
|
responses.Add (rstrr.Value);
|
||
|
}
|
||
|
r.ReadEndElement ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class WstLifetime
|
||
|
{
|
||
|
public DateTime Created = DateTime.MinValue;
|
||
|
|
||
|
public DateTime Expires = DateTime.MaxValue;
|
||
|
}
|
||
|
|
||
|
class WstEntropy
|
||
|
{
|
||
|
public object Token;
|
||
|
}
|
||
|
|
||
|
class WspAppliesTo
|
||
|
{
|
||
|
public WsaEndpointReference EndpointReference;
|
||
|
}
|
||
|
|
||
|
class WsaEndpointReference
|
||
|
{
|
||
|
public string Address;
|
||
|
}
|
||
|
|
||
|
class WstBinarySecret
|
||
|
{
|
||
|
public string Id;
|
||
|
|
||
|
public string Type;
|
||
|
|
||
|
public string Value;
|
||
|
}
|
||
|
|
||
|
class WstBinaryExchange
|
||
|
{
|
||
|
public WstBinaryExchange (string valueType)
|
||
|
{
|
||
|
ValueType = valueType;
|
||
|
}
|
||
|
|
||
|
public string ValueType;
|
||
|
|
||
|
public string EncodingType = Constants.WssBase64BinaryEncodingType;
|
||
|
|
||
|
public byte [] Value;
|
||
|
|
||
|
public void WriteTo (XmlWriter w)
|
||
|
{
|
||
|
w.WriteStartElement ("t", "BinaryExchange", Constants.WstNamespace);
|
||
|
w.WriteAttributeString ("ValueType", ValueType);
|
||
|
w.WriteAttributeString ("EncodingType", EncodingType);
|
||
|
w.WriteString (Convert.ToBase64String (Value));
|
||
|
w.WriteEndElement ();
|
||
|
}
|
||
|
}
|
||
|
}
|