File: infocard\client\System\IdentityModel\Selectors\CardSpaceSelector.cs
Project: ndp\cdf\src\WCF\System.IdentityModel.Selectors.csproj (System.IdentityModel.Selectors)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
//
// Presharp uses the c# pragma mechanism to supress its warnings.
// These are not recognised by the base compiler so we need to explictly
// disable the following warnings. See http://winweb/cse/Tools/PREsharp/userguide/default.asp 
// for details. 
//
#pragma warning disable 1634, 1691      // unknown message, unknown pragma
 
namespace System.IdentityModel.Selectors
{
 
    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.IdentityModel.Claims;
    using System.Text;
    using System.Xml;
    using System.IdentityModel.Tokens;
    using System.ServiceProcess;
    using System.Globalization;
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.CompilerServices;
    using Microsoft.InfoCards.Diagnostics;
    using Microsoft.Win32;
    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace;
 
 
    //
    // For common & resources
    //
    using Microsoft.InfoCards;
 
    //
    // Summary
    //  This structure is the native version of the GenericXmlSecurityToken
    //
    // Remark
    //   When adding new fields to this structure, add pointers to the end to make 
    //   sure that alignment is done correctly
    //
    [StructLayout(LayoutKind.Sequential)]
    struct RpcGenericXmlToken
    {
 
        public Int64 createDate;              // Date the token was created on
        public Int64 expiryDate;              // Date the token will expire on
        [MarshalAs(UnmanagedType.LPWStr)]
        public string xmlToken;               // Token
        [MarshalAs(UnmanagedType.LPWStr)]
        public string internalTokenReference; // Internal Token reference
        [MarshalAs(UnmanagedType.LPWStr)]
        public string externalTokenReference; // External Token reference
 
    }
 
    //
    // Summary
    //  This class implements the client API for the Infocard system
    //
    public static class CardSpaceSelector
    {
        static CardSpaceShim s_cardSpaceShim = new CardSpaceShim();
 
        //
        // The default quotas we apply to incoming xml messages
        //
        private static XmlDictionaryReaderQuotas DefaultQuotas = new XmlDictionaryReaderQuotas();
 
        //
        // Used by infocard.exe as well.
        //
        internal const int MaxPolicyChainLength = 50;
 
        static CardSpaceSelector()
        {
            //
            // Quotas for xml readers
            //
            DefaultQuotas.MaxDepth = 32;               // max depth of elements
            DefaultQuotas.MaxStringContentLength = 8192;             // maximum string read
            DefaultQuotas.MaxArrayLength = 20 * 1024 * 1024; // maximum byte array 
            DefaultQuotas.MaxBytesPerRead = 4096;             // max start element tag
            DefaultQuotas.MaxNameTableCharCount = 16384;            // max size of name table
 
        }
 
        // Summary
        //  Request a security token from the infocard system
        //
        // Parameters
        //  endPoint                    -  The token recipient end point.
        //  policy                      -  Policy stating the requirements for the token.
        //  requiredRemoteTokenIssuer   -  The returned token should be issued by this 
        //                                 specific issuer.
        //
        public static GenericXmlSecurityToken GetToken(XmlElement endpoint,
                                                IEnumerable<XmlElement> policy,
                                                XmlElement requiredRemoteTokenIssuer,
                                                SecurityTokenSerializer tokenSerializer)
        {
            if (null == endpoint)
            {
                throw IDT.ThrowHelperArgumentNull("endpoint");
            }
 
            if (null == policy)
            {
                throw IDT.ThrowHelperArgumentNull("policy");
            }
 
            if (null == tokenSerializer)
            {
                throw IDT.ThrowHelperArgumentNull("tokenSerializer");
            }
 
            Collection<XmlElement> policyCollection = new Collection<XmlElement>();
 
            foreach (XmlElement element in policy)
            {
                policyCollection.Add(element);
            }
 
            return GetToken(new CardSpacePolicyElement[] { new CardSpacePolicyElement(endpoint, requiredRemoteTokenIssuer, policyCollection, null, 0, false) }, tokenSerializer);
        }
 
 
        // Summary
        //  Request a security token from the infocard system
        //
        // Parameters
        //  policyChain  - an array of PolicyElements that describe the federated security chain that the client
        //                 needs a final token to unwind.
        //
        public static GenericXmlSecurityToken GetToken(CardSpacePolicyElement[] policyChain, SecurityTokenSerializer tokenSerializer)
        {
            IDT.TraceDebug("ICARDCLIENT: GetToken called with a policy chain of length {0}", policyChain.Length);
 
            InfoCardProofToken proofToken = null;
            InternalRefCountedHandle nativeCryptoHandle = null;
            GenericXmlSecurityToken token = null;
            RpcGenericXmlToken infocardToken = new RpcGenericXmlToken();
            SafeTokenHandle nativeToken = null;
            Int32 result = 0;
 
            if (null == policyChain || 0 == policyChain.Length)
            {
                throw IDT.ThrowHelperArgumentNull("policyChain");
            }
            if (null == tokenSerializer)
            {
                throw IDT.ThrowHelperArgumentNull("tokenSerializer");
            }
 
            if (null == tokenSerializer)
            {
                throw IDT.ThrowHelperArgumentNull("tokenSerializer");
            }
 
            try
            {
 
 
                RuntimeHelpers.PrepareConstrainedRegions();
                bool mustRelease = false;
                try
                {
                }
                finally
                {
                    //
                    // The PolicyChain class will do the marshalling and native buffer management for us.
                    //
                    try
                    {
                        using (PolicyChain tmpChain = new PolicyChain(policyChain))
                        {
 
                            IDT.TraceDebug("ICARDCLIENT: PInvoking the native GetToken call");
 
                            result = GetShim().m_csShimGetToken(
                                                        tmpChain.Length,
                                                        tmpChain.DoMarshal(),
                                                        out nativeToken,
                                                        out nativeCryptoHandle);
 
 
                        }
 
                        if (0 == result)
                        {
                            IDT.TraceDebug("ICARDCLIENT: The PInvoke of GetToken succeeded");
                            nativeToken.DangerousAddRef(ref mustRelease);
 
                            infocardToken = (RpcGenericXmlToken)Marshal.PtrToStructure(
                                                                          nativeToken.DangerousGetHandle(),
                                                                          typeof(RpcGenericXmlToken));
                        }
                    }
                    finally
                    {
                        if (mustRelease)
                        {
                            nativeToken.DangerousRelease();
                        }
                    }
 
                }
                if (0 == result)
                {
                    using (ProofTokenCryptoHandle crypto =
                        (ProofTokenCryptoHandle)CryptoHandle.Create(nativeCryptoHandle))
                    {
                        proofToken = crypto.CreateProofToken();
                    }
 
                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.LoadXml(infocardToken.xmlToken);
                    SecurityKeyIdentifierClause internalTokenReference = null;
                    if (null != infocardToken.internalTokenReference)
                    {
                        internalTokenReference = tokenSerializer.ReadKeyIdentifierClause(
                                           CreateReaderWithQuotas(infocardToken.internalTokenReference));
                    }
                    SecurityKeyIdentifierClause externalTokenReference = null;
                    if (null != infocardToken.externalTokenReference)
                    {
 
                        externalTokenReference = tokenSerializer.ReadKeyIdentifierClause(
                                CreateReaderWithQuotas(infocardToken.externalTokenReference));
                    }
                    IDT.TraceDebug("ICARDCLIENT: Constructing a new GenericXmlSecurityToken");
                    token = new GenericXmlSecurityToken(
                                             xmlDoc.DocumentElement,
                                             proofToken,
                                             DateTime.FromFileTimeUtc(infocardToken.createDate),
                                             DateTime.FromFileTimeUtc(infocardToken.expiryDate),
                                             internalTokenReference,
                                             externalTokenReference,
                                             null);
                }
                else
                {
                    IDT.TraceDebug("ICARDCLIENT: The PInvoke of GetToken failed with a return code of {0}", result);
 
                    //
                    // Convert the HRESULTS to exceptions
                    //
                    ExceptionHelper.ThrowIfCardSpaceException((int)result);
                    throw IDT.ThrowHelperError(new CardSpaceException(SR.GetString(SR.ClientAPIInfocardError)));
                }
            }
            catch
            {
                if (null != nativeCryptoHandle)
                {
                    nativeCryptoHandle.Dispose();
                }
 
                if (null != proofToken)
                {
                    proofToken.Dispose();
                }
                throw;
            }
            finally
            {
                if (null != nativeToken)
                {
                    nativeToken.Dispose();
                }
            }
 
            return token;
        }
 
        //
        // Summary
        //  Start the management user interface
        //
        public static void Manage()
        {
            Int32 result = CardSpaceSelector.GetShim().m_csShimManageCardSpace();
 
            //
            // Convert HRESULTS to errors
            //
            if (0 != result)
            {
                //
                // Convert the HRESULTS to exceptions
                //
                ExceptionHelper.ThrowIfCardSpaceException((int)result);
                throw IDT.ThrowHelperError(new CardSpaceException(SR.GetString(SR.ClientAPIInfocardError)));
            }
 
        }
 
        //
        // Summary
        //  Start the import card user interface
        //
        public static void Import(string fileName)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                throw IDT.ThrowHelperArgumentNull("fileName");
            }
 
 
            IDT.TraceDebug("Import Infocard has been called");
            Int32 result = CardSpaceSelector.GetShim().m_csShimImportInformationCard(fileName);
 
            //
            // Convert HRESULTS to errors
            //
            if (0 != result)
            {
                //
                // Convert the HRESULTS to exceptions
                //
                ExceptionHelper.ThrowIfCardSpaceException((int)result);
                throw IDT.ThrowHelperError(new CardSpaceException(SR.GetString(SR.ClientAPIInfocardError)));
            }
 
        }
 
        internal static CardSpaceShim GetShim()
        {
            s_cardSpaceShim.InitializeIfNecessary();
            return s_cardSpaceShim;
 
        }
 
        //
        // Summary
        //  Convert the XML data to a string
        //
        // Parameter
        //  xml - The xml data to be converted into a string
        //
        // Returns
        //   A string format of the XML
        //
        internal static string XmlToString(IEnumerable<XmlElement> xml)
        {
            StringBuilder builder = new StringBuilder();
 
            foreach (XmlElement element in xml)
            {
                if (null == element)
                {
                    throw IDT.ThrowHelperError(new ArgumentException(SR.GetString(SR.ClientAPIInvalidPolicy)));
                }
                builder.Append(element.OuterXml);
            }
 
            return builder.ToString();
        }
        private static XmlDictionaryReader CreateReaderWithQuotas(string root)
        {
            UTF8Encoding utf8 = new UTF8Encoding();
            byte[] rootbytes = utf8.GetBytes(root);
            return XmlDictionaryReader.CreateTextReader(
                rootbytes, 0, rootbytes.GetLength(0), null, DefaultQuotas, null);
        }
 
 
 
 
    }
}