|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
What is WS-SecurityAlthough web services are generally a good idea, they lack some practical features. For example, systemized security and authentication support. If developers would like to have their web services authenticated, they must write and implement it themselves. Also confidentiality of communication is not guaranteed, if SSL is not in use. Because none of them is too enjoyable, good folks from Microsoft, IBM and VeriSign created the WS-Security standard, which solves three basic problems:
How WS-Security worksWS communication between client and server is made by exchange of SOAP messages, which are in fact normal XML documents. These are transported via HTTP or HTTPS in most cases. Use of XML allows almost unlimited extension of these messages – and that’s exactly what WS-Security does. It adds further elements, which can contain various security related information. Web Service enhancementsThe WS-Security protocol is not included in current version of the .NET framework. But there is a package named “Web Service Enhancements” (WSE), which can be downloaded for free from the Microsoft’s web site. This extension implements some advanced standards, besides the WS-Security mentioned here, also WS-Routing, WS-Attachments and DIME. The current stable version is 1.0 SP1 for .NET framework 1.0 or 1.1 (version without SP1 is intended for .NET framework 1.0 only). Newly available is also “technology preview” of version 2.0, which offers even more features, like role-based authorization and protocols WS-Policy, WS-SecurityPolicy, WS-Trust, WS-SecureConversation and WS-Addressing. After installing WSE, you would be ale to use classes contained in namespace All following code has been developed in VS.NET 2003 using WSE 1.0 SP1 and tested on IIS 6.0. Custom classes are intended to be in namespace AuthenticationServerTo use authentication, you must create a class, implementing the The following is a trivial implementation, which returns the string “password”. In real world you would probably search some kind of user database. Public Class MyPasswordProvider _
Implements Microsoft.Web.Services.Security.IPasswordProvider
Public Function GetPassword(ByVal token As _
Microsoft.Web.Services.Security.UsernameToken) As String _
Implements _
Microsoft.Web.Services.Security.IPasswordProvider.GetPassword
Return "password"
End Function
End Class
A second thing you need to do is to setup Web.Config. It must tell your application that it should use your class to check passwords. WARNING: The example has added line breaks for readability. Attribute values must be on single line. <?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="microsoft.web.services"
type="Microsoft.Web.Services.Configuration.WebServicesConfiguration,
Microsoft.Web.Services, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35" />
</configSections>
<system.web>
<webServices>
<soapExtensionTypes>
<add type="Microsoft.Web.Services.WebServicesExtension,
Microsoft.Web.Services, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
<microsoft.web.services>
<security>
<passwordProvider
type="AltairCommunications.Artex.MyPasswordProvider,
AltairCommunications.Artex" />
</security>
</microsoft.web.services>
</configuration>
At this moment, all web service requests containing authentication information would be checked for their validity and in case of error refused automagically. The web services methods itself can be written the usual way. Only it is recommended to add at beginning a test, a check if user is authenticated (to allow publishing of anonymous methods too, WSE will let go through, request without any authentication information). At this time, you would probably want also to check, if the web service is called via the SOAP protocol, not by simply using HTTP GET or POST, which cannot implement WS-Security. Secured (and personalized) version of well-known HelloWorld may then look like the following: <WebMethod()> Public Function SecureHello() As String
'-- Check if I am called via SOAP
Dim RC As Microsoft.Web.Services.SoapContext = _
Microsoft.Web.Services.HttpSoapContext.RequestContext
If RC Is Nothing Then Throw New _
System.Web.Services.Protocols.SoapException_
("Only SOAP requests are accepted", _
New System.Xml.XmlQualifiedName("NotSoapCall"))
'-- Load user authentication data
Dim U As Microsoft.Web.Services.Security.UsernameToken = GetUser(RC)
If U Is Nothing Then Throw New _
System.Web.Services.Protocols.SoapException_
("You are not authenticated", _
New System.Xml.XmlQualifiedName("NotAuthenticated"))
'-- Return personalized message
Return "Hello, " & U.UserName
End Function
Private Function GetUser(ByVal C As _
Microsoft.Web.Services.SoapContext) _
As Microsoft.Web.Services.Security.UsernameToken
For Each T As Microsoft.Web.Services.Security.SecurityToken _
In C.Security.Tokens
If TypeOf T Is Microsoft.Web.Services.Security.UsernameToken _
Then Return T
Next
Return Nothing
End Function
ClientCalling of secured WS is similar to normal. WSE in VS.NET would generate a web service proxy, which would contain two versions of classes: standard (inherits Client must generate instance of Const USER_NAME As String = "user"
Const USER_PASS As String = "password"
Dim T As New TestWSE.SecureWSWse
Dim U As New Microsoft.Web.Services.Security.UsernameToken( _
USER_NAME, _
USER_PASS, _
Microsoft.Web.Services.Security.PasswordOption.SendHashed)
T.RequestSoapContext.Security.Tokens.Add(U)
Console.WriteLine T.SecureHello()
Digital signaturesThe above solution can pass authentication, but does not ensure integrity of data – message can be changed during transport. To avoid this, you must add digital signature to the message – which is simple, as well: ServerThere is no need to configure anything at the server. Only when you want to check if message is signed or not, you can use the following function: Private Function IsSigned(ByVal C As Microsoft.Web.Services.SoapContext) _
As Boolean
For Each E As _
Microsoft.Web.Services.Security.ISecurityElement In C.Security.Elements
If TypeOf E Is _
Microsoft.Web.Services.Security.Signature Then Return True
Next
Return False
End Function
ClientAt client side, you must add only one line of code, which would add the signature: Const USER_NAME As String = "user"
Const USER_PASS As String = "password"
Dim T As New TestWSE.SecureWSWse
Dim U As New Microsoft.Web.Services.Security.UsernameToken( _
USER_NAME, _
USER_PASS, _
Microsoft.Web.Services.Security.PasswordOption.SendHashed)
T.RequestSoapContext.Security.Tokens.Add(U)
T.RequestSoapContext.Security.Elements.Add( _
New Microsoft.Web.Services.Security.Signature(U))
Console.WriteLine T.SecureHello()
Data encryptionIn this phase, all communication is authenticated and digitally signed, which secures it against a counterfeit. But all data are transported in clear form and everyone who understands the SOAP protocol can read them. There are two ways to change this situation. First is to use secured transport channel for communication. You must setup web server to use HTTPS instead of HTTP. This solution is not always possible and wanted. It’s why you can use encryption of the SOAP messages itself, while sending them through an open communication channel. ServerWe will use the 3DES symmetric algorithm to encrypt message contents. Thus, both parties need to have the same encryption key. In the following example we would use 128 bit key, which means 16 bytes, represented as ASCII string The technique is similar to password provider class above. Now we need to implement interface Public Class MyDecryptionKeyProvider
Implements Microsoft.Web.Services.Security.IDecryptionKeyProvider
Public Function GetDecryptionKey(ByVal algorithmUri As String, _
ByVal keyInfo As System.Security.Cryptography.Xml.KeyInfo) _
As Microsoft.Web.Services.Security.DecryptionKey _
Implements _
Microsoft.Web.Services.Security.IDecryptionKeyProvider.GetDecryptionKey
Return New Microsoft.Web.Services.Security.SymmetricDecryptionKey( _
System.Security.Cryptography.TripleDES.Create(), _
System.Text.Encoding.ASCII.GetBytes("MY_SECRET_KEY_16"))
End Function
End Class
Also the key provider must be registered in Web.Config. To section <passwordProvider
type="AltairCommunications.Artex.MyPasswordProvider,
AltairCommunications.Artex" />
For comfort of a kind reader, here is function Private Function IsEncrypted(ByVal C As _
Microsoft.Web.Services.SoapContext) As Boolean
For Each E As Microsoft.Web.Services.Security.ISecurityElement _
In C.Security.Elements
If TypeOf E Is _
Microsoft.Web.Services.Security.EncryptedData Then
Return True
Next
Return False
End Function
ClientTo allow data encryption, also the client part must have proper encryption key. Possible implementation can look like this: Const USER_NAME As String = "user"
Const USER_PASS As String = "password"
Dim T As New TestWSE.SecureWSWse
Dim U As New Microsoft.Web.Services.Security.UsernameToken( _
USER_NAME, _
USER_PASS, _
Microsoft.Web.Services.Security.PasswordOption.SendHashed)
T.RequestSoapContext.Security.Tokens.Add(U)
T.RequestSoapContext.Security.Elements.Add( _
New Microsoft.Web.Services.Security.Signature(U))
Dim Key As New Microsoft.Web.Services.Security.SymmetricEncryptionKey( _
System.Security.Cryptography.TripleDES.Create(), _
System.Text.Encoding.ASCII.GetBytes(Me.txtKey.Text))
Key.KeyInfo.AddClause(New System.Security.Cryptography.Xml.KeyInfoName)
T.RequestSoapContext.Security.Elements.Add( _
New Microsoft.Web.Services.Security.EncryptedData(Key))
Console.WriteLine T.SecureHello()
Instead of happy end Excellent tool to debugging is possibility to save all exchanged messages to files. Simply add the following to the <microsoft.web.services>
<diagnostics>
<trace enabled="true" input="input.xml" output="output.xml" />
</diagnostics>
</microsoft.web.services>
But be warned: do not forget to switch the tracing before deploying application to production server. Like all other XML based protocols, the SOAP is pretty gossipy and trace files can grow to incredible sizes. Links
|
||||||||||||||||||||||