/// <summary>
        /// Serializes the given token to the XmlWriter.
        /// </summary>
        /// <param name="writer">XmlWriter to which the token needs to be serialized</param>
        /// <param name="token">The SecurityToken to be serialized.</param>
        /// <exception cref="ArgumentNullException">The input argument 'writer' is null.</exception>
        /// <exception cref="InvalidOperationException">The input argument 'token' is either null or not of type
        /// SessionSecurityToken.</exception>
        public override void WriteToken(XmlWriter writer, SecurityToken token)
        {
            if (writer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
            }

            if (token == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("token");
            }

            SessionSecurityToken sessionToken = token as SessionSecurityToken;

            if (sessionToken == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4046, token, TokenType)));
            }

            string ns, elementName, contextIdElementName, instance;

            if (sessionToken.SecureConversationVersion == WSSecureConversationFeb2005Constants.NamespaceUri)
            {
                ns                   = WSSecureConversationFeb2005Constants.Namespace;
                elementName          = WSSecureConversationFeb2005Constants.ElementNames.Name;
                contextIdElementName = WSSecureConversationFeb2005Constants.ElementNames.Identifier;
                instance             = WSSecureConversationFeb2005Constants.ElementNames.Instance;
            }
            else if (sessionToken.SecureConversationVersion == WSSecureConversation13Constants.NamespaceUri)
            {
                ns                   = WSSecureConversation13Constants.Namespace;
                elementName          = WSSecureConversation13Constants.ElementNames.Name;
                contextIdElementName = WSSecureConversation13Constants.ElementNames.Identifier;
                instance             = WSSecureConversation13Constants.ElementNames.Instance;
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4050)));
            }

            XmlDictionaryWriter dicWriter;
            SessionDictionary   dictionary = SessionDictionary.Instance;

            if (writer is XmlDictionaryWriter)
            {
                dicWriter = (XmlDictionaryWriter)writer;
            }
            else
            {
                dicWriter = XmlDictionaryWriter.CreateDictionaryWriter(writer);
            }

            dicWriter.WriteStartElement(elementName, ns);
            if (sessionToken.Id != null)
            {
                dicWriter.WriteAttributeString(WSUtilityConstants.Attributes.IdAttribute, WSUtilityConstants.NamespaceURI, sessionToken.Id);
            }

            dicWriter.WriteElementString(contextIdElementName, ns, sessionToken.ContextId.ToString());

            if (sessionToken.KeyGeneration != null)
            {
                dicWriter.WriteStartElement(instance, ns);
                dicWriter.WriteValue(sessionToken.KeyGeneration);
                dicWriter.WriteEndElement();
            }

            if (!sessionToken.IsReferenceMode)
            {
                dicWriter.WriteStartElement(CookieElementName, CookieNamespace);
                byte[] cookie;

                using (MemoryStream ms = new MemoryStream())
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(ms, token);
                    cookie = ms.ToArray();
                }

                cookie = ApplyTransforms(cookie, true);
                dicWriter.WriteBase64(cookie, 0, cookie.Length);
                dicWriter.WriteEndElement();
            }

            dicWriter.WriteEndElement();
            dicWriter.Flush();
        }
        /// <summary>
        /// Reads the SessionSecurityToken from the given reader.
        /// </summary>
        /// <param name="reader">XmlReader over the SessionSecurityToken.</param>
        /// <param name="tokenResolver">SecurityTokenResolver that can used to resolve SessionSecurityToken.</param>
        /// <returns>An instance of <see cref="SessionSecurityToken"/>.</returns>
        /// <exception cref="ArgumentNullException">The input argument 'reader' is null.</exception>
        /// <exception cref="SecurityTokenException">The 'reader' is not positioned at a SessionSecurityToken
        /// or the SessionSecurityToken cannot be read.</exception>
        public override SecurityToken ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
        {
            if (reader == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
            }

            if (tokenResolver == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenResolver");
            }

            byte[]      encodedCookie = null;
            SysUniqueId contextId     = null;
            SysUniqueId keyGeneration = null;

            string ns         = null;
            string identifier = null;
            string instance   = null;

            SecurityToken     securityContextToken = null;
            SessionDictionary dictionary           = SessionDictionary.Instance;

            XmlDictionaryReader dicReader = XmlDictionaryReader.CreateDictionaryReader(reader);

            if (dicReader.IsStartElement(WSSecureConversationFeb2005Constants.ElementNames.Name, WSSecureConversationFeb2005Constants.Namespace))
            {
                ns         = WSSecureConversationFeb2005Constants.Namespace;
                identifier = WSSecureConversationFeb2005Constants.ElementNames.Identifier;
                instance   = WSSecureConversationFeb2005Constants.ElementNames.Instance;
            }
            else if (dicReader.IsStartElement(WSSecureConversation13Constants.ElementNames.Name, WSSecureConversation13Constants.Namespace))
            {
                ns         = WSSecureConversation13Constants.Namespace;
                identifier = WSSecureConversation13Constants.ElementNames.Identifier;
                instance   = WSSecureConversation13Constants.ElementNames.Instance;
            }
            else
            {
                //
                // Something is wrong
                //
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(
                                                                              SR.GetString(SR.ID4230, WSSecureConversationFeb2005Constants.ElementNames.Name, dicReader.Name)));
            }

            string id = dicReader.GetAttribute(WSUtilityConstants.Attributes.IdAttribute, WSUtilityConstants.NamespaceURI);

            dicReader.ReadFullStartElement();
            if (!dicReader.IsStartElement(identifier, ns))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(
                                                                              SR.GetString(SR.ID4230, WSSecureConversation13Constants.ElementNames.Identifier, dicReader.Name)));
            }

            contextId = dicReader.ReadElementContentAsUniqueId();
            if (contextId == null || string.IsNullOrEmpty(contextId.ToString()))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4242)));
            }

            //
            // The token can be a renewed token, in which case we need to know the
            // instance id, which will be the secondary key to the context id for
            // cache lookups
            //
            if (dicReader.IsStartElement(instance, ns))
            {
                keyGeneration = dicReader.ReadElementContentAsUniqueId();
            }

            if (dicReader.IsStartElement(CookieElementName, CookieNamespace))
            {
                // Get the token from the Cache, which is returned as an SCT
                SecurityToken cachedToken = null;

                SecurityContextKeyIdentifierClause sctClause = null;
                if (keyGeneration == null)
                {
                    sctClause = new SecurityContextKeyIdentifierClause(contextId);
                }
                else
                {
                    sctClause = new SecurityContextKeyIdentifierClause(contextId, keyGeneration);
                }

                tokenResolver.TryResolveToken(sctClause, out cachedToken);

                if (cachedToken != null)
                {
                    securityContextToken = cachedToken;

                    dicReader.Skip();
                }
                else
                {
                    //
                    // CookieMode
                    //
                    encodedCookie = dicReader.ReadElementContentAsBase64();

                    if (encodedCookie == null)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4237)));
                    }
                    //
                    // appply transforms
                    //
                    byte[] decodedCookie = ApplyTransforms(encodedCookie, false);

                    using (MemoryStream ms = new MemoryStream(decodedCookie))
                    {
                        BinaryFormatter formatter = new BinaryFormatter();
                        securityContextToken = formatter.Deserialize(ms) as SecurityToken;
                    }

                    SessionSecurityToken sessionToken = securityContextToken as SessionSecurityToken;
                    if (sessionToken != null && sessionToken.ContextId != contextId)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4229, sessionToken.ContextId, contextId)));
                    }

                    if (sessionToken != null && sessionToken.Id != id)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4227, sessionToken.Id, id)));
                    }
                }
            }
            else
            {
                //
                // SessionMode
                //

                // Get the token from the Cache.
                SecurityToken cachedToken = null;

                SecurityContextKeyIdentifierClause sctClause = null;
                if (keyGeneration == null)
                {
                    sctClause = new SecurityContextKeyIdentifierClause(contextId);
                }
                else
                {
                    sctClause = new SecurityContextKeyIdentifierClause(contextId, keyGeneration);
                }

                tokenResolver.TryResolveToken(sctClause, out cachedToken);

                if (cachedToken != null)
                {
                    securityContextToken = cachedToken;
                }
            }

            dicReader.ReadEndElement();

            if (securityContextToken == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4243)));
            }

            return(securityContextToken);
        }