Using WSE 3.0 for Web Service Authentication

Web Services Enhancements (WSE) is a webservice standard which provides cross-platform security for webservices. WSE provides various security specifications like WS-Security, WS-Policy, WS-Trust, WS-Privacy, WS-SecureConversation, WS-Federation, WS-Authorization which can be used to provide authentication, authorization and message level security using digital signing and encryption based on particular requirements on hand. More information on WSE and the areas it addresses can be seen here (This document is a old but provides a an overview of WSE security-model). Another good article on MSDN Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication explain different security scenarios and how WSE can be used in each one of them.

In the following I will provide a step-by-step detail on how to use WSE 3.0 for authenticating webservices with your custom user database. The custom database can be an ASP.NET Membership database or other custom user database. (You must have Visual Studio 2005 installed to proceed with the following. Please click on the images to enlarge)

1. Download WSE 3.0 from http://www.microsoft.com/downloads/details.aspx?FamilyID=018A09FD-3A74-43C5-8EC1-8D789091255D&displaylang=en and install it on your machine.

2. Create a new ASP.NET Webservice website project. Right Click the project select the “WSE Settings 3.0″ option as shown below.

3. This will open the following WSE settings dialog. Select the “Enable this project for WSE” and “Enable Microsoft WSE Soap Protocol Factory” from the settings dialog.

4. Go to the Policy Tab and select “Enable Policy”. Add a new Policy with the name “CustomServicePolicy” (or any name).

5. After you add a new Policy, the following Policy settings wizard will open and you will be required to define your policy.

6. Select the Authentication method. The Authentication method can be Anonymous, Username, Certificate and Windows. In this sample I am going to select the username as we care going to pass username and password for the authentication. You can use other methods like windows if required. Also select that you are seting this policy for a service. (In case you are creating a policy for a client to access WSE webservice you can select the “Secure Client Application” option). Click next to proceed.

7. In the following screen you can select “Enable WS-Security 1.1 Extensions” and select Protection Order as “None”. You can select other protection methods if you want to sign and encrypt your messages using a X.25 certificate.

8. Click next to proceed, you will be shown the following screen with the informaiton about the Policy that you have defined.

9. After defining the Policy, go to you service class and add this Policy to the class using the Policy Attribute as shown in the following screenshot. You will be required to add Microsoft.Web.Services3.dll into your project to reference Policy attribute and other WSE classes. The WSE documentation says that this reference will be automatically added to your project if you enable WSE for your project as we did but I have observed that you have to manually add this reference and it is not added automcatically. You can get this dll from the following path C:\Program Files\Microsoft WSE\v3.0\ (The path may be different based on your installation location).

Note that after configuring WSE settings, there is an extra configuration file “wse3policyCache.config” which has been added to the project.

10. Now we need to write a Custom Token Manager which will authenticate the username and password sent by the user. Add a new Class “CustomTokenManager” in the project and inherit it from Microsoft.Web.Services3.Security.Tokens.UsernameTokenManager. Override the AuthenticateToken method, WSE soap filter will call this method to obtain the clear text password for the user. You can write your custom code to access your ASP.NET membership database or other user database to obtain the password. You can get the username from the UsernameToken passed as a parameter to the AuthenticateToken method.

11. After you have you CustomTokenManager ready, you need to set this in web.config in the WSE security settings so WSE can use this class when user authentication is required.

 

Now your service is ready to use and it will authenticate the incoming user with your custom database usign the CustomTokenManager class that you have created.

To write a client for a WSE service, you need to have WSE 3.0 installed on the client machine. Moreover, you will have to enable WSE for your project (step 3) before adding the webreference to the server. If WSE is installed on the client machine and is enabled for your project, the WSDL.exe toll will generate an additional proxy class ending with Wse if the service supports WSE. In our case there will be two proxy classes that will be generated on the client. Service and ServiceWse. Use ServiceWse for accessing the service.

The following code shows how to pass username and password as UserNameToken in WS-Security header.

Dim oService As New WSETestService.ServiceWse

Dim U As New Microsoft.Web.Services3.Security.Tokens.UsernameToken(“<User_Name>”, “<Password>”, Security.Tokens.PasswordOption.SendHashed)
oService.SetClientCredential(U)

Dim oPolicy As New Policy()
oPolicy.Assertions.Add(New UsernameOverTransportAssertion())
oService.SetPolicy(oPolicy)

oService.HelloWorld()

Following is the SOAP request with the UserNameToken in the WSE header with username and password of the user. The password is passed as SHA-1 hash of the actual password. (Note that you selected Security.Tokens.PasswordOption.SendHashed inUserNameToken constructor from the client when creating the token, you can choose to send clear text password as well)

<inputMessage utc=”9/18/2007 1:10:30 PM” messageId=”urn:uuid:8c890d37-28a0-423f-8aaa-1b35e7f6a021″>
<processingStep description=”Unprocessed message”>
<soap:Envelope xmlns:soap=”
http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:wsa=”http://schemas.xmlsoap.org/ws/2004/08/addressing” xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd” xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd”>
<soap:Header>
<wsa:Action>
http://tempuri.org/HelloWorld</wsa:Action>
<wsa:MessageID>urn:uuid:8c890d37-28a0-423f-8aaa-1b35e7f6a021</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
</wsa:ReplyTo>
<wsa:To>
http://localhost:1841/WebServiceAuthentication/Service.asmx</wsa:To>
<wsse:Security soap:mustUnderstand=”1″>
<wsu:Timestamp wsu:Id=”Timestamp-dd031f35-cc14-4426-b34f-bfff66d03991″>
<wsu:Created>2007-09-18T13:10:30Z</wsu:Created>
<wsu:Expires>2007-09-18T13:15:30Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken xmlns:wsu=”
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd” wsu:Id=”SecurityToken-2ee318dd-56ef-4f26-877d-2a199ff5b4e3″>
<wsse:Username>aleem</wsse:Username>
<wsse:Password Type=”
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest”>CyI4oSXQgRMdYF416fHcD0IDpIE=</wsse:Password>
<wsse:Nonce>NVU8Adj9tEMZQpBPoPfJMw==</wsse:Nonce>
<wsu:Created>2007-09-18T13:10:30Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>

</soap:Header>
<soap:Body>
<HelloWorld xmlns=”
http://tempuri.org/” />
</soap:Body>
</soap:Envelope>
</processingStep>
<processingStep description=”Entering SOAP filter Microsoft.Web.Services3.Design.RequireSoapHeaderAssertion+RequireSoapHeaderFilter” />
<processingStep description=”Exited SOAP filter Microsoft.Web.Services3.Design.RequireSoapHeaderAssertion+RequireSoapHeaderFilter” />
<processingStep description=”Entering SOAP filter Microsoft.Web.Services3.Design.UsernameOverTransportAssertion+ServiceInputFilter” />
<processingStep description=”Exited SOAP filter Microsoft.Web.Services3.Design.UsernameOverTransportAssertion+ServiceInputFilter” />
<processingStep description=”Processed message”>
<soap:Envelope xmlns:soap=”
http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:wsa=”http://schemas.xmlsoap.org/ws/2004/08/addressing” xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd” xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd”>
<soap:Header />
<soap:Body>
<HelloWorld xmlns=”
http://tempuri.org/” />
</soap:Body>
</soap:Envelope>
</processingStep>
</inputMessage>

About these ads

18 thoughts on “Using WSE 3.0 for Web Service Authentication

  1. Pingback: Passing Extra Information in WS-Security UserNameToken « Aleem’s Weblog

  2. You indicate that “The custom database can be an ASP.NET Membership database or other custom user database. ” however I am using the aspnetdb to retain the password however it is Hashed. I call the web service using .SendHashed and have a custom Tokenmanager but how do I pull out a clear text password to return from my asp.net membership DB?

    Any assistance would be greatly appreaciated.

  3. Hi Daniel,

    This appears to be a problem. However, I can think of two solutions.

    1. Change the Password format in your ASP.NET Membership DB to store passwords in clear text. In this case all new user passwords will be saved in clear text but for old users you will have to enforce a change in password.

    2. Use ‘SendPlainText’ PasswordOption instead of ‘SendHased’. In this case you will receive the clear text password, then you can hash this password yourself and comapre it with ASP.NET Membership DB hash of the same password. (ASP.NET Membership DB Hashes the password using SHA1 and the hash is always the same)

    I know both of the above solutions are not perfect but basically SHA1 is a one way algorithm and a hashed value cannot be changed back to clear text.

    Hope this helps.

  4. Hi Aleem,

    This is pretty helpful article.
    I am also doing on same.
    I need to have some more details by discussing with you.
    Can you please give me any of your contact email id so that I will be able to communicate with you regarding the same.

    I am really in need for earlier response on the same.

    Thanks in advance.

    Gauri

  5. Pingback: munchie

  6. hi
    I created one WCF Webservice with BasicHttp Binding and SelfSSL.
    I want to call this services my various clients like vs2003,2005 and java.
    When I call my wcf service iam getting error An error occurred when verifying security for the message

    See my code:

    wcfService.Service1Wse sc=new wcfService.Service1Wse();
    SoapContext requestcontext =sc.RequestSoapContext ;
    requestcontext.Security.Timestamp.TtlInSeconds = -1;
    UsernameToken token;
    token = new UsernameToken(“abc”, “12333″,PasswordOption.SendHashed);
    requestcontext.Security.Tokens.Add(token);
    MessageSignature sig = new MessageSignature(token);
    requestcontext.Security.Elements.Add(new MessageSignature(token));
    Response.Write(sc.Hello());

    If I pass plain text password option. My dontnet clients are working. But not java.
    If I pass Hashed password option iam getting same above error.

    Please give me some solution.

    Thanks & Regards
    Rao

    • Hi Walter,

      I tried to do this example.

      My scenario is like this:
      1. I have a Web Service.
      2. I have a Client to call the web Service.

      try
      {
      localhost.ServiceWse oService = new ServiceWse();
      oService.PreAuthenticate = true;
      oService.Credentials = System.Net.CredentialCache.DefaultCredentials;

      Microsoft.Web.Services3.Security.Tokens.UsernameToken userToken
      = new Microsoft.Web.Services3.Security.Tokens.UsernameToken(“user1″, “p@ssw0rd”, Microsoft.Web.Services3.Security.Tokens.PasswordOption.SendHashed);

      oService.SetClientCredential(userToken);
      Policy oPolicy = new Policy();
      oPolicy.Assertions.Add(new UsernameOverTransportAssertion());
      oService.SetPolicy(oPolicy);

      string retStr = oService.HelloWorld();

      catch (System.Web.Services.Protocols.SoapHeaderException soapex)
      {
      // Error goes here saying
      }

      System.Web.Services.Protocols.SoapHeaderException: Microsoft.Web.Services3.Security.SecurityFault: The security token could not be authenticated or authorized —> System.ArgumentException: WSE562: The incoming username token contains a password hash. The built-in UsernameTokenManager does not support this type of UsernameToken. Please see the documentation for more details on the UsernameTokenManager.AuthenticateToken method. …etc

      I cannot retrieve the “Hello World” in the retStr.

      Currently I am using VS2008.

      Please advise …

      Thanks.

  7. Hi, I have created a web service with WSE 3.0 using USERNAMETOKEN for the client authentication, and choosing SIGN AND ENCRYPT in the message protection wizard page.
    Looking the conseguent SOAP message, I don’t understant what algorithms and keys are used, and the order they are applied.
    Can you help me?

    Regards
    Mik

  8. “Enable Microsoft Web Service Enhancement Soap Protocal Factory” is grayed out for me in my asp.net project. It is only available when i setup a new website.

    How do i use it in my asp.net web project?

  9. Hi,

    Thank You for Your article. I have one problem. I implemented Username Token as You suggested on Web Service and windows form windows form client.

    When I invoke Web Method by client seems to work fine : I can attache to method AuthenticateToken, It ask for password and username,,,, but when I invoked this Web service by browser it returnt me value without asking for password,,,shoudn’t be some null exception? if yes, what I did wrong?

  10. I have created a WSE3.0 enabled webservice with UserNameToken & Policies. Can’t I access the service without WSE3.0 in my client?

  11. Hi!!

    I read your excelent post, I have a problem when I invoke a Web service secure developed with java using as a client vb.net.

    Do you have an example for consume a java secure web service with vb.net or C#?

    this code works just for a web service with user and password security.

    ‘El primero con token
    Dim userToken As New UsernameToken(“cliente”, “cliente”, _
    PasswordOption.SendPlainText)
    Dim serviceProxy As New local.apiverdom.rzamudio.MyWebService1()
    Dim requestContext As SoapContext = serviceProxy.RequestSoapContext
    requestContext.Security.Tokens.Add(userToken)
    requestContext.Security.Timestamp.TtlInSeconds = 60
    MessageBox.Show(serviceProxy.Porfavorconecta())
    ‘Fin con token

    but when the web service has a Sign an verify signature option and Encrypt and decrypt doesn’t works.

  12. Pingback: WEB development links | Размисли

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