A few days ago I wrote an article about WCF message headers
We used a scenario there that users who wanted to invoke the public service, had to pass their subscriptionid by message header. If the subscriptionid was not present, the user would not be allowed to invoke any service operation. To secure that scenario, we would have to use Transport or Message security, so that we are able of encrypting the subscriptionid message header, so that people with bad intentions would not be able to read your subscriptionid and use it for their own purposes.
Another possibility, maybe not such a good one, would be to work with a custom username and password validation. Let’s assume every company that is registered with us is registered with their company name and a private subscriptionid. Instead of using message headers to be granted access to the service, we will use a custom password validator against our store to validate against a username and password, in our case the company name and the subscriptionid which is their password.
In this case we will use message security with self-signed certificate. If you are not aware of what this is and how this works, please read up on this post:
WCF message security and client certificate authentication with self-signed certificates
Just as with the other blog posts, I’ll add the solution and service setup to be complete:
Our service contract:
Our service implementation:
Basically the solution is completely the same as what we used for our message header subscriptionid solution. But instead of passing the client subscriptionid by message header, we will now pass it as a clientcredential username and password.
To create our own custom username and password validator we need to derive from System.IdentityModel.Selectors.UserNamePasswordValidator. You will need to add a reference to System.IdentityModel to be able to reach this UserNamePasswordValidator. When deriving from this class, we need to override the abstract void method Validate:
In a real scenario, you would validate the username and password against a store, like a database, which holds the custom credentials.
In our case, we will just validate whether the password equals our subscriptionid we used in the message headers authentication post
If the subscriptionid passed along does not match our static subscriptionid, a SecurityTokenException will be thrown, which will return to the client.
Our service configuration looks as following:
If you do not know how to work with message security or self-signed certificates, first read up on this post
As you can notice, we defined Message security with clientCredentialType “Username”. The behavior linked to our service also has at the <serviceCredentials> a <userNameAuthentication> specified. We set the userNamePasswordValidationMode to Custom instead of MembershipProvider or Windows. Next on we need to define the customUsernamePasswordValidatorType, which should point to our custom validator class we created. We reference it by referencing our SaasServiceUsernameAuthentication by full name (complete namespace) and the second parameter is the name of the dll.
Passing the username and password in the client console application:
This is not complete fault-tolerant code, but it does the job for the demo. The subscriptionid we use is the subscriptionid that our service expects.
If we now execute our client console application:
We get the result we expected.
If we now change the subscriptionid at the client to a subscriptionid that would be incorrect or invalid:
And we execute our client console application again:
An security error gets returned to the client, as the validate function throw an error at our custom username and password validator.
Any suggestions, remarks or improvements are always welcome.
If you found this information useful, make sure to support me by leaving a comment.
Cheers and have fun,