Wednesday, February 18, 2009

Passing security credentials to C# 2.0 Web Service using SOAP Header



In a project ,we had a web service that required the client to pass security credentials (user id and password) while calling some of the web methods. First we thought to add two additional parameters (user id and password) to every web method that required authentication. This strategy looked very repetitive and made the method parameter list longer. After exploring for a while we discovered a nice solution of passing credentials through SOAP header. To implement this we need to perform the following steps:

Web Service:

1. Inherit a class from the “System.Web.Services.Protocols.SoapHeader” class that contains the security credential related fields. Put this class into the same file that contains the web service class.

public class SecurityInfo : SoapHeader
{
public string UserID;
public string Password;
}

2. Add a public field into the web service class of the type “SecurityInfo”.

public SecurityInfo SecurityCredentials = new SecurityInfo();

3. Add a “SoapHeader” attribute to the web method that requires access to security credentials passed by the client application. The parameter name of the “SoapHeader” attribute must be same as the public field declared in the above step (“SecurityCredentials” in this case).


[WebMethod(Description = "A method that requires authentication")]
[SoapHeader("SecurityCredentials")]
public void PerformASensitiveTask()
{
//Call the authentication method here with the security credential.

Authenticate(SecurityCredentials);

}

[WebMethod(Description = "Another method that requires
authentication")]
[SoapHeader("SecurityCredentials")]
public void PerformAnotherSensitiveTask()
{
//Call the authentication method here with the security credential.
Authenticate(SecurityCredentials);

}


private void Authenticate(SecurityInfo credentials)
{
// validation logic goes here. An exception is thrown if not validated.
string userId = credentials.UserID;
string password = credentials.Password;
//.....
}


So the final web service code looks like this:


public class TestService : System.Web.Services.WebService
{
public SecurityInfo SecurityCredentials = new SecurityInfo();
public TestService()
{
}

[WebMethod(Description = "A method that requires authentication")]
[SoapHeader("SecurityCredentials")]
public void PerformASensitiveTask()
{
//Call the authentication method here with the security credential.
Authenticate(SecurityCredentials);
}

[WebMethod(Description = "Another method that requires authentication")]
[SoapHeader("SecurityCredentials")]
public void PerformAnotherSensitiveTask()
{
//Call the authentication method here with the security credential.
Authenticate(SecurityCredentials);
}

private void Authenticate(SecurityInfo credentials)
{
// validation logic goes here. An exception is thrown if not validated.
string userId = credentials.UserID;
string password = credentials.Password;
//.....
}

}

public class SecurityInfo : SoapHeader
{
public string UserID;
public string Password;
}


Web Service Consumer (Console App):

After adding a web reference to the web service, Visual Studio automatically adds a “SecurityInfoValue” property to the consumer-side proxy. The security credential class “SecurityInfo” is also exposed to the client application.We just need to instantiate an object of this class,set the credentials and set it into the “SecurityInfoValue” property of the client side proxy class of the web service.We can call multiple web methods after that with the same instance in the current scope.All the web methods will have access to the security credentials.The client code looks like this:



static void Main(string[] args)
{
TestWebService.TestService srvc = new
ServiceTest.TestWebService.TestService();

TestWebService.SecurityInfo sec = new
TestWebService.SecurityInfo();

sec.UserID = "ID";
sec.Password = "Password";
srvc.SecurityInfoValue = sec;

srvc.PerformASensitiveTask();

srvc.PerformAnotherSensitiveTask();

}


I think using “Soap Header” to pass credentials to multiple web methods of a web service is really an elegant solution.

No comments: