Customizing the AD FS sign-in pages per relying party trust


UPDATE: Windows Server 2016 allows this out of the box. See here: Customizing user signin for AD FS relying parties https://technet.microsoft.com/en-us/library/mt593302.aspx

The way the Windows Server 2012 R2 ADFS customization works currently does not enable you to modify the graphical end user experience based on the relying party trust (RP) the user is trying to access. So the look and feel of the sign-in page is the same for every user whether they are trying to access to the relying party trust A, the relying party trust B, their Office 365 environment or simply the IDP initiated sign-in page.

In fact, we can totally go fancy and customize per relying party trust by doing a bit of JavaScript. Modifying the onload.js script of the sign-in page is a supported operation as long as we don’t do crazy stuff in it. You’ll find the general guidance about sign-in pages customization here:

JavaScript customization per RP in a nutshell

The onload.js script is loaded on every pages that the ADFS server is returning. So we got to be very careful, a JavaScript error will show up all the time if you aren’t careful with your syntax. One way to do it is the following:

  1. Read the window.location.href of the current page
  2. Check if it contains the identifier or return URL of a specific RP
  3. If yes, change the logo and the illustration of the sign-in page

It means we will need the following:

  1. A custom web theme for our farm
  2. Register a custom URI for our custom logo and custom illustration
  3. Modify the onload.js script

If you are looking for more example of such customization, you can have a look here: Customizing the IDP images in the Home Realm Discovery page. I’ll cover them in details below anyway…

1. A custom web theme for our farm

Let’s create a new theme. The following requires administrative rights on the ADFS farm.

New-AdfsWebTheme -Name Yoga -SourceName default

And you can customize it to suit your taste (use the guidance you can find in the two links at the beginning of this post). Once you’re done, set the new theme as active:

Set-AdfsWebConfig -ActiveThemeName Yoga

Here is what it looks like in my case after my customization (this is the IDP initiated sign-in page):

If you have any question on the actual modification done to reach this, feel free to use the comment section.

2. Register a custom URI for our custom logo and custom illustration

We are going to add a new logo and a new illustration. ADFS isn’t an IIS service, you don’t really have an inetpub folder where you can store your files. Everything is stored in the ADFS database (which is actually cool because all servers of the farm -including the proxies- will get your changes). So you need to add two URIes. I saved my new logo (logo-claimy.png) and illustration (illustration-claimy.jpg) in the local folder C:\Theme on my ADFS server. Here are the following commands:

Set-AdfsWebTheme -TargetName Yoga -AdditionalFileResource @{Uri=“/adfs/portal/logo/logo-claimy.png”;Path=“C:\Theme\logo-claimy.png”}

Set-AdfsWebTheme -TargetName Yoga -AdditionalFileResource @{Uri=“/adfs/portal/illustration/illustration-claimy.jpg”;Path=“C:\Theme\illustration-claimy.jpg”}

Once you executed those two commands, you technically delete the actual files. These commands had imported the images in the database and there is no link anymore with a local file.

3. Modify the onload.js script

Before modifying it, you need to get a hold on it. So export the current version of the script on the disk:

Export-AdfsWebTheme –Name Yoga –DirectoryPath c:\ExportedTheme

You will now have the file onload.js on the folder C:\ExportedTheme\script. we will need to detect what is the relying party trust the user is trying to access. In my case, I do have a relying party trust at the location https://web.piaudonn.com/claimy. When a user is trying to access this one, it get redirected to the sign-in page. I suggest the following:

if ( window.location.href.indexOf(“https%3a%2f%2fweb.piaudonn.com%2fclaimy”) != -1 ) {
 //Change logo
 //Change illustration
}

If the location of the page contains the path of the relying party trust, then I execute something that change the logo and the illustration. We are using the indexOf function. This function returns the position of a string. If it returns something different than -1 it means that that the string has been found. Two issues with this check. The first one is that if the redirection is going through a WAP the coding for the colon and the double slash (://) is not %3a%2f%2f but %3A%2F%2F. And the second is that if you enable the user to update its password (when it expires for example), the user is redirected to the password update page (in my case https://adfs.piaudonn.com/adfs/portal/updatepassword) which does not have the RP URL in the location. For that case we also need to look at where the user comes from with the JavaScript document.referrer.

var locationUrl = window.location.href.toLowerCase() ;
var referrerUrl = document.referrer.toLowerCase() ;
if ( locationUrl.indexOf(“https%3a%2f%2fweb.piaudonn.com%2fclaimy”) != -1 || referrerUrl.indexOf(“https%3a%2f%2fweb.piaudonn.com%2fclaimy”) != -1 ) {
 //Change logo
 //Change illustration
}

Now that we detect if a user is trying to access to a specific RP, we can customize the logo and the illustration. We just do some overrides. The only tricky part is the illustration since the source of the illustration is actually defined in a CSS component Here is a suggestion:

var locationUrl = window.location.href.toLowerCase() ;
var referrerUrl = document.referrer.toLowerCase() ;
if ( locationUrl.indexOf(“https%3a%2f%2fweb.piaudonn.com%2fclaimy”) != -1 || referrerUrl.indexOf(“https%3a%2f%2fweb.piaudonn.com%2fclaimy”) != -1 ) {
//Change logo
document.getElementsByClassName(‘logoImage’)[0].src = “/adfs/portal/logo/logo-claimy.png” ;
//Change illustration
document.getElementsByTagName(‘style’)[0].innerHTML = “.illustrationClass {background-image:url(/adfs/portal/illustration/illustration-claimy.jpg);}” ;
}

The same way you can also customize the logon description text and other sections:

var locationUrl = window.location.href.toLowerCase() ;
var referrerUrl = document.referrer.toLowerCase() ;
if ( locationUrl.indexOf(“https%3a%2f%2fweb.piaudonn.com%2fclaimy”) != -1 || referrerUrl.indexOf(“https%3a%2f%2fweb.piaudonn.com%2fclaimy”) != -1 ) {
 //Change logo
 document.getElementsByClassName(‘logoImage’)[0].src = “/adfs/portal/logo/logo-claimy.png” ;
 //Change illustration
 document.getElementsByTagName(‘style’)[0].innerHTML = “.illustrationClass {background-image:url(/adfs/portal/illustration/illustration-claimy.jpg);}” ;
 //Change the login message
if ( document.getElementById(‘loginMessage’) ) {

  document.getElementById(‘loginMessage’).innerHTML = “<p>You’re about to access Claimy!</p><p>Sign in with your account</p>” ;
}

}

Now you add at the end of the onload.js JavaScript and import back the modified file with the following command:

Set-AdfsWebTheme -TargetName Yoga -AdditionalFileResource @{Uri=“/adfs/portal/script/onload.js”;Path=“C:\ExportedTheme\script\onload.js”}

Now you just have to try

I access to the IDP initiated sign-in page:

I access to the Claimy app and get redirected to the custom sign-in page:

You can do it for multiple RP too…

Hope this helps!

Comments (12)

  1. Jack says:

    You’re Amazing

  2. anonymouscommenter says:

    When you have more than one Claim Provider Trust, this is the default user experience:

    The Piaudonn

  3. harshal says:

    Really amazing work here…. Been wondering about this for long and stopped here at rest 🙂

  4. tom says:

    I am looking to integrate chrome book authentication with adfs however there is always a second login to authenticate on the device. Google docs direct that we reference a script but I don’t know where to place in Onload.js. Any guidance is appreciated..

    http://www.chromium.org/administrators/advanced-integration-for-saml-sso-on-chrome-devices

  5. Hi Tom – Please send your question here:
    https://social.technet.microsoft.com/Forums/windowsserver/en-US/home?forum=ADFS you’ll have a broader audience. Thanks!

  6. Bellopeda says:

    I am looking to integrate chrome book authentication with adds, however there is always a second login to authenticate on
    http://example.com">the device.

  7. Scott says:

    So if I am publishing an app via the WAP this will not work as expected correct?

  8. Scott says:

    So I attempted to try this with the Microsoft claim app. I cant get it to work. I modified the code identical to what your code shows and the page never displays my customizations. Any ideas?

  9. Scott says:

    If anyone has any ideas on how to get this to work it would be appreciated. It simply wont work for me.

  10. Eliezer Fernandes says:

    This code works only with the WS-FED protocol.
    With SAML protocol does not work, because it does not exist the Wtrealm parameter to identify the URL of the application.
    Someone found a way to do this with Windows 2012 R2 SAML?

    1. Correct. SAML query string are GZip compressed in the URL and unless the application inject a query string that we can catch in the URL, this won’t be possible.

Skip to main content