Programming
Get Localized Month Names in .NET
[Test]
public void Junk()
{
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo(“da-DK”);
string[] localizedMonths = System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.MonthNames;
string[] invariantMonths = System.Globalization.DateTimeFormatInfo.InvariantInfo.MonthNames;
System.Console.Out.WriteLine(“Current Culture is ” + System.Globalization.CultureInfo.CurrentCulture.EnglishName);
for (int month = 0; month < 12; month++)
{
System.Console.Out.WriteLine(localizedMonths[month]);
System.Console.Out.WriteLine(invariantMonths[month]);
}
}
Rhino Mocks Callbacks
Rhino Mocks Callbacks are what I have been trying to find for 2 days!
My problem is that I needed to test the internals of a method by checking to see that a value had been evaluated properly. The result of this operation gets passed to my DAL to be inserted into my DB. My test was to test my Business Layer so I needed to mock the DAL to prevent the DB hit from occurring. The problem was, how could I grab the value from inside my BL method?
With Rhino Mocks, I mocked my DAL and recoreded an Expect on the method that does the DB insert. Now all I needed to do was to replace the default implementation of my DAL method with one used for testing. The internals of the testing method would be able to read the params being passed to the DAL from the BL, thus allowing me to verify that the BL evaluated what it was supposed to properly before passing the data on to be inserted.
Rhino Mocks Callbacks to the rescue! I love the power of delegates, unfortunately it’s still the largest concept that repeatedly trips me up. After locating this post on using Rhino Mocks Callbacks, I was finally able to accomplish my goal.
The application in the example below is a WCF service which accepts TFS Notification messages when a WorkItem changes. When I recieve the notification from TFS, I am logging the message in a log table. One of the params that is sent from TFS contains the publisher’s url in an XML string. My BL needs to select the value of the attribute containing this url and insert it into a column in my table. Thus, what I wanted to test was that my xpath is correct (and if TFS changes something in subsequent versions I’ll know immediately that they changed an expected format).
WCF Method to receive the TFS notification:
public void Notify(string eventXml, string tfsIdentityXml, SubscriptionInfo subscriptionInfo)
{
XmlDocument eventXmlDoc = new XmlDocument();
XmlDocument tfsIdentityXmlDoc = new XmlDocument();
try
{
eventXmlDoc.LoadXml(eventXml);
tfsIdentityXmlDoc.LoadXml(tfsIdentityXml);
TfsNotificationDto tfsNotificationDto = new TfsNotificationDto
{
Message = eventXml,
Date = DateTime.Now,
Publisher = tfsIdentityXmlDoc.SelectSingleNode("TeamFoundationServer").Attributes["url"].Value,
Subscriber = "",
Success = 'F'
};
this._repo.LogTfsNotification(tfsNotificationDto);
}
catch (Exception)
{
throw;
}
}
Test method utilizing Rhino Mocks to mock the DAL:
[Test]
public void TestLogTfsNotification()
{
string pub = string.Empty;
With.Mocks(delegate
{
IRepository repo = Mocker.Current.StrictMock<IRepository>();
TfsNotificationDto tfsNotificationDto = RepositoryTests.MockTfsNotificationDto;
Expect.Call(() => repo.LogTfsNotification(tfsNotificationDto)).Callback(new Delegates.Function<bool, TfsNotificationDto>(notification => { pub = notification.Publisher; return true;}));
Mocker.Current.ReplayAll();
ITfsEventService service = new TfsEventService(repo);
service.Notify(eventXml, tfsIdentityXml, subscriptionInfo);
});
Assert.AreEqual(this.publisher, pub);
}
What I can now do is in the LogTfsNotification method of the mocked repo, I can now read the parameter passed to it from the service.Notify method. Service.Notify is extracting the subscriber url and packages it up into a TfsNoficationDto that is passed to LogTfsNotification. Thus I can do notification.Publisher to see what value was extracted from the xml in the service object of my BL.
.NET RSA Encryption Class
The following class is the class I created to RSA encrypt database passwords. The implementation is a case study of need for this at a former client.
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Xml;
namespace Utility
{
public class RSAEncryption
{
private XmlDocument publicKey = null;
private XmlDocument privateKey = null;
private System.Security.Cryptography.RSACryptoServiceProvider rsa;
public RSAEncryption(XmlDocument publicKey) : this(publicKey, null)
{
;
}
public RSAEncryption(XmlDocument publicKey, XmlDocument privateKey)
{
this.publicKey = publicKey;
this.privateKey = privateKey;
RSACryptoServiceProvider.UseMachineKeyStore = true;
this.rsa = new RSACryptoServiceProvider();
}
public string EncryptData(string data2Encrypt)
{
byte[] cipherbytes = null;
try
{
rsa.FromXmlString(this.publicKey.OuterXml);
byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
cipherbytes = rsa.Encrypt(plainbytes, false);
}
catch (Exception ex)
{
Logger.LogException(ex, this);
throw ex;
}
return Convert.ToBase64String(cipherbytes);
}
public string DecryptData(string data2Decrypt)
{
byte[] plain = null;
try
{
byte[] getpassword = Convert.FromBase64String(data2Decrypt);
rsa.FromXmlString(this.privateKey.OuterXml);
plain = rsa.Decrypt(getpassword, false);
}
catch (Exception ex)
{
Logger.LogException(ex, this);
throw ex;
}
return System.Text.Encoding.UTF8.GetString(plain);
}
public static void CreateNewKeys(string publicKeyPath, string privateKeyPath)
{
try
{
Logger.LogInfo("Creating new keys", new object());
Logger.LogInfo("Creating RSA Crypto Service Provider", new object());
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
Logger.LogInfo(string.Format("Deleting private key: {0}", privateKeyPath), new object());
if (File.Exists(privateKeyPath)) File.Delete(privateKeyPath);
XmlDocument publicPrivateKeyXML = new XmlDocument();
publicPrivateKeyXML.LoadXml(rsa.ToXmlString(true));
Logger.LogInfo(string.Format("Creating private key: {0}", privateKeyPath), new object());
publicPrivateKeyXML.Save(privateKeyPath);
Logger.LogInfo(String.Format("Deleting public key: {0}", publicKeyPath), new object());
if (File.Exists(publicKeyPath)) File.Delete(publicKeyPath);
XmlDocument publicOnlyKeyXML = new XmlDocument();
publicOnlyKeyXML.LoadXml(rsa.ToXmlString(false));
Logger.LogInfo(String.Format("Creating public key: {0}", publicKeyPath), new object());
publicOnlyKeyXML.Save(publicKeyPath);
}
catch (Exception ex)
{
Logger.LogException(ex, new object());
throw ex;
}
}
}
}
This class is designed to use public & private key pairs that are stored on a file system in xml using RSA encryption. The production implementation of this is for decrypting database passwords at runtime in a web application. My database connection strings are stored in the web.config for the application and the passwords are embedded in these connection strings. Normally these passwords could be stored in clear on the server since no one other than the administrator can access the box. However, this thought fell apart once we put in an application to schedule releases. This application allowed us to schedule when a release was happening, what date, who it affects, etc. The other thing the application allowed for was the attachment of the change to go into production. This application release schedule is an internal application and since all the code is compiled, placing the code changes in this list was great for our needs because it tied the code change directly to the request so that if we had a historical question about anything we could always look back in the application release schedule.
The one problem with this though had to do with the connection strings. In many cases the release would cause a change to the web.config. Since this web.config has production database passwords, we didn’t want to attach it to the request in clear, as it was the one glaring item that someone who wished to be malicious could do something with. So our solution was to encrypt the password. We could have encrypted the whole connection string, but personally I like to be able to see information about the connection in clear as it makes for easier debugging in my opinion. Plus, if the user doesn’t have the password they can’t do too much with the other information.
Thus was born the class listing above. This class is a generic RSA Encryption class that can generate a new public/private key pair to xml stored on the file system and can encrypt and decrypt from keys passed to it retrieved from the file system (or anywhere else for that matter). I chose to use RSA encryption for a couple of reasons. One is that since the password is stored and retrieved from the web.config, a one way hash wouldn’t do much for us. I could have used a symmetric key algorithm, but then all of the developers would have to have access to the one key that would encrypt and decrypt the password. RSA, or any asymmetric algorithm, allowed me to give the developers a key to encrypt with while protecting the one key that can decrypt.
I keep referring to the keys being stored on the file system because the production implementation works like this…
We generate the public/private key pair to be used in production. One trusted developer or an admin has permissions to do this (I created a utility to generate the key/pairs so a non-programmer can be assigned the task of managing the keys). Once the keys are generated, the public key is stored in source control. This way all the developers have access to the public key for encrypting passwords to go into a connection string. The admin then takes the private key and installs it to a secure directory on the server that the application user account has access to. So at this point, the public key is…erm…public, and the private key is secured so that only the server admin and the application user have access. What this does is minimize who can decrypt a password. Sure anyone could encrypt and insert a new password and that password would be decryped properly at runtime, it’s pretty much useless unless that change has been done on the database as well. In the scenario presented in this post, one developer will have permissions to modify the database password, thus this individual is responsible for encrypting the password. With this policy in place, no one other than this point person knows the production db password, and that’s the way I want it. Getting back to the decryption part, we have stored the private key in a secure directory that the application user has access to. At runtime, when the database connection is created, the application is configured to pull the private key from this secure directory, pass it into the above listed class so that the decrypt method can be called. Since all of this is happening in memory, there should be no easy way for an attacker to view the password in clear.
As for how this works in development, the developer can pretty much do whatever he wants regarding this. The data access layer can still work just fine with non-encrypted strings, so in development the programmer can enter whatever the password is for his local database. The encryption utility is also stored in source control so any developer can create his own custom keys and use those to encrypt/decrypt in his local environment. Everyone just needs to be sure that the production config always go out the door with its password encrypted using the production public key.
For more information on RSA Encryption in .NET, here are some good references:
http://www.codeproject.com/KB/security/SimpleEncryption.aspx
Regular Expression for Locating a Password in a Connection String
I used this RegEx to locate an encrypted password in a connection string. I wrote a utility that would allow for the encryption of a password string so that the clear text password could be replaced by the encrypted string in the config. I did this because I didn’t want the whole string encrypted, just the password. Thus at runtime the logic needed to retrieve the connection string from the config, find the password value and run it through the decryption algorithm. This is the explanation for the RegEx I used to accomplish this.
string passwordGroup = "pwd"; string searchExpression = "(?i)password=(?<" + passwordGroup + @">[0-9a-zA-Z\+/=]+)";
Example strings that this expression will be run against are :
<add name="AConnectionString" connectionString="Provider=OraOLEDB.Oracle;Data Source=XE; User ID=uid0; Password=AcQtF5W9CGmph8NxtPVfyPnDBxrmHU=;OLEDB.NET=true;Unicode=True" />
<add name="DBConnName" connectionString="packet size=4096;user id=uid0;data source=SERVER01;persist security info=True;initial catalog=catalogName;password=IkX+129i/iUshSJc0O3rCxHKz2lv6+mRNe91vIw=" />
(?i) - This is a modifier affecting how the remainder of the string is processed.
(?x) - this syntax indicates that this is a modifier. The x will be replaced with an appropriate set of modifiers. In my case those are i, s, & m.
i - turns on case insensitivity for the remainder of the string.
password= - Represents a literal string. I am using this string to find the position at which to start the regex match for the password value I am searching for. In this case the expression will begin matching at the p in password.
(?<” + passwordGroup + @”>[0-9a-zA-Z\+/=]+) - boils down to (?<pwd>[0-9a-zA-Z\+/=]+). Let’s take a look at the first part of this expression:
(?<>) - This is the .NET syntax for creating a named group. Groups are organizational structures used to pluck particular search strings out of a larger string. By default regex engines will sequentially number the groups starting at 0. In my case, I want to give my group a specific name for retrieval from the match, thus this syntax. In my expression the “pwd” string represents the name for my matching group. The contents of the matched group will be the string returned by the evaluation of the expression inside the parenthesis.
[0-9a-zA-Z\+/=]+ - matches any string containing alphanumeric characters as well as matching on +, /, and =. These 3 extra characters are allowed in the set of characters the encrypted string may contain. As you can see both examples show that the password field will either end with a ” or a ;. Since neither of those two terminating characters are in the set of allowed characters, the match will end there. Thus the match will start at the “p” in password and end before either the ; or the ” at the end of the password value.
This expression will return an entire match of: password=value. From this match one group will exist which will contain only the password value.
My entire method using this expression and extracting the named group:
protected string RetrievePasswordValue(string connectionString)
{
string passwordGroup = "pwd";
string searchExpression = "(?i)password=(?<" + passwordGroup + @">[0-9a-zA-Z\+/=]+)";
try
{
Match passwordMatch = Regex.Match(connectionString, searchExpression);
return passwordMatch.Groups[passwordGroup].Value;
}
catch (Exception ex)
{
// Do something better than this exception handling, obviously
throw ex;
}
}
}
I’m no regex expert by any means, so there may be better ways to write the expression. Please leave a comment if you see a glaring problem with my expression. One thing I could probably do to it would be to add a more explicit terminator on ” or ; rather than have it end by just not being in the set of valid characters.
Here are some great links for learning and testing your regular expressions:
http://www.regular-expressions.info
http://derekslager.com/blog/posts/2007/09/a-better-dotnet-regular-expression-tester.ashx
Creating a WCF Service Reference to a Secured Service
I have a WCF service I created that is secured over HTTPS using client certificates. How I got my client talking to this service was easy, I just created a service reference using Visual Studio to my service. Simple, right? Well it was until I needed to update my reference. You see, I initially created my service reference before I secured my service. So I was talking to an unsecured service over HTTP. However, what happens when that security changes? Well, what I did was just change the URL to the secure one and everything worked fine until I needed to update the implementation of my service proxy. When you need to do that, the service reference tool in Visual Studio will no longer cut it.
The documentation provided by Microsoft will show you how to create a service reference to a secured service. The following is a reprint of the section for creating the service reference since the entire MSDN article takes you through creating the certs from the ground up. This article assumes that you already have a working service and client that are communicating with client certificates over HTTPS.
- In your service’s web.config enable your MEX endpoint:
- The first thing you should notice is that the binding configuration for both the service and the mex endpoint use the same configuration. This configuration is what specifies that these endpoints will be using certificates over HTTPS.
- Now that we have the mex endpoint setup on the service, we can start working on the client reference. Create yourself a new temp directory that you can work in to create the new service reference.
- In this dir create a new text file named svcutil.exe.config.
- Paste the following into the contents of this file:
- Modify the clientCertificate node to match the client certificate that you already have specified in your client config.
- Create the service proxy
- Copy svcutil.exe into the temp directory you are working in so that the exe will use the custom config you just created. (Copy in the exe? I know this sounds dumb, but this is what the MSDN documentation says to do. Not wanting to do this I tried to just point svcutil.exe to my new config
- Execute:
- This will create 2 files: an app.config and a service proxy (*.cs) file.
- Now you can go to your client application and remove any existing service reference that you have.
- Compare your existing client app.config to the one we just created and merge the new one into the existing one as appropriate. I can’t really tell you what to do beyond this aside from telling you to manually diff these since your implemenation may be different from mine.
- Copy the .cs file into your client project. Check the namespacing of this file. Mine didn’t wrap the service interface in the namespace properly when mine was generated.
- At this point you should be able to test your changes. You should now be executing on the new proxy we created communicating securely to your service.
svcutil https://ServerName/WCFTestService /config:app.config
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="WsBindingConfig" contract="IISServicePOC.IService1"></endpoint> <endpoint address = "mex" binding = "wsHttpBinding" bindingConfiguration="WsBindingConfig" name="mexEndpoint" contract = "IMetadataExchange"/>
<configuration> <system.serviceModel> <client> <endpoint behaviorConfiguration="ClientCertificateBehavior" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="IMetadataExchange" name="https" /> </client> <bindings> <wsHttpBinding> <binding name="Binding1"> <security mode="Transport"> <transport clientCredentialType="Certificate" /> </security> </binding> </wsHttpBinding> </bindings> <behaviors> <endpointBehaviors> <behavior name="ClientCertificateBehavior"> <clientCredentials> <clientCertificate findValue="CN=clienttempcert" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectDistinguishedName" /> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> </system.serviceModel> </configuration>
WCF Services SSL with Certificate Authentication
I figure since I beat my head against the desk trying to get this to work for half a week I figure I should probably post what I did in case I ever have to do this again. WCF security is not the most straight-forward configuration, and throwing in certificates sure doesn’t help the matter. What also doesn’t help is that I knew very little about certificates heading into this task.
Goals:
- Create a WCF Web Service who’s messages are SOAP over HTTPS utilizing certificate authentication.
- Create a client application that can communicate with a service configured for HTTPS using certificates for authentication.
Out of scope: We will not worry about authorization at this point. We just want a client to be able to communicate with the service.
Create the service:
Start by creating a standard WCF service by using the WCF Service Library project template. Let’s modify the service interface (IService1.cs) provided to expose a few methods for testing:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace WebServicePOC { // NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in App.config. [ServiceContract] public interface IService1 { [OperationContract] string GetData(int value); [OperationContract] string GetExecutingUser(); [OperationContract] CompositeType GetDataUsingDataContract(CompositeType composite); } // Use a data contract as illustrated in the sample below to add composite types to service operations [DataContract] public class CompositeType { bool boolValue = true; string stringValue = "Hello "; [DataMember] public bool BoolValue { get { return boolValue; } set { boolValue = value; } } [DataMember] public string StringValue { get { return stringValue; } set { stringValue = value; } } } }
Now let’s modify the service implementation (Service1.cs) to do something when one of the methods on the service interface is invoked:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace WebServicePOC { // NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in App.config. public class Service1 : IService1 { public string GetData(int value) { return string.Format("You entered: {0}", value); } public string GetExecutingUser() { return System.Threading.Thread.CurrentPrincipal.Identity.Name; } public CompositeType GetDataUsingDataContract(CompositeType composite) { if (composite.BoolValue) { composite.StringValue += "Suffix"; } return composite; } } }
Now we should be able to compile our basic service. If you run a debug session on your new service you should be presented with the WCF Test Client application. This app will hookup to your service and provide you with a way to test the methods in your service. Invoke your methods and make sure everything is working as designed. Right now your service is being hosted by the default WCF Service Host. For this project we eventually want to expose our service over HTTPS. We could write a custom host to do that or we could host it in IIS. My vote is IIS since it already has HTTPS support, so let’s configure the service for IIS hosting.
Configure Service for IIS Hosting:
Since Microsoft wrote all this WCF stuff we may as well check-in with them on how to get a service hosted in thier web server. Indeed they do have documentation on getting this up and running.
As for converting your service to run under IIS, at this point it would simplify things to change to an ASP.NET project template for the service since the service will be exposed over HTTP/HTTPS. To do so create a new project in your solution using the ASP.NET Web Application project template. Copy in the IService.cs and Service.cs files from the first service we created and modify the namespaces to match your new ASP.NET project namespace. Next, we need to create a file that we can use as the entry point to our service in IIS. Create a new file named Service.svc in your project and add the following line to the .svc file:
<%@ ServiceHost language=c# Debug="true" Service="IISJunkService.Service1" %>
Compile your new service, set your .svc file as the startup file, and kick-off a debug session. Hrm, according to the message…”Service ‘IISJunkService.Service1′ has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element.“…we haven’t configured an endpoint yet.
Add the following configuration to your web.config to setup an endpoint for your service:
<configuration> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="basicBindingConfig"> <security mode="None" /> </binding> </basicHttpBinding> </bindings> <services> <service behaviorConfiguration="IISJunkService.Service1Behavior" name="IISJunkService.Service1"> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicBindingConfig" contract="IISJunkService.IService1"> </endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="IISJunkService.Service1Behavior"> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" /> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
Now try again to debug your service. You should see a default page that looks like the following:
Our service is running under the Visual Studio web host, but we said we wanted it running under IIS. To do this open up the IIS Manager. Under an existing site add a new virtual directory. For the physical location of the virtual directory choose the directory that your service source is in. Set read and execute permissions on the directory. Browse to the new url and you should now see the same screen as above, only hosted on a port that IIS is providing services for.
Now that we have our service up and running in IIS, let’s create a client to communicate with the service we just created. Create a new project using the Console Application project template. Once the project has been created you can create a service reference to the url you just exposed through IIS. You will notice after you add the service reference that your client’s app.config has been modified. The addition of the service reference has added an endpoint configuration to your config. This will tell WCF on the client side exactly where and how to communicate with the service. Modify the Main() method in Program.cs to call a method on your service:
static void Main(string[] args)
{
try
{
JunkService.IService1 service = new JunkService.Service1Client();
Console.Write("GetData: ");
Console.WriteLine(service.GetData(12).ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.InnerException.Message);
}
Console.ReadLine();
}
Debug your client app. If all is right with WCF you will see the following output:
GetData: You entered: 12
SSL
Service SSL
So now we have a service hosted in IIS and we are able to talk to the service from our custom client app. Since everything is being transmitted in clear now, let’s add a layer of transport level security. This will mean that the transmission of our messages will be encrypted from prying eyes. Since we are running in IIS we can fairly easily modify the service to communicate via HTTPS.
To do so, in the IIS Manager:
- Right click on your service’s virtual directory
- Choose Properties
- Select the Directory Security tab
- Click Edit under Secure Communications
- Check Require secure channel (SSL)

Now if you try and refresh your service in a web browser you will get a 403.4 forbidden error telling you the service only communicates via HTTPS. So go ahead and change the protocol in the url to https://. You should now see the service’s default page again.
At this point you should be wondering what you have to do to get your client talking to the service again since we have changed protocols. Your first thought might be that all we need to do is change the endpoint url in the client configuration to point to the https:// location, and…you’d be wrong. At this point we need to modify the bindings in both the service and the client to make all this work in an encrypted transmission protocol scenario.
Let’s first start by modifying the service to enable transport level encryption. In your service’s web.config locate the bindingsnode. By default you will have one binding already defined as basicHttpBinding. We no longer need that binding, so you can remove it and replace it with this:
<wsHttpBinding> <binding name="WsBindingConfig"> <security mode="Transport"> <transport clientCredentialType="None"/> </security> </binding> </wsHttpBinding>
This new binding defines a more advanced http binding, one in which we can define transport level security. How does this binding know we want to communicate over HTTPS? I don’t know. Apparently it’s smart. Ultimately, the transport level security configuration within a wsHttpBinding means SSL. So just accept it. You will notice that with this binding, I have chosen to change the name of the binding. If you also change this name, then you must also change the reference to your binding in your endpoint. You may as well rename it because you need to modify the binding type in the endpoint anyways. Your new endpoint should look something like this:
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="WsBindingConfig" contract="IISJunkService.IService1">
You will notice that the bindingand bindingConfiguration attributes have been modified.
Lastly with the service we can modify the serviceMetadata nodes to enable httpsGet for discovery of our service. My node has been modified to look like this:
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
Client SSL
Now that we have our service all set to talk over SSL let’s do the same for the client. Open the client’s app.config. We will need to change the bindings and endpoints in the client configuration just like we did the server. Your new binding config should look like this:
<wsHttpBinding> <binding name="WSHttpBinding_IService1"> <security mode="Transport"> <transport clientCredentialType="None"/> </security> </binding> </wsHttpBinding>
And your endpoint will look like this:
<endpoint address="https://server/JunkService/Service.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1" contract="JunkService.IService1" name="BasicHttpBinding_IService1" />
That should be it. Give your client a compile and run it. You should see the same result as before except now it’s talking over a secure channel.
Authentication
Up to this point we have created a WCF service, created a client to use the service, and secured the service’s communication. The last step is to force the client to authenticate with the service so that any-old client can’t just talk to our precious service. Our service can be secured in a number of ways including, username/password, windows, certificates, and others. The three I called out are probably the most common ways to secure a service, each with its own drawbacks. Username/password is probably the easiest to implement, but in the context for which I am developing this service it’s not appropriate. In production the service’s client will actually be another service. Username/password would work in this scenario, except it could be problematic if we have to change the password at a future point. Windows security is nice, but not so much when working across domains. In this case someone from outside the hosted domain will be communicating with the service, eliminating this option. That leaves certificates. Certs will definitely do the job, the problem is they are one of the most complex forms of authentication to setup. However, since the other options are less appropriate, we are stuck with certs.
Enable Certs on the Service
The first thing we have to do is create ourselves some certificates. For this to work we will need at least two certs. One will be installed server-side, the other client-side. The following steps are a summary of Microsoft’s Documentation.
- Create a Root Certificate Authority to use to sign the client/server certs.
makecert -n "CN=RootCaClientTest" -r -sv RootCaClientTest.pvk RootCaClientTest.cer
This step creates a certificate named RootCaClientTest.cer and a private key file named RootCaClientTest.pvk.
- Create a Certificate Revocation List File from the Root Certificate
makecert -crl -n "CN=RootCaClientTest" -r -sv RootCaClientTest.pvk RootCaClientTest.crl
- Install Your Client Root Certificate Authority on the Client and Server Machines
Repeat the following steps on both the client and server machines:- Copy the RootCaClientTest.cer file to the client and server machines.
- Click Start and then click Run.
- In the command line, type MMC and then click OK.
- In the Microsoft Management Console, on the File menu, click Add/Remove Snap-in.
- In the Add Remove Snap-in dialog box, click Add.
- In the Add Standalone Snap-in dialog box, select Certificates and then click Add.
- In the Certificates snap-in dialog box, select the Computer account radio button (because the certificate needs to be made available to all users), and then click Next.
- In the Select Computer dialog box, leave the default Local computer: (the computer this console is running on) selected and then click Finish.
- In the Add Standalone Snap-in dialog box, click Close.
- In the Add/Remove Snap-in dialog box, click OK.
- In the left pane, expand the Certificates (Local Computer) node, and then expand the Trusted Root Certification Authorities folder.
- Under Trusted Root Certification Authorities, right-click the Certificatessubfolder, click All Tasks, and then click Import.
- On the Certificate Import Wizard welcome screen, click Next.
- On the File to Import screen, click Browse.
- Browse to the location of the signed root CA RootCaClientTest.cer file copied in Step 1, select the file, and then click Open.
- On the File to Import screen, click Next.
- On the Certificate Store screen, accept the default choice and then click Next.
- On the Completing the Certificate Import Wizard screen, click Finish.
- Install the Certificate Revocation List File on the Server and Client Machines
Repeat the following steps on both the client and server machines:- Copy the RootCaClientTest.crl file to the client and server machines.
- Click Start and then click Run.
- In the command line, type MMC and then click OK.
- In the Microsoft Management Console, on the File menu, click Add/Remove Snap-in.
- In the Add Remove Snap-in dialog box, click Add.
- In the Add Standalone Snap-in dialog box, select Certificates and then click Add.
- In the Certificates snap-in dialog box, select the Computer account radio button (because the certificate needs to be made available to all users), and then click Next.
- In the Select Computer dialog box, leave the default Local computer: (the computer this console is running on) selected and then click Finish.
- In the Add Standalone Snap-in dialog box, click Close.
- In the Add/Remove Snap-in dialog box, click OK.
- In the left pane, expand the Certificates (Local Computer) node, and then expand the Trusted Root Certification Authorities folder.
- Under Trusted Root Certification Authorities, right-click the Certificatessubfolder, select All Tasks, and then click Import.
- On the Certificate Import Wizard welcome screen, click Next.
- On the File to Import screen, click Browse.
- On the Files of Type screen, select Certificate Revocation List.
- Browse to the location of the signed root CA RootCaClientTest.crl file copied in Step 1, select the file, and then click Open.
- On the File to Import screen, click Next.
- On the Certificate Store screen, accept the default choice and then click Next.
- On the Completing the Certificate Import Wizard screen, click Finish.
- Create and Install Your Temporary Client Certificate
makecert -sk MyKeyName -iv RootCaClientTest.pvk -n "CN=tempClientcert" -ic RootCaClientTest.cer -sr currentuser -ss my -sky signature -pe
In this command:
- -sk specifies the key container name for the certificate. This needs to be unique for each certificate you create.
- -iv specifies the private key file from which the temporary certificate will be created. You need to specify the root certificate private key file name that was created in the previous step and make sure that it is available in the current directory. This will be used for signing the certificate and for key generation.
- -n specifies the key subject name for the temporary certificate. The convention is to prefix the subject name with “CN = ” for “Common Name”.
- -ic specifies the file containing the root CA certificate file generated in the previous step.
- -sr specifies the store location where the certificate will be installed. The default location is currentuser. For certificate authentication, this is the default location that Microsoft Internet Explorer uses for when browsing Web sites that require a client certificate.
- -ss specifies the store name for the certificate. My is the personal store location of the certificate.
- -sky specifies the key type, which could be either signature or exchange. Using signature makes the certificate capable of signing and enables certificate authentication.
- -pe specifies that the private key is generated in the certificate and installed with it in the certificate store. When you double-click the certificate on the General tab, you should see the message “You have a private key that corresponds to this certificate†displayed at the bottom. This is a requirement for certificate authentication. If the certificate does not have the corresponding private key, it cannot be used for certificate authentication.
- In the Enter Private Key Password dialog box, enter the password for the root CA private key file specified in Step 2, and then click OK.
Now that we have our certs created and installed we can require client certs on the service. In IIS go back to the Secure Communications dialog and check the Require client certificates radio button.

Now browse to your service. Since you have now required client certificates, you should be prompted to choose a certificate to send to the server. In this prompt you should see your tempClientcert that we just created.

Choose your tempClientcert and click OK. Whoops. Looks like we still have some problems. If you see the following error you are still doing alright with all this.
What this error means is that while you submitted a certificate to the service, the service isn’t configured to accept client certificates. Previously we defined a wsHttpBinding with Transport level security. That specified that we would be running under HTTPS. Contained within that binding is a transport node with an attribute of clientCredentialType. Change the value of this attribute to Certificate:
<transport clientCredentialType="Certificate"/>
Try refreshing your browser and you should see an error-free service welcome page.
Note:
One thing about server security I was confused on was the contents of the server’s config. When I was putting this together I was going through a number of resources that was telling me to put a section like the following into the server config:
<serviceCertificate
findValue=”35 84 6c 21 74 f6 69 81 4b 4d b9 b8 7d 0a 8f 2c”
storeLocation=”LocalMachine”
storeName=”My”
x509FindType=”FindBySerialNumber” />
Based on this, I thought that the server needed to specify a certificate in the same way as the client did in order to securely communicate.
During my development I was trying to gain a better understanding of what was going on with all this certificate security stuff. One thing I did was to remove the serviceCertificate node and see if the client would no longer be able to communicate with the service. To my surprise, everything still worked. So the service doesn’t need this configuration?
It turns out this does not need to be specified when running under SSL, which makes logical sense. The SSL certificate is the server’s certificate. By specifying transport security in a wsHttpBinding there is not a need for this explicit certificate definition on the server side. This Microsoft Documentation is a great resource when configuring WCF services this way.
The reason why some of the documentation and blog posts were having me define this configuration was because the examples were not communicating over SSL. Secure services configured without SSL is outside the scope of this post.
Enable Certs on the Client
If you try running your client application now you should receive a 403 error. To fix this we are going to need to modify the client app.config to instruct it to load and pass a certificate to the service.
The first thing to do is to add a new behaviors node:
<system.serviceModel> <behaviors> <endpointBehaviors> <behavior name="CustomBehavior"> <clientCredentials> <clientCertificate findValue="tempClientcert" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName" /> <serviceCertificate> <authentication certificateValidationMode="ChainTrust"/> </serviceCertificate> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> </system.serviceModel>
This node will tell the client where to load the client certificate from. In this case we are loading from the local user certificate store and looking the cert up by its x509 name.
Now that we have that node in place we need to tell our end point to use this certificate. You will notice that we have named this behavior CustomBehavior. We can use that name to add a new attribute to our endpoint. The endpoint should now look like this:
<endpoint address="https://server/JunkService/Service.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1" contract="JunkService.IService1" name="BasicHttpBinding_IService1" behaviorConfiguration="CustomBehavior" />
Lastly, we need to tell the client that we will be using Client authentication. Previously we were not using any authentication. On the transport node simply change the clientCredentialType attribute to Certificate from None.
You can now give your client a whirl and see if everything is communicating. If you see the proper result, all is well in WCF land. You can also check to make sure everything is working by hitting your service with a browser. If you see the service’s welcome page you know everything is working properly.
Machine-to-Machine
Up to this point we have everything running on a single machine, which is also the host for our service. The point of using a service is to allow client machines to communicate with the service remotely. The next steps will allow us to get another machine up and running with our client application. These next steps assume that you have found a client machine to use to test this out on. If not I’ll wait while you find one…
Ok, now that you have a client machine, make sure it can talk to your server. A simple ping test should do. Once you have the machines talking, using a browser, browse to the service from the client machine. If everything is configured properly, at this point you will recieve a 403 error with the message The page requires a client certificate. This error is good. It indicates we need to give the browser a certificate to authenticate with.
At this point, jump back to your server. We need to use the Certificate Authority we created to create a client cert we can give to the client. The last step we took while creating the certificate authority, revocation list, and cert was to create the cert. We can now export that cert and install it on our remote machine.
Jump back to the mmc console that you were using to create your certificate authority. If you browse to Certificates – Current Owner\Personal\Certificatesyou should see the certificate you created named tempClientcert (if not hit F5 to refresh). Right click on this certificate and choose All Tasks > Export. Walk through the wizard and select Yes, export the private key when asked. The rest of the defaults should be fine. You can then name your export file with a .pfx extension.
Once you cert has been exported get it moved over to your client machine. One other thing you also need to have installed on the client machine is the Certificate Authority we created. During this process you created a file named RootCaClientTest.cer. Move this file over to the client machine as well. Once both of these files are there, Import the Certificate Authority into the machine’s certificate store:
- Click Start and then click Run.
- In the command line, type MMC and then click OK.
- In the Microsoft Management Console, on the File menu, click Add/Remove Snap-in.
- In the Add Remove Snap-in dialog box, click Add.
- In the Add Standalone Snap-in dialog box, select Certificates and then click Add.
- In the Select Computer dialog box, leave the default Local computer: (the computer this console is running on) selected and then click Finish.
- In the Add Standalone Snap-in dialog box, click Close.
- In the Add/Remove Snap-in dialog box, click OK.
- In the left pane, expand the Certificates (Local Computer) node, and then expand the Trusted Root Certification Authorities folder.
- Under Trusted Root Certification Authorities, right-click the Certificatessubfolder, click All Tasks, and then click Import.
- On the Certificate Import Wizard welcome screen, click Next.
- On the File to Import screen, click Browse.
- Browse to the location of the signed root CA RootCaClientTest.cer file copied in Step 1, select the file, and then click Open.
- On the File to Import screen, click Next.
- On the Certificate Store screen, accept the default choice and then click Next.
- On the Completing the Certificate Import Wizard screen, click Finish.
Now you can import the certificate. The easiest way to import the certificate into the client machine’s certificate store is to:
- Open Internet Explorer
- Choose Tools > Internet Options
- Select the Content tab
- Click the Certificates button.
- Click the Import button
- Choose the .pfx file that you just created
- Once you finish with the wizard, click the Clear SSL state button under the Content tab
Now if you try to access your service via a web browser (keeping your fingers crossed) you should see the service welcome page. Once you see your service welcome page you can move your client application to the client machine and give it a try. Just make sure to check your settings to be sure you are not pointing to localhost for your service reference, but to the proper machine name.
You have now created a service with transport security that uses certificate authentication and a client that communicates with your service. You may now take a break for milk and cookies. You deserve it!
Repeat the following steps on both the client and server machines:
- Copy the RootCaClientTest.cer file to the client and server machines.
- Click Start and then click Run.
- In the command line, type MMC and then click OK.
- In the Microsoft Management Console, on the File menu, click Add/Remove Snap-in.
- In the Add Remove Snap-in dialog box, click Add.
- In the Add Standalone Snap-in dialog box, select Certificates and then click Add.
- In the Certificates snap-in dialog box, select the Computer account radio button (because the certificate needs to be made available to all users), and then click Next.
- In the Select Computer dialog box, leave the default Local computer: (the computer this console is running on) selected and then click Finish.
- In the Add Standalone Snap-in dialog box, click Close.
- In the Add/Remove Snap-in dialog box, click OK.
- In the left pane, expand the Certificates (Local Computer) node, and then expand the Trusted Root Certification Authorities folder.
- Under Trusted Root Certification Authorities, right-click the Certificatessubfolder, click All Tasks, and then click Import.
- On the Certificate Import Wizard welcome screen, click Next.
- On the File to Import screen, click Browse.
- Browse to the location of the signed root CA RootCaClientTest.cer file copied in Step 1, select the file, and then click Open.
- On the File to Import screen, click Next.
- On the Certificate Store screen, accept the default choice and then click Next.
- On the Completing the Certificate Import Wizard screen, click Finish.
Post Build Copy
I always forget the xcopy syntax for my post build steps.
xcopy /Y /V /R /I $(ProjectDir)publickey.xml $(TargetDir)
Working with Streams
Since I can never remember how to work with Streams, here’s an example of reading and writing to a memory stream.
[TestMethod]
public void GetPostTEDDelimted_Test()
{
DateTime startDate = DateTime.Parse("01/01/1900");
DateTime endDate = DateTime.Parse("01/01/1900");
IList<string> postTEDData = this.businessFacade.GetData();
Assert.AreEqual(102, postTEDData.Count);
System.IO.MemoryStream ms = null;
System.IO.TextWriter writer = null;
System.IO.TextReader reader = null;
LumenWorks.Framework.IO.Csv.CsvReader csvReader = null;
int counter = 0;
try
{
ms = new System.IO.MemoryStream();
writer = new System.IO.StreamWriter(ms);
reader = new System.IO.StreamReader(ms);
foreach (string record in postTEDData)
{
writer.WriteLine(record);
}
writer.Flush();
ms.Seek(0, System.IO.SeekOrigin.Begin);
csvReader = new LumenWorks.Framework.IO.Csv.CsvReader(reader, false, ',');
while (csvReader.ReadNextRecord())
{
counter++;
}
}
finally
{
if (writer != null) writer.Close();
if (reader != null) reader.Close();
if (ms != null) ms.Close();
}
Assert.AreEqual(102, counter);
Assert.AreEqual(100, csvReader.FieldCount);
}
Is there any way in Hibernate to join on another table using a composite key?
Question:
Is there any way in Hibernate to join on another table using a composite key? Trying to add fields to a class that come from another table. I’d like to join with the JCDATESUM table using the same branchNumber + jobNumber composite key, but the <key /> element seems to only support a single column???
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.model"> <class name="BillingSummary" table="JSUM" mutable="false" lazy="true"> <!-- <cache usage="read-only"/> --> <composite-id name="id" class="SummaryID" mapped="false"> <key-property name="branchNumber" type="com.dao.hibernate.usertype.DB2CharType" column="JP" length="3" /> <key-property name="jobNumber" type="com.dao.hibernate.usertype.DB2CharType" column="JN" length="6" /> </composite-id> ... ... ... <join table="JSUM"> <key /> <property name="customerName" type="com.dao.hibernate.usertype.DB2CharType" column="JS" /> </join> </class> </hibernate-mapping>
Answer:
Look at: http://docs.jboss.org/hibernate/stable/core/reference/en/html/example-mappings.html
They have some complicated mappings toward the bottom that involves composite keys.
yeah…as usual – simple solution
<key> <column name="JP" /> <column name="JN" /> </key>

