Azure Pack Tenant portal extensibilities – Part 2

Multiple domain names and themes on a single Tenant portal

On to the First extensibility then! Before I go on further to explain how this is done, let’s re-iterate on the scenario we’re trying to tackle here.

Problem Statement

Contoso Hosting is a hosting company that has stood up a private cloud stack with Azure Pack. Contoso has two huge customers called Customer1 and Customer2 (innovative names… I know! but let’s call them these for simplicity Smile ). Customer1 is a hosting company themselves who would like to offer the services provided by Contoso, to their own customers. Customer2 is an enterprise customer who would like to provide Contoso's services to their different departments.

Both of these customers would like Contoso to provide them their own personalized portals due to their business requirements. Customer1 would like to get the portal located at https://www.customer1.com and Customer2 at https://www.europe.customer2.com and would like the portals to be styled with their own respective themes.

Solution

One of the extensibilities that can be leveraged is the option that enables you to support multiple themes and domain names for a single Azure Pack Tenant Portal. This way, on the same tenant portal website, you can add additional IIS bindings, add multiple themes and set the WAP Portal and API layer to treat these as different entities and cater to each one differently. That’s the one-liner for this extensibility!

Why would you go in for this extensibility?

The merits of this extensibility are that

  1. Infrastructure footprint is low. If you need more than three or more domains, the infrastructure cost for maintaining multiple tenant portals goes up steeply
  2. You do not have to maintain different load balanced instances of the Tenant Portal. You can set up one portal in HA and scale that depending on your load
  3. All the data lives within the context of one portal. You do not have to maintain multiple “different” portals
  4. If your customers don’t have different scale requirements you could just have all of them on the same portal instance and scale that service uniformly.

Important Notes:

  1. I am using Active Directory Federation Services (AD FS) as the Identity Provider for this extensibility.  You cannot use this extensibility with the ASP.NET Membership Provider. The main requirement for this in terms of Identity Providers is that the Identity Provider should be capable of supporting Multiple Relying Parties. My recommendation would be using AD FS. Also, I am assuming that your AD FS is already set up. If you haven’t set up AD FS, please follow the blog post at http://blogs.technet.com/b/privatecloud/archive/2013/12/02/federated-identities-to-windows-azure-pack-through-ad-fs-part-1-of-3.aspx for instructions on setting AD FS up.
  2. I am also assuming that you as the reader know how to set up relying party trusts with AD FS. If not, please glance over my previous blog post here http://blogs.technet.com/b/privatecloud/archive/2013/11/27/federated-identities-to-windows-azure-pack-through-ad-fs-part-2-of-3.aspx.
  3. I am not going over DNS changes required for this. It is assumed that the DNS is already set up and the domains are pointing to the Tenant Portal machine. Please ensure that you are able to access these domains before you begin this extensibility. This will save you a lot of troubleshooting later on.
  4. This is a fairly advanced extensibility, so make sure you take snapshots after before and after Step 3 in case you need to go back.

This extensibility involves 4 steps:

  1. Add additional bindings in IIS for the Tenant Portal website
  2. Copy the different themes into Content folder of the Tenant Portal website
  3. Modify the WAP Configuration Databases to accommodate for the new domain names
  4. Setting up trust with your Identity Provider

1. Add IIS bindings to Tenant Portal

The first step is to add additional HTTPS bindings to your Tenant Portal website.

  1. Open Internet Information Services Manager (IIS) on the computer that hosts your Windows Azure Pack tenant portal (MgmtSvc-TenantSite).
  2. In the left pane tree-view, select MgmtSvc-TenantSite, select the Bindings action, select Add in the Site Bindings dialog and add the port, Host Name and SSL certificate information.
  3. Ensure that you select ‘Require Server Name Indication’
  4. Assign the appropriate SSL certificate to the host name.
    Note: These are recommended to be real certificates from a trusted CA. If you’re using Self-Signed Certificates, please make sure that the certs are in the Trusted Root Certification Authorities of all the machines you’re using.
  5. Select OK to close the dialog.
  6. Add as many bindings as there are host names that need configuring.
    image

In our example, I am going to add two bindings called customer1.com and europe.customer2.com to my Tenant Portal
image

2. Add themes to Tenant Portal

The next step is to tell the Tenant Portal what theme to load when the Tenant Portal is accessed through each of the above domains. Create custom themes for each of your customers as appropriate and follow the steps below

  1. Go to C:\inetpub\MgmtSvc-TenantSite\Content on your Tenant Portal Machine and create a folder called ‘ThirdPartyThemesByDomain’
  2. Copy your themes inside that folder. Make sure to name the folders based on the domain name you would like them to be served for.

In Our scenario, I am going to create two theme folders called customer1.com and europe.customer.com and copy them to the Third Party themes folder as below:

image

3. Modify WAP configuration Databases

Now would be a good time to take a snapshot of your Tenant Portal Machine. The next step involves making changes to the WAP Configuration Database.

This step involves composing a couple of JSON and modifying the Portal Config Store and API Config Store. What we’re doing here is

  1. Telling the Portal that it needs to expose a different Realm and a different ReplyToEndpoint for each domain.
  2. We are also telling the API layer to support these values while validating the user’s token.
  3. Additionally, we are setting up the Portal and API to trust an identity system and telling the portal redirect the users here for authentication

To save you the trouble of modifying the database manually, I have automated this step in a PowerShell Script.

The script can be downloaded from https://gallery.technet.microsoft.com/Setting-up-Multiple-themes-1258f8f0 .

After downloading the script, open it up in PowerShell ISE and fill in the appropriate input data and execute the script.

image

In our scenario, I am filling the inputs as above. This needs to be understood clearly to understand this extensibility.

To  explain, given that I need a domain called customer1.com, I am telling the Tenant Portal to identify itself as http://azureservices/customer1 to its identity system and to the API layer and set the redirect Url to https://customer1.com so that the STS can redirect to this Url after authentication. Similarly, for the second domain Europe.customer2.com, I am telling the tenant portal to advertise itself as http://azureservices/customer2 and setting the replyTo address to https://europe.customer2.com.

Why do I need the tenant portal to have different Realms?

There are 2 reasons:

  1. Since customer1 and customer 2 are at different URLs, your STS needs different identifiers to redirect the users to after authentication. Hence the STS will not allow you to register two Relying Parties with the same identifier.
  2. Both customer1 and customer2 may have different Identity systems that they would like their user to login with. In this case, AD FS (or any STS) needs an unique identifier from the portal so that it can automatically redirect it to the right identity system. (In the 4th part of this series, I will discuss how this is done. If you’re really curious you can find this information under the “Set specific Identity Providers to a Relying Party” section in the  Active Directory Federation Services (AD FS) with Azure Pack Tips, Tricks & Troubleshooting blog post!

Provide the Federation Metadata of your Identity System to tell the Tenant Portal about your identity system and give the script a whirl. At the end of execution, it will open up a notepad file with the original Relying Party and Identity Provider values before the execution. Save this text file in case you need to go back to original settings.

To see if the script did its job right, you can visit https://<<domain>>/federationmetadata/2007-06/federationmetadata.xml and download the federation metadata file. You should get a different metadata file for each of the domains you’ve set up. In our scenario when I visit https://customer1.com/federationmetadata/2007-06/federationmetadata.xml, I get the following file. Note the entityId and was:Address fields

image

when I visit https://europe.customer2.com/federationmetadata/2007-06/federationmetadata.xml

image

In the interest of being thorough, I am providing an explanation below as to what the script does. It is good to understand this, but if you’re not interested in these details, you can skip to Step 4.

Portal Config Store Modifications:

  1. The Tenant portal needs to issue a different realm based off the incoming domain name. to do that you go to the Tenant Portal’s Config store at Microsoft.MgmtSvc.PortalConfigStore and Add a key called Authentication.RelyingPartyByDomain and setting the Value to be in the following format.
    {“<<Domain1>>”:{“EncryptionCertificate”:null,”Realm”:”<<YourRealm1Here>>”,”ReplyTo”:”<<YourReplyToAddress1”>>”}, {“<<Domain2>>”:{“EncryptionCertificate”:null,”Realm”:”<<YourRealm2Here>>”,”ReplyTo”:”<<YourReplyToAddress2”>>”}}

For our scenario, the row will look like


Namespace Name Value    Created    Modified
TenantSite Authentication.
RelyingPartyByDomain
{"europe.customer2.com":{"Realm":"http://azureservices/customer2",
"ReplyTo":"https://eu
rope.customer2.com",
"EncryptionCertificate":null},
"customer1.com":{"Realm":"http://azureservices/customer1",
"ReplyTo":"https://customer1.com",
"EncryptionCertificate":null}}
2015-01-15 13:49:07.0000000 +00:00    2015-01-15 13:49:07.0000000 +00:00

API Config Store Modifications:

The [Microsoft.MgmtSvc.Store].[Config].[Settings] table stores information required by the Service Management API. The [Authentication.RelyingParty.Primary] key under the [Namespace] ‘TenantAPI’ stores information about the portal and realms that is trusted by the API layer.
Similarly, the [Authentication.IdentityProvider.Primary] key under the [Namespace] ‘TenantAPI’ stores about the STS that sends the signed token. These keys are used by the Service Management API layer to verify the validity of the incoming claims and provide access to the user. The Service Management API can understand 2 additional keys which will not be present in the table by default and will have to be added to the table manually. These are:

Authentication.IdentityProvider.Primary.Multiple

This is an array that takes multiple JSON strings and is used to identify the different Relying Parties

Authentication.RelyingParty.Primary.Multiple

This is an array that takes multiple JSON strings and is used to identify the different Identity Providers

  1. Edit the [Microsoft.MgmtSvc.Store].[Config].[Settings] table and add an additional row with Namespace TenantAPI and Name as Authentication.RelyingParty.Primary.Multiple. The value for this field should be if the format
    [{"EncryptionCertificate":null,"Realm":"<<YourRealm1Here>>","ReplyTo":"<<YourReplyToAddress1”>>"}, {"EncryptionCertificate":null,"Realm":"<<YourRealm2Here>>","ReplyTo":"<<YourReplyToAddress2”>>"}]

    Replace the values to match the value in the Portal Store as done above. You can add more array elements to the template above based on the number of Portals you have. In our scenario, My table will look like

    Namespace Name Value    Created    Modified
    TenantAPI Authentication.
    RelyingParty.
    Primary.Multiple
    [{"Realm":"http://azureservices/customer1",
    "ReplyTo":"https://customer1.com","EncryptionCertificate":null},{"Realm":"http://azureservices/customer2",
    "ReplyTo":"https://europe.customer2.com","EncryptionCertificate":null}]
    2015-01-15 13:49:… 2015-01-15 13:49:…

     

  2. The JSON string array representing the various Identity Providers needs to be composed. This is done by using the following template

    [{"Realm":"http://<<ADFSFQDN>>/adfs/services/trust","Endpoint":"https://<<ADFSFQDN>>/adfs/ls/","Certificates":["SigningCertificate"]},"Realm":"http://<<ADFSFQDN>>/adfs/services/trust","Endpoint":"https://<<ADFSFQDN>>/adfs/ls/","Certificates":["SigningCertificate"]}]

    My table looks like

    Namespace Name Value    Created    Modified
    TenantAPI Authentication.
    IdentityProvider.
    Primary.Multiple
    [{"Certificates":["MIIC3DCCAcSgAwIBAgIQJFolmpo+w<<truncated>>"],
    "Endpoint":"https://adfs.contoso.org/adfs/ls/",
    "Realm":"http://adfs.contoso.org/adfs/services/trust"},
    {"Certificates":["MIIC3DCCAcSgAwIBAgIQJ
    <<truncated>>"],
    "Endpoint":"https://adfs.contoso.org/adfs/ls/",
    "Realm":"http://adfs.contoso.org/adfs/services/trust"}]
    2015-01-15 13:49:… 2015-01-15 13:49:…

     

  3. Delete the [Authentication.RelyingParty.Primary] and [Authentication.IdentityProvider.Primary] values under the [TenantAPI] Namespace in the [Microsoft.MgmtSvc.Store].[Config].[Settings] database table as a security measure to prevent conflicts
  4. Perform ‘iisreset’ on the ‘MgmtSvc-TenantAPI’ machines for the changes to get picked up by the Service Management API

4. Setting up trust with the Identity Provider

The final step is to tell your Identity System about the tenant portal. Because we would like the Tenant Portal to work with two different domain names and two different realms, these would form two separate Relying Parties with AD FS.

Use this blog http://blogs.technet.com/b/privatecloud/archive/2013/12/17/federated-identities-to-windows-azure-pack-through-ad-fs-part-2-of-3.aspx to understand how to register Relying parties with AD FS. Follow the steps under the AD FS Configuration section replacing values as appropriate. We will set up two Relying Parties to support our scenario using the two federation metadata files mentioned above
https://europe.customer2.com/federationmetadata/2007-06/federationmetadata.xml
https://customer1.com/federationmetadata/2007-06/federationmetadata.xml

image

Please ensure you’ve followed all the steps in the ADFS configuration section of that blog as appropriate using the realm values in our current context and remember to Enable JWT tokens Smile

Now when I visit https://europe.customer2.com, I get redirected to my AD FS sign in page and after a successful login, I am taken back to my Tenant portal with a “red” theme.

image

When I visit https://customer1.com , I am directed to the same AD FS again, and after successful login, I am taken back to my Tenant portal, with a “green” theme

image

Voila! You now have the same tenant portal giving you two different themes and is capable of supporting two different URLs!

If you’ve noticed, although we’ve set up two different domain names for the Tenant Portal, login still happens through the Contoso Active directory. In the fourth part of this blog, I will talk about how to point these to different identity providers. If you’re really curious you can find this information under the “Set specific Identity Providers to a Relying Party” section in the  Active Directory Federation Services (AD FS) with Azure Pack Tips, Tricks & Troubleshooting blog post! Smile

In the next post, I will talk about how to set up Multiple tenant portals with Azure Pack!