Using a local ADFS with Exchange 15 Update 1

As it seems the explanations from my older post (see here: Using a local ADFS with Exchange) is okay for Exchange 15, but is not okay for Exchange 15 with CU1 proxying to a backend E14 SP3 Server (especially in the barrier-free version).

The problem, which we encountered happens, because our custom WSFederationAuthenticationModule still opens the request and the proxy does not like that at all.
So there need to be some adjustments to make it work again.

1) Use another realm in System.IdentityModel
2) Use another WSFederationAuthenticationModule
3) Switch off the rewriting of http://mail.contoso.com/ to http://mail.contoso.com/owa/ (redirecting is fine, but rewriting is baaaaaaaad).

1. Use another Realm
The base problem is opening the request to examine if there is any ADFS-related data present. To bypass this we need a way to identify request, which are not authenticated or are targeted to the WSFederation endpoint. Luckyly we can just change the realm to an non-present folder in Exchange.

<federationConfiguration>
    <cookieHandler requireSsl="false" />
    <wsFederation passiveRedirectEnabled="true"
                  issuer="https://login.contoso.de/adfs/ls/"
                  realm="https://mail.contoso.de/owa/adfs/" <!-- This here changed: /adfs/ is a non-existent path -->
                  requireHttps="true" />
</federationConfiguration>

Make sure you use this realm as WSFederation-Endpoint in your ADFS configuration.

To complete it we have to reconfigure the audience uris:

<audienceUris>
  <add value="https://mail.contoso.de/" /> <!-- probably you can remove this one, but it does not hurt to have it -->
  <add value="https://mail.contoso.de/owa/" />
  <add value="https://mail.contoso.de/owa/adfs/" />
</audienceUris>

2. WSFederationAuthenticationModule
The older custom WSFederationAuthenticaionModule will open the request, so it is not suitable. This here will fix the problem for (and that has to be assumed here) the realm being a non-existent address

namespace ZDV.IdentityModel.Services
{
    class ExchangeFederationAuthenticationModule : System.IdentityModel.Services.WSFederationAuthenticationModule
    {
        protected override void OnAuthenticateRequest(object sender, EventArgs args)
        {
            var skip = Thread.CurrentPrincipal != null;

            try
            {
                var passiveEndpoint = System.IdentityModel.Services.FederatedAuthentication
                                            .FederationConfiguration
                                            .WsFederationConfiguration
                                            .Realm;

                var passiveEndpointUri = new Uri(passiveEndpoint);
                skip = skip && Uri.Compare(passiveEndpointUri, HttpContext.Current.Request.Url,
                                           UriComponents.Path, UriFormat.UriEscaped,
                                           StringComparison.OrdinalIgnoreCase) != 0;
            }
            catch (Exception)
            {
                skip = false;
            }

            if (skip) return;

            base.OnAuthenticateRequest(sender, args);
        }
    }
}

Adjust the names in the web.config and

<location inheritInChildApplications="false">
    <system.webServer>
      <serverRuntime uploadReadAheadSize="0" />
      <modules>
        <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="" />
        <add name="WSFederationAuthenticationModule" type="ZDV.IdentityModel.Services.ExchangeFederationAuthenticationModule, ZDV.IdentityModel.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e09b5e339c6d1313" preCondition="" />
        <!-- Exchange other Module definitions -->
      </modules>
      <!-- Lots of other config -->
    <system.webServer>
</location>
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="ZDV.IdentityModel.Services" publicKeyToken="e09b5e339c6d1313" culture="neutral" />
      <codeBase version="1.0.0.0" href="file:///C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\bin\ZDV.IdentityModel.Services.dll" />
    </dependentAssembly>
    <!-- Lots of dependentAssemblies here -->
  </assemblyBinding>
</runtime>

3. Remove Rewriting
The update adds an rewriting mechanism to the wwwroot, which should be removed and replaced by some redirections:

<configuration>
  <system.webServer>
        <rewrite>
            <rules>
                <clear />
                <rule name="Trailing Slash OWA ECP" stopProcessing="true">
                    <match url="(.*[^/])$" />
                    <conditions logicalGrouping="MatchAny" trackAllCaptures="false">
                        <add input="{URL}" pattern="^/owa$" />
                        <add input="{URL}" pattern="^/ecp$" />
                    </conditions>
                    <action type="Redirect" url="{R:1}/" />
                </rule>
                <!--
                <rule name="Redirect Logon Requests" stopProcessing="true">
                    <match url="^owa/auth/logon\.aspx$" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
                    <action type="Redirect" url="https://mail.uni-mainz.de/owa/" />
                </rule> -->
                <rule name="Redirect Logout Requests" stopProcessing="true">
                    <match url="^owa/logoff\.owa$" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
                    <action type="Redirect" url="https://login.uni-mainz.de/adfs/ls/?wa=wsignout1.0" />
                </rule>
                <rule name="Redirect Logout Requests (alt)" stopProcessing="true">
                    <match url="^owa/auth/logoff\.aspx$" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
                    <action type="Redirect" url="https://login.uni-mainz.de/adfs/ls/?wa=wsignout1.0" />
                </rule>
                <rule name="Redirect mail.students" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{HTTP_HOST}" pattern="mail.students.uni-mainz.de" />
                    </conditions>
                    <action type="Redirect" url="https://mail.uni-mainz.de/{R:1}" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
<!-- We do not need this here!
  <location inheritInChildApplications="false">
    <system.webServer>
      <modules>
        <add name="OwaUrlModule" type="Microsoft.Exchange.HttpProxy.OwaUrlModule,Microsoft.Exchange.OwaUrlModule,Version=15.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" preCondition="" />
      </modules>
    </system.webServer>
    <system.web>
      <machineKey validationKey="AutoGenerate,IsolateApps" />
      <compilation defaultLanguage="c#" debug="false">
        <assemblies>
          <add assembly="Microsoft.Exchange.OwaUrlModule, Version=15.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </assemblies>
      </compilation>
    </system.web>
  </location>
  -->
</configuration>
Advertisements
Leave a comment

2 Comments

  1. Hi,

    I am trying to implement the same thing and I think I am close to get it working. Owa redirect to ADFS for logon and ADFS redirect to /owa/adfs. After there is a 302 to redirect from /owa/adfs to /owa and I am getting the following error:

    [InvalidOperationException: Unknown protocol type Unknown]
    Microsoft.Exchange.HttpProxy.ProxyModule.SelectHandlerForAuthenticatedRequest(HttpContext httpContext) +1681
    Microsoft.Exchange.HttpProxy.ProxyModule.OnPostAuthorizeInternal(HttpApplication httpApplication) +85
    Microsoft.Exchange.HttpProxy.c__DisplayClassb.b__a() +549
    Microsoft.Exchange.Common.IL.ILUtil.DoTryFilterCatch(TryDelegate tryDelegate, FilterDelegate filterDelegate, CatchDelegate catchDelegate) +40
    Microsoft.Exchange.HttpProxy.Diagnostics.SendWatsonReportOnUnhandledException(MethodDelegate methodDelegate) +408
    System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165

    Did you ever get this error? The OWA Virtual Directory is configured as Windows Auth and here are the relevant part of my web.config:

    <!– –>

    Thanks for your help!

    Reply
    • I did not see that specific error until now, but it looks as if you had the wrong Handler in use.
      Wordpress stripped the web.config, perhaps you can try to insert it again or paste it somewhere else.

      If I encountered errors I always used the FailedRequestTracing, which does a good job in determining the root cause.
      Also look if the request has the expected identity in IIS logs.

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: