AD FS 2012 R2 ships with the InsideCorporateNetwork Claim. It evaluates to “True” when a request is received directly at AD FS, or “False”, if a request is received at the WAP. This Claim doesn’t exist in AD FS 2.0/2.1, and it’s fair to say this is one of the more poorly understood differences in behaviour across the versions.
I’ve recently been asked to find out if it’s possible to create an InsideCorporateNetwork Claim in AD FS 2.0/2.1. The benefit of creating it for the older versions is that InsideCorporateNetwork would be usable in exactly the same way that we use it in AD FS 2012 R2 and later, which opens up the following options:
- We can focus on Allow rules, which can be added and removed as modules (more on this in a moment).
- We can pass InsideCorporateNetwork through to Azure AD for Azure MFA whitelisting (rather than having to add IP addresses in the Azure portal, and also allowing us to whitelist more than 50 IP addresses).
- We can pass through Persistent Single Sign On (PSSO, or Keep Me Signed In) for WIA users.
- We work with an organisation that has a newer farm and an older farm in two different forests. Creating this Claim gives us the option to settle on a single set of baseline rules that are common to the two Business Units, and to simplify any divergence from the common rules.
- We can benefit from community troubleshooting and rules creation advice that has been created for the later versions of AD FS, without the conceptual weight of having to redesign for AD FS 2.0/2.1.
All told, it makes things better.
What AD FS 2.0/2.1 does have instead of InsideCorporateNetwork is the x-ms-proxy Claim, which is added under the hood by default in AD FS 2.1 or after installing Hotfix Rollup 1 or later for AD FS 2.0. This Claim will be present without doing anything extra, but I would recommend also creating the Claim Description for it (manually, or with the Client Access Policy Builder). Also, it should be passed through from the Claims Provider Trust for Active Directory (again, manually, or with the Client Access Policy Builder). All of this is documented as the pre-requisites for getting the x-ms-proxy Claim working with the AD FS Proxy, as documented by Microsoft in their Limiting Access to Office 365 Services Based on the Location of the Client article, although in practice the Update Rollup Package is the thing that gets it working and the rest of these steps are about making it visible in a predictable and expected way.
In the New Claim Types section at the bottom of this article, you will see that Microsoft recommends combining an EXISTS rule for the x-ms-proxy Claim with any of the other evaluations. What this means is that, “Adding this clause to a new, custom rule specifies that the request has come from the federation server proxy (i.e., it has the x-ms-proxy header). It is recommended that all rules include this.” However, this recommendation is formed on the basis of adding an EXISTS condition to a Deny rule. I am typically looking for ways to avoid the double-negative logic and repetition of conditions across rules that comes with Deny Claims, so over the last year I have started to focus on approaches to remove the Permit All Users Issuance Authorisation Rule, replacing it with explicit Allow rules, which have the added benefit of being modular (so they can be added/removed independently, without having to unpick multiple conditions in a single rule). I also feel that the Permit All Users Claim is typically too open to unknowns and future changes for an organisation who is concerned enough about security that they are specifying custom Issuance Authorisation Rules.
So I’ve set about taking what is documented by Microsoft for x-ms-proxy in Deny rules, and tried to find the best way to first use x-ms-proxy to get an InsideCorporateNetwork Claim, and then to convert the Deny logic to Allow logic. Note: one of the fundamental differences in the Claims is that x-ms-proxy carries the name of the Proxy the request passed through (and so it doesn’t exist if the user signs on directly at AD FS), whereas InsideCorporateNetwork always exists as either “True” or “False” (where “False” means the user signed on at the Web Application Proxy).
Here’s an overview of the steps I took to create new rules that restrict access to requests received directly at AD FS (Inside Corporate Network), which was greatly assisted by the fantastic new ClaimsXray tool.
1) Fulfilled all the pre-requisites I mention above.
2) Create a new Claims Description for InsideCorporateNetwork. I just copied this from AD FS 2012 R2. It could actually be called anything, but I think it makes sense to align with the later versions.
3) Configured a Relying Party for ClaimsXray: https://adfshelp.microsoft.com/ClaimsXray/ (it is a GREAT newish tool).
4) Added two new Acceptance Transform Rules to the Claims Provider Trust for Active Directory. It is quite important to add them here, as they then become useful everywhere else (to be passed through, transformed or evaluated in Issuance Authorisation AND Issuance Transform rules – which are two separate bits of the Claims Pipeline), and this approach avoids rule duplication (or even multiplication, across multiple Relying Parties). The first Rule I’ve added issues InsideCorporateNetwork = false if x-ms-proxy exists. The second rule issues InsideCorporateNetwork = true if x-ms-proxy doesn’t exist. Note: the Claims Provider Trust is also where the five Client Access Policy Claims get Passed Through, so this aligns well with Microsoft’s thinking. I’ve included the syntax for these two new rules below.
5) Initially, configure the ClaimsXray RP to Permit All Users, and then created two Pass Through rules for x-ms-proxy and InsideCorporateNetwork in the Issuance Transform Rules tab (not the Issuance Authorisation Rules tab).
6) Configure the Office 365 RP to Permit Access to InsideCorporateNetwork = True. Remove the Permit All rule.
7) Test with ClaimsXray until the Claims values look like you expect they should, then remove the Permit All rule, and replace it with Permit InsideCorporateNetwork = true. This should now block ClaimsXray externally and you should see InsideCorporateNetwork = true internally.
8) Test Office 365 access, which should now block access externally.
Note: in the real world you would probably combine this with another rule that allows a specific type of external access, or perhaps legacy Outlook access via the x-ms-forwarded-client-ip Claim, but I thought it was important to focus on this most basic scenario first.
And here are the two new Claim Provider Trust (for Active Directory typically) Issuance Acceptance Rules that came out the back of it.
Rule #1: “If x-ms-proxy exists, issue InsideCorporateNetwork = False”
c:[Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy“]
=> issue(Type = “http://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork“, Value = “False”);
Rule #2: “If x-ms-proxy doesn’t exist, issue InsideCorporateNetwork = True”
NOT EXISTS([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy“])
=> issue(Type = “http://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork“, Value = “True”);
If anyone is cleverer with Regex and/or Claims Syntax than me, and can consolidate these rules down to one, I would welcome that feedback.
One thing tripped us up along the way. We’ve found forward proxies may also write to the HTTP Header that populates the x-ms-proxy Claim. We expect that the AD FS URL should be exempted for internal users, so in principle this shouldn’t be a problem, but if for any reason it isn’t exempted, or if the exemptions don’t reach a client that should have them, these users will evaluate as though they are external, since the x-ms-proxy Claim will exist.
In response to this issue, I thought through whether we should change the rule to look for the specific AD FS Proxy Server DNS names rather than using an EXISTS/NOT EXISTS rules, but I think this would be a weaker approach since the AD FS Proxy DNS name could be spoofed trivially, and we are using these rules as an integral part of Conditional Access Policy. One of the good things about the InsideCorporateNetwork Claim in AD FS 2012+ is that it isn’t susceptible to the weaknesses of the HTTP-Header-derived approach. In my view, we have uplifted AD FS 2.0/2.1 security to this same level by taking the EXISTS approach, so I wouldn’t advise weakening it by reverting to the specific DNS names.
Hope this helps someone!