Introduction

When I started working with WSE3, I just wanted to test how to authenticate a web service call with a username and password. I read the Implementing Direct Authentication with UsernameToken in WSE 3.0 article and I found it was very useful will all of the issues regarding to security. Wait a minute. It was so complicated for a newbie like me. I didn't care how to secure the message between client and web services at this time yet. I just wanted to pass a username and password as plain text and the web service to do authentication for each method call. I will leave the message encrypting tasks between client and web service for another article.

Background

Using the Code

UsernameToken with username and password will be attached to the SOAP header when the client makes a call to the web service. To do custom authentication at server side, you need to override the AuthenticateToken method of the UsernameTokenManager class. We will create a class library project called UsernameAssertionLibrary and add a class called ServiceUsernameTokenManager that inherits from UsernameTokenManager.

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Design;
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.Tokens;
namespace UsernameAssertionLibrary
{
publicclass ServiceUsernameTokenManager : UsernameTokenManager
{
///<spanclass="code-SummaryComment"><summary/></span>
/// Constructs an instance of this security token manager.
/// <spanclass="code-SummaryComment"></summary/></span>
public ServiceUsernameTokenManager()
{
}
/// <spanclass="code-SummaryComment"><summary/></span>
/// Constructs an instance of this security token manager.
/// <spanclass="code-SummaryComment"></summary/></span>
/// <paramname="nodes"/>An XmlNodeList containing XML elements from a configuration file.</param/>
public ServiceUsernameTokenManager(XmlNodeList nodes)
: base(nodes)
{
}
/// <spanclass="code-SummaryComment"><summary/></span>
/// Returns the password or password equivalent for
/// the username provided.
/// <spanclass="code-SummaryComment"></summary/></span>
/// <paramname="token"/>The username token</param/>
/// <spanclass="code-SummaryComment"><returns/>The password (or password equivalent) for the
</span>
/// username<spanclass="code-SummaryComment"></returns/></span>
protected override string AuthenticateToken(UsernameToken token)
{
string username = token.Username;
// it's up to you where you will get a password for some user
// you may:
// 1) get the password hash from web.config or system registry
// if you are implementing per-server security
// 2) get the password from the database or
// XML file for the given user name
// for example purposes we just return a reversed value of
// username
char[] ch = username.ToCharArray();
Array.Reverse(ch);
return new String(ch);
}
}
}

The AuthenticateToken method will be called by WSE3 to retrieve the password of token.Username. You can implement this method to get a password from database, XML file, etc. for the given username. WSE3 will check if the password returned by AuthenticationToken matches with the password in the SOAP header. If they don't match, an exception will be sent to the client.

Now that we have the UsernameAssertionLibrary DLL, we need to register it to our web service. Add an ASP.NET web service project to the solution. We need to add reference to the UsernameAssertionLibrary class library to the web service project or we can copy UsernameAssertionLibrary.dll to the bin directory of the web service folder.

To enable WSE 3.0, right click on the web service project and click WSE Settings 3.0.

Under the General tab, check both Enable this project for Web Services Enhancements and Enable Microsoft Web Services Enhancement Soap Protocol Factory.

Under the Security tab, in the Security Tokens Managers area, click Add. Fill in the fields as follows:

Under the Policy tab, check Enable Policy and click Add. Name your new application policy "ServerPolicy" and then click OK. In the WSE Security Settings Wizard window:

Select Secure a service application and Username; then click Next

Check Specify Username Token in code and click Next

Select None (reply on transport protection), click Next and Finish

Don't worry about the setting for Protection Order. We just make it work first before we can think how we should protect information sent via the network. There are several way you can secure your message -- for example, using SSL or WSE3.0 to encrypt the SOAP message -- but it is not in this very first look at WSE3.0.

Under the Diagnostics tab, select Enable Message Trace. Enter InputTrace.webinfo into the Input text box and OutputTrace.webinfo into the Output text box. These are XML files you can use to trace SOAP messages sent from the client and service.

Now we need to code for our web service. Add reference to Microsoft.Web.Services3 to the project. Open Service.cs and copy the code:

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using Microsoft.Web.Services3;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[Microsoft.Web.Services3.Policy("ServerPolicy")]
publicclass Service : System.Web.Services.WebService
{
public Service ()
{
//Uncomment the following line if using designed components
//InitializeComponent();
}
[WebMethod]
publicstring HelloMyFriend()
{
//Say hello to the guy that you know
return"Hello " +
RequestSoapContext.Current.IdentityToken.Identity.Name;
}
}

The attribute [Microsoft.Web.Services3.Policy("ServerPolicy")] will register our ServerPolicy, which is configured in wse3policyCache.config to the service. We have a web method called HelloMyFriend() that returns a string Hello + the username in the token, which is passed in the SOAP header when the client makes a HelloMyFriend call. There is no code in the HelloMyFiend method to authenticate the username, but WSE will call AuthenticateToken() from our custom Username Token Manager to retrieve the password. It will then compare the password with the one in SOAP header sent from the client.

Now we will see how we can have username and password in the SOAP header when we make a service call. Add a Console Application project to our solution called TestWebService and add reference to Microsoft.Web.Services3. Before you can make a call to the web service, you need to have a proxy. You can either use Add Web Preference in Visual Studio or use WseWsdl3.exe to generate a proxy class. I used WseWsdl3.exe; the default is in Program Files\Microsoft WSE\v3.0\Tools. Here is the command to generate the ServiceProxy.cs class.

Add ServiceProxy.cs to our TestWebService project. Like the server side, the client also needs to have a policy. You need to configure the client to enable WSE3.0. To enable WSE 3.0, right click on the TestWebService project and click WSE Settings 3.0.

Under the General tab, check Enable this project for Web Services Enhancements.

Under the Policy tab, check Enable Policy and click Add. Name your new application policy "ClientPolicy" and click OK. In the WSE Security Settings Wizard window:

Select Secure a client application and Username and click Next

Check Specify Username Token in code and click Next

Select None (reply on transport protection), click Next and Finish

Under the Diagnostics tab, select Enable Message Trace. Enter InputTrace.webinfo into the Input text box and OutputTrace.webinfo into the Output text box.

Now try to run TestWebService. If you change the password to "nimda1" you will get an exception. You can open OutputTrace.webinfo to see the SOAP message. You might think that the username and password should not be seen. There are several way to secure messages, for example, using SSL (point to point) or WSE3.0 (end to end).

History

6 July, 2007 -- Original version posted

12 July, 2007 -- Updated

4 September, 2007 -- Article edited and moved to the main CodeProject.com article base

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

About the Author

Comments and Discussions

Hi, I am using WSE 3.0 to give security to on webservice. I have implemented the webservice and i am using that webserice in my applicaion. But it works only for user'admin'. I want to change the username and password. How do i change it? Can anybody tell me how to change it?