|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ServiceModel.Channels;
using System.IdentityModel.Tokens;
using System.IdentityModel.Selectors;
using System.Runtime.Serialization;
using Microsoft.Xml;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Globalization;
using System.ServiceModel.Dispatcher;
using System.Security.Authentication.ExtendedProtection;
namespace System.ServiceModel.Security
{
internal class RequestSecurityToken : BodyWriter
{
private string _context;
private string _tokenType;
private string _requestType;
private BinaryNegotiation _negotiationData;
private XmlElement _rstXml;
private IList<XmlElement> _requestProperties;
private ArraySegment<byte> _cachedWriteBuffer;
private int _cachedWriteBufferLength;
private int _keySize;
private Message _message;
private SecurityKeyIdentifierClause _renewTarget;
private SecurityKeyIdentifierClause _closeTarget;
private OnGetBinaryNegotiationCallback _onGetBinaryNegotiation;
private SecurityStandardsManager _standardsManager;
private bool _isReceiver;
private bool _isReadOnly;
private object _appliesTo;
private DataContractSerializer _appliesToSerializer;
private Type _appliesToType;
private object _thisLock = new Object();
public RequestSecurityToken()
: this(SecurityStandardsManager.DefaultInstance)
{
}
public RequestSecurityToken(MessageSecurityVersion messageSecurityVersion, SecurityTokenSerializer securityTokenSerializer)
: this(SecurityUtils.CreateSecurityStandardsManager(messageSecurityVersion, securityTokenSerializer))
{
}
public RequestSecurityToken(MessageSecurityVersion messageSecurityVersion,
SecurityTokenSerializer securityTokenSerializer,
XmlElement requestSecurityTokenXml,
string context,
string tokenType,
string requestType,
int keySize,
SecurityKeyIdentifierClause renewTarget,
SecurityKeyIdentifierClause closeTarget)
: this(SecurityUtils.CreateSecurityStandardsManager(messageSecurityVersion, securityTokenSerializer),
requestSecurityTokenXml,
context,
tokenType,
requestType,
keySize,
renewTarget,
closeTarget)
{
}
public RequestSecurityToken(XmlElement requestSecurityTokenXml,
string context,
string tokenType,
string requestType,
int keySize,
SecurityKeyIdentifierClause renewTarget,
SecurityKeyIdentifierClause closeTarget)
: this(SecurityStandardsManager.DefaultInstance,
requestSecurityTokenXml,
context,
tokenType,
requestType,
keySize,
renewTarget,
closeTarget)
{
}
internal RequestSecurityToken(SecurityStandardsManager standardsManager,
XmlElement rstXml,
string context,
string tokenType,
string requestType,
int keySize,
SecurityKeyIdentifierClause renewTarget,
SecurityKeyIdentifierClause closeTarget)
: base(true)
{
if (standardsManager == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("standardsManager"));
}
_standardsManager = standardsManager;
if (rstXml == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("rstXml");
_rstXml = rstXml;
_context = context;
_tokenType = tokenType;
_keySize = keySize;
_requestType = requestType;
_renewTarget = renewTarget;
_closeTarget = closeTarget;
_isReceiver = true;
_isReadOnly = true;
}
internal RequestSecurityToken(SecurityStandardsManager standardsManager)
: this(standardsManager, true)
{
// no op
}
internal RequestSecurityToken(SecurityStandardsManager standardsManager, bool isBuffered)
: base(isBuffered)
{
if (standardsManager == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("standardsManager"));
}
_standardsManager = standardsManager;
_requestType = _standardsManager.TrustDriver.RequestTypeIssue;
_requestProperties = null;
_isReceiver = false;
_isReadOnly = false;
}
public ChannelBinding GetChannelBinding()
{
if (_message == null)
{
return null;
}
ChannelBindingMessageProperty channelBindingMessageProperty = null;
ChannelBindingMessageProperty.TryGet(_message, out channelBindingMessageProperty);
ChannelBinding channelBinding = null;
if (channelBindingMessageProperty != null)
{
channelBinding = channelBindingMessageProperty.ChannelBinding;
}
return channelBinding;
}
/// <summary>
/// Will hold a reference to the outbound message from which we will fish the ChannelBinding out of.
/// </summary>
public Message Message
{
get { return _message; }
set { _message = value; }
}
public string Context
{
get
{
return _context;
}
set
{
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
_context = value;
}
}
public string TokenType
{
get
{
return _tokenType;
}
set
{
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
_tokenType = value;
}
}
public int KeySize
{
get
{
return _keySize;
}
set
{
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
if (value < 0)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SRServiceModel.ValueMustBeNonNegative));
_keySize = value;
}
}
public bool IsReadOnly
{
get
{
return _isReadOnly;
}
}
public delegate void OnGetBinaryNegotiationCallback(ChannelBinding channelBinding);
public OnGetBinaryNegotiationCallback OnGetBinaryNegotiation
{
get
{
return _onGetBinaryNegotiation;
}
set
{
if (this.IsReadOnly)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
}
_onGetBinaryNegotiation = value;
}
}
public IEnumerable<XmlElement> RequestProperties
{
get
{
if (_isReceiver)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemNotAvailableInDeserializedRST, "RequestProperties")));
}
return _requestProperties;
}
set
{
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
if (value != null)
{
int index = 0;
Collection<XmlElement> coll = new Collection<XmlElement>();
foreach (XmlElement property in value)
{
if (property == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(String.Format(CultureInfo.InvariantCulture, "value[{0}]", index)));
coll.Add(property);
++index;
}
_requestProperties = coll;
}
else
{
_requestProperties = null;
}
}
}
public string RequestType
{
get
{
return _requestType;
}
set
{
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
if (value == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
_requestType = value;
}
}
public SecurityKeyIdentifierClause RenewTarget
{
get
{
return _renewTarget;
}
set
{
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
_renewTarget = value;
}
}
public SecurityKeyIdentifierClause CloseTarget
{
get
{
return _closeTarget;
}
set
{
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
_closeTarget = value;
}
}
public XmlElement RequestSecurityTokenXml
{
get
{
if (!_isReceiver)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemAvailableInDeserializedRSTOnly, "RequestSecurityTokenXml")));
}
return _rstXml;
}
}
internal SecurityStandardsManager StandardsManager
{
get
{
return _standardsManager;
}
set
{
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
if (value == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
}
_standardsManager = value;
}
}
internal bool IsReceiver
{
get
{
return _isReceiver;
}
}
internal object AppliesTo
{
get
{
if (_isReceiver)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemNotAvailableInDeserializedRST, "AppliesTo")));
}
return _appliesTo;
}
}
internal DataContractSerializer AppliesToSerializer
{
get
{
if (_isReceiver)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemNotAvailableInDeserializedRST, "AppliesToSerializer")));
}
return _appliesToSerializer;
}
}
internal Type AppliesToType
{
get
{
if (_isReceiver)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemNotAvailableInDeserializedRST, "AppliesToType")));
}
return _appliesToType;
}
}
protected Object ThisLock
{
get
{
return _thisLock;
}
}
internal void SetBinaryNegotiation(BinaryNegotiation negotiation)
{
if (negotiation == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("negotiation");
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
_negotiationData = negotiation;
}
internal BinaryNegotiation GetBinaryNegotiation()
{
if (_isReceiver)
{
return _standardsManager.TrustDriver.GetBinaryNegotiation(this);
}
else if (_negotiationData == null && _onGetBinaryNegotiation != null)
{
_onGetBinaryNegotiation(this.GetChannelBinding());
}
return _negotiationData;
}
public SecurityToken GetRequestorEntropy()
{
return this.GetRequestorEntropy(null);
}
internal SecurityToken GetRequestorEntropy(SecurityTokenResolver resolver)
{
if (_isReceiver)
{
return _standardsManager.TrustDriver.GetEntropy(this, resolver);
}
else
return null;
}
public void SetAppliesTo<T>(T appliesTo, DataContractSerializer serializer)
{
if (this.IsReadOnly)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly));
if (appliesTo != null && serializer == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
}
_appliesTo = appliesTo;
_appliesToSerializer = serializer;
_appliesToType = typeof(T);
}
public void GetAppliesToQName(out string localName, out string namespaceUri)
{
if (!_isReceiver)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemAvailableInDeserializedRSTOnly, "MatchesAppliesTo")));
_standardsManager.TrustDriver.GetAppliesToQName(this, out localName, out namespaceUri);
}
public T GetAppliesTo<T>()
{
return this.GetAppliesTo<T>(DataContractSerializerDefaults.CreateSerializer(typeof(T), DataContractSerializerDefaults.MaxItemsInObjectGraph));
}
public T GetAppliesTo<T>(XmlObjectSerializer serializer)
{
if (_isReceiver)
{
if (serializer == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
}
return _standardsManager.TrustDriver.GetAppliesTo<T>(this, serializer);
}
else
{
return (T)_appliesTo;
}
}
private void OnWriteTo(XmlWriter writer)
{
if (_isReceiver)
{
_rstXml.WriteTo(writer);
}
else
{
_standardsManager.TrustDriver.WriteRequestSecurityToken(this, writer);
}
}
public void WriteTo(XmlWriter writer)
{
if (writer == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
if (this.IsReadOnly)
{
// cache the serialized bytes to ensure repeatability
if (_cachedWriteBuffer.Array == null)
{
MemoryStream stream = new MemoryStream();
using (XmlDictionaryWriter binaryWriter = XmlDictionaryWriter.CreateBinaryWriter(stream, XD.Dictionary))
{
this.OnWriteTo(binaryWriter);
binaryWriter.Flush();
stream.Flush();
stream.Seek(0, SeekOrigin.Begin);
bool gotBuffer = stream.TryGetBuffer(out _cachedWriteBuffer);
if (!gotBuffer)
{
throw new UnauthorizedAccessException(SRServiceModel.UnauthorizedAccess_MemStreamBuffer);
}
_cachedWriteBufferLength = (int)stream.Length;
}
}
writer.WriteNode(XmlDictionaryReader.CreateBinaryReader(_cachedWriteBuffer.Array, 0, _cachedWriteBufferLength, XD.Dictionary, XmlDictionaryReaderQuotas.Max), false);
}
else
this.OnWriteTo(writer);
}
public static RequestSecurityToken CreateFrom(XmlReader reader)
{
return CreateFrom(SecurityStandardsManager.DefaultInstance, reader);
}
public static RequestSecurityToken CreateFrom(XmlReader reader, MessageSecurityVersion messageSecurityVersion, SecurityTokenSerializer securityTokenSerializer)
{
return CreateFrom(SecurityUtils.CreateSecurityStandardsManager(messageSecurityVersion, securityTokenSerializer), reader);
}
internal static RequestSecurityToken CreateFrom(SecurityStandardsManager standardsManager, XmlReader reader)
{
return standardsManager.TrustDriver.CreateRequestSecurityToken(reader);
}
public void MakeReadOnly()
{
if (!_isReadOnly)
{
_isReadOnly = true;
if (_requestProperties != null)
{
_requestProperties = new ReadOnlyCollection<XmlElement>(_requestProperties);
}
this.OnMakeReadOnly();
}
}
internal protected virtual void OnWriteCustomAttributes(XmlWriter writer) { }
internal protected virtual void OnWriteCustomElements(XmlWriter writer) { }
internal protected virtual void OnMakeReadOnly() { }
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
WriteTo(writer);
}
}
}
|