Access Control Service: Handling Errors

Another common problem with external authentication is how to deal with sign in errors. In active federation like WS-Trust there are well defined SOAP faults to communicate problem to a client.

But with web applications, the error information is typically generated and displayed on the external sign in page. The relying party does not know about the error, nor can it help the user in any way.

The Access Control Service allows to post sign in errors to a specified page. You setup this page in the relying party registration. That means that whenever an error occurs in ACS, the error information gets packaged up as a JSON string and posted to the page specified. This way you get structued error information back into you application so you can display a friendlier error message or log the error.

I added error page support to my ACS2 sample, which can be downloaded here.

How to turn the JSON error into CLR types
The JSON schema is reasonably simple, the following class turns the JSON into an object:

[DataContract]
public class AcsErrorResponse
{
    [
DataMember(Name = "context"
, Order = 1)]
   
public string Context { get; set
; }

    [
DataMember(Name = "httpReturnCode"
, Order = 2)]
   
public string HttpReturnCode { get; set
; }

    [
DataMember(Name = "identityProvider"
, Order = 3)]   
   
public string IdentityProvider { get; set
; }

    [
DataMember(Name = "timeStamp"
, Order = 4)]
   
public string TimeStamp { get; set
; }

    [
DataMember(Name = "traceId"
, Order = 5)]
   
public string TraceId { get; set
; }

    [
DataMember(Name = "errors"
, Order = 6)]
   
public List<AcsError> Errors { get; set
; }

   
public static AcsErrorResponse Read(string
json)
    {
       
var serializer = new DataContractJsonSerializer(
typeof(AcsErrorResponse
));
       
var response = serializer.ReadObject(
new MemoryStream(Encoding.Default.GetBytes(json))) as AcsErrorResponse
;

       
if (response != null
)
        {
           
return
response;
        }
       
else
        {
           
throw new ArgumentException("json"
);
        }
    }
}

[
DataContract
]
public class AcsError
{
    [
DataMember(Name = "errorCode"
, Order = 1)]
   
public string Code { get; set
; }
       
    [
DataMember(Name = "errorMessage"
, Order = 2)]
   
public string Message { get; set; }
}

Retrieving the error information
You then need to provide a page that takes the POST and deserializes the information. My sample simply fills a view that shows all information. But that’s for diagnostic/sample purposes only. You shouldn’t show the real errors to your end users.

public class SignInErrorController : Controller
{
    [
HttpPost
]
   
public ActionResult
Index()
    {
       
var errorDetails = Request.Form["ErrorDetails"
];
       
var response = AcsErrorResponse
.Read(errorDetails);
       
return View("SignInError", response);
    }
}

Also keep in mind that the error page is an anonymous page and that you are taking external input. So all the usual input validation applies.

This entry was posted in IdentityModel. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s