One of my recent projects was to customize the appearance of the Active Directory Federation Services (AD FS) 3.0 sign-in page to give it a look specific to the company associated with the user who’s logging in. This article describes how I was able to dynamically customize the AD FS 3.0 sign-in page logo to provide a company specific logo and help text on our AD FS sign-in page based on the domain part of the UPN when logging into AD FS to access Office 365 resources using a federated domain.
The team I work with takes care of the IT services for several separate companies under a shared ownership structure. We keep our users in a common Active Directory domain, but they are organized into different organizational units named after each company. Each company has its own UPN suffix setup in AD to match their primary email domain. We use Office 365 to host our email, and have setup the domains as federated domains with DirSync.
Using the PowerShell cmdlets, it’s easy to customize the AD FS 3.0 sign-in page. However, just those cmdlets alone won’t allow for a dynamic sign-in page. You can pick a logo, help text, and a custom canvas image to customize the look of your sign-in page, but getting a different logo to show up based on a dynamic condition isn’t possible with only the cmdlets.
AD FS can be used in a much broader scope than I’m using in this case. So, for this task I’m working within the following considerations:
- This AD FS installation is only used as an identity provider (IDP). AD FS can be used in the resource provider role, but I’m only concerned with it as an IDP in this case. I’ve not used the resource provider piece of AD FS, so I’m not sure what role that element might play in this customization, possibly none.
- I’m only concerned with the work flow I describe below. There are other workflows that AD FS can be used in where you pick a relying party from a drop down on the AD FS sign-in page which then redirects an authenticated user out to the replying parties resource. We don’t use that much, so it’s not in the scope of what we were wanting to accomplish here.
Normal User Workflow:
We instruct our users to access Outlook Web Access (OWA) by navigating with their browser to mail.example.com. We’ve setup corresponding DNS entries and redirects on one of our web servers to redirect users from mail.example.com to http://outlook.com/example.com. This gives the user an easy to remember URL for accessing OWA from any computer. Since example.com is configured as a federated domain with Office 365, Office 365 redirects the client to our AD FS sign-in page. The user then logs into AD FS with their UPN and password. Once authenticated, they are redirected back to OWA where they are granted access to their mailbox.
It can also work by navigating to http://outlook.office365.com. When the user enters their UPN into the login form found there, the form recognizes their domain as a federated domain and redirects the client to the AD FS sign-in page. The workflow proceeds as in the pervious scenario after successfully authenticating with Active Directory through the AD FS sign-in page.
The Objective:
As mentioned earlier, we’re supporting multiple companies under the same ownership structure. Those companies don’t necessarily know about each other or the organizational entity that handles their IT, HR, and accounting. We want to keep it that way. They just know that the ownership structure brings with it the back office business services that they need so they can focus on executing their business model. These back office business service units represent themselves to these multiple companies as being part of those companies.
We like that the AD FS sign-in page was easy to customize with a company logo and help message so that it affirmatively indicates to the user that they are logging into something coming from their company. However, we don’t want someone from Company A logging into http://outlook.com/companya.com to see the logo for Company B, or vice-versa. There also isn’t a common non-specific logo and help message we could include on the AD FS sign-in page and still maintain the perception of the IT resources being specific to each company. When a user follows the workflow through Office 365 to our AD FS sign-in page, we want them to see a logo and help message specific to their company.
The Solution:
I found that depending on which path you take through the workflow for logging into OWA, the query string in the request to the AD FS server would have either a “whr” or “username” parameter. I assume the “whr” parameter is short for Windows Home Realm. It would have the value of the federated domain given in the http://outlook.com/example.com URL. Alternatively, if you entered the workflow through the login form on http://outlook.office365.com, the query string would have the UPN that the user entered in the login form as a “username” parameter. This contains the UPN suffix setup in AD.
With this observation my hypothesis was that we could change the content of the page by:
- adding JavaScript to the onload.js file to include logic that checks the query string for the presence of one of those parameters
- extracts the domain part from the username in that scenario
- match the parameter value against a list of expected domain values
- rewrite the HTML elements containing the logo and the help message.
This turned out to be fairly simple to accomplish.
The Details:
These two TechNet pages are the best references I’ve found for how to customize the AD FS sign in page:
Customizing the AD FS Sign-in Pages
Advanced Customization of AD FS Sign-in Pages
Briefly, the process for this customization works like this:
- All this is done from or on the primary ADFS server. If you have more than one AD FS server in your farm, changes on the primary server are replicated to the secondary server.
- Create another web theme using the active theme as a source [PowerShell]
- Export the new web theme to disk [PowerShell]
- Modify the onload.js and / or style sheet files from the exported theme to change the appearance of the pages
- Install images, style sheets, and the updated onload.js file into the new ADFS web theme created earlier [PowerShell]
- Set the new theme as the active theme and test your results
Make sure to read the “Things to know before you start” section of the “Advanced Customization of AD FS Sign-in Pages” article. It discusses what some of the parts of the theme are meant for, limitations for what you can do, and some best practices.
I’m not going to provide the whole content of the JavaScript we added to the onload.js file, but here’s a summary of what it contains:
- An array of values defining:
- federated domains we have configured and are expecting in the query string parameters
- The company display names for each domain to be used in the help message
- The file name of the logo file to display.
- A handful of variables with strings for default values used later in the script, ie a phone number
- A function to parse the location.search property for the ‘whr’ or ‘username’ parameter and return the value of that parameter
- A function to rewrite the innerHTML property of the ‘header’ DIV for the logo image and ‘introduction’ DIV for the help message based on the domain property parsed earlier and passed to this function
Therefore, after adding this script content, the onload.js script looks for the ‘whr’ or ‘username’ parameters in the query string, which are put there by the redirect from either http://outlook.com/domain.com or entering your UPN into the login form at http://outlook.office365.com. Those parameters are compared to “domain” values in the JavaScript array, and when a match is found, the script rewrites the HTML content of the ‘header’ and ‘introduction’ DIV elements to contain the logo and help message on the AD FS sign-in page.
Answers to some likely questions:
- How do I know which AD FS web theme is the active theme to make a copy of which then gets modified (from step 2 above).
- PS C:\> Get-AdfsWebConfig
- ActiveThemeName : custom.01222015.v1
- PS C:\> Get-AdfsWebConfig
- How do I copy a web theme:
- New-AdfsWebTheme –Name CUSTOM-THEME-NAME –SourceName custom.01222015.v1
- To use the out of the box default theme, use “default” as the SourceName
- New-AdfsWebTheme –Name CUSTOM-THEME-NAME –SourceName custom.01222015.v1
- How do I install extra images, overwrite the onload.js file, or overwrite the style sheets into the copied theme (from step 5 above).
- Add an image:
- Set-AdfsWebTheme -TargetName CUSTOM-THEME-NAME -AdditionalFileResource @{Uri=”/adfs/portal/logo/IMAGE-FILE-NAME.jpg“; path=”c:\PATH\TO\IMAGE-To-Upload\IMAGE-FILE-NAME.jpg“}
- See the suggestions for file size and image dimensions in the customization guide from TechNet linked above
- Overwrite the onload.js file:
- Set-AdfsWebTheme -TargetName CUSTOM-THEME-NAME -AdditionalFileResource @{Uri=”/adfs/portal/script/onload.js”; path=”c:\PATH\TO\script\onload.js”}
- Overwrite the style sheet in your custom theme:
- Set-AdfsWebTheme -TargetName CUSTOM-THEME-NAME -StyleSheet @{locale=””;path=”c:\PATH\TO\css\style.css”}
- Add an image:
- How do I set the updated theme to be the active one:
- Set-AdfsWebConfig -ActiveThemeName CUSTOM-THEME-NAME
Conclusion:
There are some limitations to what you can do with the JavaScript, which are mentioned in the ‘Advanced Customization’ guide on TechNet linked above. However, it’s relatively easy to customize the content of the of the AD FS 3.0 sign-in page on the client side using JavaScript in the onload.js file.
please provide the code in the js file. i have been tring to get this done for ever but cant get the code right. thanks
sev7n, I’ll contact you via the email used in the comment with more info.
Matt,
I would be extremely interested in the code you used as well. You hit it right on with your scenario and needing to keep brands apart.
Thanks,
Matt,
I’m also curious about the javascript code. Any possiblity you can share it?
Kind regards,
Thomas
Hi Matt,
Please provide me with the code as well. I want to test out the same scenario but for windows azure pack.
I’ve put the JavaScript on GitHub.
https://github.com/Utegrad/adfs-onload-javascript