Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


.NET Web Services Security : Page 3

.NET has a lot to offer when it comes to both developing and consuming secure Web services. .NET allows developers to either rely on Windows-based authentication or develop custom authentication mechanisms. Each option has its own tradeoffs and implications on the programming models.

Integrated Windows Authentication
Integrated authentication is a Windows protocol that uses a proprietary password-hashing algorithm and requires both the client and the Web service to run on Windows stations. When using Integrated authentication, you can send credentials over HTTP, because they are not sent in clear text. Integrated authentication relies on the fact that Windows already knows the identity and credentials of the client (more precisely, the security token of the client's thread), which it can capture and provide as authentication credentials. To use Integrated authentication, the client needs to initialize the Credentials property of the wrapper class by assigning to it the credentials returned from the DefaultCredentials static property of CredentialsCache:>

SecureCalculator calc = new SecureCalculator(); calc.Credentials = CredentialCache. DefaultCredentials; calc.PreAuthenticate = true; //Optional calc.Add(2,3);

If the client's identity is not adequate and you need to explicitly provide other Windows credentials, then you should use Basic or Digest authentication.

Custom Authentication
When you use custom Web services authentication, you do not rely on IIS to authenticate the callers. Instead, you will need to obtain the caller's credentials somehow, and verify them against a custom repository, typically a database. The source files accompanying this article contain the UserManager helper class, defined as:

public class UserManager { public UserManager(); public bool Authenticate(string userName, string password); //Other members and methods }

UserManager accesses a database and authenticates the caller against the entries in the database. You will see UserManager used in the custom authentication code samples.

If the callers provide valid credentials, they are allowed to call the Web method; otherwise, the Web service can throw an exception. Custom authentication is appropriate when the callers do not have accounts on the server and when the number of identities is considerably large. An important distinction between custom authentication and Windows authentication is that custom authentication offers a fine level of control over which calls to Web methods the Web service authenticates. For example, a Web method that returns current inventory status is less sensitive than a Web method that processes a purchase order. In the interest of throughput, you may choose to only authenticate purchasing calls.

When using custom authentication, you need to allow anonymous access to the service by selecting the Anonymous access check box in the IIS Authentication Mode dialog box, and by setting the authentication mode in the Web service configuration file to None:

<authentication mode="None" />

Using custom authentication you can use whatever custom mechanism you want, but in general, you will likely use a log-in method, SOAP headers, or SOAP extensions. Each of these mechanisms has its variations and you can come up with your own tweaks as well.

Log-in Method
The log-in method, as the name implies, involves exposing a dedicated method on the Web service that accepts the caller's credentials. Needless to say, you should use the log-in method only over a secure channel (HTTPS) because the credentials are transmitted in clear text. When the Web service authenticates a caller, it stores the caller's authentication in a session variable. In each Web method call that requires authentication, you need to explicitly verify that the caller's session state variable indicates an authenticated caller.

Custom authentication is appropriate when the callers do not have accounts on the server, and when the number of identities is considerably large.
Listing 3 shows the server-side code for security using the log-in method. The SecureCalculator Web service encapsulates and uses a Session variable to set the value of the Boolean IsAuthenticated property. Note that every Web method that deals with security has to enable session state support explicitly by setting the EnableSession property of the WebMethod attribute to true:


The LogIn() method of the SecureCalculator shown in Listing 3 uses the UserManager helper class to verify that the caller provided valid credentials, and if so, it sets the IsAuthenticated property to true. Before doing anything else, every method must verify that the caller is authenticated by checking the value of IsAuthenticated. The Web server only authenticates the caller the first time the caller connects to the service; subsequent calls are not authenticated. The caller will be logged out once the session ends or when the cookie used to manage the session expires. For increased security you can also provide a LogOut() method that allows the client to explicitly log out.

A .NET client using the log-in method of authentication has to enable support for cookies in the Web service wrapper class by initializing the CookieContainer property, typically by modifying the wrapper class constructor:

public class SecureCalculator : SoapHttpClientProtocol { public SecureCalculator() { CookieContainer = new System.Net.CookieContainer(); Url = "http://<...>/SecureCalculator.asmx"; } public bool LogIn(string userName, string password); public void LogOut(); public int Add(int num1,int num2); //Other methods }

The client, of course, needs to call LogIn() before using secure methods of the Web service:

SecureCalculator calc = new SecureCalculator(); calc.LogIn("UserName","Password"); calc.Add(2,3); calc.LogOut(); calc.Add(2,3); //Throws exception

You can take the log-in method approach one step further by factoring it into a base class and adding declarative authentication support using a custom principal. A principal is an object that represents an identity and its role membership. Listing 4 shows the LogInWebService abstract class. Like the LogIn() method in Listing 3, LogInWebService uses a session variable to indicate whether the caller is authenticated and encapsulates the session variable in the IsAuthenticated property. LogInWebService also uses a session variable to store the user name and encapsulates the session variable in the UserName property.

It is always a good practice to encapsulate session variables and expose logical properties around them. This eases the task of maintenance and provides a single place to enforce business rules. For example, UserName only allows the user name to be set if the user is authenticated.

The LogIn() and LogOut() methods of LogInWebService are nearly the same as the methods of the same name shown in Listing 3. One difference is that in LogInWebService, LogIn() stores the user name in the UserName property if the caller is authenticated, while LogOut() resets the user name if the caller logs out. The main difference between the methods, however, is in the LogInWebService constructor. If the caller is authenticated (because it already called the LogIn() method), the constructor creates a generic identity around the user name, and provides it to a generic principal. Then, the constructor installs the generic principal as the principal of the current thread:

IIdentity identity= new GenericIdentity(UserName); IPrincipal principal = new GenericPrincipal(identity,null); Thread.CurrentPrincipal = principal;

Both GenericIdentity and GenericPrincipal are defined in the System.Security.Principal namespace. The purpose of this is clear when you examine a Web service that derives from LogInWebService:

public class SecureCalculator : LogInWebService { [PrincipalPermission(SecurityAction.Demand, Authenticated = true)] [WebMethod(EnableSession=true)] public int Add(int num1,int num2) { return num1+num2; } }

All the SecureCalculator needs to do is add the PrincipalPermission attribute to sensitive methods, and demand that the caller is authenticated. The PrincipalPermission attribute looks for the current principal associated with the current thread, GenericPrincipal in this case, and asks it if the user is authenticated. The GenericPrincipal installed by default returns false, but ours returns true. This makes developing secure Web services trivial, and it provides the benefits of declarative security.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date