Question

I have searched (probed ,even) for an answer to this but haven't come up with anything useful so far. I'm pretty new to ADFS, STS's in general and WIF so please excuse any obvious ignorance or inappropriate use of terminology. ;)

I'm currently integrating a custom MVC3 app with an external IdP, via ADFS. The ADFS to IdP setup is all done and working.

Some parts of the site are accessible to anon users - in the web.config authentication mode has been set to none. The other parts are protected by having their controllers/action methods decorated by a custom System.Web.Mvc.AuthorizeAttribute.

All the usual modifications to the web.config for using the WsFederationAuthenticationModule have been made and it works 95%; the user can browse to the anon accessible parts of the site. When they try and hit the protected parts, the authorize attribute checks if they have some custom information from our IdP in the IClaimsPrincipals associated with the HttpContext.Current.User and then sets the ActionResult to 401 if not; The WsFederationAuthenticationModule kicks in and redirects them to the IdP's login page. When they enter their details, they're then successfully redirected with some FedAuth cookies and the authorization then passes.

The problem starts when they get to the IdP's login page. This particular IdP has a link to return you directly to our site (to the same page the original request was made to), with this SAML response embedded somewhere (this is according to their documentation)

urn:oasis:names: tc:SAML:2.0:status: AuthnFailed

At this point, they are now "Unauthorized" and all the user will see (at least in dev) is a 401 page. You have to kill the session or otherwise get rid of that cookie to start again.

What I need to do is intercept that redirect request from the IdP, and essentially check for that particular SAML status, because the user should then be redirected to one of the unauthorized areas as if nothing has happened. I've tried something like this in the global.asax:

 protected void Application_Start()
    {
        // mvc stuff here....

        // add handler to intercept handling creation of security tokens by WsFederationAuthnticationModule
        FederatedAuthentication.ServiceConfigurationCreated += OnServiceConfigurationCreated;
    }

    void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
    {
        FederatedAuthentication
            .WSFederationAuthenticationModule
            .SessionSecurityTokenCreated += WSFederationAuthenticationModule_SecuityTokenCreated;
    }

    public void WSFederationAuthenticationModule_SecuityTokenCreated (Object sender, SessionSecurityTokenCreatedEventArgs args) 
    {          
        var token = args.SessionToken;
        // do something with the session token here e.g. check for SAML status
    }

.. but I cant see anything useful on that token; nothing to indicate a specific response status. The fact that there is a FedAuth cookie at all but no custom info from the Idp is a dead give away that the user has been there but somehow failed to authenticate, but in principle I want to be able to see that status. I might have to deal with timeouts at the IdP as well....

Maybe I'm doing this all wrong, or just plain old don't understand, but can somehow fill me in on how to determine those response statuses?

Phew. Thank you! :D

Was it helpful?

Solution

Ok, so I'm going to answer my own question.

The answer to whether I can get that custom status from my IdP is a no, at the moment. :(

But this is only because ADFS is not setup to capture it and pass it on. Apparently you need to do some custom coding for capturing information from the back channel that is opened between ADFS and the IdP.... well beyond the current scope of work.

As a work around for the moment:

  • If a request is made to the site and there is NO SAML token, its a new request by a user who has made no auth attempt at the Idp
  • If there is a SAML token but no ID from the IdP in the token (which is only present when they auth properly), then the user failed Auth for some reason
    • If there is a SAML token with the ID present, the user auth'd properly

Not great but acceptable. BTW, all credit goes to YMC in this SO post for the following code which lets you check for SAML tokens:

void WSFederationAuthenticationModule_SecurityTokenReceived(object sender, SecurityTokenReceivedEventArgs e)
    {
        var message = SignInResponseMessage.CreateFromFormPost(Request) as SignInResponseMessage;
        var rstr = new WSFederationSerializer()
            .CreateResponse(message,
            new WSTrustSerializationContext(
                SecurityTokenHandlerCollectionManager.CreateDefaultSecurityTokenHandlerCollectionManager()));
    } 

Pce!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top