Web Apps vs Web Services: 302s and 401s are not always good Friends
- by Your DisplayName here!
It is not very uncommon to have web sites that have web UX and services content. The
UX part maybe uses WS-Federation (or some other redirect based mechanism). That means
whenever an authorization error occurs (401 status code), this is picked by the corresponding
redirect module and turned into a redirect (302) to the login page. All is good.
But in services, when you emit a 401, you typically want that status code to travel
back to the client agent, so it can do error handling. These two approaches conflict.
If you think (like me) that you should separate UX and services into separate apps,
you don’t need to read on. Just do it ;)
If you need to mix both mechanisms in a single app – here’s how I solved it for a
project.
I sub classed the redirect module – this was in my case the WIF WS-Federation HTTP
module and modified the OnAuthorizationFailed method. In there I check for
a special HttpContext item, and if that is present, I suppress the redirect.
Otherwise everything works as normal:
class ServiceAwareWSFederationAuthenticationModule : WSFederationAuthenticationModule
{
protected override void OnAuthorizationFailed(AuthorizationFailedEventArgs e)
{
base.OnAuthorizationFailed(e);
var isService
= HttpContext.Current.Items[AdvertiseWcfInHttpPipelineBehavior.DefaultLabel];
if (isService
!= null)
{
e.RedirectToIdentityProvider
= false;
}
}
}
Now the question is, how do you smuggle that value into the HttpContext.
If it is a MVC based web service, that’s easy of course. In the case of WCF, one approach
that worked for me was to set it in a service behavior (dispatch message inspector
to be exact):
public void BeforeSendReply(
ref Message reply, object correlationState)
{
if (HttpContext.Current
!= null)
{
HttpContext.Current.Items[DefaultLabel]
= true;
}
}
HTH