File: System\IdentityModel\Tokens\BootstrapContext.cs
Project: ndp\cdf\src\WCF\IdentityModel\System.IdentityModel.csproj (System.IdentityModel)
//------------------------------------------------------------------------------
//     Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------
 
using System.Runtime.Serialization;
using System.Xml;
using System.IO;
 
namespace System.IdentityModel.Tokens
{
    /// <summary>
    /// Represents a serializable version of a token that can be attached to a <see cref="System.Security.Claims.ClaimsIdentity"/> to retain the 
    /// original token that was used to create <see cref="System.Security.Claims.ClaimsIdentity"/>
    /// </summary>
    [Serializable]
    public class BootstrapContext : ISerializable
    {
        SecurityToken _token;
        string _tokenString;
        byte[] _tokenBytes;
        SecurityTokenHandler _tokenHandler;
 
        const string _tokenTypeKey = "K";
        const string _tokenKey = "T";
        const char _securityTokenType = 'T';
        const char _stringTokenType = 'S';
        const char _byteTokenType = 'B';
 
        protected BootstrapContext(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                return;
 
            switch (info.GetChar(_tokenTypeKey))
            {
                case _securityTokenType:
                    {
                        SecurityTokenHandler sth = context.Context as SecurityTokenHandler;
                        if (sth != null)
                        {
                            using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(Convert.FromBase64String(info.GetString(_tokenKey)), XmlDictionaryReaderQuotas.Max))
                            {
                                reader.MoveToContent();
                                if (sth.CanReadToken(reader))
                                {
                                    string tokenName = reader.LocalName;
                                    string tokenNamespace = reader.NamespaceURI;
                                    SecurityToken token = sth.ReadToken(reader);
 
                                    if (token == null)
                                    {
                                        _tokenString = Text.Encoding.UTF8.GetString(Convert.FromBase64String(info.GetString(_tokenKey)));
                                    }
                                    else
                                    {
                                        _token = token;
                                    }
                                }
                            }
                        }
                        else
                        {
                            _tokenString = Text.Encoding.UTF8.GetString(Convert.FromBase64String(info.GetString(_tokenKey)));
                        }
                    }
 
                    break;
 
                case _stringTokenType:
                    {
                        _tokenString = info.GetString(_tokenKey);
                    }
                    break;
 
                case _byteTokenType:
                    {
                        _tokenBytes = (byte[])info.GetValue(_tokenKey, typeof(byte[]));
                    }
                    break;
 
                default:
                    break;
            }
        }
 
        /// <summary>
        /// A SecurityToken and a SecurityTokenHandler that can serialize the token.
        /// </summary>
        /// <param name="token"><see cref="SecurityToken"/> that can be serialized. Cannot be null.</param>
        /// <param name="tokenHandler"><see cref="SecurityTokenHandler"/> that is responsible for serializing the token. Cannon be null.</param>
        /// <exception cref="ArgumentNullException"> thrown if 'token' or 'tokenHandler' is null.</exception>
        /// <remarks>The <see cref="SecurityTokenHandler"/> is used not used to deserialize the token as it cannot be assumed to exist</remarks>
        public BootstrapContext(SecurityToken token, SecurityTokenHandler tokenHandler)
        {
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }
 
            if (tokenHandler == null)
            {
                throw new ArgumentNullException("tokenHandler");
            }
 
            _token = token;
            _tokenHandler = tokenHandler;
        }
 
        /// <summary>
        /// String that represents a SecurityToken.
        /// </summary>
        /// <param name="token">string that represents a token.  Can not be null.</param>
        /// <exception cref="ArgumentNullException"> thrown if 'token' is null.</exception>
        public BootstrapContext(string token)
        {
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }
 
            _tokenString = token;
        }
 
        /// <summary>
        /// String that represents a SecurityToken.
        /// </summary>
        /// <param name="token">string that represents a token.  Can not be null.</param>
        /// <exception cref="ArgumentNullException"> thrown if 'token' is null.</exception>
        public BootstrapContext(byte[] token)
        {
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }
 
            _tokenBytes = token;
        }
 
        #region ISerializable Members
        /// <summary>
        /// Called to serialize this context.
        /// </summary>
        /// <param name="info"><see cref="SerializationInfo"/> container for storing data. Cannot be null.</param>
        /// <param name="context"><see cref="StreamingContext"/> contains the context for streaming and optionally additional user data.</param>
        /// <exception cref="ArgumentNullException"> thrown if 'info' is null.</exception>
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (_tokenBytes != null)
            {
                info.AddValue(_tokenTypeKey, _byteTokenType);
                info.AddValue(_tokenKey, _tokenBytes);
            }
            else if (_tokenString != null)
            {
                info.AddValue(_tokenTypeKey, _stringTokenType);
                info.AddValue(_tokenKey, _tokenString);
            }
            else if (_token != null && _tokenHandler != null)
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    info.AddValue(_tokenTypeKey, _securityTokenType);
                    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(ms, Text.Encoding.UTF8, false))
                    {
                        _tokenHandler.WriteToken(writer, _token);
                        writer.Flush();
                        info.AddValue(_tokenKey, Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length));
                    }
                }
            }
        }
 
        #endregion
 
        /// <summary>
        /// Gets the string that was passed in constructor. If a different constructor was used, will be null.
        /// </summary>
        public byte[] TokenBytes
        {
            get { return _tokenBytes; }
        }
 
        /// <summary>
        /// Gets the string that was passed in constructor. If a different constructor was used, will be null.
        /// </summary>
        public string Token
        {
            get { return _tokenString; }
        }
 
        /// <summary>
        /// Gets the SecurityToken that was passed in constructor. If a different constructor was used, will be null.
        /// </summary>
        public SecurityToken SecurityToken
        {
            get { return _token; }
        }
 
        /// <summary>
        /// Gets the SecurityTokenHandler that was passed in constructor. If a different constructor was used, will be null.
        /// </summary>
        public SecurityTokenHandler SecurityTokenHandler
        {
            get { return _tokenHandler; }
        }
    }
}