Rory Primrose

Learn from my mistakes, you don't have time to make them yourself

View project on GitHub

Dynamic realm discovery for federated authentication

Posted on February 14, 2013

I have a web role (RP) running in Windows Azure that uses ACS 2.0 as the identity provider (IP). The web role is configured with a certificate to work with the authentication negotiation and subsequent security session. The certificate supports both and The issue is that the federation authentication configuration of the web role can only specify one realm and the realm attribute is a required value.

<wsFederation passiveRedirectEnabled="true" issuer="http://[addressOfAcs]" realm="" requireHttps="true" />

This works great if the user is browsing on and then goes through the authentication process. A security token will be issued for to which the user is redirected back to. The RP will then validate that the token was issued to the configured audience uri. These thankfully allow multiple addresses to be specified.

    <add value="" />
    <add value="" />

The problem is when you want to use the www-less address or any other host header for that matter. In this case, the user is browsing and goes through the authentication process. The token will be issued for but the user is then redirected back to the original address under the location. An exception is then thrown at this point.

System.IdentityModel.Services.FederationException : ID3206: A SignInResponse message may only redirect within the current web application: ‘’ is not allowed. Stack trace at System.IdentityModel.Services.WSFederationAuthenticationModule.SignInWithResponseMessage(HttpRequestBase\ request)
at System.IdentityModel.Services.WSFederationAuthenticationModule.OnAuthenticateRequest(Object\ sender, EventArgs args) at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

The fix here is to put together some dynamic realm discovery logic. Creating a custom WSFederationAuthenticationModule class provides some good hooks into the authentication process. We want to override OnRedirectingToIdentityProvider and set the realm as per the location of the current request.

For example:

namespace MyApplication.Web.Security
    using System;
    using System.IdentityModel.Services;
    using System.Security.Principal;
    using System.Web;
    using Seterlund.CodeGuard;
    public class DynamicRealmFederationAuthenticationModule : WSFederationAuthenticationModule
        protected override void OnRedirectingToIdentityProvider(RedirectingToIdentityProviderEventArgs e)
            e.SignInRequestMessage.Realm = DetermineDynamicRealm();
        private static Uri BuildRequestedAddress(HttpRequest request)
            Guard.That(() => request).IsNotNull();
            Guard.That(() => request.Headers).IsNotNull();
            Guard.That(() => request.Url).IsNotNull();
            var originalRequest = request.Url;
            var serverName = request.Headers["Host"];
            var address = string.Concat(originalRequest.Scheme, "://", serverName);
            address += originalRequest.PathAndQuery;
            return new Uri(address);
        private string DetermineDynamicRealm()
            // Set the realm to be the current domain name
            string realm;
            const string SecureHttp = "https://";
            var hostUri = BuildRequestedAddress(HttpContext.Current.Request);
            var port = string.Empty;
            if (Realm.StartsWith(SecureHttp, StringComparison.OrdinalIgnoreCase))
                realm = SecureHttp;
                if (hostUri.Port != 443)
                    port = ":" + hostUri.Port;
                realm = "http://";
                if (hostUri.Port != 80)
                    port = ":" + hostUri.Port;
            realm += hostUri.Host + port;
            return realm;

A couple of things to note about this code.

Firstly, the DetermineDynamicRealm method could have been streamlined, but I also needed it to cater for my location development environment. The local environment uses the Azure SDK emulator for the web role and a custom website project as a development STS. Both the web role and the development STS use straight http as well as custom ports. The DetermineDynamicRealm method logic caters for both local development and production deployment.

Secondly, the BuildRequestedAddress method uses request headers to figure out the port of the request from the browser. This is because the web role sits behind a load balancer that does some trickery with ports. We need to look at the headers of the request to determine the port as the browser sees it rather than how the request on the current HttpContext sees it.

Next up, the web.config needs to be updated to use this module rather than the module that comes out of the box.

<add name="WSFederationAuthenticationModule" type="MyApplication.Web.Security.DynamicRealmFederationAuthenticationModule, MyApplication.Web" preCondition="managedHandler" />

The only remaining step is to set up ACS with an additional RP configuration for You should now be able to authenticate and be redirected back to either or