How to configure UAG to send Request Headers to published Web Applications

Summary:

I recently had a customer ask if they could send header values with Forefront Unified Access Gateway (UAG) to published web servers. While this is pretty simple once you know how to do it, I found there was little documentation on this topic, so I thought I would share this information in this blog. For this demonstration, I used the RTM version of UAG 2010 and a simple IIS server as the sample web server – any web server will do.

Author’s thought on security of Headers:

While UAG can be a replacement for a traditional agent based SSO solution, one should consider the security ramifications of depending on header values as a security control. Traditional “agent based” solutions, such as CA’s SiteMinder or Microsoft’s Active Directory Federation Services (ADFS) provide protection at the web server and they encrypt conversations from the authorizing store (policy / ADFS server) to the web agent. This simply means that the agents only trust the authorizing store, and they both encrypt the communication to verify the data in the communications. I have had some customers say “the vendor name here agent does not support the application, so we just send in a header value and the application then knows who the logged on user is”. This technically works, but ANY application, web page or web server can send a header value, so this is VERY insecure as a single security control. Most people augment this risk by restricting the web server to only accept HTTP/HTTPS connections from the proxy or gateway solution (UAG in this case). This is a risk mitigating approach, but is really susceptible to any device claiming to be that IP address or any administrator changing the configuration for personal gain. Something like IPSEC (between the UAG server and the webserver) is a better choice, but really depending on header variables for security is a bad choice. Header variables can help provide data to published applications, much like ADFS does with “Claims Aware” applications. If you want to securely depend on the authenticity of header values, please encrypt them with a unique key only shared between the web server and the UAG server. For my demonstration, I did not encrypt them, but adding encryption / decryption code is quite simple.

Configuration Process:

Step 1:

Create the file “..\Microsoft Forefront Unified Access Gateway\von\InternalSite\inc\CustomUpdate\uag1postpostvalidate.inc” where “uag” is the trunk name and 1 = secure (0 = insecure or HTTP). If your trunk name is “widget” and you are using a HTTPS site (everyone should be), the file name would be “..\Microsoft Forefront Unified Access Gateway\von\InternalSite\inc\CustomUpdate\widget1postpostvalidate.inc”. If the site were a HTTP the file name would be: “..\Microsoft Forefront Unified Access Gateway\von\InternalSite\inc\CustomUpdate\widget0postpostvalidate.inc”. Notice we add files to the “CustomeUpdate” directory. This is the only supported method, so please always work on files in the “CustomUpdate” directory.

See my example file below (figure 1) that performs a LDAP lookup to my Active Directory Domain named “SCD-LABS.NET” using the logged in user’s id and password to retrieve the displayname, mail and title. For a list of all “Session” variables that UAG exposes, see the appendix.

clip_image002

Figure 1 -- <trunkname>1postpostvalidate.inc

<%

If Session("repository1") = "SCD-LABS" then

   Dim oConn

   Dim rs

   Set oConn = Server.CreateObject("ADODB.Connection")

   oConn.Provider = "ADSDSOObject"

   oConn.Open "Ads Provider", Session("repository1") & "\" & Session("user_name1"), Session("password1")

   Set rs = oConn.Execute("<LDAP://dc=SCD-LABS,dc=net>;(&(objectClass=user)(sAMAccountName=" _

      & Session("user_name1") & "));displayname,mail,title;subtree")

   if not rs.eof then

      if rs.recordcount = 1 then

         SetSessionParamWithType g_cookie, "Hybrid_WhlStatusFlagX", trim(rs("displayname").value), "filter"

         SetSessionParamWithType g_cookie, "Hybrid_WhlStatusFlagY", trim(rs("title").value), "filter"

      end if

   else

         SetSessionParamWithType g_cookie, "Hybrid_WhlStatusFlagX", "ERROR: User Not found", "filter"

         SetSessionParamWithType g_cookie, "Hybrid_WhlStatusFlagY", "ERROR: User Not found", "filter"

   end if

   set oConn = nothing

   set rs = nothing

End if

%>

Step 2:

Modify your Application Wrapper File “..\Microsoft Forefront Unified Access Gateway\von\Conf\WebSites\uag\conf\CustomUpdate\WhlFiltAppWrap_HTTPS.XML” where uag = the trunk name. If my trunk name were widget, the file name would be “..\Microsoft Forefront Unified Access Gateway\von\Conf\WebSites\widget\conf\CustomUpdate\WhlFiltAppWrap_HTTPS.XML”. If you do not have a file in the CustomUpdate directory, copy the one from “..\Microsoft Forefront Unified Access Gateway\von\Conf\WebSites\widget\conf\WhlFiltAppWrap_HTTPS.XML” and make the following modifications shown below (figure 2). Always work on files in the “CustomUpdate” directory.

I added the content between the “<!-- Added header code here -->” sections. In human readable form, I have restricted my change to the Application Type “HeaderTest” and to any URL, as defined by the .* parameter, which is a regular express for * meaning all URLs. I could have used .*/Login.jsp.* which would indicate any path as long as the target file is login.jsp and with any following query string. Next I added 2 headers, MyHeaderX and MyHeaderY respectively. The actual value of this header is from a variable, defined by the using_variables=”true” parameter and then named the variables – which were defined in step 2. Why those names and how many variables can I use did you ask? UAG (former IAG, former eGap by Whale) defined these variables and out of the box provides 9 variables pre-defined that you can use. You can use Hybrid_WhlStatusFlagQ - Hybrid_WhlStatusFlagY. Other variables are already used.

clip_image004

Figure 2 -- Application Wrapper File

      <!-- Added header code here -->

      <APPLICATION>

      <APPLICATION_TYPE>HeaderTest</APPLICATION_TYPE>

         <URL>

         <URL_NAME>.*</URL_NAME>

         <ADD>

         <HEADER>

            <NAME>MyHeaderX</NAME>

            <VALUE encoding="" using_variables="true">Hybrid_WhlStatusFlagX</VALUE>

         </HEADER>

         <HEADER>

            <NAME>MyHeaderY</NAME>

            <VALUE encoding="" using_variables="true">Hybrid_WhlStatusFlagY</VALUE>

         </HEADER>

         </ADD>

         </URL>

      </APPLICATION>

      <!-- Added header code here -->

   </REQUEST>

</HEADER_CHANGE>

</MANIPULATION>

</APP_WRAP>

Step 3:

Perform an IIS Reset to apply the XML file changes.

Step 4:

Setup an application in UAG that matches the Application Type in step 2. I called my “Header Test” but the important match was the Application Type, which is “HeaderTest” (no spaces). After setting up the application, activate the changes.

clip_image006

Figure 3 -- Website setup in UAG

Step 5:

Browse the website published by UAG and view the headers with a simple header program. I include my simple program in the appendix. Notice that the values are real values from my Active Directory Store. Also notice that because these are request variable, the web server prepends “HTTP_” to the name. Also note, if you have made a mistake and did not set the values, the header variables, will assume the value TRUE.

clip_image008

Figure 4 -- Testing the change and see the headers

Appendix

Demonstration file default.asp:

<TABLE>

      <TR>

           <TD>

                <B>Server Varriable</B>

           </TD>

           <TD>

                <B>Value</B>

           </TD>

      </TR>

      <% For Each name In Request.ServerVariables %>

      <TR>

           <TD>

                <%= name %>

           </TD>

           <TD>

                <%= Request.ServerVariables(name) %>

           </TD>

      </TR>

      <% Next %>

</TABLE>

Important ASP Session Strings that UAG exposes:

There are 28 Session objects, but listed below are the more often used session objects that are strings (text values):

Session Object Name

Description

Example Value

site_name

This is the trunk name

uag

secure

Indicates if this is an HTTPS connection

1

login_type

This indicates the login type, example forms

2

source_ip

This is the client’s real IP address

1.1.1.99

lang

This is the language

en-US

session_id

This is the sessionId

E702F25F-85EF-4627-9693-FB5E42EE0899

CredentialsNum

This is the number of credentials a user has

1

CurrentCredentialsNum

This is the current credential set we are on

1

repository1

This is the current repository name

SCD-LABS

user_name1

This is the username as input by the user

Kevinsay

password1

This is the password as input by the user

MySecretPassword1212!

full_user_name1

This is the full user name as derived

SCD-LABS\kevinsay

Author:

Kevin Saye - Security Technical Specialist, Microsoft