proxy.cs
上传用户:hbhltzc
上传日期:2022-06-04
资源大小:1925k
文件大小:37k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. using System;
  2. using System.IO;
  3. using System.Windows.Forms;
  4. using System.ComponentModel;
  5. using System.Text;
  6. using System.Net;
  7. using System.Net.Cache;
  8. using System.Diagnostics;
  9. using System.Globalization;
  10. using System.Runtime.InteropServices;
  11. using System.Xml;
  12. namespace XmlNotepad {
  13.     public class XmlProxyResolver : XmlUrlResolver {
  14.         WebProxyService ps;
  15.         public XmlProxyResolver(IServiceProvider site) {
  16.             ps = site.GetService(typeof(WebProxyService)) as WebProxyService;
  17.         }
  18.         public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) {
  19.             if (absoluteUri == null) {
  20.                 throw new ArgumentNullException("absoluteUri");
  21.             }
  22.             if (absoluteUri.Scheme == "http" && (ofObjectToReturn == null || ofObjectToReturn == typeof(Stream))) {
  23.                 try {
  24.                     return GetResponse(absoluteUri);
  25.                 } catch (Exception e) {
  26.                     if (WebProxyService.ProxyAuthenticationRequired(e)) {
  27.                         WebProxyState state = ps.PrepareWebProxy(this.Proxy, absoluteUri.AbsoluteUri, WebProxyState.DefaultCredentials, true);
  28.                         if (state != WebProxyState.Abort) {
  29.                             // try again...
  30.                             return GetResponse(absoluteUri);
  31.                         }
  32.                     }
  33.                     throw;
  34.                 }
  35.             } else {
  36.                 return base.GetEntity(absoluteUri, role, ofObjectToReturn);
  37.             }
  38.         }
  39.         Stream GetResponse(Uri uri) {
  40.             WebRequest webReq = WebRequest.Create(uri);
  41.             webReq.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.Default);
  42.             webReq.Credentials = CredentialCache.DefaultCredentials;
  43.             webReq.Proxy = this.Proxy;
  44.             WebResponse resp = webReq.GetResponse();
  45.             return resp.GetResponseStream();
  46.         }
  47.         IWebProxy Proxy {
  48.             get { return HttpWebRequest.DefaultWebProxy; }
  49.         }
  50.     }
  51.     enum WebProxyState {
  52.         NoCredentials = 0,
  53.         DefaultCredentials = 1,
  54.         CachedCredentials = 2,
  55.         PromptForCredentials = 3,
  56.         Abort = 4
  57.     } ;
  58.     internal class WebProxyService {
  59.         private IServiceProvider site;
  60.         private NetworkCredential cachedCredentials;
  61.         private string currentProxyUrl;
  62.         public WebProxyService(IServiceProvider site) {
  63.             this.site = site;
  64.         }
  65.         //---------------------------------------------------------------------
  66.         // public methods
  67.         //---------------------------------------------------------------------
  68.         public static bool ProxyAuthenticationRequired(Exception ex) {
  69.             bool authNeeded = false;
  70.             System.Net.WebException wex = ex as System.Net.WebException;
  71.             if ((wex != null) && (wex.Status == System.Net.WebExceptionStatus.ProtocolError)) {
  72.                 System.Net.HttpWebResponse hwr = wex.Response as System.Net.HttpWebResponse;
  73.                 if ((hwr != null) && (hwr.StatusCode == System.Net.HttpStatusCode.ProxyAuthenticationRequired)) {
  74.                     authNeeded = true;
  75.                 }
  76.             }
  77.             return authNeeded;
  78.         }
  79.         /// <summary>
  80.         /// This method attaches credentials to the web proxy object.
  81.         /// </summary>
  82.         /// <param name="proxy">The proxy to attach credentials to.</param>
  83.         /// <param name="webCallUrl">The url for the web call.</param>
  84.         /// <param name="oldProxyState">The current state fo the web call.</param>
  85.         /// <param name="newProxyState">The new state for the web call.</param>
  86.         /// <param name="okToPrompt">Prompt user for credentials if they are not available.</param>
  87.         public WebProxyState PrepareWebProxy(IWebProxy proxy, string webCallUrl, WebProxyState oldProxyState, bool okToPrompt) {
  88.             WebProxyState newProxyState = WebProxyState.Abort;
  89.             if (string.IsNullOrEmpty(webCallUrl)) {
  90.                 Debug.Fail("PrepareWebProxy called with an empty WebCallUrl.");
  91.                 webCallUrl = "http://go.microsoft.com/fwlink/?LinkId=81947";
  92.             }
  93.             // Get the web proxy url for the the current web call.
  94.             Uri webCallProxy = null;
  95.             if (proxy != null) {
  96.                 webCallProxy = proxy.GetProxy(new Uri(webCallUrl));
  97.             }
  98.             if ((proxy != null) && (webCallProxy != null)) {
  99.                 // get proxy url.
  100.                 string proxyUrl = webCallProxy.Host;
  101.                 if (string.IsNullOrEmpty(currentProxyUrl)) {
  102.                     currentProxyUrl = proxyUrl;
  103.                 }
  104.                 switch (oldProxyState) {
  105.                     case WebProxyState.NoCredentials:
  106.                         // Add the default credentials only if there aren't any credentials attached to
  107.                         // the DefaultWebProxy. If the first calls attaches the correct credentials, the
  108.                         // second call will just use them, instead of overwriting it with the default credentials.
  109.                         // This avoids multiple web calls. Note that state is transitioned to DefaultCredentials
  110.                         // instead of CachedCredentials. This ensures that web calls be tried with the
  111.                         // cached credentials if the currently attached credentials don't result in successful web call.
  112.                         if ((proxy.Credentials == null)) {
  113.                             proxy.Credentials = CredentialCache.DefaultCredentials;
  114.                         }
  115.                         newProxyState = WebProxyState.DefaultCredentials;
  116.                         break;
  117.                     case WebProxyState.DefaultCredentials:
  118.                         // Fetch cached credentials if they are null or if the proxy url has changed.
  119.                         if ((cachedCredentials == null) ||
  120.                             !string.Equals(currentProxyUrl, proxyUrl, StringComparison.OrdinalIgnoreCase)) {
  121.                             cachedCredentials = GetCachedCredentials(proxyUrl);
  122.                         }
  123.                         if (cachedCredentials != null) {
  124.                             proxy.Credentials = cachedCredentials;
  125.                             newProxyState = WebProxyState.CachedCredentials;
  126.                             break;
  127.                         }
  128.                         // Proceed to next step if cached credentials are not available.
  129.                         goto case WebProxyState.CachedCredentials;
  130.                     case WebProxyState.CachedCredentials:
  131.                     case WebProxyState.PromptForCredentials:
  132.                         if (okToPrompt) {
  133.                             if (DialogResult.OK == PromptForCredentials(proxyUrl)) {
  134.                                 proxy.Credentials = cachedCredentials;
  135.                                 newProxyState = WebProxyState.PromptForCredentials;
  136.                             } else {
  137.                                 newProxyState = WebProxyState.Abort;
  138.                             }
  139.                         } else {
  140.                             newProxyState = WebProxyState.Abort;
  141.                         }
  142.                         break;
  143.                     case WebProxyState.Abort:
  144.                         throw new InvalidOperationException();
  145.                     default:
  146.                         throw new ArgumentException(string.Empty, "oldProxyState");
  147.                 }
  148.             } else {
  149.                 // No proxy for the webCallUrl scenario.
  150.                 if (oldProxyState == WebProxyState.NoCredentials) {
  151.                     // if it is the first call, change the state and let the web call proceed.
  152.                     newProxyState = WebProxyState.DefaultCredentials;
  153.                 } else {
  154.                     Debug.Fail("This method is called a second time when 407 occurs. A 407 shouldn't have occurred as there is no default proxy.");
  155.                     // We dont have a good idea of the circumstances under which
  156.                     // WebProxy might be null for a url. To be safe, for VS 2005 SP1,
  157.                     // we will just return the abort state, instead of throwing
  158.                     // an exception. Abort state will ensure that no further procesing
  159.                     // occurs and we will not bring down the app.
  160.                     // throw new InvalidOperationException();
  161.                     newProxyState = WebProxyState.Abort;
  162.                 }
  163.             }
  164.             return newProxyState;
  165.         }
  166.         //---------------------------------------------------------------------
  167.         // private methods
  168.         //---------------------------------------------------------------------
  169.         /// <summary>
  170.         /// Retrieves credentials from the credential store.
  171.         /// </summary>
  172.         /// <param name="proxyUrl">The proxy url for which credentials are retrieved.</param>
  173.         /// <returns>The credentails for the proxy.</returns>
  174.         private NetworkCredential GetCachedCredentials(string proxyUrl) {
  175.             return Credentials.GetCachedCredentials(proxyUrl);
  176.         }
  177.         /// <summary>
  178.         /// Prompt the use to provider credentials and optionally store them.
  179.         /// </summary>
  180.         /// <param name="proxyUrl">The server that requires credentials.</param>
  181.         /// <returns>Returns the dialog result of the prompt dialog.</returns>
  182.         private DialogResult PromptForCredentials(string proxyUrl) {
  183.             DialogResult dialogResult = DialogResult.Cancel;
  184.             bool prompt = true;
  185.             while (prompt) {
  186.                 prompt = false;
  187.                 NetworkCredential cred;
  188.                 dialogResult = Credentials.PromptForCredentials(proxyUrl, out cred);
  189.                 if (DialogResult.OK == dialogResult) {
  190.                     if (cred != null) {
  191.                         cachedCredentials = cred;
  192.                         currentProxyUrl = proxyUrl;
  193.                     } else {
  194.                         // Prompt again for credential as we are not able to create
  195.                         // a NetworkCredential object from the supplied credentials.
  196.                         prompt = true;
  197.                     }
  198.                 }
  199.             }
  200.             return dialogResult;
  201.         }
  202.     }
  203.     internal sealed class Credentials {
  204.         /// <summary>
  205.         /// Prompt the user for credentials.
  206.         /// </summary>
  207.         /// <param name="target">
  208.         /// The credential target. It is displayed in the prompt dialog and is
  209.         /// used for credential storage.
  210.         /// </param>
  211.         /// <param name="credential">The user supplied credentials.</param>
  212.         /// <returns>
  213.         /// DialogResult.OK = if Successfully prompted user for credentials.
  214.         /// DialogResult.Cancel = if user cancelled the prompt dialog.
  215.         /// </returns>
  216.         public static DialogResult PromptForCredentials(string target, out NetworkCredential credential) {
  217.             DialogResult dr = DialogResult.Cancel;
  218.             credential = null;
  219.             string username;
  220.             string password;
  221.             IntPtr hwndOwner = IntPtr.Zero;
  222.             // Show the OS credential dialog.
  223.             dr = ShowOSCredentialDialog(target, hwndOwner, out username, out password);
  224.             // Create the NetworkCredential object.
  225.             if (dr == DialogResult.OK) {
  226.                 credential = CreateCredentials(username, password, target);
  227.             }
  228.             return dr;
  229.         }
  230.         /// <summary>
  231.         /// Get the cached credentials from the credentials store.
  232.         /// </summary>
  233.         /// <param name="target">The credential target.</param>
  234.         /// <returns>
  235.         /// The cached credentials. It will return null if credentails are found
  236.         /// in the cache.
  237.         /// </returns>
  238.         public static NetworkCredential GetCachedCredentials(string target) {
  239.             NetworkCredential cred = null;
  240.             string username;
  241.             string password;
  242.             // Retrieve credentials from the OS credential store.
  243.             if (ReadOSCredentials(target, out username, out password)) {
  244.                 // Create the NetworkCredential object if we successfully
  245.                 // retrieved the credentails from the OS store.
  246.                 cred = CreateCredentials(username, password, target);
  247.             }
  248.             return cred;
  249.         }
  250.         //---------------------------------------------------------------------
  251.         // private methods
  252.         //---------------------------------------------------------------------
  253.         /// <summary>
  254.         /// This function calls the OS dialog to prompt user for credential.
  255.         /// </summary>
  256.         /// <param name="target">
  257.         /// The credential target. It is displayed in the prompt dialog and is
  258.         /// used for credential storage.
  259.         /// </param>
  260.         /// <param name="hwdOwner">The parent for the dialog.</param>
  261.         /// <param name="userName">The username supplied by the user.</param>
  262.         /// <param name="password">The password supplied by the user.</param>
  263.         /// <returns>
  264.         /// DialogResult.OK = if Successfully prompted user for credentials.
  265.         /// DialogResult.Cancel = if user cancelled the prompt dialog.
  266.         /// </returns>
  267.         private static DialogResult ShowOSCredentialDialog(string target, IntPtr hwdOwner, out string userName, out string password) {
  268.             DialogResult retValue = DialogResult.Cancel;
  269.             userName = string.Empty;
  270.             password = string.Empty;
  271.             string titleFormat = SR.CredentialDialog_TitleFormat;
  272.             string descriptionFormat = SR.CredentialDialog_DescriptionTextFormat;
  273.             // Create the CREDUI_INFO structure. 
  274.             NativeMethods.CREDUI_INFO info = new NativeMethods.CREDUI_INFO();
  275.             info.pszCaptionText = string.Format(CultureInfo.CurrentUICulture, titleFormat, target);
  276.             info.pszMessageText = string.Format(CultureInfo.CurrentUICulture, descriptionFormat, target);
  277.             info.hwndParentCERParent = hwdOwner;
  278.             info.hbmBannerCERHandle = IntPtr.Zero;
  279.             info.cbSize = Marshal.SizeOf(info);
  280.             // We do not use CREDUI_FLAGS_VALIDATE_USERNAME flag as it doesn't allow plain user
  281.             // (one with no domain component). Instead we use CREDUI_FLAGS_COMPLETE_USERNAME.
  282.             // It does some basic username validation (like doesnt allow two "" in the user name.
  283.             // It does adds the target to the username. For example, if user entered "foo" for
  284.             // taget "bar.com", it will return username as "bar.comfoo". We trim out bar.com
  285.             // while parsing the username. User can input "foo@bar.com" as workaround to provide
  286.             // "bar.comfoo" as the username.
  287.             // We specify CRED_TYPE_SERVER_CREDENTIAL flag as the stored credentials appear in the 
  288.             // "Control Panel->Stored Usernames and Password". It is how IE stores and retrieve
  289.             // credentials. By using the CRED_TYPE_SERVER_CREDENTIAL flag allows IE and VS to
  290.             // share credentials.
  291.             // We dont specify the CREDUI_FLAGS_EXPECT_CONFIRMATION as the VS proxy service consumers
  292.             // dont call back into the service to confirm that the call succeeded.
  293.             NativeMethods.CREDUI_FLAGS flags = NativeMethods.CREDUI_FLAGS.SERVER_CREDENTIAL |
  294.                                                 NativeMethods.CREDUI_FLAGS.SHOW_SAVE_CHECK_BOX |
  295.                                                 NativeMethods.CREDUI_FLAGS.COMPLETE_USERNAME |
  296.                                                 NativeMethods.CREDUI_FLAGS.EXCLUDE_CERTIFICATES;
  297.             StringBuilder user = new StringBuilder(Convert.ToInt32(NativeMethods.CREDUI_MAX_USERNAME_LENGTH));
  298.             StringBuilder pwd = new StringBuilder(Convert.ToInt32(NativeMethods.CREDUI_MAX_PASSWORD_LENGTH));
  299.             int saveCredentials = 0;
  300.             // Ensures that CredUPPromptForCredentials results in a prompt.
  301.             int netError = NativeMethods.ERROR_LOGON_FAILURE;
  302.             // Call the OS API to prompt for credentials.
  303.             NativeMethods.CredUIReturnCodes result = NativeMethods.CredUIPromptForCredentials(
  304.                 info,
  305.                 target,
  306.                 IntPtr.Zero,
  307.                 netError,
  308.                 user,
  309.                 NativeMethods.CREDUI_MAX_USERNAME_LENGTH,
  310.                 pwd,
  311.                 NativeMethods.CREDUI_MAX_PASSWORD_LENGTH,
  312.                 ref saveCredentials,
  313.                 flags);
  314.             if (result == NativeMethods.CredUIReturnCodes.NO_ERROR) {
  315.                 userName = user.ToString();
  316.                 password = pwd.ToString();
  317.                 try {
  318.                     if (Convert.ToBoolean(saveCredentials)) {
  319.                         // Try reading the credentials back to ensure that we can read the stored credentials. If
  320.                         // the CredUIPromptForCredentials() function is not able successfully call CredGetTargetInfo(),
  321.                         // it will store credentials with credential type as DOMAIN_PASSWORD. For DOMAIN_PASSWORD
  322.                         // credential type we can only retrive the user name. As a workaround, we store the credentials
  323.                         // as credential type as GENERIC.
  324.                         string storedUserName;
  325.                         string storedPassword;
  326.                         bool successfullyReadCredentials = ReadOSCredentials(target, out storedUserName, out storedPassword);
  327.                         if (!successfullyReadCredentials ||
  328.                             !string.Equals(userName, storedUserName, StringComparison.Ordinal) ||
  329.                             !string.Equals(password, storedPassword, StringComparison.Ordinal)) {
  330.                             // We are not able to retrieve the credentials. Try storing them as GENERIC credetails.
  331.                             // Create the NativeCredential object.
  332.                             NativeMethods.NativeCredential customCredential = new NativeMethods.NativeCredential();
  333.                             customCredential.userName = userName;
  334.                             customCredential.type = NativeMethods.CRED_TYPE_GENERIC;
  335.                             customCredential.targetName = CreateCustomTarget(target);
  336.                             // Store credentials across sessions.
  337.                             customCredential.persist = (uint)NativeMethods.CRED_PERSIST.LOCAL_MACHINE;
  338.                             if (!string.IsNullOrEmpty(password)) {
  339.                                 customCredential.credentialBlobSize = (uint)Marshal.SystemDefaultCharSize * ((uint)password.Length);
  340.                                 customCredential.credentialBlob = Marshal.StringToCoTaskMemAuto(password);
  341.                             }
  342.                             try {
  343.                                 NativeMethods.CredWrite(ref customCredential, 0);
  344.                             } finally {
  345.                                 if (customCredential.credentialBlob != IntPtr.Zero) {
  346.                                     Marshal.FreeCoTaskMem(customCredential.credentialBlob);
  347.                                 }
  348.                             }
  349.                         }
  350.                     }
  351.                 } catch {
  352.                     // Ignore that failure to read back the credentials. We still have
  353.                     // username and password to use in the current session.
  354.                 }
  355.                 retValue = DialogResult.OK;
  356.             } else if (result == NativeMethods.CredUIReturnCodes.ERROR_CANCELLED) {
  357.                 retValue = DialogResult.Cancel;
  358.             } else {
  359.                 Debug.Fail("CredUIPromptForCredentials failed with result = " + result.ToString());
  360.                 retValue = DialogResult.Cancel;
  361.             }
  362.             info.Dispose();
  363.             return retValue;
  364.         }
  365.         /// <summary>
  366.         /// Generates a NetworkCredential object from username and password. The function will
  367.         /// parse username part and invoke the correct NetworkCredential construction.
  368.         /// </summary>
  369.         /// <param name="username">username retrieved from user/registry.</param>
  370.         /// <param name="password">password retrieved from user/registry.</param>
  371.         /// <returns></returns>
  372.         private static NetworkCredential CreateCredentials(string username, string password, string targetServer) {
  373.             NetworkCredential cred = null;
  374.             if ((!string.IsNullOrEmpty(username)) && (!string.IsNullOrEmpty(password))) {
  375.                 string domain;
  376.                 string user;
  377.                 if (ParseUsername(username, targetServer, out user, out domain)) {
  378.                     if (string.IsNullOrEmpty(domain)) {
  379.                         cred = new NetworkCredential(user, password);
  380.                     } else {
  381.                         cred = new NetworkCredential(user, password, domain);
  382.                     }
  383.                 }
  384.             }
  385.             return cred;
  386.         }
  387.         /// <summary>
  388.         /// This fuction calls CredUIParseUserName() to parse the user name.
  389.         /// </summary>
  390.         /// <param name="username">The username name to pass.</param>
  391.         /// <param name="targetServer">The target for which username is being parsed.</param>
  392.         /// <param name="user">The user part of the username.</param>
  393.         /// <param name="domain">The domain part of the username.</param>
  394.         /// <returns>Returns true if it successfully parsed the username.</returns>
  395.         private static bool ParseUsername(string username, string targetServer, out string user, out string domain) {
  396.             user = string.Empty;
  397.             domain = string.Empty;
  398.             if (string.IsNullOrEmpty(username)) {
  399.                 return false;
  400.             }
  401.             bool successfullyParsed = true;
  402.             StringBuilder strUser = new StringBuilder(Convert.ToInt32(NativeMethods.CREDUI_MAX_USERNAME_LENGTH));
  403.             StringBuilder strDomain = new StringBuilder(Convert.ToInt32(NativeMethods.CREDUI_MAX_DOMAIN_TARGET_LENGTH));
  404.             // Call the OS API to do the parsing.
  405.             NativeMethods.CredUIReturnCodes result = NativeMethods.CredUIParseUserName(username,
  406.                                                     strUser,
  407.                                                     NativeMethods.CREDUI_MAX_USERNAME_LENGTH,
  408.                                                     strDomain,
  409.                                                     NativeMethods.CREDUI_MAX_DOMAIN_TARGET_LENGTH);
  410.             successfullyParsed = (result == NativeMethods.CredUIReturnCodes.NO_ERROR);
  411.             if (successfullyParsed) {
  412.                 user = strUser.ToString();
  413.                 domain = strDomain.ToString();
  414.                 // Remove the domain part if domain is same as target. This is to workaround
  415.                 // the COMPLETE_USERNAME flag which add the target to the user name as the 
  416.                 // domain component.
  417.                 // Read comments in ShowOSCredentialDialog() for more details.
  418.                 if (!string.IsNullOrEmpty(domain) &&
  419.                     string.Equals(domain, targetServer, StringComparison.OrdinalIgnoreCase)) {
  420.                     domain = string.Empty;
  421.                 }
  422.             }
  423.             return successfullyParsed;
  424.         }
  425.         /// <summary>
  426.         /// Retrieves credentials from the OS store.
  427.         /// </summary>
  428.         /// <param name="target">The credential target.</param>
  429.         /// <param name="username">The retrieved username.</param>
  430.         /// <param name="password">The retrieved password.</param>
  431.         /// <returns>Returns true if it successfully reads the OS credentials.</returns>
  432.         private static bool ReadOSCredentials(string target, out string username, out string password) {
  433.             username = string.Empty;
  434.             password = string.Empty;
  435.             if (string.IsNullOrEmpty(target)) {
  436.                 return false;
  437.             }
  438.             IntPtr credPtr = IntPtr.Zero;
  439.             IntPtr customCredPtr = IntPtr.Zero;
  440.             try {
  441.                 bool queriedDomainPassword = false;
  442.                 bool readCredentials = true;
  443.                 // Query the OS credential store.
  444.                 if (!NativeMethods.CredRead(
  445.                         target,
  446.                         NativeMethods.CRED_TYPE_GENERIC,
  447.                         0,
  448.                         out credPtr)) {
  449.                     readCredentials = false;
  450.                     // Query for the DOMAIN_PASSWORD credential type to retrieve the 
  451.                     // credentials. CredUPromptForCredentials will store credentials
  452.                     // as DOMAIN_PASSWORD credential type if it is not able to resolve
  453.                     // the target using CredGetTargetInfo() function.
  454.                     if (Marshal.GetLastWin32Error() == NativeMethods.ERROR_NOT_FOUND) {
  455.                         queriedDomainPassword = true;
  456.                         // try queryiing for CRED_TYPE_DOMAIN_PASSWORD
  457.                         if (NativeMethods.CredRead(
  458.                             target,
  459.                             NativeMethods.CRED_TYPE_DOMAIN_PASSWORD,
  460.                             0,
  461.                             out credPtr)) {
  462.                             readCredentials = true;
  463.                         }
  464.                     }
  465.                 }
  466.                 if (readCredentials) {
  467.                     // Get the native credentials if CredRead succeeds.
  468.                     NativeMethods.NativeCredential nativeCredential = (NativeMethods.NativeCredential)Marshal.PtrToStructure(credPtr, typeof(NativeMethods.NativeCredential));
  469.                     password = (nativeCredential.credentialBlob != IntPtr.Zero) ?
  470.                                             Marshal.PtrToStringUni(nativeCredential.credentialBlob, (int)(nativeCredential.credentialBlobSize / Marshal.SystemDefaultCharSize))
  471.                                             : string.Empty;
  472.                     username = nativeCredential.userName;
  473.                     // If we retrieved the username using the credentials type as DOMAIN_PASSWORD, and 
  474.                     // we are not able to retrieve password, we query the GENERIC credentials to
  475.                     // retrieve the password. Read comments in the ShowOSCredentialDialog() funtion
  476.                     // for more details.
  477.                     if (string.IsNullOrEmpty(password) && queriedDomainPassword) {
  478.                         // Read custom credentials.
  479.                         if (NativeMethods.CredRead(
  480.                                 CreateCustomTarget(target),
  481.                                 NativeMethods.CRED_TYPE_GENERIC,
  482.                                 0,
  483.                                 out customCredPtr)) {
  484.                             NativeMethods.NativeCredential customNativeCredential = (NativeMethods.NativeCredential)Marshal.PtrToStructure(customCredPtr, typeof(NativeMethods.NativeCredential));
  485.                             if (string.Equals(username, customNativeCredential.userName, StringComparison.OrdinalIgnoreCase)) {
  486.                                 password = (customNativeCredential.credentialBlob != IntPtr.Zero) ?
  487.                                                         Marshal.PtrToStringUni(customNativeCredential.credentialBlob, (int)(customNativeCredential.credentialBlobSize / Marshal.SystemDefaultCharSize))
  488.                                                         : string.Empty;
  489.                             }
  490.                         }
  491.                     }
  492.                 }
  493.             } catch (Exception) {
  494.                 username = string.Empty;
  495.                 password = string.Empty;
  496.             } finally {
  497.                 if (credPtr != IntPtr.Zero) {
  498.                     NativeMethods.CredFree(credPtr);
  499.                 }
  500.                 if (customCredPtr != IntPtr.Zero) {
  501.                     NativeMethods.CredFree(customCredPtr);
  502.                 }
  503.             }
  504.             bool successfullyReadCredentials = true;
  505.             if (string.IsNullOrEmpty(username) ||
  506.                 string.IsNullOrEmpty(password)) {
  507.                 username = string.Empty;
  508.                 password = string.Empty;
  509.                 successfullyReadCredentials = false;
  510.             }
  511.             return successfullyReadCredentials;
  512.         }
  513.         /// <summary>
  514.         /// Generates the generic target name.
  515.         /// </summary>
  516.         /// <param name="target">The credetial target.</param>
  517.         /// <returns>The generic target.</returns>
  518.         private static string CreateCustomTarget(string target) {
  519.             if (string.IsNullOrEmpty(target)) {
  520.                 return string.Empty;
  521.             }
  522.             return "Credentials_" + target;
  523.         }
  524.     }
  525.     #region NativeMethods
  526.     static class NativeMethods {
  527.         private const string advapi32Dll = "advapi32.dll";
  528.         private const string credUIDll = "credui.dll";
  529.         private const string user32Dll = "User32.dll";
  530.         private const string sensapiDll = "sensapi.dll";
  531.         public const int
  532.         ERROR_INVALID_FLAGS = 1004,  // Invalid flags.
  533.         ERROR_NOT_FOUND = 1168,  // Element not found.
  534.         ERROR_NO_SUCH_LOGON_SESSION = 1312,  // A specified logon session does not exist. It may already have been terminated.
  535.         ERROR_LOGON_FAILURE = 1326;  // Logon failure: unknown user name or bad password.
  536.         [Flags]
  537.         public enum CREDUI_FLAGS : uint {
  538.             INCORRECT_PASSWORD = 0x1,
  539.             DO_NOT_PERSIST = 0x2,
  540.             REQUEST_ADMINISTRATOR = 0x4,
  541.             EXCLUDE_CERTIFICATES = 0x8,
  542.             REQUIRE_CERTIFICATE = 0x10,
  543.             SHOW_SAVE_CHECK_BOX = 0x40,
  544.             ALWAYS_SHOW_UI = 0x80,
  545.             REQUIRE_SMARTCARD = 0x100,
  546.             PASSWORD_ONLY_OK = 0x200,
  547.             VALIDATE_USERNAME = 0x400,
  548.             COMPLETE_USERNAME = 0x800,
  549.             PERSIST = 0x1000,
  550.             SERVER_CREDENTIAL = 0x4000,
  551.             EXPECT_CONFIRMATION = 0x20000,
  552.             GENERIC_CREDENTIALS = 0x40000,
  553.             USERNAME_TARGET_CREDENTIALS = 0x80000,
  554.             KEEP_USERNAME = 0x100000,
  555.         }
  556.         [StructLayout(LayoutKind.Sequential)]
  557.         public class CREDUI_INFO : IDisposable {
  558.             public int cbSize;
  559.             public IntPtr hwndParentCERParent;
  560.             [MarshalAs(UnmanagedType.LPWStr)]
  561.             public string pszMessageText;
  562.             [MarshalAs(UnmanagedType.LPWStr)]
  563.             public string pszCaptionText;
  564.             public IntPtr hbmBannerCERHandle;
  565.             public void Dispose() {
  566.                 Dispose(true);
  567.                 GC.SuppressFinalize(this);
  568.             }
  569.             protected virtual void Dispose(bool disposing) {
  570.                 if (disposing) {
  571.                     // Release managed resources.
  572.                 }
  573.                 // Free the unmanaged resource ...
  574.                 hwndParentCERParent = IntPtr.Zero;
  575.                 hbmBannerCERHandle = IntPtr.Zero;
  576.             }
  577.             ~CREDUI_INFO() {
  578.                 Dispose(false);
  579.             }
  580.         }
  581.         public enum CredUIReturnCodes : uint {
  582.             NO_ERROR = 0,
  583.             ERROR_CANCELLED = 1223,
  584.             ERROR_NO_SUCH_LOGON_SESSION = 1312,
  585.             ERROR_NOT_FOUND = 1168,
  586.             ERROR_INVALID_ACCOUNT_NAME = 1315,
  587.             ERROR_INSUFFICIENT_BUFFER = 122,
  588.             ERROR_INVALID_PARAMETER = 87,
  589.             ERROR_INVALID_FLAGS = 1004,
  590.         }
  591.         // Copied from wincred.h
  592.         public const uint
  593.             // Values of the Credential Type field.
  594.         CRED_TYPE_GENERIC = 1,
  595.         CRED_TYPE_DOMAIN_PASSWORD = 2,
  596.         CRED_TYPE_DOMAIN_CERTIFICATE = 3,
  597.         CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 4,
  598.         CRED_TYPE_MAXIMUM = 5,                           // Maximum supported cred type
  599.         CRED_TYPE_MAXIMUM_EX = (CRED_TYPE_MAXIMUM + 1000),    // Allow new applications to run on old OSes
  600.         // String limits
  601.         CRED_MAX_CREDENTIAL_BLOB_SIZE = 512,         // Maximum size of the CredBlob field (in bytes)
  602.         CRED_MAX_STRING_LENGTH = 256,         // Maximum length of the various credential string fields (in characters)
  603.         CRED_MAX_USERNAME_LENGTH = (256 + 1 + 256), // Maximum length of the UserName field.  The worst case is <User>@<DnsDomain>
  604.         CRED_MAX_GENERIC_TARGET_NAME_LENGTH = 32767,       // Maximum length of the TargetName field for CRED_TYPE_GENERIC (in characters)
  605.         CRED_MAX_DOMAIN_TARGET_NAME_LENGTH = (256 + 1 + 80),  // Maximum length of the TargetName field for CRED_TYPE_DOMAIN_* (in characters). Largest one is <DfsRoot><DfsShare>
  606.         CRED_MAX_VALUE_SIZE = 256,         // Maximum size of the Credential Attribute Value field (in bytes)
  607.         CRED_MAX_ATTRIBUTES = 64,          // Maximum number of attributes per credential
  608.         CREDUI_MAX_MESSAGE_LENGTH = 32767,
  609.         CREDUI_MAX_CAPTION_LENGTH = 128,
  610.         CREDUI_MAX_GENERIC_TARGET_LENGTH = CRED_MAX_GENERIC_TARGET_NAME_LENGTH,
  611.         CREDUI_MAX_DOMAIN_TARGET_LENGTH = CRED_MAX_DOMAIN_TARGET_NAME_LENGTH,
  612.         CREDUI_MAX_USERNAME_LENGTH = CRED_MAX_USERNAME_LENGTH,
  613.         CREDUI_MAX_PASSWORD_LENGTH = (CRED_MAX_CREDENTIAL_BLOB_SIZE / 2);
  614.         internal enum CRED_PERSIST : uint {
  615.             NONE = 0,
  616.             SESSION = 1,
  617.             LOCAL_MACHINE = 2,
  618.             ENTERPRISE = 3,
  619.         }
  620.         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  621.         public struct NativeCredential {
  622.             public uint flags;
  623.             public uint type;
  624.             public string targetName;
  625.             public string comment;
  626.             public int lastWritten_lowDateTime;
  627.             public int lastWritten_highDateTime;
  628.             public uint credentialBlobSize;
  629.             public IntPtr credentialBlob;
  630.             public uint persist;
  631.             public uint attributeCount;
  632.             public IntPtr attributes;
  633.             public string targetAlias;
  634.             public string userName;
  635.         };
  636.         [DllImport(advapi32Dll, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CredReadW")]
  637.         [return: MarshalAs(UnmanagedType.Bool)]
  638.         public static extern bool
  639.         CredRead(
  640.             [MarshalAs(UnmanagedType.LPWStr)]
  641. string targetName,
  642.             [MarshalAs(UnmanagedType.U4)]
  643. uint type,
  644.             [MarshalAs(UnmanagedType.U4)]
  645. uint flags,
  646.             out IntPtr credential
  647.             );
  648.         [DllImport(advapi32Dll, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CredWriteW")]
  649.         [return: MarshalAs(UnmanagedType.Bool)]
  650.         public static extern bool
  651.         CredWrite(
  652.             ref NativeCredential Credential,
  653.             [MarshalAs(UnmanagedType.U4)]
  654. uint flags
  655.             );
  656.         [DllImport(advapi32Dll)]
  657.         public static extern void
  658.         CredFree(
  659.             IntPtr buffer
  660.             );
  661.         [DllImport(credUIDll, EntryPoint = "CredUIPromptForCredentialsW", CharSet = CharSet.Unicode)]
  662.         public static extern CredUIReturnCodes CredUIPromptForCredentials(
  663.             CREDUI_INFO pUiInfo,  // Optional (one can pass null here)
  664.             [MarshalAs(UnmanagedType.LPWStr)]
  665. string targetName,
  666.             IntPtr Reserved,      // Must be 0 (IntPtr.Zero)
  667.             int iError,
  668.             [MarshalAs(UnmanagedType.LPWStr)]
  669. StringBuilder pszUserName,
  670.             [MarshalAs(UnmanagedType.U4)]
  671. uint ulUserNameMaxChars,
  672.             [MarshalAs(UnmanagedType.LPWStr)]
  673. StringBuilder pszPassword,
  674.             [MarshalAs(UnmanagedType.U4)]
  675. uint ulPasswordMaxChars,
  676.             ref int pfSave,
  677.             CREDUI_FLAGS dwFlags);
  678.         /// <returns>
  679.         /// Win32 system errors:
  680.         /// NO_ERROR
  681.         /// ERROR_INVALID_ACCOUNT_NAME
  682.         /// ERROR_INSUFFICIENT_BUFFER
  683.         /// ERROR_INVALID_PARAMETER
  684.         /// </returns>
  685.         [DllImport(credUIDll, CharSet = CharSet.Auto, SetLastError = true, EntryPoint = "CredUIParseUserNameW")]
  686.         public static extern CredUIReturnCodes CredUIParseUserName(
  687.             [MarshalAs(UnmanagedType.LPWStr)]
  688. string strUserName,
  689.             [MarshalAs(UnmanagedType.LPWStr)]
  690. StringBuilder strUser,
  691.             [MarshalAs(UnmanagedType.U4)]
  692. uint iUserMaxChars,
  693.             [MarshalAs(UnmanagedType.LPWStr)]
  694. StringBuilder strDomain,
  695.             [MarshalAs(UnmanagedType.U4)]
  696. uint iDomainMaxChars
  697.             );
  698.     }
  699.     #endregion
  700. }