How Identity Providers can show custom error messages in CardSpace

 

Wouldn’t you like to show your users a custom error message instead of this generic one?

 

Generic network error message 

 

Now you can with the latest .Net Framework 3.5 release (Beta 2 as of this blog). Your Identity Provider can simply return a SOAP fault and CardSpace will display the Fault Reason Text. This feature is great because it enables you to present the user with help and support information such as phone numbers or URLs. Your error message can now look like this:

 

 Plain text custom error message

 

Your fault reason text can also be language specific. CardSpace will display the correct fault reason text based on the UI locale.

Custom error message in Spanish 

Frequently Asked Questions

 

What is the format of a SOAP message?

 

<s:Envelope xmlns:a="https://www.w3.org/2005/08/addressing" xmlns:s="https://www.w3.org/2003/05/soap-envelope">

  <s:Header>

    <a:Action s:mustUnderstand="1">https://www.w3.org/2005/08/addressing/soap/fault</a:Action>

  </s:Header>

  <s:Body>

    <s:Fault>

      <s:Code>

        <s:Value>s:Sender</s:Value>

      </s:Code>

      <s:Reason>

        <s:Text xml:lang="en"> In English …</</s:Text>

        <s:Text xml:lang="es-ES">In Spanish …</s:Text>

      </s:Reason>

    </s:Fault>

  </s:Body>

</s:Envelope>

 

Note that this SOAP message must be secured just like a typical application message. That is, it must contain the necessary Security headers (with all the necessary signature and encryption requirements based on the binding). CardSpace will only display secured fault messages. It will not display unsecured fault messages.

 

Can I present rich HTML information?

CardSpace will only display plain text messages.

How do I return a custom error message with WCF?

 

Your code snippet will look something like this:

 

using System.ServiceModel;

FaultReasonText defaultMessage = new FaultReasonText(@"Our record on file shows that you are not authorized to use this service. If you have forgotten your user name or your password, please visit

https://www.contoso.com/help for further assistance.

You can also call (123) 456-7890 to speak with one of our customer care representatives.", "en");

FaultReason reason = new FaultReason(defaultMessage);

throw new FaultException(reason);

 

 

 The FaultReasonText has constructors that take the culture info (see https://msdn2.microsoft.com/en-us/library/system.servicemodel.faultreasontext.faultreasontext.aspx). The list of culture names is documented at https://msdn2.microsoft.com/en-us/library/system.globalization.cultureinfo.aspx. You can even do something like this:

 

FaultReasonText defaultMessage = new FaultReasonText(@"The default error message", "en");

FaultReasonText spanish = new FaultReasonText("(In Spanish) Español", "es-ES");

List<FaultReasonText> reasonInDifferentLanguages = new List<FaultReasonText>();

reasonInDifferentLanguages.Add(defaultMessage);

reasonInDifferentLanguages.Add(spanish);

FaultReason reason = new FaultReason(reasonInDifferentLanguages);

throw new FaultException(reason);

 

There are a few caveats. Due to the way the WCF channel stack processes a SOAP message; the fault message will be sent as a secured fault message if you throw the FaultException in the following places:

1. Within the code path of ServiceAuthorizationManager.CheckAccessCore

2. Within the code path of the Identity Provider’s Issue operation.

 

If you want to show a friendly error message due to authentication failures, the above steps is not sufficient because the WCF channel stack will send back the exception as an unsecured fault message. Since CardSpace only displays secured fault messages, the user will not see the friendly message that you have sent back. Instead the user will see the generic version.

 

The workaround is to use the security extensibility points in WCF to delay throwing an exception until the WCF channel stack calls into the ServiceAuthorizationManager.CheckAccessCore. The steps below use the UserNamePasswordValidator as an example; the same principle applies to other types of validation as well:

 

1. Implement a custom UserNamePasswordValidator to validate the user name and password.

2. Implement a custom UserNameSecurityTokenAuthenticator to call your custom UserNamePasswordValidator. If the user name and password validation succeeds, return a custom IAuthorizationPolicy that will pull in other claims permitted for this user. If the password validation fails, return an invalid authorization policy. The job of this invalid authorization policy is to insert an “invalidusernamepassword” claim when called upon.

3. Implement a custom ServiceAuthorizationManager  to check for the “invalidusernamepassword” claim in the AuthorizationContext. If it exists, throw your friendly FaultException message. If it does not exist, you can check the other claims to grant /deny access.

4. Wire up these customizations by implementing a custom ServiceCredentialsSecurityTokenManager and a custom ServiceCredentials. Then replace the ServiceCredentials on ServiceHost with the custom one.

 

For further details regarding the above (including code samples), do visit these resources:

· UserNamePasswordValidator

· Govind’s blog on plugging in a custom UserNamePasswordAuthenticator. Govind’s office, by the way, is on the same floor as mine. It was really convenient for me to walk over and ask him questions about how the security layer works in the WCF channel stack J.

· MSDN article on Custom Security Token Authenticator

· How to create a custom Service Credentials

 

Is there a sample I can play around with?

Brian on our team is working on samples right now. He’ll post it once the samples are ready.

 

 

Cool new feature, isn’t it. Do let us know how else we can help you build a better Identity solution.

 

 

Dedicated to your success,

Tak Wai, Wong

Software Design Engineer in Test

CardSpace Team

Comments

  • Anonymous
    October 12, 2007
    Hi guys. Great post - and I'm glad we're getting better errors in the near future! This was something we weren't too happy about in the first version.But I was wondering if there's any special support for known soap faults, such as WS-Trust or WS-Security or the identity faults? I'm especially thinking about wst:FailedAuthentication (and the very similar sounding wsse:FailedAuthentication) and ic:InformationCardRefreshRequired.Do these faults have special handling, or do you still just display the reason code from the fault message? (Which might be the best way, at least then we can offer some kind of support, such as phone numbers)Keep the posts coming!CheersMatt
  • Anonymous
    October 15, 2007
    Q: Can a card be marked as "not exportable"? A: No this is not possible at the moment. After a card has
  • Anonymous
    October 19, 2007
    This may be a little off topic - will we be able to decrypt tokens under ASP.NET medium trust?
  • Anonymous
    October 23, 2007
    Customers and partners exploring the possibility of becoming identity providers have provided us consistent
  • Anonymous
    October 23, 2007
    Customers and partners exploring the possibility of becoming identity providers have provided us consistent
  • Anonymous
    October 29, 2007
    I was still trying to figure out a way to use multi-factor authentication for cardspace. However, I was facing a very specific problem. I think this is the feature that solves the problem for me !!Great work !!http://dy-verse.blogspot.com/2007/10/two-factor-authentication-for-cardspace.html
  • Anonymous
    October 30, 2007
    Matt,With regard to your question on custom error messages:1) Yes, CardSpace will show your reason text even if the fault code is one of the pre-defined ones like ic:InformationCardRefreshRequired.2) For an authentication failure, please see the caveat in the blog post if your Identity Provider is implemented with WCF.Tak Wai