<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dev @ Work &#187; WCF</title>
	<atom:link href="http://www.devatwork.nl/tag/wcf/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.devatwork.nl</link>
	<description>A day in the life of a developer</description>
	<lastBuildDate>Tue, 18 Oct 2011 16:32:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>WCF Username Authentication</title>
		<link>http://www.devatwork.nl/2007/05/wcf-username-authentication/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=wcf-username-authentication</link>
		<comments>http://www.devatwork.nl/2007/05/wcf-username-authentication/#comments</comments>
		<pubDate>Thu, 31 May 2007 12:26:55 +0000</pubDate>
		<dc:creator>Trilobyte</dc:creator>
				<category><![CDATA[.NET Framework]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[WCF]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/index.php/2007/05/31/wcf-username-authentication/</guid>
		<description><![CDATA[In this post I will explain how you can build an Windows Communication Foundation web service and client which use a Username and Password combination to authenticate a user.]]></description>
			<content:encoded><![CDATA[<p>In this post I will explain how you can build an Windows Communication Foundation web service and client which use a Username and Password combination to authenticate a user. The most difficult action is to create a X509 certificate which is used to encrypt messages passed back and forward to the server.</p>
<p>In this application we will use WCF’s wsHttpBinding and message level security provided by an X509 certificate. The X509 certificate encryption is required by WCF because the client credentials (username/password) are passed as clear text in the SOAP message.</p>
<p>There is one problem that we will face during this series of posts. WCF is reluctant to accept a test certificate, it requires a lot of extra work to get it done. However once you understand the steps that you need to take, you will find it an repetitive but easy task.</p>
<p>I hope you find this post useful. If you have any questions or comments, feel free to post them as reactions on this post. Enjoy!</p>
<p><span id="more-25"></span></p>
<h2>Generating a Certificate</h2>
<p>The first step is to create a test X509 certificate, which is used to encrypt the messages. The certificate will be placed in the ‘My’ folder on the ‘Local Machine’ store under the name ‘MyServerCert’.</p>
<p>To generate the necessary certificate, execute the following command in the windows SDK command line utility:</p>
<pre class="brush: bash; title: ; notranslate">makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=MyServerCert -sky exchange –pe</pre>
<p><strong>Warning</strong>: This certificate should be used for testing purposes only.</p>
<h2>Setting Up the Service</h2>
<p>There are several steps we need to perform on the service, to force it to use username/password validation.</p>
<p>The first step is to implement the validator class which takes the username/password combination and ensures they are correct. First make sure you reference the System.IdentityModel assembly, next create a new class and derive it from System.IdentityModel.Selectors.UserNamePasswordValidator. Now override the Validate function derived from UserNamePasswordValidator.</p>
<p>Now you can write code that checks if the username/password combination is valid, if the combination is not valid throw a System.IdentityModel.Tokens.SecurityTokenException.</p>
<p>Here is my implementation:</p>
<pre class="brush: csharp; title: ; notranslate">public class UsernameValidator: UserNamePasswordValidator
{
public override void Validate(string userName, string password)
	{
		// validate arguments
		if (string.IsNullOrEmpty(userName))
			throw new ArgumentNullException(&quot;userName&quot;);
		if (string.IsNullOrEmpty(password))
			throw new ArgumentNullException(&quot;password&quot;);

		// check if the user is not test
		if (userName != &quot;test&quot; || password != &quot;test&quot;)
			throw new SecurityTokenException(&quot;Unknown username or password&quot;);
	}
}</pre>
<p>The next step is to configure the service to use our custom validator and enforce the username/password client credentials.</p>
<p>First create a new binding with the following configuration:</p>
<pre class="brush: xml; title: ; notranslate">&lt;bindings&gt;
&lt;wshttpbinding&gt;
		&lt;binding name=&quot;mySecureBinding&quot;&gt;
			&lt;security mode=&quot;Message&quot;&gt;
				&lt;message clientCredentialType=&quot;UserName&quot; /&gt;
			&lt;/security&gt;
		&lt;/binding&gt;
	&lt;/wshttpbinding&gt;
&lt;/bindings&gt;</pre>
<p>Notice that the binding enforces message level security and the client has to provide the UserName credentials.</p>
<p>Now that the binding is ready we need to define some behaviour for the service endpoint:</p>
<pre class="brush: xml; title: ; notranslate">&lt;behaviors&gt;
&lt;servicebehaviors&gt;
		&lt;behavior name=&quot;defaultProfile&quot;&gt;
			&lt;servicecredentials&gt;
				&lt;servicecertificate findValue=&quot;MyServerCert&quot; x509FindType=&quot;FindBySubjectName&quot; storeLocation=&quot;LocalMachine&quot; storeName=&quot;My&quot; /&gt;
				&lt;usernameauthentication userNamePasswordValidationMode=&quot;Custom&quot; customUserNamePasswordValidatorType=&quot;Premotion.Services.UsernameValidator, App_Code&quot; /&gt;
			&lt;/servicecredentials&gt;
		&lt;/behavior&gt;
	&lt;/servicebehaviors&gt;
&lt;/behaviors&gt;</pre>
<p>There are two interesting elements in this section: serviceCertificate and userNameAuthentication. The first specifies the certificate which the service uses to encrypt and decrypt the messages. The second element specifies our custom validator.</p>
<p>Now make sure all your endpoints use the correct binding and behaviour. That’s all for the server!</p>
<h2>Modifying the Client</h2>
<p>Modifying the client could have been an easy task, if we had accesses to a valid certificate. WCF will not accept the test certificate without a bunch of tricks. First I will pretend the service certificate is valid, then I will explain how to get WCF to accept the test certificate.</p>
<p>The first step is to create a new binding in the application configuration:</p>
<pre class="brush: xml; title: ; notranslate">&lt;bindings&gt;
&lt;wshttpbinding&gt;
		&lt;binding name=&quot;mySecureBinding&quot;&gt;
			&lt;security mode=&quot;Message&quot;&gt;
				&lt;message clientCredentialType=&quot;UserName&quot; /&gt;
			&lt;/security&gt;
		&lt;/binding&gt;
	&lt;/wshttpbinding&gt;
&lt;/bindings&gt;</pre>
<p>This exactly the same binding as we configured the service with.</p>
<p>The next is to set the username/password credentials in code. The following code should be placed next to the code which instantiates the service client:</p>
<pre class="brush: csharp; title: ; notranslate">base.ClientCredentials.UserName.UserName	= &quot;test&quot;;
base.ClientCredentials.UserName.Password	= &quot;test&quot;;</pre>
<p>That is all. If you have a valid certificate you can run the code, if you have the test certificate perform the steps below to get the code running.</p>
<h2>Bypass Certificate Validation</h2>
<p>First make sure you reference the System.IdentityModel assembly. The first step is to create a class which validates the certificates and derive it from System.IdentityModel.Selectors.X509CertificateValidator. Override the Validate method. You can leave the implementation empty if you want all the certificates to pass. If you detect a wrong certificate you can throw a System.IdentityModel.Tokens.SecurityTokenValidationException.</p>
<p>Here is my implementation:</p>
<pre class="brush: csharp; title: ; notranslate">public class MyX509Validator: X509CertificateValidator
{
	public override void Validate(X509Certificate2 certificate)
	{
		// validate argument
		if (certificate == null)
			throw new ArgumentNullException(&quot;certificate&quot;);

		// check if the name of the certifcate matches
		if (certificate.SubjectName.Name != &quot;CN=MyServerCert&quot;)
			throw new SecurityTokenValidationException(&quot;Certificated was not issued by thrusted issuer&quot;);
	}
}</pre>
<p>The next step is to create a new endpoint behaviour, which tells WCF to use our custom certificate validator:</p>
<pre class="brush: xml; title: ; notranslate">&lt;behaviors&gt;
&lt;endpointbehaviors&gt;
		&lt;behavior name=&quot;myClientBehavior&quot;&gt;
			&lt;clientcredentials&gt;
				&lt;servicecertificate&gt;
					&lt;authentication certificateValidationMode=&quot;Custom&quot; customCertificateValidatorType=&quot;Premotion.Services.MyX509Validator,client&quot; /&gt;
				&lt;/servicecertificate&gt;
			&lt;/clientcredentials&gt;
		&lt;/behavior&gt;
	&lt;/endpointbehaviors&gt;
&lt;/behaviors&gt;</pre>
<p>The last step is to set the DNS identity for the endpoint:</p>
<pre class="brush: xml; title: ; notranslate">&lt;client&gt;
	&lt;endpoint address=&quot;http://localhost:1494/services/coreservice.svc&quot; binding=&quot;wsHttpBinding&quot; bindingConfiguration=&quot;mySecureBinding&quot; contract=&quot;Premotion.Services.ICoreServiceClientContact&quot; name=&quot;CoreService&quot; behaviorConfiguration=&quot;myClientBehavior&quot;&gt;
		&lt;identity&gt;
			&lt;dns value=&quot;MyServerCert&quot;/&gt;
		&lt;/identity&gt;
	&lt;/endpoint&gt;
&lt;/client&gt;</pre>
<p>Now everything is finished and you can execute the code.</p>
<p>You can download the sample by clicking <a href="http://www.devatwork.nl/wp-content/uploads/wcfusername.zip">here</a>, make sure you create the certificate manually! I hope you gained some insight on how WCF works with username/password authentication. Thank you for reading, if you have any questions or comments post them.</p>

	Tags: <a href="http://www.devatwork.nl/tag/wcf/" title="WCF" rel="tag">WCF</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2007/05/wcf-username-authentication/feed/</wfw:commentRss>
		<slash:comments>74</slash:comments>
		</item>
	</channel>
</rss>

