The Labs \ Source Viewer \ SSCLI \ System.Net \ CredentialHostKey

  1. //------------------------------------------------------------------------------
  2. // <copyright file="CredentialCache.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Net
  16. {
  17.     using System.Net.Sockets;
  18.     using System.Collections;
  19.     using System.Runtime.InteropServices;
  20.     using System.Security.Permissions;
  21.     using System.Globalization;
  22.    
  23.     // More sophisticated password cache that stores multiple
  24.     // name-password pairs and associates these with host/realm
  25.     /// <devdoc>
  26.     /// <para>Provides storage for multiple credentials.</para>
  27.     /// </devdoc>
  28.     public class CredentialCache : ICredentials, ICredentialsByHost, IEnumerable
  29.     {
  30.        
  31.         // fields
  32.        
  33.         private Hashtable cache = new Hashtable();
  34.         private Hashtable cacheForHosts = new Hashtable();
  35.         internal int m_version;
  36.        
  37.         private int m_NumbDefaultCredInCache = 0;
  38.        
  39.         // [thread token optimization] The resulting counter of default credential resided in the cache.
  40.         internal bool IsDefaultInCache {
  41.             get { return m_NumbDefaultCredInCache != 0; }
  42.         }
  43.        
  44.         // constructors
  45.        
  46.         /// <devdoc>
  47.         /// <para>
  48.         /// Initializes a new instance of the <see cref='System.Net.CredentialCache'/> class.
  49.         /// </para>
  50.         /// </devdoc>
  51.         public CredentialCache()
  52.         {
  53.         }
  54.        
  55.         // properties
  56.        
  57.         // methods
  58.        
  59.         /// <devdoc>
  60.         /// <para>Adds a <see cref='System.Net.NetworkCredential'/>
  61.         /// instance to the credential cache.</para>
  62.         /// </devdoc>
  63.         // UEUE
  64.         public void Add(Uri uriPrefix, string authType, NetworkCredential cred)
  65.         {
  66.             //
  67.             // parameter validation
  68.             //
  69.             if (uriPrefix == null) {
  70.                 throw new ArgumentNullException("uriPrefix");
  71.             }
  72.             if (authType == null) {
  73.                 throw new ArgumentNullException("authType");
  74.             }
  75.             if ((cred is SystemNetworkCredential)) {
  76.                 throw new ArgumentException(SR.GetString(SR.net_nodefaultcreds, authType), "authType");
  77.             }
  78.            
  79.             ++m_version;
  80.            
  81.             CredentialKey key = new CredentialKey(uriPrefix, authType);
  82.            
  83.             GlobalLog.Print("CredentialCache::Add() Adding key:[" + key.ToString() + "], cred:[" + cred.Domain + "],[" + cred.UserName + "]");
  84.            
  85.             cache.Add(key, cred);
  86.             if (cred is SystemNetworkCredential) {
  87.                 ++m_NumbDefaultCredInCache;
  88.             }
  89.         }
  90.        
  91.        
  92.         public void Add(string host, int port, string authenticationType, NetworkCredential credential)
  93.         {
  94.             //
  95.             // parameter validation
  96.             //
  97.             if (host == null) {
  98.                 throw new ArgumentNullException("host");
  99.             }
  100.            
  101.             if (authenticationType == null) {
  102.                 throw new ArgumentNullException("authenticationType");
  103.             }
  104.            
  105.             if (host.Length == 0) {
  106.                 throw new ArgumentException(SR.GetString(SR.net_emptystringcall, "host"));
  107.             }
  108.            
  109.             if (port < 0) {
  110.                 throw new ArgumentOutOfRangeException("port");
  111.             }
  112.             if ((credential is SystemNetworkCredential)) {
  113.                 throw new ArgumentException(SR.GetString(SR.net_nodefaultcreds, authenticationType), "authenticationType");
  114.             }
  115.            
  116.             ++m_version;
  117.            
  118.             CredentialHostKey key = new CredentialHostKey(host, port, authenticationType);
  119.            
  120.             GlobalLog.Print("CredentialCache::Add() Adding key:[" + key.ToString() + "], cred:[" + credential.Domain + "],[" + credential.UserName + "]");
  121.            
  122.             cacheForHosts.Add(key, credential);
  123.             if (credential is SystemNetworkCredential) {
  124.                 ++m_NumbDefaultCredInCache;
  125.             }
  126.         }
  127.        
  128.        
  129.         /// <devdoc>
  130.         /// <para>Removes a <see cref='System.Net.NetworkCredential'/>
  131.         /// instance from the credential cache.</para>
  132.         /// </devdoc>
  133.         public void Remove(Uri uriPrefix, string authType)
  134.         {
  135.             if (uriPrefix == null || authType == null) {
  136.                 // these couldn't possibly have been inserted into
  137.                 // the cache because of the test in Add()
  138.                 return;
  139.             }
  140.            
  141.             ++m_version;
  142.            
  143.             CredentialKey key = new CredentialKey(uriPrefix, authType);
  144.            
  145.             GlobalLog.Print("CredentialCache::Remove() Removing key:[" + key.ToString() + "]");
  146.            
  147.             if (cache[key] is SystemNetworkCredential) {
  148.                 --m_NumbDefaultCredInCache;
  149.             }
  150.             cache.Remove(key);
  151.         }
  152.        
  153.        
  154.         public void Remove(string host, int port, string authenticationType)
  155.         {
  156.             if (host == null || authenticationType == null) {
  157.                 // these couldn't possibly have been inserted into
  158.                 // the cache because of the test in Add()
  159.                 return;
  160.             }
  161.            
  162.             if (port < 0) {
  163.                 return;
  164.             }
  165.            
  166.            
  167.             ++m_version;
  168.            
  169.             CredentialHostKey key = new CredentialHostKey(host, port, authenticationType);
  170.            
  171.             GlobalLog.Print("CredentialCache::Remove() Removing key:[" + key.ToString() + "]");
  172.            
  173.             if (cacheForHosts[key] is SystemNetworkCredential) {
  174.                 --m_NumbDefaultCredInCache;
  175.             }
  176.             cacheForHosts.Remove(key);
  177.         }
  178.        
  179.         /// <devdoc>
  180.         /// <para>
  181.         /// Returns the <see cref='System.Net.NetworkCredential'/>
  182.         /// instance associated with the supplied Uri and
  183.         /// authentication type.
  184.         /// </para>
  185.         /// </devdoc>
  186.         public NetworkCredential GetCredential(Uri uriPrefix, string authType)
  187.         {
  188.             if (uriPrefix == null)
  189.                 throw new ArgumentNullException("uriPrefix");
  190.             if (authType == null)
  191.                 throw new ArgumentNullException("authType");
  192.            
  193.             GlobalLog.Print("CredentialCache::GetCredential(uriPrefix=\"" + uriPrefix + "\", authType=\"" + authType + "\")");
  194.            
  195.             int longestMatchPrefix = -1;
  196.             NetworkCredential mostSpecificMatch = null;
  197.             IDictionaryEnumerator credEnum = cache.GetEnumerator();
  198.            
  199.             //
  200.             // Enumerate through every credential in the cache
  201.             //
  202.            
  203.             while (credEnum.MoveNext()) {
  204.                
  205.                 CredentialKey key = (CredentialKey)credEnum.Key;
  206.                
  207.                 //
  208.                 // Determine if this credential is applicable to the current Uri/AuthType
  209.                 //
  210.                
  211.                 if (key.Match(uriPrefix, authType)) {
  212.                    
  213.                     int prefixLen = key.UriPrefixLength;
  214.                    
  215.                     //
  216.                     // Check if the match is better than the current-most-specific match
  217.                     //
  218.                    
  219.                     if (prefixLen > longestMatchPrefix) {
  220.                        
  221.                         //
  222.                         // Yes-- update the information about currently preferred match
  223.                         //
  224.                        
  225.                         longestMatchPrefix = prefixLen;
  226.                         mostSpecificMatch = (NetworkCredential)credEnum.Value;
  227.                     }
  228.                 }
  229.             }
  230.            
  231.             GlobalLog.Print("CredentialCache::GetCredential returning " + ((mostSpecificMatch == null) ? "null" : "(" + mostSpecificMatch.UserName + ":" + mostSpecificMatch.Domain + ")"));
  232.            
  233.             return mostSpecificMatch;
  234.         }
  235.        
  236.        
  237.         public NetworkCredential GetCredential(string host, int port, string authenticationType)
  238.         {
  239.             if (host == null) {
  240.                 throw new ArgumentNullException("host");
  241.             }
  242.             if (authenticationType == null) {
  243.                 throw new ArgumentNullException("authenticationType");
  244.             }
  245.             if (host.Length == 0) {
  246.                 throw new ArgumentException(SR.GetString(SR.net_emptystringcall, "host"));
  247.             }
  248.             if (port < 0) {
  249.                 throw new ArgumentOutOfRangeException("port");
  250.             }
  251.            
  252.            
  253.             GlobalLog.Print("CredentialCache::GetCredential(host=\"" + host + ":" + port.ToString() + "\", authenticationType=\"" + authenticationType + "\")");
  254.            
  255.             NetworkCredential match = null;
  256.            
  257.             IDictionaryEnumerator credEnum = cacheForHosts.GetEnumerator();
  258.            
  259.             //
  260.             // Enumerate through every credential in the cache
  261.             //
  262.            
  263.             while (credEnum.MoveNext()) {
  264.                
  265.                 CredentialHostKey key = (CredentialHostKey)credEnum.Key;
  266.                
  267.                 //
  268.                 // Determine if this credential is applicable to the current Uri/AuthType
  269.                 //
  270.                
  271.                 if (key.Match(host, port, authenticationType)) {
  272.                    
  273.                     match = (NetworkCredential)credEnum.Value;
  274.                 }
  275.             }
  276.            
  277.             GlobalLog.Print("CredentialCache::GetCredential returning " + ((match == null) ? "null" : "(" + match.UserName + ":" + match.Domain + ")"));
  278.             return match;
  279.         }
  280.        
  281.        
  282.        
  283.         /// <devdoc>
  284.         /// [To be supplied]
  285.         /// </devdoc>
  286.        
  287.         //
  288.         // IEnumerable interface
  289.         //
  290.        
  291.         public IEnumerator GetEnumerator()
  292.         {
  293.             return new CredentialEnumerator(this, cache, cacheForHosts, m_version);
  294.         }
  295.        
  296.        
  297.         /// <devdoc>
  298.         /// <para>
  299.         /// Gets
  300.         /// the default system credentials from the <see cref='System.Net.CredentialCache'/>.
  301.         /// </para>
  302.         /// </devdoc>
  303.         public static ICredentials DefaultCredentials {
  304.             get {
  305.                 //This check will not allow to use local user credentials at will.
  306.                 //Hence the username will not be exposed to the network
  307.                 new EnvironmentPermission(EnvironmentPermissionAccess.Read, "USERNAME").Demand();
  308.                 return SystemNetworkCredential.defaultCredential;
  309.             }
  310.         }
  311.        
  312.         public static NetworkCredential DefaultNetworkCredentials {
  313.             get {
  314.                 //This check will not allow to use local user credentials at will.
  315.                 //Hence the username will not be exposed to the network
  316.                 new EnvironmentPermission(EnvironmentPermissionAccess.Read, "USERNAME").Demand();
  317.                 return SystemNetworkCredential.defaultCredential;
  318.             }
  319.         }
  320.        
  321.         private class CredentialEnumerator : IEnumerator
  322.         {
  323.            
  324.             // fields
  325.            
  326.             private CredentialCache m_cache;
  327.             private ICredentials[] m_array;
  328.             private int m_index = -1;
  329.             private int m_version;
  330.            
  331.             // constructors
  332.            
  333.             internal CredentialEnumerator(CredentialCache cache, Hashtable table, Hashtable hostTable, int version)
  334.             {
  335.                 m_cache = cache;
  336.                 m_array = new ICredentials[table.Count + hostTable.Count];
  337.                 table.Values.CopyTo(m_array, 0);
  338.                 hostTable.Values.CopyTo(m_array, table.Count);
  339.                 m_version = version;
  340.             }
  341.            
  342.             // IEnumerator interface
  343.            
  344.             // properties
  345.            
  346.             object IEnumerator.Current {
  347.                 get {
  348.                     if (m_index < 0 || m_index >= m_array.Length) {
  349.                         throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
  350.                     }
  351.                     if (m_version != m_cache.m_version) {
  352.                         throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
  353.                     }
  354.                     return m_array[m_index];
  355.                 }
  356.             }
  357.            
  358.             // methods
  359.            
  360.             bool IEnumerator.MoveNext()
  361.             {
  362.                 if (m_version != m_cache.m_version) {
  363.                     throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
  364.                 }
  365.                 if (++m_index < m_array.Length) {
  366.                     return true;
  367.                 }
  368.                 m_index = m_array.Length;
  369.                 return false;
  370.             }
  371.            
  372.             void IEnumerator.Reset()
  373.             {
  374.                 m_index = -1;
  375.             }
  376.            
  377.         }
  378.         // class CredentialEnumerator
  379.        
  380.     }
  381.     // class CredentialCache
  382.    
  383.    
  384.     // Abstraction for credentials in password-based
  385.     // authentication schemes (basic, digest, NTLM, Kerberos)
  386.     // Note this is not applicable to public-key based
  387.     // systems such as SSL client authentication
  388.     // "Password" here may be the clear text password or it
  389.     // could be a one-way hash that is sufficient to
  390.     // authenticate, as in HTTP/1.1 digest.
  391.    
  392.     //
  393.     // Object representing default credentials
  394.     //
  395.     internal class SystemNetworkCredential : NetworkCredential
  396.     {
  397.         static internal readonly SystemNetworkCredential defaultCredential = new SystemNetworkCredential();
  398.        
  399.         // We want reference equality to work. Making this private is a good way to guarantee that.
  400.         private SystemNetworkCredential() : base(string.Empty, string.Empty, string.Empty)
  401.         {
  402.         }
  403.     }
  404.    
  405.    
  406.     internal class CredentialHostKey
  407.     {
  408.        
  409.         internal string Host;
  410.         internal string AuthenticationType;
  411.         internal int Port;
  412.        
  413.         internal CredentialHostKey(string host, int port, string authenticationType)
  414.         {
  415.             Host = host;
  416.             Port = port;
  417.             AuthenticationType = authenticationType;
  418.         }
  419.        
  420.         internal bool Match(string host, int port, string authenticationType)
  421.         {
  422.             if (host == null || authenticationType == null) {
  423.                 return false;
  424.             }
  425.             //
  426.             // If the protocols dont match this credential
  427.             // is not applicable for the given Uri
  428.             //
  429.             if (string.Compare(authenticationType, AuthenticationType, StringComparison.OrdinalIgnoreCase) != 0) {
  430.                 return false;
  431.             }
  432.             if (string.Compare(Host, host, StringComparison.OrdinalIgnoreCase) != 0) {
  433.                 return false;
  434.             }
  435.             if (port != Port) {
  436.                 return false;
  437.             }
  438.            
  439.             GlobalLog.Print("CredentialKey::Match(" + Host.ToString() + ":" + Port.ToString() + " & " + host.ToString() + ":" + port.ToString() + ")");
  440.             return true;
  441.         }
  442.        
  443.        
  444.         private int m_HashCode = 0;
  445.         private bool m_ComputedHashCode = false;
  446.         public override int GetHashCode()
  447.         {
  448.             if (!m_ComputedHashCode) {
  449.                 //
  450.                 // compute HashCode on demand
  451.                 //
  452.                
  453.                 m_HashCode = AuthenticationType.ToUpperInvariant().GetHashCode() + Host.ToUpperInvariant().GetHashCode() + Port.GetHashCode();
  454.                 m_ComputedHashCode = true;
  455.             }
  456.             return m_HashCode;
  457.         }
  458.        
  459.         public override bool Equals(object comparand)
  460.         {
  461.             CredentialHostKey comparedCredentialKey = comparand as CredentialHostKey;
  462.            
  463.             if (comparand == null) {
  464.                 //
  465.                 // this covers also the compared==null case
  466.                 //
  467.                 return false;
  468.             }
  469.            
  470.             bool equals = (string.Compare(AuthenticationType, comparedCredentialKey.AuthenticationType, StringComparison.OrdinalIgnoreCase) == 0) && (string.Compare(Host, comparedCredentialKey.Host, StringComparison.OrdinalIgnoreCase) == 0) && Port == comparedCredentialKey.Port;
  471.            
  472.             GlobalLog.Print("CredentialKey::Equals(" + ToString() + ", " + comparedCredentialKey.ToString() + ") returns " + equals.ToString());
  473.            
  474.             return equals;
  475.         }
  476.        
  477.         public override string ToString()
  478.         {
  479.             return "[" + Host.Length.ToString(NumberFormatInfo.InvariantInfo) + "]:" + Host + ":" + Port.ToString(NumberFormatInfo.InvariantInfo) + ":" + ValidationHelper.ToString(AuthenticationType);
  480.         }
  481.        
  482.     }
  483.     // class CredentialKey
  484.    
  485.     internal class CredentialKey
  486.     {
  487.        
  488.         internal Uri UriPrefix;
  489.         internal int UriPrefixLength = -1;
  490.         internal string AuthenticationType;
  491.        
  492.         internal CredentialKey(Uri uriPrefix, string authenticationType)
  493.         {
  494.             UriPrefix = uriPrefix;
  495.             UriPrefixLength = UriPrefix.ToString().Length;
  496.             AuthenticationType = authenticationType;
  497.         }
  498.        
  499.         internal bool Match(Uri uri, string authenticationType)
  500.         {
  501.             if (uri == null || authenticationType == null) {
  502.                 return false;
  503.             }
  504.             //
  505.             // If the protocols dont match this credential
  506.             // is not applicable for the given Uri
  507.             //
  508.             if (string.Compare(authenticationType, AuthenticationType, StringComparison.OrdinalIgnoreCase) != 0) {
  509.                 return false;
  510.             }
  511.            
  512.             GlobalLog.Print("CredentialKey::Match(" + UriPrefix.ToString() + " & " + uri.ToString() + ")");
  513.            
  514.             return IsPrefix(uri, UriPrefix);
  515.         }
  516.         //
  517.         // IsPrefix (Uri)
  518.         //
  519.         // Determines whether <prefixUri> is a prefix of this URI. A prefix
  520.         // match is defined as:
  521.         //
  522.         // scheme match
  523.         // + host match
  524.         // + port match, if any
  525.         // + <prefix> path is a prefix of <URI> path, if any
  526.         //
  527.         // Returns:
  528.         // True if <prefixUri> is a prefix of this URI
  529.         //
  530.         internal bool IsPrefix(Uri uri, Uri prefixUri)
  531.         {
  532.            
  533.             if (prefixUri.Scheme != uri.Scheme || prefixUri.Host != uri.Host || prefixUri.Port != uri.Port)
  534.                 return false;
  535.            
  536.             int prefixLen = prefixUri.AbsolutePath.LastIndexOf('/');
  537.             if (prefixLen > uri.AbsolutePath.LastIndexOf('/'))
  538.                 return false;
  539.            
  540.             return String.Compare(uri.AbsolutePath, 0, prefixUri.AbsolutePath, 0, prefixLen, StringComparison.OrdinalIgnoreCase) == 0;
  541.         }
  542.        
  543.         private int m_HashCode = 0;
  544.         private bool m_ComputedHashCode = false;
  545.         public override int GetHashCode()
  546.         {
  547.             if (!m_ComputedHashCode) {
  548.                 //
  549.                 // compute HashCode on demand
  550.                 //
  551.                
  552.                 m_HashCode = AuthenticationType.ToUpperInvariant().GetHashCode() + UriPrefixLength + UriPrefix.GetHashCode();
  553.                 m_ComputedHashCode = true;
  554.             }
  555.             return m_HashCode;
  556.         }
  557.        
  558.         public override bool Equals(object comparand)
  559.         {
  560.             CredentialKey comparedCredentialKey = comparand as CredentialKey;
  561.            
  562.             if (comparand == null) {
  563.                 //
  564.                 // this covers also the compared==null case
  565.                 //
  566.                 return false;
  567.             }
  568.            
  569.             bool equals = (string.Compare(AuthenticationType, comparedCredentialKey.AuthenticationType, StringComparison.OrdinalIgnoreCase) == 0) && UriPrefix.Equals(comparedCredentialKey.UriPrefix);
  570.            
  571.             GlobalLog.Print("CredentialKey::Equals(" + ToString() + ", " + comparedCredentialKey.ToString() + ") returns " + equals.ToString());
  572.            
  573.             return equals;
  574.         }
  575.        
  576.         public override string ToString()
  577.         {
  578.             return "[" + UriPrefixLength.ToString(NumberFormatInfo.InvariantInfo) + "]:" + ValidationHelper.ToString(UriPrefix) + ":" + ValidationHelper.ToString(AuthenticationType);
  579.         }
  580.        
  581.     }
  582.     // class CredentialKey
  583.    
  584. }
  585. // namespace System.Net

Developer Fusion