Share via


How to: Perform Custom Authentication Using SOAP Headers

This topic is specific to a legacy technology. XML Web services and XML Web service clients should now be created using Windows Communication Foundation.

The following custom solution is built using ASP.NET to provide an authentication mechanism using SOAP headers. The solution involves a custom IHttpModule on the Web server that executes the following steps:

  1. The HTTP Module parses HTTP messages to check whether they are SOAP messages.

  2. If the HTTP Module detects a SOAP message, it reads the SOAP headers.

  3. If the SOAP message has the SOAP header with authentication credentials, HTTP Module raises a custom global.asax event.

In the sample provided, the HTTP Module authenticates the user and sets Context properties that a Web service can use to decide whether the client is authorized access to the Web service.

Note

In this sample, the text is sent over the network in clearly readable text (it is not encrypted). If clear text is not secure enough for your application, add an encryption algorithm.

Example

The following code example is an HTTP Module that parses HTTP messages for SOAP requests. If the HTTP message is a SOAP message, the custom WebServiceAuthenticationEvent is raised.

using System;
using System.Web;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Text;
using System.Web.Services.Protocols;

namespace Microsoft.WebServices.Security {

      public sealed class WebServiceAuthenticationModule : IHttpModule 
      {
         private WebServiceAuthenticationEventHandler 
                       _eventHandler = null;

         public event WebServiceAuthenticationEventHandler Authenticate 
         {
           add { _eventHandler += value;}
           remove {_eventHandler -= value;}
         }
 
         public void Dispose() 
         {
         }

         public void Init(HttpApplication app) 
         {
           app.AuthenticateRequest += new
                      EventHandler(this.OnEnter);
         }

         private void OnAuthenticate(WebServiceAuthenticationEvent e) 
         {
           if (_eventHandler == null)
               return;

             _eventHandler(this, e);
             if (e.User != null)
                e.Context.User = e.Principal;
         }

         public string ModuleName
         {
           get{ return "WebServiceAuthentication"; }
         }

         void OnEnter(Object source, EventArgs eventArgs) {
           HttpApplication app = (HttpApplication)source;
           HttpContext context = app.Context;
           Stream HttpStream = context.Request.InputStream;

           // Save the current position of stream.
           long posStream = HttpStream.Position;

           // If the request contains an HTTP_SOAPACTION 
           // header, look at this message.
           if (context.Request.ServerVariables["HTTP_SOAPACTION"]
                          == null)
              return;

           // Load the body of the HTTP message
           // into an XML document.
           XmlDocument dom = new XmlDocument();
           string soapUser;
           string soapPassword;

           try 
           {
             dom.Load(HttpStream);

             // Reset the stream position.
             HttpStream.Position = posStream;

             // Bind to the Authentication header.
             soapUser =
                 dom.GetElementsByTagName("User").Item(0).InnerText;
             soapPassword =
                 dom.GetElementsByTagName("Password").Item(0).InnerText;
           } 
           catch (Exception e) 
           {
             // Reset the position of stream.
             HttpStream.Position = posStream;

             // Throw a SOAP exception.
             XmlQualifiedName name = new
                          XmlQualifiedName("Load");
             SoapException soapException = new SoapException(
                       "Unable to read SOAP request", name, e);
             throw soapException;
           }

           // Raise the custom global.asax event.
           OnAuthenticate(new WebServiceAuthenticationEvent                        (context, soapUser, soapPassword));
           return;
      }
    }
}

The following code example is the custom authentication event that is raised by the HTTP Module, if a SOAP request is received.

namespace Microsoft.WebServices.Security {
    using System;
    using System.Web;
    using System.Security.Principal;

    public class WebServiceAuthenticationEvent : EventArgs {
       private Iprincipal _IPrincipalUser;
       private HttpContext _Context;
       private string _User;
       private string _Password;

       public WebServiceAuthenticationEvent(HttpContext context)
       {
            _Context = context;
       }

       public WebServiceAuthenticationEvent(HttpContext context,
                       string user, string password)
       {
           _Context = context;
           _User = user;
           _Password = password;
       }
       public  HttpContext Context 
       { 
         get { return _Context;}
       }
       public IPrincipal Principal 
       { 
         get { return _IPrincipalUser;} 
         set { _IPrincipalUser = value;}
       }
       public void Authenticate()
       {
         GenericIdentity i = new GenericIdentity(User);
         this.Principal = new GenericPrincipal(i, new String[0]);
       }
       public void Authenticate(string[] roles)
       {
         GenericIdentity i = new GenericIdentity(User);
         this.Principal = new GenericPrincipal(i, roles);
       }
       public string User 
       {
         get { return _User; }
         set { _User = value; }
       }
       public string Password
       {
         get { return _Password; }
         set { _Password = value; }
       }
       public bool HasCredentials {
         get 
         {
              if ((_User == null) || (_Password == null))
                return false;
              return true;
         }
       }
    }
}

The following code example is the delegate for the custom WebServiceAuthenticationEvent event.

namespace Microsoft.WebServices.Security 
{
   using System;

   public delegate void WebServiceAuthenticationEventHandler(Object sender,  WebServiceAuthenticationEvent e);
}

The following code example is a Web service that defines the Authentication SOAP header that a client must pass. The Web service does not have to do the authentication. Rather, it can inspect the User.Identity.IsAuthenticated property to determine if the HTTP Module has authenticated the user.

<%@ WebService Language="C#" Class="SecureWebService" %>

using System;
using System.Web.Services;
using System.Web.Services.Protocols;

public class Authentication : SoapHeader {
  public string User;
  public string Password;
}

public class SecureWebService : WebService{
  public Authentication authentication;

  [WebMethod]
  [SoapHeader("authentication")]
  public string ValidUser(){
    if (User.IsInRole("Customer"))
      return "User is in role customer";

    if (User.Identity.IsAuthenticated)
      return "User is a valid user";
    return "not authenticated";
  }
}

The following code example is a Web service client that passes the necessary credentials for a custom SOAP header authentication mechanism within an Authentication SOAP header.

// Create a new instance of a Web service proxy class.
SecureWebService s = new SecureWebService();

// Create the Authentication SOAP header and set values.
Authentication a = new Authentication();
a.User = user.Value;
a.Password = password.Value;

// Assign the Header.
s.AuthenticationValue = a;

string result = s.ValidUser();
span1.InnerHtml = result;

See Also

Tasks

How to: Configure an XML Web Service for Windows Authentication

Reference

NetworkCredential
CredentialCache
X509Certificate

Concepts

Securing XML Web Services Created Using ASP.NET

Other Resources

Securing ASP.NET Web Applications
XML Web Services Using ASP.NET