Re: friendly error messages for usernameForCertificateSecurity



I have been experimenting recently with possible workarounds to this same
problem.

As far as I can determine, the
CustomeUsernameTokenManager.AuthenticateToken() method is called as part of
the receive security filter processing to create the
Microsoft.Web.Services3.Security.Security object that is passed to the
current policy assertion's ValidateMessageSecurity() method. Only if the
message security is valid is it put into the OperationState for the current
context. The consequence is that if you cause AuthenticateToken() to fail by
throwing an exception or returning a null response then the Security
instance isn't stored in the OperationState and is therefore unavailable to
the service's SendSecurityFilter, and thus the missing security header in
the response received at the client.

To work around this behaviour I created a
CustomUsernameForCertificateAssertion that subclasses the
Microsoft.Web.Services3.Design.UsernameForCertificateAssertion class. The
basic idea then is to not throw an error from AuthenticateToken() but set
the token.Principal to have an Identity whose property IsAuthenticated
returns false. This is tested in an overloaded ValidateMessageSecurity()
method in my custom assertion's service input filter and then throw an error
if not valid. This error is then returned in a properly formatted Response
message with a valid security header and appears as a SoapException with som
well known message text.

Misconfigurations could lead to unexpected security exposures, for example
having a custom username token manager that always succeeds but forgetting
to match to a custom username for certificate assertion implementation. I
minimised the exposure by placing a marker interface on my policy assertion
and checking for it in a new base for my custom username manager. To
illustrate this, here are some code snippits:

hope this helps your thought processes and experiments,
--p.


// CustomUsernameForCertificateAssertion that checks IsAuthenticated on
Identity
public class CustomUsernameForCertificateAssertion :
UsernameForCertificateAssertion, IDeferredAuthenticateToken
{
protected class MyServiceInputFilter : ServiceInputFilter
{
#region Constructor and private fields ...

public override SoapFilterResult ProcessMessage( SoapEnvelope
envelope )
{
// used in custom token manager base
envelope.Context.MessageState.Set<PolicyAssertion>(
_assertion );

return base.ProcessMessage( envelope );
}

public override void ValidateMessageSecurity( SoapEnvelope envelope,
Security security, MessageProtectionRequirements request )
{
base.ValidateMessageSecurity( envelope, security, request );

SecurityToken token = envelope.Context.IdentityToken;

if ( !token.Identity.IsAuthenticated )
{
throw new throw new SoapException( "Authentication
error", SoapException.ServerFaultCode );
}
}
}

#region Rest of class ...
}

// Base for custom token managers that always succeed
public abstract class UsernameTokenManagerBase : UsernameTokenManager
{
protected sealed override string AuthenticateToken( UsernameToken
token )
{
string password = AuthenticateTokenCore( token );

GenericIdentity identity = null;
GenericPrincipal principal = null;

// if failed, throw exception unless assertion implements
IDeferredAuthenticateToken.
if ( string.IsNullOrEmpty( password ) )
{
SoapContext context = SoapContext.Current;

PolicyAssertion assertion =
context.MessageState.Get<PolicyAssertion>();

if ( assertion != null && ( assertion is
IDeferredAuthenticateToken ) )
{
identity = new GenericIdentity( string.Empty );
principal = new GenericPrincipal( identity, null );
}
else
{
throw new ApplicationException( "The user couldn't be
authenticated" );
}
}
else
{
identity = new GenericIdentity( token.Username );
principal = new GenericPrincipal( identity, null );
}

token.Principal = principal;

return token.Password;
}

// new method a custom token manager must implement
protected abstract string AuthenticateTokenCore( UsernameToken
token );
}

// custom token manager, this one happens to validate against a Membership
DB.
public class CustomUsernameTokenManager : UsernameTokenManagerBase
{
protected override string AuthenticateTokenCore ( UsernameToken
token )
{
bool validCredentials = Membership.ValidateUser( token.Username,
token.Password );

// if failed, return null.
if ( !validCredentials )
{
return null;
}

GenericIdentity identity = new GenericIdentity(
token.Username );
GenericPrincipal principal = new GenericPrincipal( identity,
null );

token.Principal = principal;

return token.Password;
}
}

In the Web.Config in the security section of <microsoft.web.services3> add
something similar to:

<securityTokenManager>
<add localName="UsernameToken"
namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; type="CustomTokenManagers.CustomUsernameTokenManager, CustomTokenManagers"/></securityTokenManager>and in your policy file add an extension element: <extensions> <extension name="usernameForCertificateSecurity" type="CustomTokenManagers.CustomUsernameForCertificateAssertion,CustomTokenManagers"/> </extensions>"geobier" <geobier@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in messagenews:D9CB7856-822A-457E-8993-59153D9E4076@xxxxxxxxxxxxxxxx> This has been asked several times on the web, but I have yet to see asolution.>> In short:>> Using usernameForCertificateSecurity, with a custom UsenameTokenManager,> AuthenticateToken detects an error ( "Invalid user id or password","account> is locked", "account expires in 5 days"). How can this error message be> returned to the client in a simple way.>> More specifically:>> protected override string AuthenticateToken(UsernameToken token)> {> ....>> // password is invalid!!!!> // What is the code to put here?????> // throw new SoapException("Bad juju", new XmlQualifiedName("geb:hi"));> }>> In the code above if I comment out the throwing of the soap exception onthe> client side, I receive back the dreaded:>> "WSE910: An error happened during the processing of a response message,and> you can find the error in the inner exception.">> the inner exception is equally useless:>> "Security requirements are not satisfied because the security header isnot> present in the incoming message.">> If you recast the outer exception as follows:>> catch (Exception exc)> {> Microsoft.Web.Services3.ResponseProcessingException temp => (Microsoft.Web.Services3.ResponseProcessingException) exc;> string message = temp.Response.Fault.Message;> }>> you CAN get to the original message, ("bad juju") just follow the --->three> deep:>> message:>> System.Web.Services.Protocols.SoapHeaderException: Server unavailable,> please try later ---> System.ApplicationException: WSE841: An erroroccured> processing an outgoing fault response. --->> System.Web.Services.Protocols.SoapException:> System.Web.Services.Protocols.SoapException: Bad juju\r\n at> Ingenix.Omx.WS.UTM.AuthenticateToken(UsernameToken token) in> C:\\WebSites\\HelloWSE\\TokenManager\\TokenManager.cs:line 200\r\n at>Microsoft.Web.Services3.Security.Tokens.UsernameTokenManager.VerifyToken(SecurityToken> token)\r\n at Ingenix.Omx.WS.UTM.VerifyToken(SecurityToken token) in> C:\\WebSites\\HelloWSE\\TokenManager\\TokenManager.cs:line 169\r\n at>Microsoft.Web.Services3.Security.Tokens.SecurityTokenManager.LoadXmlSecurityToken(XmlElement> element)\r\n at>Microsoft.Web.Services3.Security.Tokens.SecurityTokenManager.GetTokenFromXml(XmlElement> element)\r\n at> Microsoft.Web.Services3.Security.Security.LoadToken(XmlElement element,> SecurityConfiguration configuration, Int32& tokenCount)\r\n at> Microsoft.Web.Services3.Security.Security.LoadXml(XmlElement element)\r\n> at Microsoft.Web.Services3.Security.Security.CreateFrom(SoapEnvelope> envelope, String localActor, String serviceActor)\r\n at>Microsoft.Web.Services3.Security.ReceiveSecurityFilter.ProcessMessage(SoapEnvelope> envelope)\r\n at> Microsoft.Web.Services3.Pipeline.ProcessInputMessage(SoapEnvelope> envelope)\r\n at> Microsoft.Web.Services3.WseProtocol.FilterRequest(SoapEnvelope> requestEnvelope)\r\n at> Microsoft.Web.Services3.WseProtocol.RouteRequest(SoapServerMessage> message)\r\n at> System.Web.Services.Protocols.SoapServerProtocol.Initialize()\r\n at> System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type,> HttpContext context, HttpRequest request, HttpResponse response, Boolean&> abortProcessing)\r\n --- End of inner exception stackace ---\r\n ---> End of inner exception stack trace ---" string>> Trying to tell my clients that they need to parse this message to get the> true error message is a less then desireable solution.>> Questions:>> 1) Is there some way to have the exception show up in the InnerMessage> exception tree? Telling my clients to follow the inner exception tree isa> much better solution.>> 2) Is there an alternative way of communicating the error information back> rather then throwing an exception. The above example uses aSoapException,> if you change it to thrown new Exception("bad juju"), the results are> similar. Anyone got a better solution?>> Restrictions:>> Custom assertion policy on the client side is not going to be anacceptable> solution with my clients. We are already pushing the limits on client> configuration complexity using the canned policies.>> On the server side, which I control, I am willing to code as complicated a> solution as required to be able to return to my clients a reasonablemessage.>> Observation:>> This seems like a common use case for this security case. All the> quickstarts and examples I was able to track down skip this issue. Ionly> found one client side example that mentioned this case and it simplyshowed> the client catching the exception, without actually going into what the> exception contained. Is anyone actually really using this stuff (sigh)?As> I said, other people have asked this question before.>> Alternative:>> One thought I have been playing with is always accepting the credential,but> setting a flag in the UsernameToken indicating that the user did not> validate, with a reason code. My server side protected webmethods wouldthen> do a validation check at entry, and at that point I could return areasonable> error message or SoapException. This is one heck of an ugly workaround,but> gets me out of this mess. Opinions?>> thanks,> --george>>>>>>>> --> thanks,> --george

.



Relevant Pages

  • Re: .NET Deployment: Minimum Customer Effort
    ... to simply deploy a custom your custom .NET security policy as ... MVP Security ... > configuration, installation of .msi file using MMC, etc. ... > agree to the permissions demanded by our code? ...
    (microsoft.public.dotnet.security)
  • Re: Interpop between WSS4J and WSE3 using UsernameForCertificateSecurity
    ... us to be leary of custom implementations when we already have interop ... each WSE 3.0 policy can only contain single security ... policy assertion that perform message layer securing. ...
    (microsoft.public.dotnet.framework.webservices.enhancements)
  • Re: Security Implementation
    ... > WSE and using one of the security token types ... Anyway, if you go the WSE route, you can secure ... > all method calls by requiring a UserName token or a SecurityContextToken. ... > yourself using Win32 LogonUser api or custom DB. ...
    (microsoft.public.dotnet.general)
  • Re: arrange form data in same order as on form
    ... > that has all the security provisions and knowledge accumulated over ... Custom read and parse routines are easy to write and not only offer ... Those average figures have been exemplified many times over ...
    (comp.lang.perl.misc)
  • Re: creating custom HttpContext.Current.User.Identity
    ... some reason you can't, you can easily use the GenericPrincipal class with ... your custom IIdentity implementation. ... GenericIdentity (or most of the framework IIdentity or IPrincipal ...
    (microsoft.public.dotnet.framework.aspnet.security)

Loading