Dynamics CRM in the Field

Information from the Microsoft Dynamics CRM PFE team working in the field

CRM 2011 and ASP.NET Single Sign-on: Use WAUTH for Integrated Web Apps

CRM 2011 and ASP.NET Single Sign-on: Use WAUTH for Integrated Web Apps

Rate This
  • Comments 2

What is 'wauth' and why do your integrated web apps need it to achieve seamless single sign-on (SSO) with Dynamics CRM 2011 (on-premise)? Suffice it to say that simply configuring Windows Identity Foundation (WIF) in your ASP.NET web app and federating it as a relying party (RP) to the same Identity Provider (IdP) targeted by your CRM environment will not always provide a seamless SSO experience. Achieving a seamless experience requires handling a scenario presented by CRM 2011's custom WIF implementation. Don't worry, we'll help you there…but before we show you the "how", let's answer the "what" and "why".

What is 'wauth'?

The passive WS-Federation protocol's wsignin1.0 request message contains an optional parameter, 'wauth', which correlates to a SAML assertion regarding authentication context. When specified, it instructs the IdP's Security Token Service (STS) to use a certain method for authenticating the requestor. This assertion is then incorporated into the SAML security token(s) issued by the STS for subsequent authorization activities. On the other hand, if 'wauth' is not included in the request, the IdP determines the appropriate method (Active Directory Federation Services [ADFS] 2.0 provides the ability to configure the authentication method priority).

Why then, if 'wauth' is optional, do web apps integrated within CRM 2011 need to leverage it?

Think about the process of enabling your CRM environment for claims authentication. There are two primary steps. First, you configure internal claims using a hostname for users to authenticate on the corporate domain (or federated domain) via integrated windows authentication (Kerberos). Second, you configure the Internet Facing Deployment (IFD) with a separate hostname for users that need to authenticate from external locations using the IdP's forms-based authentication process.

How then does the IdP know CRM's desired authentication method for internal and external realms? You guessed it, CRM's authentication module declares a 'wauth' URI in the redirect requests to the IdP! Curious? Open your Internet Explorer Developer Tools (F12) and capture a network trace to view the redirect request URL in both scenarios. In that trace you'll see encoded versions of the following 'wauth' URI's:

  • Internal: wauth=urn:federation:authentication:windows
  • External (IFD): wauth=urn:oasis:names:tc:SAML:1.0:am:password

For custom web apps integrated to CRM via iframe, SiteMap, or Ribbon Action, the user will already be authenticated via either CRM's internal or external realm. Thus, a SAML assertion will have been established regarding authentication context before the user even enters the authentication pipeline of your application. When the IdP receives the authentication redirect request from your web app, it will attempt to use an issued security token for a federated RP as proof that a security token can be safely issued for the requesting RP without requiring a separate submission of credentials by the user. If the authentication context assertion on the previously issued token(s) doesn't apply to the authentication method being employed for the current request, the IdP will ignore the token(s) and attempt to gather the user's credentials before issuing a token for the current RP.

How does this translate to the user experience for your integrated application? Without ensuring that the IdP leverages the same authentication method as was used when authenticating for CRM, the user will encounter an unexpected prompt to supply credentials. If accessing CRM via the external (IFD) URL, this could mean that the user encounters an integrated windows authentication dialog or vice versa depending on the IdP's configuration.

Is configuration an option?

You could specify a URI value for the authenticationType attribute on the wsFederation configuration element in web.config. This will cause all sign-in requests from your RP application to include the 'wauth' parameter using the specified URI. If your CRM deployment only supports one of the two claims-based authentication methods, you may find this acceptable. Otherwise, a programmatic approach to conditionally specify the 'wauth' assertion is your best recourse.

How do I make conditional 'wauth' assertions in the sign-in requests from a relying party web app?

Fortunately, you can reliably handle either authentication scenario without requiring major surgery to your application. You need to first intercept the sign-in request being issued by your application before the user is redirected to the IdP. This can be accomplished by implementing a handler for the WSFederationAuthenticationModule (WS-FAM) RedirectingToIdentityProvider event. Next, within the event handler, you need to determine the appropriate authentication method and conditionally assign the 'wauth' parameter value on the intercepted redirect request. The conditional assignment can occur based on an inspection of the referrer URL hostname to determine if the user accessed CRM via IFD. Without further ado, let's dive into the code:

Pre-requisite(s): The recommendation below assumes that you configured your CRM deployment for claims authentication, have a working knowledge of the basics, and configured WS-FAM for your application. If not, the SDK provides a walkthrough that I recommend you review before proceeding.

In your ASP.NET web application project, add or open the Global application class (Global.asax.cs) file and reference two Windows Identity Foundation (WIF) namespaces.

using Microsoft.IdentityModel.Web;
using Microsoft.IdentityModel.Web.Configuration;


Find the Application_Start event handler and register a new handler for the WIF ServiceConfigurationCreated event.

/// <summary>
/// Handler for application Start event: 
/// register handler for WSFAM ServiceConfigurationCreated event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Application_Start(object sender, EventArgs e)
{
    FederatedAuthentication.ServiceConfigurationCreated +=
        new EventHandler<ServiceConfigurationCreatedEventArgs>(FederatedAuthentication_ServiceConfigurationCreated);
}


Implement the WIF ServiceConfigurationCreated by registering an event handler for the WS-FAM RedirectingToIdentityProvider event.

/// <summary>
/// Handler for WSFAM ServiceConfigurationCreated event: 
///  register handler for WSFAM RedirectingToIdentityProvider event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks>
/// IMPORTANT: Must register other WS-FAM event handlers 
/// after configuration has been created
/// </remarks>
void FederatedAuthentication_ServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
{
    FederatedAuthentication.WSFederationAuthenticationModule.RedirectingToIdentityProvider += 
        new EventHandler<RedirectingToIdentityProviderEventArgs>(WSFederationAuthenticationModule_RedirectingToIdentityProvider);
}


Finally, implement your WS-FAM RedirectingToIdentityProvider event handler. First, compare the CRM Organization name provided as a contextual querystring parameter to the first segment of the referrer's hostname. If there is an exact (case-insensitive) match, it's safe to assume that the referrer origin is external (IFD). In that case, specify the SAML username/password AuthenticationType URI on the SignInRequestMessage. Otherwise, we'll assume the origin was internal and specify the integrated windows authentication type URI.

/// <summary>
/// Handler for WSFAM RedirectingToIdentityProvider event: 
/// infers SAML auth context (wauth) based on referrer URL scheme
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void WSFederationAuthenticationModule_RedirectingToIdentityProvider(object sender, RedirectingToIdentityProviderEventArgs e)
{
    //Assuming this is a CRM embedded app, auth context can be inferred by inspecting CRM referrer URL
    var referrer = HttpContext.Current.Request.UrlReferrer;
    var orgName = HttpContext.Current.Request.QueryString["orgname"];

    //If referrer exists and OrgName query string param is found, attempt to infer SAML auth context
    //Otherwise, let ADFS determine appropriate auth context
    if (referrer != null
        && !String.IsNullOrEmpty(orgName))
    {
        //If the OrgName matches the first sub-domain of the referrer host, 
        //assume external claims (IFD) auth context (User Name/Password)
        //Otherwise, assume internal claims auth context (Integrated Windows)
        if (referrer.Host.Substring(0, referrer.Host.IndexOf("."))
            .Equals(orgName, StringComparison.OrdinalIgnoreCase))
        {
            //Set 'wauth' request param to SAML User Name and Password authentication context
            e.SignInRequestMessage.AuthenticationType = "urn:oasis:names:tc:SAML:1.0:am:password";
        }
        else
        {
            //Set 'wauth' request param to SAML Integrated Windows authentication context
            e.SignInRequestMessage.AuthenticationType = "urn:federation:authentication:windows";
        }
    }


After you've deployed your updated web application, be sure that your hooks into CRM receive contextual details including the Organization name via querystring parameters. Find details specific to your scenario here:

Stay tuned for follow-up posts that continue the discussion of Single Sign-on between custom web apps and Dynamics CRM 2011. For now, let us know about similar scenarios you've faced, general questions, or issues with the recommended solution presented by commenting below or contacting our team directly. We look forward to hearing from you!

 

M. Austin Jones

Follow the conversation:
@maustinjones
@pfedynamics | http://www.pfedynamics.com

  • Very, very nice, Austin - Thanks!

  • Austin,

    This is a great write up - Thanks for the knowledge sharing!

Page 1 of 1 (2 items)
Leave a Comment
  • Please add 6 and 2 and type the answer here:
  • Post