After I've been unsuccesfull with my own code, I compiled the example file
from the WSE 2.0 SP2 and got the same result as mentioned in a post before
(and now solution was found, even I went through all the stuff that was
mentioned).
My CustomUsernameTokenManager class is not being called to do the server
service side verification.
On the client side the CustomUsernameTokenManager is being called with the
line:
token = new UsernameToken(username, "BadPassword", PasswordOption.SendHashed);
But in the server side it goes through without calling the constructors,
even without verifying the password! With the above token created inside the
client, the Service is returning the request without a problem!
I’m suspecting that the following Service side code is the problem:
UsernameToken usernameToken =
AppBase.GetSigningToken(RequestSoapContext.Current);
if (usernameToken == null || usernameToken.PasswordOption ==
PasswordOption.SendPlainText)
{
throw new SecurityFault(SecurityFault.FailedAuthenticationMessage,
SecurityFault.FailedAuthenticationCode);
}
And what I'm suspecting is that it is because their is no 'new' constructor
call? The AppBase.GetSigningToken looks like this:
public static SecurityToken GetSigningToken(SoapContext context)
{
foreach ( ISecurityElement element in context.Security.Elements )
{
if ( element is MessageSignature )
{
// The given context contains a Signature element.
MessageSignature sig = element as MessageSignature;
if (CheckSignature(context, sig))
{
// The SOAP Body is signed.
return sig.SigningToken;
}
}
}
return null;
}
My web.config:
<microsoft.web.services2>
<diagnostics>
<detailedErrors enabled="false" />
</diagnostics>
<security>
<securityTokenManager
type="UsernameSignCodeService.CustomUsernameTokenManager,
UsernameSignCodeService"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" qname="wsse:UsernameToken" />
</security>
</microsoft.web.services2>
What should I do to 'link' the service side as well?
Dilip Krishnan - 08 Jan 2005 17:32 GMT
Hello FrikOlivier,
Could you post the code for the Authenticate method in the CustomUsernameTokenManager
please? It should be authenticating the token there
HTH
Regards,
Dilip Krishnan
MCAD, MCSD.net
dkrishnan at geniant dot com
http://www.geniant.com
> After I've been unsuccesfull with my own code, I compiled the example
> file from the WSE 2.0 SP2 and got the same result as mentioned in a
[quoted text clipped - 61 lines]
> </microsoft.web.services2>
> What should I do to 'link' the service side as well?
FrikOlivier - 08 Jan 2005 22:21 GMT
Here is the complete file. It is the UsernameSigningCode example.
What I did in the meantime is to SHA1CryptoServiceProvider the password in
the client, Convert.ToBase64String, and then send it to the Service using
PasswordOption.SendPlainText in the UsernameToken. I then
Convert.FromBase64String the plain (encrypted) text in the Service and
compare it with the password which is stored as SHA1CryptoServiceProvider in
the Database.
This seems to work and even I use PlainText option, I don't send the actual
password. ALthough I still could not get it to use my
CustomeUsernameTokenManager....
/*================================================================================
File: UsernameTokenManager.cs
Summary: This is a sample which allows the user to send a message to a Web
service that has been signed with a username and password
----------------------------------------------------------------------------------
This file is part of the Web Services Enhancements 2.0 for Microsoft .NET
Samples.
Copyright (C) Microsoft Corporation. All rights reserved.
This source code is intended only as a supplement to Microsoft Development
Tools
and/or on-line documentation. See these other materials for detailed
information
regarding Microsoft code samples.
This sample is designed to demonstrate WSE features and is not intended
for production use. Code and policy for a production application must be
developed to meet the specific data and security requirements of the
application.
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
WARRANTIES
OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE
================================================================================*/
using System;
using System.Xml;
using System.Security.Permissions;
using Microsoft.Web.Services2.Security;
using Microsoft.Web.Services2.Security.Tokens;
namespace UsernameSignCodeService
{
/// <summary>
/// By implementing UsernameTokenManager we can verify the signature
/// on messages received.
/// </summary>
/// <remarks>
/// This class includes this demand to ensure that any untrusted
/// assemblies cannot invoke this code. This helps mitigate
/// brute-force discovery attacks.
/// </remarks>
[SecurityPermissionAttribute(SecurityAction.Demand,
Flags=SecurityPermissionFlag.UnmanagedCode)]
public class CustomUsernameTokenManager : UsernameTokenManager
{
/// <summary>
/// Constructs an instance of this security token manager.
/// </summary>
public CustomUsernameTokenManager()
{
}
/// <summary>
/// Constructs an instance of this security token manager.
/// </summary>
/// <param name="nodes">An XmlNodeList containing XML elements from
a configuration file.</param>
public CustomUsernameTokenManager(XmlNodeList nodes)
: base(nodes)
{
}
/// <summary>
/// Returns the password or password equivalent for the username
provided.
/// </summary>
/// <param name="token">The username token</param>
/// <returns>The password (or password equivalent) for the
username</returns>
protected override string AuthenticateToken( UsernameToken token )
{
// This is a very simple manager.
// In most production systems the following code
// typically consults an external database of
(username,password) pairs where
// the password is often not the real password but a password
equivalent
// (for example, the hash of the password). Provided that both
client and
// server can generate the same value for a particular username,
there is
// no requirement that the password be the actual password for
the user.
// For this sample the password is simply the reverse of the
username.
byte[] password = System.Text.Encoding.UTF8.GetBytes(
token.Username );
Array.Reverse( password );
return Convert.ToBase64String( password );
}
}
}
William Stacey [MVP] - 10 Jan 2005 04:04 GMT
> This seems to work and even I use PlainText option, I don't send the actual
> password. ALthough I still could not get it to use my
Is the protocol encrypting the PasswordOption.SendPlainText pw (i.e. your
base64 string)?

Signature
William Stacey, MVP
http://mvp.support.microsoft.com
dafan - 31 Aug 2006 04:01 GMT
Here's one of the solution:
You must put the CustomTokenManager's dll file into
GAC (Global Assembly Cache) which located into "C:\WINDOWS\assembly"
Step 1: Create a project named "CustomClass" using VS. studio 2005
Step 2: Create the CustomToken manager code as below:
Imports System
Imports System.Xml
Imports System.Security.Permissions
Imports System.Web.Security
Imports System.Security.Principal
Imports Microsoft.Web.Services3.Security
Imports Microsoft.Web.Services3.Security.Tokens
Namespace Service
<SecurityPermissionAttribute(SecurityAction.Demand, Flags:
=SecurityPermissionFlag.UnmanagedCode)> _
Public Class CustomUsernameTokenManager
Inherits UsernameTokenManager
Public Sub New()
End Sub
Public Sub New(ByRef nodes As XmlNodeList)
MyBase.New(nodes)
End Sub
Protected Overrides Function AuthenticateToken(ByVal token As
UsernameToken) As String
Dim blnValidCredential As Boolean = False
Dim objIdentity As GenericIdentity
Dim objPrincipal As GenericPrincipal
Dim strRole As String()
If token.Username = "JohnDoe" And token.Password = "johnd123"
Then
Else
Throw New ApplicationException("Can not authenticate this
user")
End If
strRole = New String() {"GuestUser"}
objIdentity = New GenericIdentity(token.Username)
objPrincipal = New GenericPrincipal(objIdentity, strRole)
token.Principal = objPrincipal
Return token.Password
End Function
End Class
End Namespace
Step 3: Before compile the project to produce the "CustomClass.dll",
you must follow the instruction from this link
(How to install an assembly in the Global Assembly Cache):
http://support.microsoft.com/default.aspx?scid=kb;en-us;315682
Step 4: Record the "AssemblyName", "Version", "Culture", "Public Key Token"
in the "C:\WINDOWS\assembly"
Step 5: Go to "Web.config" in the Server Side Web Services project
and add what you recorded in the ""C:\WINDOWS\assembly" like
the following sample:
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
......
<system.web>
<compilation debug="true" strict="false" explicit="true">
<assemblies>
<add assembly="CustomClass, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=10697CC0ABF25E2F"/>
</assemblies>
</compilation>
</system.web>
<microsoft.web.services3>
<policy fileName="wse3policyCache.config"/>
<security>
<securityTokenManager>
<add localName="UsernameToken" type="CustomClass.Service.
CustomUsernameTokenManager, CustomClass, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=10697CC0ABF25E2F" namespace="
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"/
</securityTokenManager>
</security>
</microsoft.web.services3>
</configuration>
That's all folk.
To.Ph.
------------------------------------------------------------------------------
-------------------------------
------------------------------------------------------------------------------
------------------------------
>After I've been unsuccesfull with my own code, I compiled the example file
>from the WSE 2.0 SP2 and got the same result as mentioned in a post before
[quoted text clipped - 60 lines]
>
>What should I do to 'link' the service side as well?