In a recent installment, I walked you through the creation of a basic Web service that provides query access to a SQL Server database using both C# and VB.NET. Another aspect to consider when creating a Web service is security. Publishing a Web
service via the Internet makes it available to an infinite number
of users. The data might be sensitive, so you must control who may
access it.

ASP.NET-based security

The first roadblock for a user accessing an
ASP.NET application is authentication. Authenticated users are
called principals.

The next step in the security process is
authorization. This establishes which resources and operations the
principal is allowed to access. ASP.NET supports three
authentication schemes: Windows, Passport, and Forms:

  • Windows: authentication
    performed by Internet Information Services (IIS)
  • Passport: the Passport
    services that Microsoft offers
  • Forms: unauthenticated
    users are redirected to HTML form using HTTP redirection

Connection between ASP.NET and Web service
security

Web services developed with the .NET Framework
utilize the same ASP.NET security paradigm as its starting point.
In addition, Web service-focused standards like
WS-I
and SOAP-based
security may be used. For this article, I’ll use a simple example
of Windows-based security to limit access to our Web service.

Windows-based authentication relies on the Web
server (IIS) to authenticate users. It takes advantage of the user
accounts on the server, and it provides the following
authentication methods:

  • Basic: The user supplies
    logon credentials (username/password), which are passed to the
    server as clear text.
  • Digest: This is the same
    approach as Basic, but the credentials are hashed before they’re
    passed to the server. It requires Internet Explorer.
  • Integrated Windows: An
    encrypted exchange between the browser and server is used to pass
    user credentials. It’s only supported by Internet Explorer.
  • Certificate: Client
    certificates are used to identify a user. The certificate is passed
    by the browser to the server. This requires the installation of the
    certificate on the client machine.
  • Anonymous: The user is
    not required to log in. The Web server creates a Windows access
    token to represent the anonymous user.

The authentication mode is designated in the
Web site Properties, accessed by way of the Internet Information
Services Administration screen. In addition, the web.config file
must be properly set up to utilize Windows authentication in an
ASP.NET application. The following sample establishes this with the
first line; the second line tells the system to pass the currently
logged on user’s credentials to the browser (impersonate):

<authentication mode=”Windows” />
<identity impersonate=”true” />

The identity element enables or disables
impersonation with a true value, resulting in the client operating
in the security context of the user account used to log onto IIS.
If this option is set to false, all code is executed under the
security context of the default IIS account. These elements are
contained within the web.config file’s system.web element.

Securing the Web service

Adding Windows authentication to the Web
service begins by accessing the necessary namespace. The
System.Web.Security and System.Security.Principal namespaces are
available, but you only need the latter. The base Web service class
(System.Web.Services.WebService) provides the User property to
access the current user. You can convert this User property easily
to a WindowsPrincipal object to utilize Windows-based
authentication.

The WindowsPrincipal class provides an Identity
property, which returns a WindowsIndentity object. The
WindowsPrincipal class also includes the IsInRole method to
determine if the current user is assigned to a role. Roles, which
are the equivalent of Windows server groups, determine if the
Windows user is assigned to a group. The following Web services
uses this basic security scheme to control access to the
service.

<%@ WebService Language=”C#”
Class=”BuilderWebServices.BuilderWebServiceExample1″ %>
using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.Services;
using System.Security.Principal;
namespace BuilderWebServices {
public class BuilderWebServiceExample1: WebService {
private const string sConn = “server=(local);Initial
Catalog=Northwind;UID=sa;PWD=”;
private SqlConnection conn = null;
private SqlCommand comm = null;
[WebMethod]
public string GetTotalFreight() {
WindowsPrincipal wp = (WindowsPrincipal)this.User;
if (wp.IsInRole(“WebService”)) {
try {
conn = new SqlConnection(sConn);
conn.Open();
comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = “SELECT SUM(Freight) FROM Orders”;
comm.CommandType = CommandType.Text;
if (comm.ExecuteScalar() == null) {
return “Database error”;
} else {
return comm.ExecuteScalar().ToString();
} } catch (SqlException ex) {
return “Database error: ” + ex.ToString();
} catch (Exception e) {
return e.ToString();
} finally {
if (conn.State == ConnectionState.Open) {
conn.Close();
}} } else { return “Security error”; } } } }

The first line in the GetTotalFreight method
determines if the user is in the WebService role before proceeding.
A simple text message is returned if the user isn’t in the role. If
opening a Web service to all users isn’t a problem, you may specify
a particular user (for the system to impersonate) in the Web.config
file, like this:

<configuration>
<system.web>
<identity impersonate=”true” name=”chester”
password=”tester”
</system.web>

</configuration>

This tells .NET to access resources using the
specific account. This allows you to provide Web service access to
all users without opening up your system to anonymous access. On
the other hand, the account credentials are stored in clear text,
thus introducing a security risk.

VB.NET equivalent

The following listing includes all the code for
the VB.NET equivalent of the example code in this article. The main
difference is the attribute before the class name declaring it as a
Web service.

<%@ WebService Language=”VB”
Class=”BuilderWebServiceExample1″ %>
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Web.Services
Imports System.Security.Principal
<System.Web.Services.WebService(Namespace:=”http://tempuri.org/Service2/Service

1″)> _
Public Class BuilderWebServiceExample1
Inherits WebService
Dim sConn As String = “server=(local);Initial
Catalog=Northwind;UID=sa;PWD=”
Dim conn As SqlConnection
Dim comm As SqlCommand
<WebMethod()> _
Public Function GetTotalFreight() As String
Dim wp As WindowsPrincipal
wp = New WindowsPrincipal(me.User)
If (wp.IsInRole(“WebService”)) Then
Try
conn = New SqlConnection(sConn)
conn.Open()
comm = New SqlCommand
comm.Connection = conn
comm.CommandText = “SELECT SUM(Freight) FROM Orders”
comm.CommandType = CommandType.Text
If (comm.ExecuteScalar() Is Nothing) Then
Return “Database error”
Else
Return comm.ExecuteScalar()
End If
Catch ex As SqlException
Return “Database error: ” + ex.ToString()
Catch ex As Exception
Return “Error: ” + ex.ToString()
Finally
If (conn.State = ConnectionState.Open) Then
conn.Close()
End If
End Try
Else
Return “Security Error”
End If
End Function
End Class

Choose carefully

Using Windows-based security provides many
administration points—IIS config files (machine.config and
web.config), as well as access control list (ACL) and IIS security
settings. Additionally, using a database backend (like SQL Server)
or an XML file to maintain security is more scalable in the long
run, but I utilized Windows security to demonstrate the simple
process of securing a custom Web service.

TechRepublic’s free .NET newsletter, delivered each Wednesday, contains useful tips and coding examples on topics such as Web services, ASP.NET, ADO.NET, and Visual Studio .NET. Automatically sign up today!