{"id":5483,"date":"2004-07-28T11:50:00","date_gmt":"2004-07-28T11:50:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/buckh\/2004\/07\/28\/authentication-in-web-services-with-httpwebrequest\/"},"modified":"2004-07-28T11:50:00","modified_gmt":"2004-07-28T11:50:00","slug":"authentication-in-web-services-with-httpwebrequest","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/buckh\/authentication-in-web-services-with-httpwebrequest\/","title":{"rendered":"Authentication in web services with HttpWebRequest"},"content":{"rendered":"<p><P>Hatteras has three tiers: client, middle, and data.&nbsp; The middle tier is an ASP.NET web service on a Windows 2003 Server running IIS 6.&nbsp; When the client (we use C# for both it and the middle tier) connects to the middle tier, it must authenticate with IIS 6.&nbsp; Depending upon the IIS configuration, that may be negotiate, NTLM, Kerberos, basic, or digest authentication.&nbsp; Here&#8217;s a page on <A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/47zhdx9d.aspx\">Internet Authentication<\/A> in .NET.<\/P>\n<P>NOTE:&nbsp; The code below uses the .NET 2.0 framework (Visual Studio 2005).<\/P>\n<P>In order to authenticate, the client must have credentials that the server recognizes as valid.&nbsp; For Windows Integrated Authentication (comprising NTLM and Kerberos) using the current logged-on user, the client can use <A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/system.net.credentialcache.defaultcredentials(VS.80).aspx\">CredentialCache.DefaultCredentials<\/A>.&nbsp; Here&#8217;s how it looks in code.<\/P>\n<BLOCKQUOTE><PRE>using System;\nusing System.IO;\nusing System.Net;<\/p>\n<p>class Creds\n{\n    public static void Main(string[] args)\n    {\n        Uri uri = new Uri(args[0]);<\/p>\n<p>        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);\n        req.Credentials = CredentialCache.DefaultCredentials;<\/p>\n<p>        \/\/ Get the response.\n        using (HttpWebResponse res = (HttpWebResponse)req.GetResponse())\n        {\n            StreamReader sr = new StreamReader(res.GetResponseStream());\n            Console.WriteLine(sr.ReadToEnd());\n        }\n    }\n}<\/PRE><\/BLOCKQUOTE>\n<P>You can find that same type of sample code in MSDN.&nbsp; However, it gets more interesting if you want to use basic or digest authentication or use credentials other than the current logged-on user.<\/P>\n<P>One interesting fact is that the HttpWebRequest.Credentials property is of type ICredentials, but it only uses instances of NetworkCredential and CredentialCache.&nbsp; If you implement ICredentials on your own class that is not one of those two classes, you can assign it to the Credentials property, but HttpWebRequest will silently ignore it.<\/P>\n<P>To go further, we need to look at the <A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/system.net.credentialcache(VS.80).aspx\">CredentialCache<\/A> class itself.&nbsp; This class is used to hold a set of credentials that are associated with hosts and authentication types.&nbsp; It has two static properties, one of which we used above, that are the &#8220;authentication credentials for the current security context in which the application is running,&#8221; which means the logged-on user in our case.<\/P>\n<UL>\n<LI><A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/system.net.icredentials(VS.80).aspx\">ICrendentials<\/A> DefaultCredentials \n<LI><A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/system.net.networkcredential(VS.80).aspx\">NetworkCredential<\/A> DefaultNetworkCredentials<\/LI><\/UL>\n<P>The difference is very subtle.&nbsp; The documentation for DefaultCredentials says, &#8220;The <B>ICredentials<\/B> instance returned by <B>DefaultCredentials<\/B> cannot be used to view the user name, password, or domain of the current security context.&#8221;&nbsp; The instance returned by DefaultNetworkCredentials, being new in .NET 2.0 and of type NetworkCredential, would presumably let you get the user name and domain, but it didn&#8217;t work for me when I tried it with the following code (UserName returned an empty string).<\/P>\n<BLOCKQUOTE><PRE>Console.WriteLine(&#8220;User name: &#8221; + CredentialCache.DefaultNetworkCredentials.UserName);<\/PRE><\/BLOCKQUOTE>\n<P>The NetworkCredential class implements both the ICredentials (<FONT face=\"Courier New\" size=\"2\">NetworkCredential GetCredential(Uri uri, String authType)<\/FONT>) and <A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/system.net.icredentialsbyhost(VS.80).aspx\">ICredentialsByHost<\/A> (<FONT face=\"Courier New\" size=\"2\">NetworkCredential GetCredential(String host, int port, String authType)<\/FONT>) interfaces.&nbsp; The ICredentialsByHost interface is new in .NET 2.0.<\/P>\n<P>The CredentialCache class has methods that let you add, get, and remove credentials for particular hosts and authentication types.&nbsp; Using this class, we can manually construct what setting <FONT face=\"Courier New\" size=\"2\">req.Credentials = CredentialCache.DefaultCredentials<\/FONT> accomplished in the original example.<\/P>\n<BLOCKQUOTE><PRE>        CredentialCache credCache = new CredentialCache();\n        credCache.Add(new Uri(&#8220;http:\/\/localhost&#8221;), &#8220;Negotiate&#8221;,\n                      CredentialCache.DefaultNetworkCredentials);\n        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);\n        req.Credentials = credCache;<\/PRE><\/BLOCKQUOTE>\n<P>The authentication type can also be explicitly specified as &#8220;NTLM&#8221; and &#8220;Kerberos&#8221; in separate calls to <FONT face=\"Courier New\" size=\"2\">Add()<\/FONT>.&nbsp; This page on <A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/system.net.authenticationschemes(VS.80).aspx\">authentication schemes<\/A> explains using Negotiate as follows.<\/P>\n<BLOCKQUOTE>\n<P>Negotiates with the client to determine the authentication scheme. If both client and server support Kerberos, it is used; otherwise NTLM is used.<\/P><\/BLOCKQUOTE>\n<P>Let&#8217;s say you want to work with basic or digest authentication.&nbsp; The documentation for CredentialsCache.DefaultCredentials and CredentialsCache.DefaultNetworkCredential says that neither will work with basic or digest.&nbsp; If we add basic to credentials cache, we get a runtime exception.<\/P>\n<BLOCKQUOTE><PRE>        credCache.Add(new Uri(&#8220;http:\/\/localhost&#8221;), &#8220;Basic&#8221;,\n                      CredentialCache.DefaultNetworkCredentials);<\/PRE><\/BLOCKQUOTE>\n<P>The exception is thrown by the <FONT face=\"Courier New\" size=\"2\">Add()<\/FONT> method.<\/P>\n<BLOCKQUOTE><PRE>Unhandled Exception: System.ArgumentException: Default credentials cannot be supplied for the Basic authentication scheme.\nParameter name: authType\nat System.Net.CredentialCache.Add(Uri uriPrefix, String authType, NetworkCredential cred)<\/PRE><\/BLOCKQUOTE>\n<P>So, in order to use basic or digest, we must create a NetworkCredential object, which is also what we need to do in order to authenticate as some identity other than the logged-on user.&nbsp; To do that, we create NetworkCredential object and add it to the CredentialCache as follows.<\/P>\n<BLOCKQUOTE><PRE>        credCache.Add(new Uri(&#8220;http:\/\/localhost&#8221;), &#8220;Basic&#8221; \/* or &#8220;Digest&#8221; *\/,\n                      new NetworkCredential(&#8220;me&#8221;, &#8220;foo&#8221;, &#8220;DOMAIN&#8221;));<\/PRE><\/BLOCKQUOTE>\n<P>Basic authentication sends the password across the wire in plain text.&nbsp; That&#8217;s okay for a secure connection, such as one using SSL, and for situations where you don&#8217;t need much security.&nbsp; Digest authentication hashes the password along with other data from the server before sending a response over the wire.&nbsp; It&#8217;s a significant step up from basic.<\/P>\n<P>Now we need to have the user name and password to create the NetworkCredential object.&nbsp; There are two parts to this.&nbsp; First is prompting the user for the name and password.&nbsp; The second is storing the information.&nbsp; For prompting there is the Windows dialog that pops up any time you go to a web site that requires authentication.&nbsp; That dialog includes a &#8220;Remember my password&#8221; checkbox.&nbsp; I don&#8217;t yet know what the managed API is for that.<\/P>\n<P>To store and retrieve the information, there is the new managed DPAPI explained by <A HREF=\"\/shawnfa\/\">Shawn Farkas<\/A> in several blog postings.<\/P>\n<UL>\n<LI><A id=\"ArchiveMonth.ascx_Days_Entries__ctl5_TitleUrl\" href=\"\/shawnfa\/archive\/2004\/05\/05\/126825.aspx\">Managed DPAPI Part I: ProtectedData<\/A> talks about persisting information securely using the new <A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/2c64xe0y(VS.80).aspx\">ProtectedData class<\/A> \n<LI><A id=\"ArchiveMonth.ascx_Days_Entries__ctl4_TitleUrl\" href=\"\/shawnfa\/archive\/2004\/05\/17\/133650.aspx\">Managed DPAPI Part II: ProtectedMemory<\/A> talks about storing information in RAM securely using the new <A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/system.security.cryptography.protectedmemory(VS.80).aspx\">ProtectedMemory class<\/A> \n<LI><A id=\"ArchiveMonth.ascx_Days_Entries__ctl1_TitleUrl\" href=\"\/shawnfa\/archive\/2004\/05\/27\/143254.aspx\">Making Strings More Secure<\/A> talks about the new <A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/7kt014s1(VS.80).aspx\">SecureString<\/A> class that makes use of ProtectedMemory<\/LI><\/UL>\n<P>[Update 3:44pm]&nbsp; The Windows dialog used when IE prompts for name and password is created by the <A href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/secauthn\/security\/creduipromptforcredentials.asp?frame=true\">CredUIPromptForCredentials<\/A>() function.&nbsp; <A href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/secauthn\/security\/creduiconfirmcredentials.asp?frame=true\">CredUIConfirmCredentials<\/A>() is used to save credentials that authenticated successfully, if desired.&nbsp; Duncan Mackenzie&#8217;s MSDN article <A href=\"http:\/\/msdn.microsoft.com\/vstudio\/using\/building\/windows\/default.aspx?pull=\/library\/en-us\/dnnetsec\/html\/dpapiusercredentials.asp\">Using Credential Management in Windows XP and Windows Server 2003<\/A>&nbsp;explains how to use it from .NET.<\/P>\n<P>[UPDATE 4\/10\/2006]&nbsp; I updated the MSDN links that were broken.<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hatteras has three tiers: client, middle, and data.&nbsp; The middle tier is an ASP.NET web service on a Windows 2003 Server running IIS 6.&nbsp; When the client (we use C# for both it and the middle tier) connects to the middle tier, it must authenticate with IIS 6.&nbsp; Depending upon the IIS configuration, that may [&hellip;]<\/p>\n","protected":false},"author":94,"featured_media":10268,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[2],"class_list":["post-5483","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-c"],"acf":[],"blog_post_summary":"<p>Hatteras has three tiers: client, middle, and data.&nbsp; The middle tier is an ASP.NET web service on a Windows 2003 Server running IIS 6.&nbsp; When the client (we use C# for both it and the middle tier) connects to the middle tier, it must authenticate with IIS 6.&nbsp; Depending upon the IIS configuration, that may [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/posts\/5483","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/users\/94"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/comments?post=5483"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/posts\/5483\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/media\/10268"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/media?parent=5483"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/categories?post=5483"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/tags?post=5483"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}