My latest project involves opening up my current companies product catalog to our partners so they can display that product data on their web site. We don't want to expose this data to just anyone, and we want to set up the system to require the partner to register with us before they can use it. The idea is that once they register, they will get a username and password.
The process of adding authentication to your web service methods is pretty easy. There are four steps.
First, define a class that will hold the authorization information. In our case we are using a partner identifier and a password.
Public Class AuthHeader
Inherits SoapHeader
Public PartnerID As String
Public Password As String
End Class
Finally, define a class that extends the SoapExtension class. This class contains the methods that will process the credentials information in the AuthHeader class. The ProcessMessage function is where most of the work is done. That is where you would want to do a lookup to your datastore that holds your authentication data. In this sample, I am doing a simple text comparison.
Public Class AuthExtension
Inherits SoapExtension
Public Overrides Sub ProcessMessage(ByVal message As SoapMessage)
If message.Stage = SoapMessageStage.AfterDeserialize Then
Dim header As SoapHeader
'loop through all the headers and find the AuthHeader that you defined.
For Each header In message.Headers
If TypeOf (header) Is AuthHeader Then
Dim credentials As AuthHeader = CType(header, AuthHeader)
If (credentials.PartnerID.ToLower() = "mypartner" And credentials.Password.ToLower() = "soaprules") Then
Return
End If
End If
Next
Throw New SoapException("Authorization Failed", SoapException.ClientFaultCode)
End If
End Sub
Public Overloads Overrides Function GetInitializer(ByVal type As Type) As Object
Return GetType(type)
End Function
Public Overloads Overrides Function GetInitializer(ByVal info As LogicalMethodInfo, ByVal attribute As SoapExtensionAttribute) As Object
Return Nothing
End Function
Public Overrides Sub Initialize(ByVal initializer As Object)
End Sub
End Class
Third, define an attribute that will be assigned to the methods on which you want authentication to occur.
<AttributeUsage(AttributeTargets.Method)> _
Public Class AuthExtensionAttribute
Inherits SoapExtensionAttribute
Private priority As Integer
Public Overrides Property Priority() As Integer
Get
Return priority
End Get
Set(ByVal Value As Integer)
priority = Value
End Set
End Property
Public Overrides ReadOnly Property ExtensionType() As Type
Get
Return GetType(AuthExtension)
End Get
End Property
End Class
Finally, Add the AuthHeader class to your web service and add the AttributeExtension to your methods.
Public myAuthHeader As AuthHeader
<AuthExtension(), WebMethod(Description:="Sample Web Service Method", EnableSession:=False), SoapHeader("MyAuthHeader", Required:=True)> _
Public Sub MyMethod(ByVal myParam1 As String, ByVal myparam2 As String)
End Sub
Calling the web method with the authheader is even simpler. Just create a local object for the AuthHeader and define the properties with your authentication information. When you add the web service to your project, the AuthHeader definiton gets added to the WSDL file so you can use it locally in your project and intellisense will work with it.
Dim webService As New MyWebService.MyWebService()
Dim myAuthHeader As InphonicProductCatalog.AuthHeader = New MyWebService.AuthHeader()
myAuthHeader.PartnerID = "mypartner"
myAuthHeader.Password = "soaprules"
webService.AuthHeaderValue = myAuthHeader
webService.MyMethod("", "")
If you are not using .Net to call the web service, then the Soap Envelope will look like the following:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthHeader xmlns="http://tempuri.org/MyWebServices">
<PartnerID>string</PartnerID>
<Password>string</Password>
</AuthHeader>
</soap:Header>
<soap:Body>
<MyMethodxmlns="http://tempuri.org/MyWebServices">
<MyParam1>string</strZip>
<MyParam2>string</strDefaultPartnerURL>
</MyMethod>
</soap:Body>
</soap:Envelope>
When I was working on this, I found the following articles helpful:
http://www.codeguru.com/Csharp/Csharp/cs_webservices/security/article.php/c5479/
http://aspnet.4guysfromrolla.com/articles/123103-1.aspx
http://www.c-sharpcorner.com/Code/2004/April/UseSoapHeaderInWebService.asp
http://www.codeproject.com/cs/webservices/authforwebservices.asp
This is fairly clever--but aren't you still sending the user/pass as clear text across the net?
Thanks
Posted by: Chris McKenzie | Thursday, May 06, 2004 at 03:43 PM
Yes, I should have noted that in the article. This works very similar to basic authentication. You should use https when using it because the username and passwords will be transmitted in clear text.
Posted by: Jason | Friday, May 07, 2004 at 03:30 PM
Writing an exact man,i admire you.
Posted by: air jordans | Thursday, November 11, 2010 at 02:03 AM
Your words help a lot, thanks!
Posted by: Chanel J12 | Thursday, March 31, 2011 at 04:44 AM
Did not work for me too. Until I Looked at the code to debug and realized the prrgaom needs to be restarted.Restart Outlook to take affect.The only Problem I have know is changing the font as I don't like the one it is using but at least its better then Plain Text
Posted by: Idha | Saturday, April 28, 2012 at 02:21 AM