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.
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.
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.
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.
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
Comments
Anonymous
November 11, 2010
Is it posible to change "Host" HEADER in Application Type "SharePoint14AAM" by this way?Anonymous
April 07, 2011
Great article. Can you please explain why the web server prepends “HTTP_” to the name?Anonymous
March 29, 2012
Great article, but I can't figure out how can I get server variable CERT_SUBJECT form UAG when using client certificate and then forward to internal server as CERT_SERVER or HTTP_CERT_SERVER.Anonymous
April 26, 2013
Can more than 9 variables be used? Seems like there are only 9 pre-defined variables per your article.Anonymous
June 24, 2013
Scripted and configured as stated - still no variables in the app header.