AppWrap and SRA
The Application Wrapper (AppWrap) and SRA are two mechanisms UAG uses to dynamically rewrite the content of textual web data it processes. When UAG delivers a page to the client, one of the core UAG components known as “the filter” parses the content of the page, and in some circumstances, alters the content. This mechanism is mostly designed to allow better compatibility for application publishing, as certain applications were not designed to be published by UAG (or by any other reverse proxy, for that matter), and won’t work properly without certain changes. For example, when publishing SharePoint, UAG needs to perform certain manipulations to allow Office applications to open documents from the site properly. To this end, UAG inserts a line into one of SharePoint’s JavaScript files (core.js) that causes the browser to call the file sharepoint.asp (a specially crafted UAG code file):
dHtmlLoadScript(“/InternalSite/sharepoint.asp?site_name=portal&secure=1”);
For the AppWrap and SRA mechanisms to work, UAG comes with a set of XML files that contain instructions for them. The XMLs contain code that instructs UAG to look for certain file patterns (in HTTP requests as well as in the responses to them) and make certain changes to them, like, for instance, “Where you see the word ‘Foo’, change it to ‘Bar’ ”. UAG comes with a built-in set of 2 files (one for SRA and one for AppWrap), but the administrator can also create custom files in addition to them, to make his own changes. These changes can be used to address certain issues with the applications behavior when published through UAG, and also affect the look and feel of the application. For example, a UAG administrator may feel that when he publishes Outlook Web Access via UAG, he doesn’t want the user’s name to appear at the top of the screen.
To make this happen, the administrator will have to configure UAG to search for this text:
<span id="spnUserTileTxt" class="userTileTxt"> , and add an HTML tag like style=display:none; to hide it.
We’ll get to the how-to for this soon, but the point is, by manipulating the HTML, as well as HTTP headers, one can accomplish a lot!
In-difference?!?!
You might be wondering what is the difference between SRA and AppWrap? Why do we need two if they can both change content? The difference between them is the order in which things happen. When UAG retrieves a file from a back-end server, the 1st thing that happens is the SRA engine processing the content. Next, the HAT engine signs the various URLs it locates, and then, the Application Wrapper performs additional changes, if such are required. If all we want to do is alter some static contents, then either of them can do the trick. If, however, we want our customization to handle URL-specific issues, it would be ideally handled by a custom SRA.
Here’s an example: We might find, in some circumstances that UAG is failing to sign some URL, because the URL is built using HTML tags that are non-standard, or built dynamically using a client-side script (for example, PeopleSoft software does this). When something like this happens, the script that builds the request may contain URL pieces that are unrecognizable. By using the SRA, we can replace the URLs in the script with something UAG can recognize, and then the HAT signature process can continue as normal.
How does it work?
As mentioned above, UAG comes with a pre-existing default set of files, which contain instructions for some of the built-in application templates, like CRM, OWA, SharePoint, Citrix and others. If you need to add other changes, you first need to decide whether you are going to use AppWrap or SRA. Some changes should be done in SRA – for example, if you are trying to fix an issue where an application’s links are not getting signed properly. Many changes can be done just as well with either mechanism.
Once decided, you need to compose an XML file with the proper “instructions”, and place the file on the UAG server. Once the file is placed in the right place, it takes effect immediately. The default files are created by UAG automatically in the following folder:
<UAG Path> \von\Conf\Websites\<Trunk_Name>\conf\
The configuration is separate for every trunk, so there is a separate set of XMLs for each trunk you may have. If you look at one of your trunks, you will find 2 files:
· WhlFiltSecureRemote_HTTP.xml or WhlFiltSecureRemote_HTTPS.xml, depending on whether the trunk is an HTTP or an HTTPS trunk. This is the configuration file for SRA
· WhlFiltAppWrap_HTTP.xml or WhlFiltAppWrap_HTTPS.xml, depending on whether the trunk is an HTTP or an HTTPS trunk. This is the configuration file for AppWrap
If you have a UAG server around, you can go ahead right now and examine the content of the files. You will find them to be quite lengthy, and possibly hard to understand…that’s perfectly normal! However, don’t be tempted to edit these files directly. These files are built from another source, so they may get overwritten and any changes you make may be lost. To support custom configuration, you need to create a folder named CustomUpdate under …\Websites\<Trunk Name>\conf, and place your custom files there. The server won’t explode if you edit the default files, but such an edit will be overwritten on your next configuration-activation. Also, such changes are unsupported.
Base 64 Encoding
Another thing to keep in mind is that since we use XML files to configure the Application Wrapper and SRA, we need to make sure that the contents of the data we are specifying doesn’t break the XML formatting. For example, the characters < and > are used by XML to specify opening and closing tags (more here). If our Search or Replace strings contain these characters, the whole thing may break apart (meaning that none of custom configuration will take effect). The solution to this is Base-64 encoding of the text. Base64 encoding is quite simple - It’s quite easy – just use some online encoding/decoding tools like this. Paste into it your string, and then copy-paste back the encoded text. You can also use the UAG Editor, which comes with UAG and has built-in functions for text editing. This editor is found here:
<UAG Path>\Common\Bin\editor.exe
To use it, simply select some text, and click on “To 64”:
Down into the mine shaft…
Here’s a typical custom AppWrap XML file:
<APP_WRAP ver="3.0" id=" WhlFiltAppWrap_HTTPS.xml"> <MANIPULATION> <MANIPULATION_PER_APPLICATION> <APPLICATION_TYPE>SharePoint14aam</APPLICATION_TYPE> <DATA_CHANGE> <URL>SignOut\.aspx</URL> <SAR> <SEARCH>Function Activate</SEARCH> <REPLACE>Function Deactivate</REPLACE> </SAR> </DATA_CHANGE> </MANIPULATION_PER_APPLICATION> </MANIPULATION> </APP_WRAP> |
As you can see, it has standard XML formatting, with nesting <> tags. It starts with a declaration of the type of file, and then starts a “manipulation” section. We specify the application type this applies to, and then, this section has a DataChange section (it could also have a Header Change section). The Data Change applies to the URL SignOut.aspx, and the \ behind the dot is not a speller…it’s a RegEx “escape” character, so that the dot will be treated literally. Later on comes a SAR (Search And Replace) section, which specifies the string to search for, and the string to replace it with. Then, all the sections are closed. Simple, huh?
The above example is a very simple one. In real life, there are a few more considerations. For example, when creating a custom file, it’s a very good idea to put in some comments as to what the change is for. This could be very important If the published application changes (which happens a lot!) and you need to revisit the customization, or if someone else needs to take ownership of the server. The syntax for comments is like this:
<!--The following change is for compatibility with EdgeSpace 4.1, added by Ben Ari on 13 Sep 1973 -->
Another consideration is the URL specification. When specifying a URL, you can use the full URL for the target file, or just part of it using RegEx. It is recommended to specify the file as accurately as possible, and avoid a too-general wildcard (like .*\.aspx), so as to reduce the risk of the change applying to unintended files. When specifying URLs, remember that the characters . * ? + ( ) { } [ ] ^ $ \ are part of the RegEx command set, , so if you want them to be treated literally, you need to ‘escape’ them by adding a back-slash symbol before the character.
Normally, the URL search is case sensitive, so specifying SIGNOUT will not “find” a URL with the string signout, but you can add the case_sensitive tag to override this default. This is used like this:
<URL case_sensitive="false">.*SignOut\.aspx</URL>
Another thing to keep in mind is that you can perform several S&Rs on a single URL using a single clause by specifying additional SAR paragraphs like this:
<APP_WRAP ver="3.0" id=" WhlFiltAppWrap_HTTPS.xml"> <MANIPULATION> <MANIPULATION_PER_APPLICATION> <APPLICATION_TYPE>GenericWebApp</APPLICATION_TYPE> <DATA_CHANGE> <URL>/hr/Editform\.aspx\?osver=6.*</URL> <SAR> <SEARCH>DHScript</SEARCH> <REPLACE></REPLACE> </SAR> <SAR> <SEARCH encoding="base64"> X2dhcS5wdXNoKFsnX3NldEFjY291bnQnLCAnVUEtMTQyMjE4LTMnXSk7</SEARCH> <REPLACE encoding="base64"> X2dhcS5wdXNoKFsnX3NldEFjY291bnQnLCAnJ10pOw==</REPLACE> </SAR> </DATA_CHANGE> </MANIPULATION_PER_APPLICATION> </MANIPULATION> </APP_WRAP> |
As you can see, the above example uses a similar syntax to completely remove parts of the HTML by simply using a blank REPLACE clause. Also, the 2nd SAR in this example is for a complex text, I encoded it using Base64.
It is VERY important to remember that search-and-replace is a double-edged sword. When an S&R function is applied, it will perform the replace blindly, as long as the string or regex pattern configured in the SEARCH tag is matched against the HTTP data. This may inadvertently make changes to another section of the page or even to another page, causing undesired behavior. In certain cases, it may even corrupt data, if the change applies to code that is being sent back to the server (like SQL update queries, for example). One must be sure to plan the change very carefully, and make sure it will be applied only to what is relevant by limiting it to the appropriate application server and URL, and if possible, using detailed SEARCH parameters. Extensive testing of the change is also highly recommended, so that you don’t find out a week after rollout into production that it causes some other page to mess-up.
What else can AppWrap do?
AppWrap has several other options that are useful. For example, it can do a Header Change (which includes editing an existing header, deleting a header, or adding one). For example, an AppWrap can be used to remove or change the value of a cookie to something else, or alter the value of the referrer header to something other than it is normally. There are additional options, which I can’t cover here. If you want to learn more, have a look at the Advanced User Guide for IAG. For the most part, the syntax for UAG is almost identical. The guide can be found here.
Another thing AppWrap can do is change content based on dynamic variables. This is useful when you need to change a link to one that refers to UAG itself. Instead of actually putting in UAG’s URL, you can simply use the variable “WhlOwnURL”. This is a better design, as it’s more flexible and will work even if you change the server’s public URL, or if you need to apply the same change to a lab server and a production server. Other variables that UAG supports are:
· WhlSessionTimeout
· WhlLogoffURL
· WhlScheduledLogoffTimer
· WhlSiteName
· WhlSecure
You can read more about these variables on page 229 of the Advanced User Guide that I mentioned above. Here’s an example of the use of WhlOwnURL:
<DATA_CHANGE> <URL case_sensitive="false">/exchange/.*?Cmd=navbar</URL> <SAR conditional_variable="UsePortalFrame" conditional_var_value="False"> <SEARCH>vw_navbar.js"></script></SEARCH> <REPLACE>vw_navbar.js"></script><script language="JavaScript" src="WhlOwnURLscripts/CacheClean.js"></script> <script language="JavaScript" src="WhlOwnURLlogoffParams.asp?site_name=WhlSiteName&secure=WhlSecure"></script> <script language="JavaScript" src="WhlOwnURLscripts/logoff.js"></script></REPLACE> </SAR> </DATA_CHANGE> |
This example is taken from the UAG default AppWrap template. This section applies to publishing OWA 2003, and its purpose is to hide the OWA log off button and to add some JavaScript related to UAG session termination. To make the read easier, I’ve decoded the text, which is Base64 encoded in the original file. You can see how it refers to several variables – can you guess what they mean?
Moving forward…SRA!
A custom SRA file would have a layout that’s quite similar to an AppWrap file. Here’s one, for example:
<WHLFILTSECUREREMOTE ver="2.2"> <DATA_CHANGE> <APPLICATION> <APPLICATION_TYPE>SharePoint14aam</APPLICATION_TYPE> <URL> <NAME>drawshape\.aspx</NAME> <SEARCH encoding="base64"> PHRpdGxlPg==</SEARCH> <REPLACE encoding="base64"> PHRpdGxlPkRlcGFydG1lbnQgb2YgZmluYW5jZSAtIA==</REPLACE> </URL> </APPLICATION> </DATA_CHANGE> </WHLFILTSECUREREMOTE> |
SRA does not allow the use of variables, but it can be configured to match a specific server and port, which AppWrap cannot do. Here are a few examples:
<DATA_CHANGE> <SERVER> <SERVER_NAME mask="255.255.255.0">192\.168\.1\.75</SERVER_NAME> <PORT>443</PORT> <URL> <NAME>/Mail\.html</NAME> <SEARCH encoding="base64">PGhlYWQ+</SEARCH> <REPLACE encoding="base64">YmFzZTY0</REPLACE> </URL> </SERVER> </DATA_CHANGE> |
<DATA_CHANGE> <SERVER> <SERVER_NAME>exchange01</SERVER_NAME> <PORT>80</PORT> <URL> <NAME>/Mail\.html</NAME> <SEARCH encoding="base64">PGhlYWQ+</SEARCH> <REPLACE encoding="base64">YmFzZTY0</REPLACE> </URL> </SERVER> </DATA_CHANGE> |
<DATA_CHANGE> <APPLICATION> <APPLICATION_TYPE>GenericWebApp</APPLICATION_TYPE> <URL> <NAME>/mail/.*/Inbox/.*\.EML\?cmd=preview</NAME> <SEARCH encoding="base64">PGhlYWQ+</SEARCH> <REPLACE encoding="base64">YmFzZTY0</REPLACE> </URL> </APPLICATION> </DATA_CHANGE> |
In the 1st example above, we are matching the server by its IP, and in the 2nd, by its hostname. Note that this refers to the INTERNAL name of the server (which is what you would define in the “Web Servers” tab of the application on UAG):
As you may have deduced from the example, the MASK tag in the SERVER_NAME tag can be omitted, and the PORT tag can be omitted as well. As with AppWrap, multiple SERVER_NAME paragraphs can be nested inside a SERVER paragraph and multiple APPLICATION_TYPE paragraphs can be nested inside an APPLICATION paragraph. Also, multiple URL paragraphs can be nested inside the APPLICATION_TYPE and multiple URL paragraphs can be nested inside a SERVER_NAME paragraph.
Adding a HAT signature
A typical troubleshooting scenario is one in which links are not being signed for some reason. This can happen if the links are built by some client side JavaScript, out of URL pieces. For example:
var hrapp_web_root = 'http'; var IntServer_url = ‘fileservny01’; var hrapp_js_root = '/vrdf/js'; var hrapp_jsp_root = '/vrdf/jsp/hrapp'; if (mode == secure) { hrapp_web_root == hrapp_web_root+'s' } var sTarget = hrapp_web_root+'://'+ var IntServer_url + var hrapp_js_root |
In the above, the resulting URL could be either “https://fileservny01/vrdf/js” or “https://fileservny01/vrdf/js”, but the text page doesn’t actually contain any URL strings that UAG can recognize. To fix it, we would need to convert the resulting string to one that has the HAT signature. For example, https://fileservny01/vrdf/js would have to become:
https://uag.createhive.com/uniquesig977dbf8e31f3e11905690532814f23eaedf4b8fa30977329b63b23e65d8cbc 8868 fb5af9e91fd3a1c405dc86ecaed7a1/uniquesig0/vrdf/js
To make this happen, we would have to create an AppWrap that replaces the URL pieces. We would need to replace line no. 2 in the above JavaScript to something like this:
var IntServer_url = ‘uag.createhive.com/uniquesig977dbf8e31f3e11905690532814f23eaedf4b8fa30977329b63b23e65d8cbc8868 fb5af9e91fd3a1c405dc86ecaed7a1/uniquesig0’;
This is not hard, and you already know what you need to make this happen. However, we consider putting in a HAT path directly to not be best practice. Instead, we have an SRA method which can be used to add the signature automatically. Here's the syntax:
<DATA_CHANGE> <SERVER> <SERVER_NAME>formserver\.createhive\.local</SERVER_NAME> <PORT>80</PORT> <URL> <NAME>/file\.js</NAME> <ADD_SIGNATURE encoding="" location="before">test/id/user</ADD_SIGNATURE> <ADD_SIGNATURE location="after" mode="regex">ows_FileRef</ADD_SIGNATURE> </URL> </SERVER> </DATA_CHANGE> |
The example above does not apply to the JavaScript I included earlier, but you can see from it that you can use the location tag to indicate that the signature can be added either BEFORE or AFTER a certain text. The search is done on static text by default, but can also be done using RegEx if you specify the mode as such, as in the 2nd ADD_SIGNATURE tag above. As usual, encoding to Base64 is often needful. The same URL syntax can be nested inside an APPLICATION tag, instead of SERVER. If so, the application type must be specified as before. It’s important to note that the signature that is added is in this format:
uniquesig977dbf8e31f3e11905690532814f23eaedf4b8fa30977329b63b23e65d8cbc8868fb5af9e91fd3a1c405dc86ecaed7a1/uniquesig0/
It does not include the public host name of the UAG portal, but if the URL is relative, it will be automatically applied by the browser. However, if the link that we want to sign is relative as well, and starts with a slash, we should adjust the location appropriately. For example, if the targeted code is something like:
<script>function serverset(){URLpart=’/ipage/customer/order/cart/or4020AddItem.action’;
And we want to sign the “URLpart” piece, we would either insert the signature after URLpart="/ or before ipage/customer/order/cart/or4020AddItem.action
How to find the application type
If the APPLICATION method is chosen, rather than SERVER, you must locate the application type that you wish to match to. If this is a custom app you have created, then you have had to choose the application type, and you can see it in the application list on UAG:
If, however, you want to apply your code to one of the built-in application types, you will need to find the ID manually. To do this, open the applications properties from the trunk's application list. Note the application's name (see screenshot below).
Now, open the file <UAG Path>\von\Conf\WizardDefaults\WizardDefaultParam.ini with a text editor of your choice, and use the FIND function to locate that text. When you have found it, look above it, for the application type in square brackets:
What else can SRA do?
An important thing to remember about SRA is that it is THE brains behind the link signing that UAG does, and even though it sometimes misses some links, it is possible to "teach" it to do it better. The default SRA configuration files ( <UAG Path>\von\Conf\SRATemplates\WhlFiltSecureRemote_HTTP.xml and WhlFiltSecureRemote_HTTPS.xml) have a long list of tags that instruct the engine how to detect links, so that they can be signed. If a link is missed by the engine, it may be possible to extend the list of tags so that the engine will detect it by default, rather than include a search-and-replace fix for a specific link. Customizing the default parsers is beyond the scope of this guide, and will be discussed another time.
Conflicts and combinations
When creating a custom AppWrap or SRA file, one must keep in mind that UAG still has to use the default built-in XML files, and we need to be careful about creating a conflicting set of files. Sometimes, we might want to intentionally override the default template, but at other times, we need to be careful, otherwise, the custom file may block built-in functionality that is important.
One common mistake is to define an extremely wide range of URLs by using something along the lines of “<NAME>.*</NAME> in the URL section. Something like this will actually override ALL other AppWrap or SRA settings for the same application-type or server-name defined anywhere else. Special care needs to be taken when working on one of the built-in application types. For example, doing this on a SharePoint or OWA application will cause huge problems. If you do need to use AppWrap or SRA to make changes to an application that has some SRA/AppWrap functionality in the default files, and you need to change the same URLs in the default template, the right way to go is to COPY the default settings into the custom file, and adjust (or add to) them in it. There’s no simple way to do this, so be prepared for some trial and error. You might also need to combine two sets of instructions. For example, you might need to combine the default set, and your custom instructions, or one customization with another. Look at the following example (AppWrap):
<MANIPULATION_PER_APPLICATION> <APPLICATION_TYPE>ExchangePub2003SP1</APPLICATION_TYPE> <DATA_CHANGE> <!-- for Exchange 2003 conditional appwrap hide log off --> <URL case_sensitive="false">.*/util_owa.js</URL> <SAR conditional_variable="UsePortalFrame" conditional_var_value="False"> <SEARCH encoding="base64">cGFyZW50LmQmFzZSArICI/Q21kP </SEARCH> <REPLACE encoding="base64">cGFyZW50LmZyY5kU2Vzc2lvbigp</REPLACE> </SAR> </DATA_CHANGE> <DATA_CHANGE> <!-- for Exchange 2003 conditional appwrap hide log off --> <URL case_sensitive="false">/exchange/.*/(inbox/?|calendarcmd=rules|\?cmd=options).*</URL> <SAR conditional_variable="UsePortalFrame" conditional_var_value="True"> <SEARCH encoding="base64">aWQ9ImxvZ29mZiI=</SEARCH> <REPLACE encoding="base64">aWQ9ImxvZ29mZiIgc3R5bm9uZSI=</REPLACE> </SAR> </DATA_CHANGE> <!-- for Exchange 2003 conditional appwrap hide log off add UAG logoff session --> <DATA_CHANGE> <URL case_sensitive="false">/exchange/.*?Cmd=navbar</URL> <SAR conditional_variable="UsePortalFrame" conditional_var_value="False"> <SEARCH encoding="base64">dndfbmF2YmFyLmpzIj48L3NjcmlwdD4=</SEARCH> <REPLACE encoding="base64">+DQo8c2NyaB0IiBzcmM9Ildob==</REPLACE> </SAR> <SAR> <SEARCH encoding="base64">dn48LmpzIj3NmlwdDjc4=</SEARCH> <REPLACE encoding="base64">+Dldob==</REPLACE> </SAR> </DATA_CHANGE> </MANIPULATION_PER_APPLICATION> |
The above example is taken from the default AppWrap file, though I’ve cut most of the S&R strings short to make it more readable (so the example is not ‘really real’…). It demonstrates how, when we want a manipulation section to address separate URLs, it has to have separate “data change” sections, each addressing its own URL. If we want to do multiple search-and-replace actions, this is OK too, as long as they are in separate SAR sections, as shown in the 3rd data change section above.
Further Reading:
The official UAG documentation contains some information about using the application wrapper:
https://technet.microsoft.com/en-us/library/ff607339.aspx
https://technet.microsoft.com/en-us/library/ff607388.aspx
If you’d like more details, samples and information about the SRA, you can find it in the original IAG Advanced User Guide, pages 289-313 and pages 219-254. This guide is very extensive and detailed, and even though it was written for IAG, most of the content applies to UAG, except some minor changes (https://blogs.technet.com/b/edgeaccessblog/archive/2009/11/17/appwrap-in-uag-what-s-new.aspx). To download the IAG Advanced User Guide, click here.
Blog post written by Ben Ari and Ran Dolev