Contact

Subscribe via Email

Subscribe via RSS/JSON

Categories

Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan

Elsewhere

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. 

Tumbbad is awesome!

I saw “Tumbbad” recently. Wasn’t aware of this movie until I came across some article on interesting Bollywood movies of 2018 and it mentioned “Andhadhun”, “Tumbbad”, “Stree”, and others. 

I had seen “Andhadhun” last week (forgot to blog about it, damn!) so I gave “Tumbbad” a shot. It’s a horror movie, and very well taken at that. It’s not horror based on special effects or just trying to be creepy by sudden appearances etc. There’s a story and they have taken it well. It’s a simple story and one that says with you for a while. Definitely watch this movie if you haven’t yet! 

Might as well talk about “Andhadhun” here. This is a Sriram Raghavan movie (nothing more needs to be said; except for “Agent Vinod” and “Badlapur” (which wasn’t as gory as I hoped it would be) I have been a huge fan of all his movies (“Johnny Gaddar” being my favorite, and now “Andhadhun”). Starring Ayushman Khurrana as a blind pianist who happens to witness a murder, this is every bit a Sriram Raghavan movie as his other best work. To top things you have some amazing music by Amit Trivedi both in terms of songs and background music (the piano plays a huge role in this movie). Watch this if you are a fan of Sriram Raghavan movies or like stuff like “Fargo” – you won’t regret it!

I also saw “Stree”, which was fine. It’s a fun horror flick which is neither too much fun nor too much horror. Would have been better if it was more horror than fun, but well … can’t do much now. This was the weakest of the three movies.  Except for one bit where they make fun of the ghost regarding its IQ and obedience etc., there is nothing too memorable about this movie. 

Poirot, unpacked

Jeez I had high hopes for “The ABC Murders”. It was one of my favorite Poirot stories and well John Malkovich is playing Poirot so it must be exciting right?

Nope!

All of Poirot’s backstories and mannerisms and character are removed. This is a Poirot TV show the way “Elementary” is a Sherlock Holmes TV show. You don’t really want to see it!

This Poirot has a goatee! *horror* No mustache, can you believe that! He starts off coloring his mustaches black, which I think the “real” Poirot too used to do… but this one has the colors dripping off his face. He is sad, a lost cause. Cops hate him, he has no purpose. There’s a lot of flashbacks to some mysterious and sad past… which turns out be even more disappointing as guess what this Poirot wasn’t even a celebrated Belgian cop! Jeez.

The murders and plot are faithful to the book but it’s not much fun to watch. Everything’s so sad and gloomy. Poirot doesn’t even use his “little gray cells” anywhere. The ABC killer is kind of given to him in his lap. And there’s no explanation given behind how he found the actual murdered either. Eugh!

Of course, watch it coz anyone would be curious to see it considering it’s Poirot. But don’t expect much. Maybe go listen to a Poirot audiobook to cleanse yourself after this! (After watching an episode of “Elementary” I went back and re-watched an episode of “Sherlock” just to forget “Elementary”).

I liked something Poirot says in the end. We have a tendency to characterize the current age as dark or more evil that the olden times. That’s not really true. There was a lot of cruelty in the past too. In fact I was reading a book “1000 years of annoying the French” and also recently I visited Tbilisi, Georgia and was reading about their history… there was a lot more war and violence in the past. There is a lot of it now too but saying that the present is worse than the past is just romanticizing the past. There’s always been evil in the world – it’s Humans. We are just bad and wicked. (And this is me channeling a lot of “Westworld” too into everything else! :)).

Speaking of TV shows checkout “Black Mirror: Bandersnatch” if you get a a chance. Good stuff! Or if you want murder mysteries set in cold and lonely country check out “Shetland”. Excellent stuff!

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.

Westworld

I re-binge-watched Westworld Season 1 last week, so I could start watching Season 2, and binge-watched Season 2 the past few days. Amazing stuff as expected! Like chocolate cream for the mind. 

I was already blown away by Season 1 when I watched it two years ago so re-watching it wasn’t a surprise, but I didn’t have too high hopes for Season 2 as many shows have a good first season and then mess it up in the second or third seasons. Season 2 of Westworld seemed to start off that way with too many action sequences and fighting but it all made sense as one went along and things started to get very interesting from around Episode 3 (the one with The Raj). The only sort of boring episode for me was Episode 8, which was about the Indians and their visions, but it too was a good episode and I have no complaints or anything. 

It’s amazing how Westworld touches a lot of topics like visions, heaven/ hell, fate, God, AI, humans vs. robots, slavery, afterlife, computers … a whole bunch of topics that seem unrelated on the surface of it but which you can connect like the writers of Westworld did. I liked the Episode 8 with Indians for this – how they explained their visions and goals, which are different to everyone else, in the context of Westworld. 

Every episode somehow managed to be more human by going more into the backstory of the characters and yet also very Westworld-y with all the topics the show handles. I didn’t expect the “twist” in the last episode. I was expecting something, and I was expecting Bernard to be in the centre of it, but boy they took things to a different level! I never had so much fun with an unreliable narrator, or generally being confused but knowing there’s a reason behind it all! (And that’s another good thing about Westworld. Unlike other shows of a similar nature, they don’t leave anything hanging. You know that by the last episode things will make sense … there’s nothing left unanswered). 

Over all, a great show. Think Matrix (the first movie) and the way you mind opened up when you watched it. That’s Westworld, over two seasons. You get a similar mind opening at the end of each season with some bits and pieces sprinkled across the episodes. Season 2 especially, I get the feeling the writers had a lot of fun with the characters, the music, the camera world (the whole Shogun World piece is so darn creative!). Season 2 is lighter on content than Season 1 so they had to stretch things a bit I think, but it was fun the way they did it and I enjoyed it a whole lot. :)

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. 

ServerManager crashes on add/ remove roles

Learnt from various forum posts when I experienced it today: If ServerManager crashes on add/ remove roles, or Get-WindowFeature and related cmdlets throw a “The given key was not present in the dictionary” error, delete HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ServerManager\ServicingStorage\ServerComponentCache and restart the server

[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.

Restore-GPO : Value does not fall within the expected range

Once in a while you Google on some error and come across an old blog post of yours … and you smile. :) That’s what happened today. I was trying to Backup-GPO and Restore-GPO between two (trusted) domains and got the above error. Turns out this is expected when restoring GPOs between domains and I had encountered it previously. The workaround is to make a new GPO in the target domain and import the settings from the backed up GPO. 

You can either do this via PowerShell – use the Import-GPO cmdlet, or via GPO – right click the GPO and select “Import Settings”. 

Funny, the post I found was from 6 years ago … had forgotten I used to play with this stuff back then too. 

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.