A simple WSE 3.0 web service to authorize by username and password

I’ve been developing a web service that authorizes based on the Web Services Enhancements (WSE) 3.0 specification.  It’s been a fairly cumbersome exercise, mainly due to poor documentation on the what and why of the process, so I’m writing down the process that I went through to create it.

  1. Install Microsoft’s WSE 3.0 and add references to Microsoft.Web.Services3 to your projects.  (I’ve included the using directives in the full code, but not in the listings below, so download the samples and look through them if you’re interested in which namespaces to include.)
  2. Develop your custom username/password validation routine by deriving it from UsernameTokenManager and overriding the AuthenticateToken method.  The generic one that I did was this:
    public class SampleUsernameTokenManager : UsernameTokenManager
    {
      protected override string AuthenticateToken(UsernameToken token)
      {
        bool Valid = (("MyUsername" == token.Username) && ("MyPassword" == token.Password));
        if (Valid)
        {
          return token.Password;
        }
        else
        {
          throw new UnauthorizedAccessException("User validation failed");
        }
      }
    }
    You would, of course, use whatever routine you needed to determine the validity of the UsernameToken.  The major consideration here is that you have to return the password if the credentials are valid.
  3. Change your web.config file by doing the following:
    • Make sure that configuration/configSections contains the following:
       <section name="microsoft.web.services3" type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    • Make sure that configuration/webServices contains the following:
       <soapExtensionImporterTypes>
        <add type="Microsoft.Web.Services3.Description.WseExtensionImporter, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </soapExtensionImporterTypes>
      <soapServerProtocolFactory type="Microsoft.Web.Services3.WseProtocolFactory, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    • Make sure that configuration/microsoft.web.services3 contains the following:
       <security>
        <securityTokenManager>
          <add type="SampleWSEService.SampleUsernameTokenManager, SampleWSEService" namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" localName="UsernameToken" />
        </securityTokenManager>
      </security>
      <policy fileName="wse3policyCache.config"/>
      The securityTokenManager element is what binds the specific security method to the class that determines the validity of the token.  The type attribute needs to refer to the fully-qualified name of the class that derives from UsernameTokenManager in the first part and have the name of the DLL containing it in the second.  The important thing to note here is that the namespace and localName attributes must be exactly as shown above!
  4. Change your wse3policyCache.config file to look like this (note that this is the minimum policy file for my example; you may want to combine other authorization methods in this file as well):<policies xmlns="http://schemas.microsoft.com/wse/2005/06/policy">
      <extensions>
        <extension name="usernameOverTransportSecurity" type="Microsoft.Web.Services3.Design.UsernameOverTransportAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <extension name="requireActionHeader" type="Microsoft.Web.Services3.Design.RequireActionHeaderAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </extensions>
        <policy name="SamplePolicy">
        <authorization>
          <allow user="*"/>
        </authorization>
        <usernameOverTransportSecurity />
        <requireActionHeader />
      </policy>
    </policies>

    Some important considerations here are:

    • Remember the name that you give the policy; you’ll use that to bind your web service to this policy.
    • The authorization section includes a default deny.  We add an allow for all users (“*”) rather than for all authenticated users (“?”) because we’re sending text usernames; if we were doing Windows-based authentication we’d restrict it to authenticated users only.
    • Alternately, you could list all valid usernames in the authorization section like this:
       <allow user="Fred"/>
      <allow user="Dolores"/>
    • Basically the authorization section allows listed users to be processed by the appropriate security token manager; it doesn’t imply that they are allowed access–only that they are allowed to reach the access mechanism you’ve defined.
  5. Bind the policy to your class that derives from WebService with the policy attribute right before the class declaration, like this:
    [Policy("SamplePolicy")]
    public class Sample : System.Web.Services.WebService
  6. To enable the client to use this, add a web reference to your web service and use the following code:
    // Make sure to connect to the Wse proxy for the service
    MySampleWSEService.SampleWse MyWebService = new MySampleWSEService.SampleWse();// Create the username token
    string Username = "MyUsername";
    string Password = "MyPassword";
    UsernameToken MyToken = new UsernameToken(Username, Password, PasswordOption.SendPlainText);
    MyWebService.SetClientCredential(MyToken);// Create the policy and specify username over transport authentication
    Policy MyPolicy = new Policy();
    MyPolicy.Assertions.Add(new UsernameOverTransportAssertion());// Apply the policy to the exchange
    MyWebService.SetPolicy(MyPolicy);
    string Response = MyWebService.HelloWorld();

You can download my sample solution that includes code for both the web service and the client.

Advertisements

11 thoughts on “A simple WSE 3.0 web service to authorize by username and password

  1. I downloaded the Code from this page, but this is giving me some error called: “The type or namespace name ‘SampleWse’ does not exist in the namespace ‘SampleWSETest.MySampleWSEService’ (are you missing an assembly reference?) C:\WSE3.0Authorization\SampleWSETest\frmMain.cs 42 36 SampleWSETest

    Can you help me with this???

  2. Sounds like the web service didn’t build or your web reference is bad. Either build the project with the web service or right-click on it under Web References and choose Update Web Reference. If it won’t update it’s probably either a changed port number from the project or something to do with your local IIS configuration.

  3. Hello Carl,

    Wonderful introduction about WSE3.0 . Below is the notes when your sample application is implemented.

    1. Custom security class fails to load and causes the SoapHeader Exception

    Work Around:
    1. Keep the custom class (SampleUsernameTokenManager) in a separate class library and include them in your server project.

    Hope this will help others.

    Cheers,
    Vidhya Rao

  4. Hi,

    I have downloaded your project, and insall wse3 in both client and server side.
    and host the webservice in IIS and create the proxy using WseWsdl3.exe tools.

    C:\Program Files\Microsoft WSE\v3.0\Tools>WseWsdl3.exe http://host/MyService.asmx?wsdl /out:MyWseAsmxProxy.cs /type:webClient

    but when i ‘m callling webservice from client application, I’m getting error “The request failed with http status401: Anauthorized”

    can you help me why i’m getting this error.

    1. Have you modified SampleUsernameTokenManager.AuthenticateToken to do the validation routines you need? The code sample is hardcoded to username = “MyUsername” and password = “MyPassword”.

      If you can debug into the server-side code, make sure that AuthenticateToken is being hit. If it’s not being hit, check that your web.config specifies to use the proper class in microsoft.web.services3/security/securityTokenManager. Make sure that your wse3policyCache.config file is readable by the IIS process. Your application event log might shed more light on the issues you’re having if it’s not picking up the config or not able to load the securityTokenManager type specified in the config.

      Good luck!

  5. Hi Carl,
    Thanks for reply..

    When I debug the service, it is hit to override Authenticate Method and validate also successful, but I’ m getting exception from this line “return token.Password”
    the function is written below and give the comment Exception occurs.

    protected override string AuthenticateToken(UsernameToken token)
    {
    // Implement username/password validation here
    bool Valid = ((“MyUsername” == token.Username) && (“MyPassword” == token.Password));

    if (Valid)
    {
    return token.Password; //////Exception occurs
    }
    else
    {
    throw new UnauthorizedAccessException(“User validation failed”);
    }
    }

    I’m thinking their is some problem in privilege in IIS level..
    can you let me know What are the privilege i have to assign.

    I gave full rights on WebService folder to asp.net account ASP.NET v4.0.
    for Temp asp.net files folder also.

  6. As you mentioned “Make sure that your wse3policyCache.config file is readable by the IIS process”

    I didn’t understand how to make wse3policyCache.config file is readable by the IIS process??

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s