// 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.Collections.Generic; using System.Collections.ObjectModel; using System.IdentityModel.Policy; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.IO; using System.Runtime.Serialization; using System.ServiceModel.Channels; using Microsoft.Xml; using System.ServiceModel.Dispatcher; namespace System.ServiceModel.Security { internal class RequestSecurityTokenResponse : BodyWriter { private SecurityStandardsManager _standardsManager; private string _context; private int _keySize; private bool _computeKey; private string _tokenType; private SecurityKeyIdentifierClause _requestedAttachedReference; private SecurityKeyIdentifierClause _requestedUnattachedReference; private SecurityToken _issuedToken; private SecurityToken _proofToken; private XmlElement _rstrXml; private DateTime _effectiveTime; private DateTime _expirationTime; private bool _isLifetimeSet; private bool _isReceiver; private bool _isReadOnly; private ArraySegment<byte> _cachedWriteBuffer; private int _cachedWriteBufferLength; private bool _isRequestedTokenClosed; private object _appliesTo; private XmlObjectSerializer _appliesToSerializer; private Type _appliesToType; private Object _thisLock = new Object(); private System.IdentityModel.XmlBuffer _issuedTokenBuffer; public RequestSecurityTokenResponse() : this(SecurityStandardsManager.DefaultInstance) { } public RequestSecurityTokenResponse(MessageSecurityVersion messageSecurityVersion, SecurityTokenSerializer securityTokenSerializer) : this(SecurityUtils.CreateSecurityStandardsManager(messageSecurityVersion, securityTokenSerializer)) { } public RequestSecurityTokenResponse(XmlElement requestSecurityTokenResponseXml, string context, string tokenType, int keySize, SecurityKeyIdentifierClause requestedAttachedReference, SecurityKeyIdentifierClause requestedUnattachedReference, bool computeKey, DateTime validFrom, DateTime validTo, bool isRequestedTokenClosed) : this(SecurityStandardsManager.DefaultInstance, requestSecurityTokenResponseXml, context, tokenType, keySize, requestedAttachedReference, requestedUnattachedReference, computeKey, validFrom, validTo, isRequestedTokenClosed, null) { } public RequestSecurityTokenResponse(MessageSecurityVersion messageSecurityVersion, SecurityTokenSerializer securityTokenSerializer, XmlElement requestSecurityTokenResponseXml, string context, string tokenType, int keySize, SecurityKeyIdentifierClause requestedAttachedReference, SecurityKeyIdentifierClause requestedUnattachedReference, bool computeKey, DateTime validFrom, DateTime validTo, bool isRequestedTokenClosed) : this(SecurityUtils.CreateSecurityStandardsManager(messageSecurityVersion, securityTokenSerializer), requestSecurityTokenResponseXml, context, tokenType, keySize, requestedAttachedReference, requestedUnattachedReference, computeKey, validFrom, validTo, isRequestedTokenClosed, null) { } internal RequestSecurityTokenResponse(SecurityStandardsManager standardsManager) : base(true) { if (standardsManager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("standardsManager")); } _standardsManager = standardsManager; _effectiveTime = SecurityUtils.MinUtcDateTime; _expirationTime = SecurityUtils.MaxUtcDateTime; _isRequestedTokenClosed = false; _isLifetimeSet = false; _isReceiver = false; _isReadOnly = false; } internal RequestSecurityTokenResponse(SecurityStandardsManager standardsManager, XmlElement rstrXml, string context, string tokenType, int keySize, SecurityKeyIdentifierClause requestedAttachedReference, SecurityKeyIdentifierClause requestedUnattachedReference, bool computeKey, DateTime validFrom, DateTime validTo, bool isRequestedTokenClosed, System.IdentityModel.XmlBuffer issuedTokenBuffer) : base(true) { if (standardsManager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("standardsManager")); } _standardsManager = standardsManager; if (rstrXml == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("rstrXml"); _rstrXml = rstrXml; _context = context; _tokenType = tokenType; _keySize = keySize; _requestedAttachedReference = requestedAttachedReference; _requestedUnattachedReference = requestedUnattachedReference; _computeKey = computeKey; _effectiveTime = validFrom.ToUniversalTime(); _expirationTime = validTo.ToUniversalTime(); _isLifetimeSet = true; _isRequestedTokenClosed = isRequestedTokenClosed; _issuedTokenBuffer = issuedTokenBuffer; _isReceiver = true; _isReadOnly = true; } 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 SecurityKeyIdentifierClause RequestedAttachedReference { get { return _requestedAttachedReference; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly)); _requestedAttachedReference = value; } } public SecurityKeyIdentifierClause RequestedUnattachedReference { get { return _requestedUnattachedReference; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly)); _requestedUnattachedReference = value; } } public DateTime ValidFrom { get { return _effectiveTime; } } public DateTime ValidTo { get { return _expirationTime; } } public bool ComputeKey { get { return _computeKey; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly)); _computeKey = 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 IsRequestedTokenClosed { get { return _isRequestedTokenClosed; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly)); _isRequestedTokenClosed = value; } } public bool IsReadOnly { get { return _isReadOnly; } } protected Object ThisLock { get { return _thisLock; } } internal bool IsReceiver { get { return _isReceiver; } } internal SecurityStandardsManager StandardsManager { get { return _standardsManager; } set { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly)); _standardsManager = (value != null ? value : SecurityStandardsManager.DefaultInstance); } } public SecurityToken EntropyToken { get { if (_isReceiver) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemNotAvailableInDeserializedRSTR, "EntropyToken"))); } return null; } } public SecurityToken RequestedSecurityToken { get { if (_isReceiver) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemNotAvailableInDeserializedRSTR, "IssuedToken"))); } return _issuedToken; } set { if (_isReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly)); _issuedToken = value; } } public SecurityToken RequestedProofToken { get { if (_isReceiver) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemNotAvailableInDeserializedRSTR, "ProofToken"))); } return _proofToken; } set { if (_isReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly)); _proofToken = value; } } public XmlElement RequestSecurityTokenResponseXml { get { if (!_isReceiver) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemAvailableInDeserializedRSTROnly, "RequestSecurityTokenXml"))); } return _rstrXml; } } internal object AppliesTo { get { if (_isReceiver) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemNotAvailableInDeserializedRST, "AppliesTo"))); } return _appliesTo; } } internal XmlObjectSerializer 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; } } internal bool IsLifetimeSet { get { if (_isReceiver) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.ItemNotAvailableInDeserializedRSTR, "IsLifetimeSet"))); } return _isLifetimeSet; } } internal SecurityToken GetIssuerEntropy(SecurityTokenResolver resolver) { if (_isReceiver) { return _standardsManager.TrustDriver.GetEntropy(this, resolver); } else return null; } public void SetLifetime(DateTime validFrom, DateTime validTo) { if (this.IsReadOnly) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.ObjectIsReadOnly)); if (validFrom.ToUniversalTime() > validTo.ToUniversalTime()) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SRServiceModel.EffectiveGreaterThanExpiration); } _effectiveTime = validFrom.ToUniversalTime(); _expirationTime = validTo.ToUniversalTime(); _isLifetimeSet = true; } public void SetAppliesTo<T>(T appliesTo, XmlObjectSerializer 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 w) { if (_isReceiver) { _rstrXml.WriteTo(w); } else { _standardsManager.TrustDriver.WriteRequestSecurityTokenResponse(this, w); } } 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 RequestSecurityTokenResponse CreateFrom(XmlReader reader) { return CreateFrom(SecurityStandardsManager.DefaultInstance, reader); } public static RequestSecurityTokenResponse CreateFrom(XmlReader reader, MessageSecurityVersion messageSecurityVersion, SecurityTokenSerializer securityTokenSerializer) { return CreateFrom(SecurityUtils.CreateSecurityStandardsManager(messageSecurityVersion, securityTokenSerializer), reader); } internal static RequestSecurityTokenResponse CreateFrom(SecurityStandardsManager standardsManager, XmlReader reader) { return standardsManager.TrustDriver.CreateRequestSecurityTokenResponse(reader); } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { WriteTo(writer); } public void MakeReadOnly() { if (!_isReadOnly) { _isReadOnly = true; this.OnMakeReadOnly(); } } protected internal virtual void OnWriteCustomAttributes(XmlWriter writer) { } protected internal virtual void OnWriteCustomElements(XmlWriter writer) { } protected virtual void OnMakeReadOnly() { } } }