Contact

Subscribe via Email

Subscribe via RSS/JSON

Categories

Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan

Elsewhere

TIL: Teams User-Agent String

Today I learnt that Teams too has a User-Agent String, and it defaults to that of the default browser of the OS. In my case, macOS with Firefox as the default, it was using the User-Agent String of Firefox. I encountered this today morning when Teams refused to sign on to our environment via ADFS because it wasn’t doing forms based as it usually did Windows Integrated Authentication, and that was failing because I am not on a domain joined machine. 

All of this happened due to a chain of events. At work enabled WIA SSO on ADFS for Safari and Firefox. At home my VPN client re-connected today morning, causing DNS resolutions to happen via the VPN DNS server than my home router, resulting in ADFS sign on for Teams going via the internal route to the ADFS server at work and since this was set to accept WIA now for Firefox it was defaulting to that instead of forms based authentication. The fix for this was to sort out my DNS troubles … so did that, and here we are! :) Good to know!

[Aside] Enable ADFS Logging

See https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging.

  1. Enable the ADFS Tracing Logs.
  2. Enable auditing via Set-AdfsProperties -AuditLevel Verbose. Disable via Set-AdfsProperties -AuditLevel Basic.

ADFS across trusted forests

I don’t know why there aren’t any blog posts on ADFS across trusted forests on the Interwebs. I know people are aware of it (we use it at our firm for instance) but whenever it comes to cross forest lookups I only find mention of the new ADFS 4.0 feature of adding a new LDAP claims store as described here or here. That has its advantages in that you don’t need any trust between the forests but assuming you have trust in place there’s an easier method that works in older versions of ADFS too. 

One comes across brief nod to this in posts that talk about the AlternateLoginID feature such as this. But there the emphasis is on the AlternateLoginID rather than cross lookup forests. Even on the help page for the Set-ADFSClaimsProviderTrust the -Lookupforests switch is mentioned as “specifies the forest DNS names that can be used to look up the AlternateLoginID”. 

If you have multiple forests linked together in a trust (like my previous lab examples for instance) all you need to do then is specify the AlternateLoginID to be something that is unique across both forests (UPN in my case) and give the names of the forests to -LookupForests

Here are my two claims provider trusts currently.  

Branch Office is my trusted forest with its own ADFS server. I want to change things such as I can use the Active Directory claims provider itself to query the remote forest. All we need to do is run the following on the ADFS server:

In the -LookupForests switch I specify all my forests (including the one where the ADFS server itself is). When running this cmdlet if you get an error about the LDAP Server being unavailable (I didn’t copy paste the error so I don’t have the exact text, sorry) and you see errors in the Event Logs along these lines “The Security System detected an authentication error for the server ldap/RELDC1.realm.county.contoso.com.  The failure code from authentication protocol Kerberos was “The name or SID of the domain specified is inconsistent with the trust information for that domain. (0xc000019b)”” then check your name suffix routing. You might not expect anything wrong with your name suffix routing (I didn’t) but that is probably the culprit (if you Google for this error that’s all you come across anyways). In my case I had the UPN suffix raxnet.global in both domains and that was causing a conflict (expected) but because the UPN suffix matched one of the domains I think it was causing issues locating the DC of that domain and hence I was getting this error. I removed the conflicting UPN suffix and the cmdlet started working. 

Above I am using the UPN as my AlternateLoginID, but I can use any other attribute too as long as it is indexed and replicated to the Global Catalog (e.g. mail, employeeID).

Check out this blog post for a flowchart on the process followed when using AlternateLoginID. One thing to bear in mind (quoting from that blog post): The AlternateLoginID lookup only occurs for the following scenarios:

  • User signs in using AD FS form-based page (FBA)
  • User on rich client application signs in against username & password endpoint
  • User performs pre-authentication through Web Application Proxy (WAP)
  • User updates the corporate account password with AD FS update password page

What this means is that if Windows Integrated Authentication fails for some reason and you get a prompt to enter the username password (not the Forms Based Page username password fields mind you) and you enter the AlternateLoginID attribute & password correctly authentication will fail. But if you enter the domain\sAmAccountname format and try to authenticate it will work. This is because when WIA fails and you type in the credentials manually it does not seem to be considered as WIA, nor is it FBA, and doesn’t fall under the 4 categories above and AlternateLoginID does not get used. 

Lastly, a cool side effect of using this way of cross-forest ADFS login is that the previous problem I mentioned of ADFS across forests not working with OWA & ECP goes away. :) I am not sure why, but now when I login to OWA from organization forest to resource forest, and then try to access ECP it works fine without any change to the claims. 

ADFS with Exchange OWA & ECP (contd.)

This is a continuation to my post from yesterday

While OWA works fine following my post yesterday, I learnt today that ECP does not work for users in the second domain. (To use correct terminology, users in the resource forest are able to login via ADFS and access both OWA & ECP but users in the organization forest are only able to access OWA. With ECP they get an error as below). 

NewImage

Yeah, sucks!

With some trial and error here’s what I learnt:

  • ECP expects the SID passed along to be that of the disabled account in the resource forest (i.e. where Exchange & ADFS are hosted). Since I am passing along the SID from the organization forest it is denying access. 
  • OWA on the other hand expects the SID passed along to be that of the active account in the organization forest (which is what we are currently passing). If one tries to make ECP happy and thus somehow pass the SID of the disabled account in the resource forest OWA complains as below. 

Screen Shot 2018 12 29 at 12 49 19 PM

I managed to work around this a bit. It is not a complete fix and I wouldn’t implement this in a production environment, but since my intention here is more to pick up ADFS than anything else I am happy I came up with this workaround. 

First off I changed my second ADFS server (the one in the organization forest) to not pass along all claims to the relying party trust with the resource forest. This is not really needed, but I had to do this for one more change I wanted to implement and figured it’s best to keep a control on the claims I pass along. As I alluded to in another post from today you can end up with duplicate claims if you pass along all claims and make changes along the way. Better to be picky. Anyways, on the second ADFS server I decided to pass along just 4 claims:

NewImage

At the risk of digressing, the first claim is why I initially decided to stop passing along all claims. I have admin accounts for myself with the same username in both forests, but differing UPNs, and I wanted it to be such that when I visit OWA or ECP with the admin account of the organization forest I am signed in to OWA or ECP of the admin account of the resource forest. That is, when I sign in as admin@two.raxnet.global (organization forest; this account has no mailbox or Exchange rights) ADFS will tell Exchange that this is actually admin@raxnet.global and let me login as the latter. That’s the point of ADFS and claims and all that after all – Exchange doesn’t do any authentication, it simply listens to what the ADFS server tells and I can do all this fun stuff on the ADFS side. 

Thus I created a claim rule like this:

It takes an incoming UPN claim, does a regex replace to substitute two.raxnet.global with raxnet.global. Easy peasy. Exchange is none the wiser and thus lets me login as admin@two.raxnet.global and access the mailbox & ECP of admin@raxnet.global. 

Going back to the original issue. I thus have 4 claims as above. 

The replying party trust from the ADFS server in the resource forest to OWA works fine as it is happy with the SID it gets from the organization forest. What. I need is a way to translate the SID of the organization forest to a SID in the resource forest, and pass that to the ECP trust. I don’t need to translate SID -> SID as such; what I really need to do is lookup the account name I am getting from the organization forest and use that to find the SID in the resource forest. When I create the linked mailbox in the resource forest I use the same username as in the organization forest so what I have to do is extract this username from the incoming claims and do a lookup using that. So far so good?

To do this I removed the claim rule on the ECP relying party trust that was passing through SID. (I let the UPN one stay as it is as that’s fine).

Then I added a custom rule like this:

Sanitize Windows account name

This takes an incoming windowsaccountname claim and makes a new claim (note, I add not issue – so this claim isn’t output ever) called “http://raxnet.global/windowsaccountname” (just a dummy URI I made up, doesn’t matter) and the value of this claim is the incoming windowsaccountaname but with the domain name replaced (i.e. remove the domain name of the organization forest, replace with the domain name of the resource forest). 

Now I added another custom rule:

Lookup SID

This one takes the claim I created above (the windowsaccountname with the domain name changed) and queries AD to find the objectSID attribute of this user account. This gives me the SID of this account in the resource forest. I now return it as a primarysid claim. 

To recap here is what I have:

NewImage

Do this and now ECP works via ADFS! :) Unfortunately if you now try to go to OWA it fails with the error I was getting earlier. :(

NewImage  

The problem here is that both OWA and ECP are in the same domain https://exchange.fqdn/ and so when I switch from OWA to ECP or vice versa I don’t hit ADFS again to re-authenticate. Since my browser already has a previously signed in session’s cookie it tries to access the new URL … and fails! And this is where I hit upon a wall and couldn’t proceed further. I figure if there’s some way to make the browser re-authenticate I can make it go to ADFS again … but I don’t know how to do that. I fiddled around with the cookie settings in IIS on the CAS server but didn’t make any progress. Exchange doesn’t let you use different URLs for OWA and ECP so there’s no way to use a different domain for either these and thus bypass cookies either. Am stuck. 

So that’s it. If anyone comes across this problem and has a better idea I’d be interested in hearing. :)

Update: A workaround.

Random ADFS notes

(Nothing new here. I was taking notes when reading up while troubleshooting an issue). 

All incoming rules can be thought of as being stored in an input rules set. 

All the claim rules are in a claim rule set. 

All rules in the claim rule set share the same input rules set. Each claim rule can also add to the shared input claim set, which can be used by subsequent rules. 

The claims created from claim rules are stored in an output claim set. This is initially empty, and is populated as the rules are processed. The claims in the output claim set are what is output when execution completes. 

Claim rules are processed top to bottom as per the list. 

Claim rules are of the format Condition statement => issuance statement;

The output of a claim rule can be to either both the input & output claim set, or only to the input claim set. If the issuance statement has an add statement it is to the input claim set only; if it has an issue statement it is to both. 

Condition syntax examples here. Key takeaways:

  • You can add or issue claims as mentioned earlier. 
  • In either case you can have Normal issuance statements that (a) creates a copy of an existing claim to the output set (am not sure how this works, I can’t think of an example) or (b) creates a new claim based on values in the input claim set (these should have the claim type specified for the new claim). 
  • You can also have Attribute Store issuance statements. In a single issuance statement you can create multiple claim types or multiple claims for a given type. The attribute store will have a query syntax. See here for examples. 
  • Both condition and issuance statements make use of expressions. 
  • Regex too is supported
  • Here are some of the claim properties available: type, value, issuer, originalissuer, valuetype. 
  • Apart from matching on == (equals, case sensitive) one can also match on != (not equals, case sensitive), =~ (regex match, case sensitive), and !~ (regex non match, case sensitive). Add a (i) to make it non case sensitive. 

It is important to remember that you can’t discard claims. As in, if the input set has a claim A and you do some modifications (transforms) to it, then both claim A and the modified claim A are passed on. This doesn’t make a 100% sense to me because I get the impression from the EXISTS function that you can discard claims. I think that applies more to temporary claims you create via the add statement.

(Update: I remembered later what I was trying to convey here. Say you have a claim rule that passes all incoming claims. Then you have other claim rules that maybe modifies one of these claims. You would think that this being a pipeline only the modified claim will be passed out, the original claim will stay as it is. But nope. Because the first claim rule was issuing all incoming claims the original claim too is passed along with the modified claim. Thus it is (a) better to not blindly pass all incoming claims and (b) if you want to make changes to an incoming claim don’t issue it, rather add it, modify, and then issue. )

Some more links:

ADFS with Exchange OWA & ECP

Follow the instructions here to setup OWA & ECP authentication via ADFS rather than the default forms based authentication. Here’s another, more concise article. Both articles talk about setting up WAP too which I didn’t do in my home lab. 

I wanted to add something extra to these articles.

In my home lab I have my primary ADFS server, which has a relying party trust setup with OWA & ECP as in these articles. Just to keep things interesting :) I also have a second domain, in a trust relationship with the first domain, and with its own ADFS server and users. The users in this second domain don’t have any Exchange mailboxes – these are hosted in the first domain. The second domain’s ADFS server has the first domain’s ADFS server as its relying party trust; and the first domain’s ADFS server has the second domain’s ADFS server as a claims provider trust apart from the default Active Directory. 

Upshot of the situation is that everyone authenticates with the ADFS server of the primary domain. They are given the choice: 

homerealm

Selecting “Branch Office” takes them to the second domain ADFS server where they can authenticate and claims are sent to the primary domain ADFS server from where it is passed on to the application. Selecting “Head Office” results in authentication against the Domain Controller of the primary domain itself. Easy peasy.

Now onto the claims setup in the primary domain as part of setting up OWA & ECP. We setup two claims: one takes the WindowsAccountName claim issued by AD and gets the user SID and sends that. 

The other claims takes the WindowsAccountName claim and gets the user UPN and sends that.

So both these claims essentially query AD and send the SID & UPN. They don’t work well with claims passed from another claims provider (such as the ADFS server in my second domain). So what I did is:

  1. On the second ADFS server I already had a rule that passed along all claims to the relying party trust of the primary ADFS server, so I did nothing additional. (If I didn’t have this in place I would have made two rules like I did in the next step). 
  2. On the trust between the primary ADFS server and OWA & ECP I removed the two rules above and made two rules that simply sent UPN & SID as UPN & SID. The idea being that the default rules only query from AD specifically, but I don’t want to limit to that. I will anyways get the UPN & SID claims either from the AD claims or the second ADFS server, so all I need do is pass these on to Exchange. 

upn-upn

That’s it. Now users in the second domain too should be able to use OWA & ECP via ADFS. 

Update: This breaks ECP. Continued in another post.

Firefox and ADFS WIA

Hat tip to this blog post. You have to add the URL of you ADFS server to the network.automatic-ntlm-auth.trusted-uris setting in about:config. Official documentation from Mozilla is here. Firefox, by default, does not negotiation authentication with a web server nor does it send NTLM responses. You have to explicitly whitelist sites you want to do this with.

Bear in mind you can’t do a domain wildcard either. So no “*.raxnet.global”, it has to be either “adfs.raxnet.global” or “https://adfs.raxnet.global”. Not like IE in that respect.

If in an enterprise of Windows computers you can manage this via GPOs. I don’t know how I missed it, but Firefox supports Group Policies since March 2018. Download the templates here. And while you are at it, you can also get it to pull in the enterprise root certs. Neat!

Also, I learnt the hard way that the settings for whitelisting sites don’t seem to take effect in private mode. So don’t waste time making these changes in a GPO and testing in private mode. :) if at all you need to re-test, you have to clear the history. 

Setting up SimpleSAMLphp on Windows Server with ADFS

Going to be brief here as it’s late at night. 

SimpleSAMLphp is a PHP application you can setup as a Relying Party in ADFS if you want a test application to play around with it. (It can do more things by the look of it – such as act as an Identity Provider itself, but I am not interested in that currently). 

Here’s what I did with it. 

1) Download it to my web server (a Windows Server 2019) and copy the extracted contents to a folder called c:\inetpub\simplesamlphp

(Update: Forgot to mention initially that I had downloaded the latest PHP on this server, following the steps here. I installed the latest version (7.2 as of this writing). Later on I came across the official IIS PHP website that offers me aa PHP 5.3 executable to install. Not sure what is the correct approach to have taken).

2) Made a DNS entry called testadfs.fqdn pointing it to my web server. Created a new website in IIS called testadfs.fqdn, pointing to c:\inetpub\simplesamlphp\www

3) SimpleSAMLphp expects the web URL to be of the form http://testadfs.fqdn/simplesaml so I made a virtual directory in IIS, under testadfs.fqdn, called simplesaml pointing it too to c:\inetpub\simplesamlphp\www

testadfs.raxnet

4) Now browsing to http://testadfs.fqdn/simplesaml works. 

Next step is configuring it!

5) Go to config\config.php and make changes as per this section of the install guide. You can use any random characters for the salt, use the GRC password generator if you want to be truly random. 

I want to use SimpleSAMLphp as identity provider (from the docs: “next steps depends on whether you want to setup a service provider, to protect a website by authentication or if you want to setup an identity provider and connect it to a user catalog”). I need to follow the steps here

6) Go to config\authsources.php and go to the entry called default-sp. Rename this to something if you want. I went to the ‘idp’ section here an added my ADFS server thus: ‘http://adfs.raxnet.global/adfs/services/trust’. Got this from the Federation Services properties in ADFS. 

identifier

Then add a line like this:

'NameIDPolicy' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',

Without this I was getting an InvalidNameIDPolicy error. Thanks to this StackOverflow post that gave me the workaround (note the accepted answer doesn’t work any more so I had to go with one of the others; looks to be a known issue with SimpleSAMLphp).

7) Go back to http://testadfs.fqdn/simplesaml and go to the Federation tab > Tools > XML to SimpleSAMPphp metadata converter. Put in the metadata URL of your ADFS – it’s of the form https://<idp fqdn>/FederationMetadata/2007-06/FederationMetadata.xml. In the resulting page go to the box for saml20-idp-remote and copy the contents. Then go to metadata\saml20-idp-remote.php and paste the contents there. 

8) Next go back to the Federation tab again and click “show metadata”. In the next page copy the URL for the XML metadata. 

show metadata

9) Go to the ADFS server, add a relying party trust, put in the above XML URL. Create the trust then edit its claims issuance policy and make a custom rule to “Pass All Claims”:

c:[]
=> issue(claim = c);

That’s all! Now I can go to the Authentication tab > Test configured authentication sources > and test the one I created above. 

[Aside] ADFS Customizations

Just a bunch of ADFS customization links for future reference. All these are customizations to the Home Realm Discovery (HRD) page. 

I haven’t gone into much detail with any of these. Some day. 

ADFS WIA Support UserAgent strings for Chrome etc.

This is more as a note to myself. Out of the box ADFS does not have WIA enabled for most browsers. You need to add the UserAgent strings of browsers you wish to enable WIA for. Here is the cmdlet with the list of agents I currently use:

This is based on this & this Microsoft Docs plus some other blog posts I read over the years. I will keep updating this blog post with any updates. 

It might be better to replace “Chrome” above with “Windows\s*NT.*Chrome”. I found this in the comments of this article. Useful so it only targets Chrome on Windows and not iOS/ Android. 

Here’s the User Agent Strings from Safari on my iPhone, Mac Book, and Vivaldi on Windows. 

  • Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1
  • Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.2 Safari/605.1.15
  • Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Vivaldi/2.1.1337.36

Matching on “Windows\s*NT.*Chrome” (which I think is regex and so should translate to the string Windows followed by zero or more spaces, followed by NT, followed by zero or more characters, followed by Chrome) will thus only pick the last User Agent String. 

Some more things to be done for WIA to work. You must add your ADFS site to the Local Intranet zone of IE. Best to use Group Policy Preferences for this, pushing out a registry key. Under the HKCU hive you can push out a key “Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\adfs.fqdn\” (or replace adfs with a * if you want *.fqdn to be matched), with a value of https and data of DWORD 00000001 in hex. Chrome, and Chromium based browsers (such as Vivaldi, Edge, etc.) will use this list so WIA will work for them automatically. 

This link from the Chromium page also mentions the SPN issue I encountered previously. The SPN generated will use the CNAME name if that exists, so better to use an A record with an IP address. 

When a server or proxy presents Chrome with a Negotiate  challenge, Chrome tries to generate a Kerberos SPN (Service Principal Name) based on the host and port of the original URI. Unfortunately, the server does not indicate what the SPN should be as part of the authentication challenge, so Chrome (and other browsers) have to guess what it should be based on standard conventions. 

The default SPN is: HTTP/<host name>, where <host name> is the canonical DNS name of the server. This mirrors the SPN generation logic of IE and Firefox.

ADFS and CNAME records – HTTP/400 error with WIA

I had heard that it is better to create an A record for ADFS (i.e. you get an IP address as the reply when querying the record) rather than a CNAME record (i.e. you get a name and the IP address of that alternate name) but didn’t know why until today. Now I know at least one reason why it is better to have an IP address. 

To begin with I must point to this blog post. The author had the same error as me, but of course he wasn’t using a CNAME, so his actual problem and fix was different. But the blog post is worth a read to know the situation. I had two domains – Domain A and Domain B – each with ADFS servers. I was trying to access the ADFS server in Domain B from a machine in Domain A, and getting prompted for credentials (expected) but once I enter the correct details it would give me an HTTP/400 error. Disabling WIA and enabling Forms Based Authentication worked, so the problem was to do with WIA. These are different domains, with trusts in place, and I was entering the correct details … so what gives? 

Looking at the System logs on my machine in Domain A (not where the ADFS server is in) I had entries like this:

The Kerberos client received a KRB_AP_ERR_MODIFIED error from the server msvc_adfs2$. The target name used was HTTP/rak2addc01.two.raxnet.global. This indicates that the target server failed to decrypt the ticket provided by the client. This can occur when the target server principal name (SPN) is registered on an account other than the account the target service is using. Ensure that the target SPN is only registered on the account used by the server. This error can also happen if the target service account password is different than what is configured on the Kerberos Key Distribution Center for that target service. Ensure that the service on the server and the KDC are both configured to use the same password. If the server name is not fully qualified, and the target domain (TWO.RAXNET.GLOBAL) is different from the client domain (TWO.RAXNET.GLOBAL), check if there are identically named server accounts in these two domains, or use the fully-qualified name to identify the server.

The highlighted entry is the clue. I was accessing the ADFS server as adfs.two.raxnet.global, and it was a CNAME to rak2addc01.two.raxnet.global, so looks like during WIA it was using the CNAME instead of the actual name and hence using the SPN HTTP/rak2addc01.two.raxnet.global rather than HTTP/adfs.two.raxnet.global. It also seemed to be using the (correct) HTTP/adfs.two.raxnet.global SPN and identifying the associated service account msvc_adfs2 but since that service account couldn’t decrypt the Kerberos tickets, I was getting an error.

ADFS 2016 prompts for credentials via a popup (and doesn’t work)

Setup ADFS in my home lab. There’s a single server called rak1adfs01.raxnet.global. The ADFS service is called adfs.raxnet.global and in DNS this is a CNAME to the server. 

When I go to https://adfs.raxnet.global/adfs/ls/IdpInitiatedSignon.htm I get a login prompt and even though I enter the correct credentials it doesn’t let me in. This is unlike what I am used to at work where we get a forms based screen and that works. 

To troubleshoot this I went to the authentication options on ADFS and under the Intranet section I unticked Windows Authentication and Microsoft Passport Authentication, leaving only Forms Authentication ticked. 

Screen Shot 2018 12 14 at 5 59 50 PM

Restarted the ADFS service and went back to ADFS page again – voila! it signs in. So the issue is definitely the WIA authentication. 

I noticed that when the prompt comes up it has my server name in it (rak1adfs.raxnet.global) rather than the ADFS service name (adfs.raxnet.global). That didn’t make sense – sounded like my browser was trying to authenticate against the server directly. 

Screen Shot 2018 12 14 at 6 03 18 PM

Could be an SPN issue? According to this article I am supposed to have an SPN of the form host/adfs.raxnet.gloabal and that does exist. 

Looking at the SPNs of rak1adfs01.raxnet.global (my ADFS server) I don’t see anything tying it to my service account. I came across another article, for a single ADFS server, which suggests setting up an SPN for http/<servername>. 

Once I did that WIA started working. (If I delete this SPN and create one for http/adfs.raxnet.global WIA fails again. I guess my issue is that since it’s a single server currently it is being treated as a single server case rather than an ADFS farm). 

I went back and enabled the Forms Authentication and everything works as usual. 

Lessons learnt: 1) WIA takes precedence over Forms Based Authentication; and 2) SPNs must be created against the single server if you have a single server install (even though you might be thinking of it as a farm install because you plan on installing more servers later). 

As an aside, some useful links: 

  • Here’s an example of a simple authentication app you can setup that uses ADFS
  • If you don’t want to install an app but just want to test ADFS authentication you can always go to https://fqdn.domain.com/adfs/ls/IdpInitiatedSignon.aspx. This will only work on ADFS 2016 if you enable it
  • Lastly, one more SAML test app that you can install. 
  • The two SPNs that are required for ADFS.

New ADFS configuration wizard does not pick up SSL certificate

Was setting up ADFS in my  home lab and I encountered the following issue. Even though I had a certificate generated and imported to the personal certificate store of the ADFS server, it was not being picked up by the configuration wizard. 

EmptyCert

I tried exporting the certificate with its private key as a PFX file and clicking the Import button above. Didn’t help either.

I also tried the following which didn’t help (but since I took some screenshots and I wasn’t aware of this way of tying certificates to a service account, I thought I’d include it here anyways). 

Launch mmc and add the Certificates snap-in. Choose Service account

Certificates

Then Local Computer. And Active Directory Federation Services

ADFS-Cert

Import the PFX certificate to its personal store. 

This too didn’t help! 

Finally, what did help was create a new certificate but use the CN and SAN name different to the server name. As in, my original certificate had a CN of “myservername.fqdn” along with some SANs of “myservername.fqdn” and “adfs.fqdfn” (the latter being what my ADFS federation service name would have been) but for the new cert I generated I went with a CN of “adfs.fqdn” and SANs of “adfs.fqdn” and “myservername.fqdn”. That worked!

NSX Edge application rules to use a different pool

Coming from a NetScaler background I was used to the concept of a failover server. As in a virtual server would have a pool of servers it would load balance amongst and if all of them are down I can define a failover server that could be used. You would define the failover server as a virtual server with no IP, and tell the primary virtual server to failover to this virtual server in case of issues.

Looking around for a similar option with NSX I discovered it’s possible using application rules. Instead of defining two virtual servers though, here you define two pools. One pool for the primary servers you want to load balance, the other pool for the failover server(s).

Then you create an application rule this:

Once again, the syntax is that of HAProxy. You define an ACLadfs_pri_down is what I am defining for my purposes as this is for load balancing some ADFS servers – and the criterion is nbsrv(pool-adfs-https-443) eq 0. The nbsrv criterion checks the pool you pas on to it (pool-adfs-https-443 in my case) and returns the number of servers that are up. So the ACL basically is a boolean one that is true if the number of usable servers is 0.

Next, the use_backend rule switches to using the backup pool I have defined (pool-bkpadfs-https-443 in this case) if the ACL is true.

That’s all. Pretty straightforward!

[Aside] Various ADFS links

No biggie, just as a reference to myself:

Update 16 July 2018: Needed to make a claim rule yesterday that converted the email address from an incoming claim to Name ID of an outgoing claim. The default GUI provided rule didn’t work, so I made a custom one:

I think I’ll add more such snippets here later.

Btw note to self: custom claim rules are useful if you want to combine multiple incoming claims – i.e. for an AND operation. If you don’t want to combine – i.e. you want to OR multiple claims – just add them as separate rules.