Web services are mandatory nowadays and for a long time security has been a tough thing to do. Now with WCF you can just configure wsHttpBinding and you're done with a great deal of security. This binding will encrypt the communication between the web service and the client, however the client should be able to do the same encryption and decryption that the service understands. Hence, your client should be a .Net client which may not always the case. You may have a Java Client which will not be able to perform wsHttpBinding, or you may have a .Net client but you want to send Ajax requests to your WCF service which again Javascript will not be able to perform wsHttpBinding because you need a .Net to do it and .Net is not available to Javascript. At the end of the day you may find that wsHttpBinding is not that great if you are not totally in a Microsoft world.
In order to have your web service available to the entire world, including Ajax and Java then you will need to make your service available under https protocol. This way you guarantee the entire world can talk to your service securely and the parameters you are sending to the web service operations are encrypted by the client automatically and decrypted by the service. Also, the service response is encrypted for you automatically using the standards public/private key strong encryption and decrypted by the client automatically.
In order to enable SSL for your WCF follow the steps outlined in this
article.
1-
Get SSL Certificate: You will need to purchase and
configure an SSL certificate for your domain name. You can buy it from VeriSign starting from $99 or you can generate your own by
installing Windows 2003 Certificate Authority then request a certificate for your machine and issue it from that certificate authority. If you use your own certificate issued by certificate authority you will encounter a trust issue and you may need to write
one line of code to avoid this trust issue. If you encounter this trust issue you will get the message
"The remote certificate is invalid according to the validation procedure", you can avoid this message by writing this line of code
ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, X509Certificate certificate, X509Chain chain,SslPolicyErrors sslPolicyErrors) { return true; };
2- Bind IIS: You will need to make sure that your IIS is bound to your domain name. usually when you host a WCF on an IIS server IIS will always recognize the local server name and does not recognize the domain name. In order to learn about this issue and find out what to do read this article here But in a nutshell, you will need to issue two command
cscript.exe //nologo %systemdrive%\inetpub\adminscripts\adsutil.vbs set W3SVC/1/ServerBindings ":80:Your_Domain_Name"
cscript.exe //nologo %systemdrive%\inetpub\adminscripts\adsutil.vbs set W3SVC/1/SecureBindings ":443:Your_Domain_Name"
3-
Enable Secure Metadata: Then for the service metadata set
httpsGetEnabled="True" in your service config more info. <>
4-
Set Binding Security Mode: Define binding properties for basicHttpBinding as per Listing 8
here
5-
Attach Binding configuration to EndPoint: Add this binding configuration to the service end point as per listing 9
here
6-
Set Mex endpoint to mexHttpsBinding: As per listing 9
here
7-
Set the baseAddress: You can set the base address optionally as per listing 9
here
You WCF Service is now secure and you can browse to it as follows.
When you try to call your service you should see the following in fiddler. one connection on port 443 and the entire communication is encrypted.
8- Require Secure Channel: Now, using IIS go to the Default web site or the site that has your service and go to Directory Security, Secure Communication, Edit and click Require Secure Channel (SSL). Now your service is not available under http. It is only available under https here is how to change the setting
Now if you try to browse to the service using http you will get the error "The page must be viewed over a secure channel as per the image below
9-
Automatically redirect http to https: If you want to redirect http to https you can read the information in this
post or this
one.
Additional References for SSL
For the user name and password: You will need to do the following
1- Send credentials at the client: In your client code make sure to send the credentials. If your client is a .Net client you can send the credentials as follows
var svc = new MySecureService.MySecureServiceClient();
var cred = new NetworkCredential("MyUserName","MyPassword");
svc.ClientCredentials = cred;
var result = svc.Operation1();
2- Implement IHttpModule: Create a class and implement System.Web.IHttpModule, you can use the following code
public class UserAuthentication : IHttpModule
{
public void Init(HttpApplication context)
{
context.AuthenticateRequest += new EventHandler(this.OnAuthenticateRequest);
context.EndRequest += new EventHandler(this.OnEndRequest);
}
public void OnAuthenticateRequest(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
var header = application.Request.Headers["Authorization"];
try
{
if (!string.IsNullOrEmpty(header))
{
header = header.Trim();
if (header.IndexOf("Basic", 0) != 0)
{
throw new Exception("Access Denied.");
}
var encodedCredentials = header.Substring(6);
var decodedBytes = Convert.FromBase64String(encodedCredentials);
var s = new ASCIIEncoding().GetString(decodedBytes);
var credentials = s.Split(new char[] { ':' });
var username = credentials[0];
var password = credentials[1];
if (!ValidateUser(username, password))
{
throw new Exception("Access Denied.");
}
}
else
{
throw new Exception("Access Denied.");
}
}
catch (Exception ex)
{
application.Response.StatusCode = 401;
application.Response.StatusDescription = ex.Message;
application.Response.Write("" + ex.Message + "");
application.Response.End();
}
}
public void OnEndRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Response.StatusCode == 401)
{
var context = HttpContext.Current;
context.Response.StatusCode = 401;
context.Response.AddHeader("WWW-Authenticate", "Basic Realm");
}
}
public void Dispose()
{
}
private bool ValidateUser(string username, string password)
{
// Insert Custom User Validation here
var validUsername = "MyUserName";
var validPassword = "MyPassword";
if (username == validUsername &&
password == validPassword)
{
return true;
}
else
{
return false;
}
}
}
3- Add Module to your web.config: In the modules section add this module in your web.config as follows
< name="UserAuthentication" type="MyNameSpace.UserAuthentication">