//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Security { using System; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel; using System.Security.Cryptography.Xml; using System.IdentityModel.Claims; using System.IdentityModel.Policy; using System.IdentityModel.Tokens; using System.IdentityModel.Selectors; using System.ServiceModel.Security.Tokens; using System.Runtime.Serialization; using System.Xml.Serialization; using System.Xml.Schema; using System.Xml; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.ServiceModel.Security; using System.Globalization; using System.ServiceModel.Dispatcher; using System.Security.Authentication.ExtendedProtection; class RequestSecurityToken : BodyWriter { string context; string tokenType; string requestType; SecurityToken entropyToken; BinaryNegotiation negotiationData; XmlElement rstXml; IList requestProperties; byte[] cachedWriteBuffer; int cachedWriteBufferLength; int keySize; Message message; SecurityKeyIdentifierClause renewTarget; SecurityKeyIdentifierClause closeTarget; OnGetBinaryNegotiationCallback onGetBinaryNegotiation; SecurityStandardsManager standardsManager; bool isReceiver; bool isReadOnly; object appliesTo; DataContractSerializer appliesToSerializer; Type appliesToType; 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")); } this.standardsManager = standardsManager; if (rstXml == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("rstXml"); this.rstXml = rstXml; this.context = context; this.tokenType = tokenType; this.keySize = keySize; this.requestType = requestType; this.renewTarget = renewTarget; this.closeTarget = closeTarget; this.isReceiver = true; this.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")); } this.standardsManager = standardsManager; this.requestType = this.standardsManager.TrustDriver.RequestTypeIssue; this.requestProperties = null; this.isReceiver = false; this.isReadOnly = false; } public ChannelBinding GetChannelBinding() { if (this.message == null) { return null; } ChannelBindingMessageProperty channelBindingMessageProperty = null; ChannelBindingMessageProperty.TryGet( this.message, out channelBindingMessageProperty ); ChannelBinding channelBinding = null; if ( channelBindingMessageProperty != null ) { channelBinding = channelBindingMessageProperty.ChannelBinding; } return channelBinding; } /// /// Will hold a reference to the outbound message from which we will fish the ChannelBinding out of. /// public Message Message { get { return message; } set { message = value; } } public string Context { get { return this.context; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); this.context = value; } } public string TokenType { get { return this.tokenType; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); this.tokenType = value; } } public int KeySize { get { return this.keySize; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); if (value < 0) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.ValueMustBeNonNegative))); this.keySize = value; } } public bool IsReadOnly { get { return this.isReadOnly; } } public delegate void OnGetBinaryNegotiationCallback( ChannelBinding channelBinding ); public OnGetBinaryNegotiationCallback OnGetBinaryNegotiation { get { return this.onGetBinaryNegotiation; } set { if (this.IsReadOnly) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); } this.onGetBinaryNegotiation = value; } } public IEnumerable RequestProperties { get { if (this.isReceiver) { // PreSharp Bug: Property get methods should not throw exceptions. #pragma warning suppress 56503 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ItemNotAvailableInDeserializedRST, "RequestProperties"))); } return this.requestProperties; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); if (value != null) { int index = 0; Collection coll = new Collection(); 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; } this.requestProperties = coll; } else { this.requestProperties = null; } } } public string RequestType { get { return this.requestType; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); if (value == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); this.requestType = value; } } public SecurityKeyIdentifierClause RenewTarget { get { return this.renewTarget; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); this.renewTarget = value; } } public SecurityKeyIdentifierClause CloseTarget { get { return this.closeTarget; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); this.closeTarget = value; } } public XmlElement RequestSecurityTokenXml { get { if (!this.isReceiver) { // PreSharp Bug: Property get methods should not throw exceptions. #pragma warning suppress 56503 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ItemAvailableInDeserializedRSTOnly, "RequestSecurityTokenXml"))); } return this.rstXml; } } internal SecurityStandardsManager StandardsManager { get { return this.standardsManager; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value")); } this.standardsManager = value; } } internal bool IsReceiver { get { return this.isReceiver; } } internal object AppliesTo { get { if (this.isReceiver) { // PreSharp Bug: Property get methods should not throw exceptions. #pragma warning suppress 56503 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ItemNotAvailableInDeserializedRST, "AppliesTo"))); } return this.appliesTo; } } internal DataContractSerializer AppliesToSerializer { get { if (this.isReceiver) { // PreSharp Bug: Property get methods should not throw exceptions. #pragma warning suppress 56503 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ItemNotAvailableInDeserializedRST, "AppliesToSerializer"))); } return this.appliesToSerializer; } } internal Type AppliesToType { get { if (this.isReceiver) { // PreSharp Bug: Property get methods should not throw exceptions. #pragma warning suppress 56503 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ItemNotAvailableInDeserializedRST, "AppliesToType"))); } return this.appliesToType; } } protected Object ThisLock { get { return this.thisLock; } } internal void SetBinaryNegotiation(BinaryNegotiation negotiation) { if (negotiation == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("negotiation"); if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); this.negotiationData = negotiation; } internal BinaryNegotiation GetBinaryNegotiation() { if (this.isReceiver) { return this.standardsManager.TrustDriver.GetBinaryNegotiation(this); } else if (this.negotiationData == null && this.onGetBinaryNegotiation != null) { this.onGetBinaryNegotiation(this.GetChannelBinding()); } return this.negotiationData; } public SecurityToken GetRequestorEntropy() { return this.GetRequestorEntropy(null); } internal SecurityToken GetRequestorEntropy(SecurityTokenResolver resolver) { if (this.isReceiver) { return this.standardsManager.TrustDriver.GetEntropy(this, resolver); } else return this.entropyToken; } public void SetRequestorEntropy(byte[] entropy) { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); this.entropyToken = (entropy != null) ? new NonceToken(entropy) : null; } internal void SetRequestorEntropy(WrappedKeySecurityToken entropyToken) { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); this.entropyToken = entropyToken; } public void SetAppliesTo(T appliesTo, DataContractSerializer serializer) { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); if (appliesTo != null && serializer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer"); } this.appliesTo = appliesTo; this.appliesToSerializer = serializer; this.appliesToType = typeof(T); } public void GetAppliesToQName(out string localName, out string namespaceUri) { if (!this.isReceiver) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ItemAvailableInDeserializedRSTOnly, "MatchesAppliesTo"))); this.standardsManager.TrustDriver.GetAppliesToQName(this, out localName, out namespaceUri); } public T GetAppliesTo() { return this.GetAppliesTo(DataContractSerializerDefaults.CreateSerializer(typeof(T), DataContractSerializerDefaults.MaxItemsInObjectGraph)); } public T GetAppliesTo(XmlObjectSerializer serializer) { if (this.isReceiver) { if (serializer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer"); } return this.standardsManager.TrustDriver.GetAppliesTo(this, serializer); } else { return (T)this.appliesTo; } } void OnWriteTo(XmlWriter writer) { if (this.isReceiver) { this.rstXml.WriteTo(writer); } else { this.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 (this.cachedWriteBuffer == 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); this.cachedWriteBuffer = stream.GetBuffer(); this.cachedWriteBufferLength = (int)stream.Length; } } writer.WriteNode(XmlDictionaryReader.CreateBinaryReader(this.cachedWriteBuffer, 0, this.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 (!this.isReadOnly) { this.isReadOnly = true; if (this.requestProperties != null) { this.requestProperties = new ReadOnlyCollection(this.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); } } }