Background
One of the best tools to complement SharePoint’s security and usability is Microsoft’s Internet Security and Acceleration Server. ISA is a multipurpose server capable of providing Single Sign-On, object caching, robust firewall rules, and dozens of other features. It slices, it dices, and it makes Julienne fries. My colleague Travis recently posted about the merits of ISA.
He and I recently collaborated on a SharePoint project with three interesting requirements. First, it required SharePoint to act as a presentation layer for other web applications, served through IFrames. These apps were hosted across numerous servers (each with varying domain names), but the client wanted to simplify access by serving all machines through a common domain. Second, each application implemented its own NTLM authentication, leading to multiple credential prompts. And finally, some applications were unencrypted or hosted on non-standard ports, but all content needed to be secured through SSL on port 443.
Thankfully, ISA accommodated each of those requirements and provided additional benefits. Addresses were made uniform by reverse-proxying all applications through the same domain. Furthermore, ISA provided Single Sign-On by delegating authentication to SharePoint and other applications. Best of all, previously insecure data was encrypted by publishing all content through SSL, regardless of origin.
While Travis handled all routing and configuration logic, I was tasked with making ISA "look good" and behave consistently with SharePoint. Here are some tips I picked up in the process:
Getting Started
ISA allows you to publish custom login forms using a mix of HTML and ISA-specifc mark-up. It comes preconfigured with two sets of form templates: one for Exchange and a generic one for ISA. These forms consist of 25 task-specific HTML files containing predefined fields and placeholders. These placeholders consist of string variables (prefixed by "@@") which are driven by a localized string dictionary named strings.txt By updating strings.txt, you can target ISA skins at specific cultures.
The easiest way to create your own skin is by copying an existing one. In my case, I made a copy of the "%ProgramFiles%Microsoft ISA ServerCookieAuthTemplatesISA" folder and then skinned individual HTML files. Customizing the form is simply a matter of modifying HTML, with one exceptions:
Any reference to another file must be URL-encoded and preceded by the string "/cookieauth.dll?GetPic?formdir=%FORMDIR%&image=". This applies to any external reference you make, such as graphics, CSS files, or Javascript. The reason for this is that ISA will otherwise force all requests to be authenticated. By adding a the DLL prefix, ISA knows that those objects should be sent over the wire as-is. What is the "formdir" parameter? It’s a numerical identifier for the custom ISA skin you’re working with. When you first try to hit ISA, it will rewrite the URL to contain the "formdir=" parameter, so update your external request to match that.
Caveats
There are four significant caveats to be aware of when customizing login forms:
- When working with multiple ISA servers in a cluster, each server needs to have the custom HTML authorization templates. While other configuration changes to ISA automatically propagate to other servers, HTML changes need to be manually copied to each machine in the cluster. This is crucial, since users may otherwise bounce between servers and see inconsistent skins.
- Each time the "Microsoft Firewall" service is started, it loads login form templates and caches them in memory. This means that changes made to templates while ISA is running do not take effect until ISA is restarted. Depending on how many machines are in the cluster and how many rules are used, the time to restart will vary (but generally takes at least ninety seconds). Hopefully, Microsoft will use a FileSystemWatcher to dynamically check for changes in the next iteration of ISA.
- There’s no way to use templates such as master pages or server-side includes. As I mentioned before, ISA uses 25 different HTML files and each is laid out in a slightly different way. In most cases, your users will only deal with a handful of pages (such as "usr_pwd.htm" for logging in with a password, "logout.htm" for logging out, and "error.htm" for handling exceptions), but you’ll still need to edit and maintain them individually. This means that in order to add a new link at the top or change the background color, you’ll need to update each file individually.
- The way custom form directories are tracked is inflexible. As mentioned above, if you have multiple ISA skins (such as one for Exchange and another for SharePoint), each one needs to reference the "formdir" parameter when including external objects. This becomes a problem when you work with multiple skins, as in the case of separate dev, test, staging, and production skins. Each time you promote ISA files between them, you’ll need to update their internal "formdir" references.
Public vs. Private Assets
This is a configuration topic, but it’s important for designers to be aware of as well. Each application you publish through ISA is controlled through an ISA Rule and processed by a Web Listener. Your first inclination may be to publish all of SharePoint through one rule. It’s one application after all, right?
Well, the problem with that approach is that all SharePoint assets would then require authentication through ISA. This includes public anonymous pages in the /_layouts/ directory, web services in the _vti_bin, and other objects like favicons and graphics. In this scenario, SharePoint Designer won’t work since it won’t know how to log into ISA. Moreover, you won’t be able to reference CSS or Javascript files from your SharePoint site because each will require authentication.
Fortunately, there’s an easy workaround. Set up two ISA rules; one for public access and the other for authenticated users. The public rule’s authentication setting should be configured as "No delegation, but client may authenticate directly". This way, public pages will be served without requiring authentication (although it will still allow it) and core SharePoint pages will still be secured.