Thursday, September 22, 2011

ADFS Idp Initiated SSO - RelayState


AD FS 2.0 does not support specifying the RelayState in the case of IdP-initiated request. (The support for RelayState is limited to echoing back in SP-initiated requests.) The relying party must identify the target resource in its configuration.



To pass RelayState in ADFS 2.0, there is a non-supported workaround which requires some custom code (for additional information, please refer to the discussions HOW CAN I SPECIFY THE TARGET URL DIRECTLY IN THE SAML REQUEST AND HAVE AD FS 2.0 AUTOMATICALLY REDIRECT?[1] and SPECIFY RELAYSTATE URL[2].


The workaround requires two critical tweaks in the Sign-In Pages:


1. Edit the Global.asx.cs file, and add, after line 22 (HttpResponse response = HttpContext.Current.Response;) the following code:
if ( !String.IsNullOrEmpty( request.Params["SAMLResponse"] )
!String.IsNullOrEmpty( request.Params["SAMLart"] ) )
{
if ( !String.IsNullOrEmpty( request.Params["RelayState"] ) )
{
HttpCookie cookie = new HttpCookie( "rs", request.Params["RelayState"] );
cookie.Expires = DateTime.UtcNow.AddMinutes( 10 );
Response.Cookies.Add( cookie );
}
}
It basically looks for SAMLResponse/SAMLart with a RelayState, and then “stuff” the RelayState in a cookie.


1. Edit the page IdpInitiatedSignOn.aspx.cs by adding after line 56 (string rpIdentity = Context.Request.QueryString [RpIdentityQueryParameter]) the following code:


HttpCookie cookie = Context.Request.Cookies.Get( "rs" );
if ( null != cookie && !String.IsNullOrEmpty( cookie.Value ) )
{
rpIdentity = cookie.Value;
cookie.Expires = DateTime.UtcNow.AddDays( -1 );
cookie.Value = "";
Context.Response.Cookies.Add( cookie );
}


//
// If the query string specified a certain relying party, sign in to that relying party.
//
if ( !String.IsNullOrEmpty( rpIdentity ) )
{
string decodedIdentity = Server.UrlDecode( rpIdentity );
if ( decodedIdentity == IdpAsRpIdentifier )
{
decodedIdentity = String.Empty;
}


//
// If app is not in list of known RPs, assume it is a WS-Federation app and redirect to it.
//


bool found = false;
foreach( DataRow row in RelyingParties.Rows )
{
if ( row[0] == rpIdentity )
{
found = true;
}
}


if ( found )
{
SignIn( rpIdentity, new SignOnRequestParameters() );
}
else
{
//
// TODO: Fill in your own trusted WS-Federation app URLs below.
//
if ( rpIdentity == "https://example.com/a_trusted_url"
rpIdentity == "https://example.org/another_trusted_url" )
{
Response.Redirect( rpIdentity );
}
}
}
It basically extracts that cookie and uses it to start an IdP initiated sign on.


Moreover, if the RelayState doesn’t map on to a known SAML 2.0-based relying party, there is a place in the code to enter a list of known WS-Federation URIs to have AD FS 2.0 redirect to.


For 90% of cases (including SharePoint 2007/2010 and, more generally, WIF 1.0-based applications), this will kick off an SP-initiated sign in and “it just works”.


No comments:

Post a Comment