//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ using System; using System.Collections.Generic; using System.Diagnostics; using System.IdentityModel; using System.IdentityModel.Policy; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.Security.Claims; using System.Runtime; using System.ServiceModel; using System.ServiceModel.Security; using System.ServiceModel.Security.Tokens; using System.Xml; namespace System.ServiceModel.Security { /// /// This class derives from System.ServiceModel.Security.WSSecurityTokenSerializer and wraps a collection of SecurityTokenHandlers. /// Any call to this serilaizer is delegated to the token handler and delegated to the base class if no token handler /// is registered to handle this particular token or KeyIdentifier. /// class WsSecurityTokenSerializerAdapter : WSSecurityTokenSerializer { SecureConversationVersion _scVersion; SecurityTokenHandlerCollection _securityTokenHandlers; bool _mapExceptionsToSoapFaults; ExceptionMapper _exceptionMapper = new ExceptionMapper(); /// /// Initializes an instance of /// /// /// The containing the set of /// objects used for serializing and validating tokens found in WS-Trust messages. /// public WsSecurityTokenSerializerAdapter( SecurityTokenHandlerCollection securityTokenHandlerCollection ) : this( securityTokenHandlerCollection, MessageSecurityVersion.Default.SecurityVersion ) { } /// /// Initializes an instance of /// /// /// The containing the set of /// objects used for serializing and validating tokens found in WS-Trust messages. /// /// The SecurityTokenVersion of the base WSSecurityTokenSerializer. public WsSecurityTokenSerializerAdapter( SecurityTokenHandlerCollection securityTokenHandlerCollection, SecurityVersion securityVersion ) : this( securityTokenHandlerCollection, securityVersion, true, new SamlSerializer(), null, null ) { } /// /// Initializes an instance of /// /// /// The containing the set of /// objects used for serializing and validating tokens found in WS-Trust messages. /// /// The SecurityVersion of the base WSSecurityTokenSerializer. /// Flag that determines if the serailization shoudl be BSP compliant. /// Serializer for SAML 1.1 tokens. /// SecurityStateEncoder used for resolving SCT. /// The collection of known claim types. public WsSecurityTokenSerializerAdapter( SecurityTokenHandlerCollection securityTokenHandlerCollection, SecurityVersion securityVersion, bool emitBspAttributes, SamlSerializer samlSerializer, SecurityStateEncoder stateEncoder, IEnumerable knownTypes ) : this( securityTokenHandlerCollection, securityVersion, TrustVersion.WSTrust13, SecureConversationVersion.WSSecureConversation13, emitBspAttributes, samlSerializer, stateEncoder, knownTypes ) { } /// /// Initializes an instance of /// /// /// The containing the set of /// objects used for serializing and validating tokens found in WS-Trust messages. /// /// The SecurityVersion of the base WSSecurityTokenSerializer. /// The TrustVersion of the serializer uses. /// The SecureConversationVersion of the serializer. /// Flag that determines if the serailization shoudl be BSP compliant. /// Serializer for SAML 1.1 tokens. /// SecurityStateEncoder used for resolving SCT. /// The collection of known claim types. public WsSecurityTokenSerializerAdapter( SecurityTokenHandlerCollection securityTokenHandlerCollection, SecurityVersion securityVersion, TrustVersion trustVersion, SecureConversationVersion secureConversationVersion, bool emitBspAttributes, SamlSerializer samlSerializer, SecurityStateEncoder stateEncoder, IEnumerable knownTypes ) : base( securityVersion, trustVersion, secureConversationVersion, emitBspAttributes, samlSerializer, stateEncoder, knownTypes ) { if ( securityTokenHandlerCollection == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "securityTokenHandlerCollection" ); } _scVersion = secureConversationVersion; _securityTokenHandlers = securityTokenHandlerCollection; } /// /// Gets and Sets the property that describes if exceptions /// should be mapped to SOAP Fault exceptions. Default is false. /// public bool MapExceptionsToSoapFaults { get { return _mapExceptionsToSoapFaults; } set { _mapExceptionsToSoapFaults = value; } } /// /// Gets the SecurityTokenHandlerCollection. /// public SecurityTokenHandlerCollection SecurityTokenHandlers { get { return _securityTokenHandlers; } } /// /// Gets or sets the ExceptionMapper to be used when throwing exceptions. /// public ExceptionMapper ExceptionMapper { get { return _exceptionMapper; } set { if ( value == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "value" ); } _exceptionMapper = value; } } /// /// Checks if one of the wrapped SecurityTokenHandlers or the base WSSecurityTokenSerializer /// can read the security token. /// /// Reader to a Security token. /// 'True' if the serializer can read the given Security Token. /// The input parameter 'reader' is null. protected override bool CanReadTokenCore( XmlReader reader ) { if ( reader == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" ); } if ( _securityTokenHandlers.CanReadToken( reader ) ) { return true; } return base.CanReadTokenCore( reader ); } /// /// Checks if one of the wrapped SecurityTokenHandlers or the base WSSecurityTokenSerializer /// can write the given security token. /// /// SecurityToken instance. /// 'True' if the serializer can write the given security token. /// The input parameter 'token' is null. protected override bool CanWriteTokenCore( SecurityToken token ) { if ( token == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "token" ); } if ( _securityTokenHandlers.CanWriteToken( token ) ) { return true; } return base.CanWriteTokenCore( token ); } /// /// Deserializes the SecurityToken from the given XmlReader. /// /// Reader to a Security token. /// Instance of SecurityTokenResolver. /// 'True' if the serializer can read the given Security Token. /// The input parameter 'reader' is null. protected override SecurityToken ReadTokenCore( XmlReader reader, SecurityTokenResolver tokenResolver ) { if ( reader == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" ); } try { foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers ) { if ( securityTokenHandler.CanReadToken( reader ) ) { SecurityToken token = securityTokenHandler.ReadToken( reader, tokenResolver ); SessionSecurityToken sessionToken = token as SessionSecurityToken; if ( sessionToken != null ) { if ( sessionToken.SecureConversationVersion.AbsoluteUri != _scVersion.Namespace.Value ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation( SR.GetString( SR.ID4053, sessionToken.SecureConversationVersion, _scVersion ) ); } return SecurityContextSecurityTokenHelper.ConvertSessionTokenToSecurityContextSecurityToken(sessionToken); } else { return token; } } } return base.ReadTokenCore( reader, tokenResolver ); } catch ( Exception ex ) { if ( !( MapExceptionsToSoapFaults && _exceptionMapper.HandleSecurityTokenProcessingException( ex ) ) ) { throw; } Fx.Assert( false, "ExceptionMapper did not handle an exception correctly." ); // This should never happen. ExceptionMapper will handle the exception, in which case, // a fault exception is thrown or the original exception gets thrown. } return null; } /// /// Serializes the SecurityToken to the XmlWriter. /// /// XmlWriter to write to. /// The SecurityToken to serializer. /// The input parameter 'writer' or 'token' is null. protected override void WriteTokenCore( XmlWriter writer, SecurityToken token ) { if ( writer == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "writer" ); } if ( token == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "token" ); } try { // // Wire the session handler for SCT // SecurityContextSecurityToken sct = token as SecurityContextSecurityToken; if ( sct != null ) { // // Bare SCT tokens are wrapped with a SessionSecurityToken. // The property SessionSecurityToken.IsSecurityContextSecurityTokenWrapper will be true. // token = SecurityContextSecurityTokenHelper.ConvertSctToSessionToken( sct, _scVersion ); } SecurityTokenHandler securityTokenHandler = _securityTokenHandlers[token]; if ( ( securityTokenHandler != null ) && ( securityTokenHandler.CanWriteToken ) ) { securityTokenHandler.WriteToken( writer, token ); return; } base.WriteTokenCore( writer, token ); } catch ( Exception ex ) { if ( !( MapExceptionsToSoapFaults && _exceptionMapper.HandleSecurityTokenProcessingException( ex ) ) ) { throw; } Fx.Assert( false, "ExceptionMapper did not handle an exception correctly." ); // This should never happen. ExceptionMapper will handle the exception, in which case, // a fault exception is thrown or the original exception gets thrown. } } /// /// Checks if one of the wrapped SecurityTokenHandlers or the base WSSecurityTokenSerializer /// can read the security key identifier. /// /// Reader pointing at a Security Key Identifier {ds:Keyinfo}. /// 'True' if the serializer can read the given Security Key Identifier. /// The is null. protected override bool CanReadKeyIdentifierCore( XmlReader reader ) { if ( reader == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" ); } if ( reader.IsStartElement( XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace ) ) { return true; } else { return base.CanReadKeyIdentifierCore( reader ); } } /// /// Reads an SecurityKeyIdentifier from a XML stream. /// /// An XML reader positioned at an SecurityKeyIdentifier (ds: KeyInfo) as defined in 'http://www.w3.org/TR/xmldsig-core'. /// SecurityKeyIdentifier. /// The is null. /// If the is not positioned at KeyInfo element. protected override SecurityKeyIdentifier ReadKeyIdentifierCore( XmlReader reader ) { if ( reader == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" ); } if ( reader.IsStartElement( XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace ) ) { KeyInfo keyInfo = new KeyInfo( this ); keyInfo.ReadXml( XmlDictionaryReader.CreateDictionaryReader( reader ) ); return keyInfo.KeyIdentifier; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperXml( reader, SR.GetString( SR.ID4192 ) ); } } /// /// Checks if the wrapped SecurityTokenHandler or the base WSSecurityTokenSerializer can read the /// SecurityKeyIdentifierClause. /// /// Reader to a SecurityKeyIdentifierClause. /// 'True' if the SecurityKeyIdentifierCause can be read. /// The input parameter 'reader' is null. protected override bool CanReadKeyIdentifierClauseCore( XmlReader reader ) { if ( reader == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" ); } foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers ) { if ( securityTokenHandler.CanReadKeyIdentifierClause( reader ) ) { return true; } } return base.CanReadKeyIdentifierClauseCore( reader ); } /// /// Checks if the wrapped SecurityTokenHandler or the base WSSecurityTokenSerializer can write the /// given SecurityKeyIdentifierClause. /// /// SecurityKeyIdentifierClause to be checked. /// 'True' if the SecurityTokenKeyIdentifierClause can be written. /// The input parameter 'keyIdentifierClause' is null. protected override bool CanWriteKeyIdentifierClauseCore( SecurityKeyIdentifierClause keyIdentifierClause ) { if ( keyIdentifierClause == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "keyIdentifierClause" ); } foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers ) { if ( securityTokenHandler.CanWriteKeyIdentifierClause( keyIdentifierClause ) ) { return true; } } return base.CanWriteKeyIdentifierClauseCore( keyIdentifierClause ); } /// /// Deserializes a SecurityKeyIdentifierClause from the given reader. /// /// XmlReader to a SecurityKeyIdentifierClause. /// The deserialized SecurityKeyIdentifierClause. /// The input parameter 'reader' is null. protected override SecurityKeyIdentifierClause ReadKeyIdentifierClauseCore( XmlReader reader ) { if ( reader == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" ); } try { foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers ) { if ( securityTokenHandler.CanReadKeyIdentifierClause( reader ) ) { return securityTokenHandler.ReadKeyIdentifierClause( reader ); } } return base.ReadKeyIdentifierClauseCore( reader ); } catch ( Exception ex ) { if ( !( MapExceptionsToSoapFaults && _exceptionMapper.HandleSecurityTokenProcessingException( ex ) ) ) { throw; } Fx.Assert( false, "ExceptionMapper did not handle an exception correctly." ); // This should never happen. ExceptionMapper will handle the exception, in which case, // a fault exception is thrown or the original exception gets thrown. } return null; } /// /// Serializes the given SecurityKeyIdentifierClause in a XmlWriter. /// /// XmlWriter to write into. /// SecurityKeyIdentifierClause to be written. /// The input parameter 'writer' or 'keyIdentifierClause' is null. protected override void WriteKeyIdentifierClauseCore( XmlWriter writer, SecurityKeyIdentifierClause keyIdentifierClause ) { if ( writer == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "writer" ); } if ( keyIdentifierClause == null ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "keyIdentifierClause" ); } try { foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers ) { if ( securityTokenHandler.CanWriteKeyIdentifierClause( keyIdentifierClause ) ) { securityTokenHandler.WriteKeyIdentifierClause( writer, keyIdentifierClause ); return; } } base.WriteKeyIdentifierClauseCore( writer, keyIdentifierClause ); } catch ( Exception ex ) { if ( !( MapExceptionsToSoapFaults && _exceptionMapper.HandleSecurityTokenProcessingException( ex ) ) ) { throw; } Fx.Assert( false, "ExceptionMapper did not handle an exception correctly." ); // This should never happen. ExceptionMapper will handle the exception, in which case, // a fault exception is thrown or the original exception gets thrown. } } } }