Real World Claims 2: Provision ADFS and SharePoint Demo Environment

This post is part 2 of a series, and is a companion to my presentation titled Real World Claims in ADFS and SharePoint 2010. This presentation will be given Saturday, April 13th, 12 noon at SharePoint Saturday, The Conference, Washington, DC April 11-13, 2011. Table of contents, additional links, slides, video recording, and other funny liner notes will be posted in Part 1 as they become available.

Planning an Enterprise Class Demo Environment for SharePoint and ADFS
First, I need a demo environment. I know I'm not gonna have much fun trying to show off our cool stuff unless I can squeeze SharePoint, Active Directory, and ADFS onto my laptop somehow. Quite possibly I won't even have network access while I am giving this demo – a big problem for a solution based heavily on Public Key Infrastructure. Plus, a lot has changed in the time since SharePoint 2010 first went RTM back in May of last year. We had a service pack of Windows 2008 R2 and one for SharePoint too, as well as a major release of ADFS. While we witnessed many bugs and issues over the past year, I want to be sure I'm presenting on the current state of the art. So, I begin by downloading new ISOs for everything. (There doesn't appear to be an image for SharePoint with SP1 included from install, but no biggie.)

What's the environment going to look like?

Server 1: DEMO\MasterControl
Active Directory, ADFS, SQL Server 2008 R2, [optional] Certificate Authority
normally you would put these services on multiple machines
typically installed behind the company firewall

Server 2: DEMO\SmartyPants
IIS, SharePoint 2010, ADFS Proxy
would normally be a WFE with an SP application server on another box
single server will suffice for this demo
if web facing, typically installed in the DMZ

I like this configuration, because it should be easy enough to do with only two VMs, but it will effectively mimic some of the inter-machine network traffic you would normally expect to see in the real world. The presentation is called "Real World Claims" after all. I could potentially re-use this demo environment for a multitude of purposes, including BI solutions or other stuff too.

One thing I want to talk about in a bit more detail here. At the time of this writing, I do not know 100% what the effect of taking these machines off the network will be. There are two things about my plan that concern me somewhat: 1) I am configuring this environment as a sub-domain of my forest, instead of an independent forest, and 2) I am using the certificate authority on the root domain of my forest. I've done some basic research into this, and it is my belief that certificates and CRLs (certificate revocation lists) are cached on the servers for a sufficient period of time such that – if I leave this system up and running at my hotel – I can disconnect it from the internet long enough to deliver my demo without any adverse impact. Time will tell, but later this week I plan to test this before it would be too late to formulate a backup plan. (Actually, my backup plan would be to install a standalone CA on my demo box, but even under those circumstances I am not certain how Kerberos will react.)

Now I need to install all these things. Having done this many, many times I can tell you it isn't all that exciting. Here's the basic rundown.

Step 1: Core Install and Configuration on MasterControl
Not much to say here. Install Windows Server 2008 R2 Standard Edition <yawn />     


Can somebody tell me, why the heck is there a close/cancel button on this window? Now we configure the network, install all updates, and rename the machine.
Keep in mind that these need to work when disconnected from the Internet.
For now, I am using local addresses and,
but eventually I may switch to and

Next, run dcpromo to promote the server to an Active Directory domain controller.


In retrospect, I am having second thoughts about whether it was wise to join this demo environment to my existing forest. I guess we'll find out!




Oh, hey, I should probably make a second physical site for these servers.


Notice that I made this DC a global catalog server, because I'll be running it some physical distance from the forest.




One other thing I did is that I configured a new physical site on the domain, because I'm going to run these demo machines on my laptop in a [potentially] disconnected scenario.

Okay, inside joke: above site location named "I'm on a Boat" is actually a song by rapper T-Pain, sorta similar to "Like a Boss". At Liquid Mercury, we've been talking for over a year about doing a code camp on a Caribbean cruise! And now, you know the reference #nullreferenceexception.

Step 2: Install ADFS 2.0 on MasterControl
After downloading the ADFS 2.0 RTW, the installer will ask you if you want to install an ADFS Server or an ADFS Proxy. For this machine we're going to install the server. In this case, we do the GUI install and we know that ADFS will install to the Windows Internal Database. Later, I'll probably want to upgrade this server to use SQL Server instead (more info: here). Other than those two choices, it's a pretty brain dead installer. Then, we open the admin tool and do the real work.

After the installer completes, you can find the ADFS 2.0 Management console in the Start Menu under Administration Tools. To start the Configuration Wizard, click the link shown above next to the [extremely obvious] red arrow.



Now, personally, I'm a glutton for punishment, so I'm going to install this machine as the first member of a farm, even though I know that for the purposes of my demo it'll be the only machine to host ADFS - and I've effectively limited my load balancing options by using the WID instead of SQL.


Here, I'll use the default certificate for the Default Web Site in IIS, which happens to be the domain controller server certificate. Later I can generate a new certificate especially for SSL. The name of the ADFS web site is not glamorous. If this were a production environment, I'd possibly choose a cleaner name like "", but this will suffice for now, and I can always change it later.

Next, I create an OU in AD called Services, which is where I'll keep all the service accounts I need to create. Then I create an account in that OU. I call my account "ADFS Service" with logon "DEMO\adfs-service". Keeping this account in its own OU with other service accounts helps me find them easily and manage Group Policy Objects more easily if I need them later on. (Hint: I will.)



Finally, we confirm settings and click Finish to run the wizard, and ... <drumroll />


Oh crap. Better fix that. :-(


Now that the installer is finished, we need to address that error we got. Run these commands to give SPNs to the NetBIOS and DNS names for the ADFS server

SETSPN -A HTTPS/ DEMO\adfs-service
SETSPN -A HTTPS/mastercontrol DEMO\adfs-service

You also want to trust the ADFS service account for delegation. This is something I often forget to do. To accomplish this, jump into Start > Administration Tools > AD Users and Computers, find its user account and view its properties.


Note that the Delegation tab only appears as an option after an account's SPN is defined using the commands shown earlier.


After you complete the wizard, you'll see that IIS now has the virtual directories for /adfs and /adfs/ls under Default Web Site.

Something to keep in mind here, even though it doesn't apply on a new server: if you were doing anything special with Default Web Site that caused you to reconfigure it, the ADFS wizard is just going to drop its stuff right on top of your other changes. Be watchful for this, since they might have conflicting settings.

I'll kick the can down the road a bit farther on the rest of ADFS configuration we'll need to do.

Step 3: Configure a Certificate Authority
[A few words here about the idea of a standalone CA] I had considered using a standalone CA on my demo domain controller, but eventually I decided it wasn't needed and uninstalled it.

In my case, I'm going to use the Certificate Authority on the root of my forest. This works for me because I already have one set up, and I've tested it a few times with other development environments. I can be reasonably sure it's going to work when it's time to run my demo.

Creating a Certificate Template for ADFS / STS
For the most part, we're able to get by with either existing certificates that were created by AD when our servers were provisioned, or by creating certificates through the interface provided by IIS. But, Secure Token Services (and in particular ADFS) require a few special tweaks that will deviate slightly from the Web Server template provided out-of-the-box in AD Certificate Authority.

1. Specifically, ADFS wants you to use a certificate with a 2048 bit or higher key strength. Depending on your version of Windows and how long the CA has been in service, you might still be generating SSL certificates with 1024 bit keys.
2. As you'll also see, we'll need to be able to export the private keys for this certificate. This is something that is not enabled on the Web Server template.
3. Lastly, the version of your certificate template can make a big difference. 2008 compatible templates allow you to set up signature hash algorithms with SHA-512 or MD5, neither of which is supported by ADFS 2.0. In fact, ADFS is extremely fickle about what certificates it is willing to use – as we'll see. So, you need to be careful in the type of template you create, or risk losing a night of sleep to troubleshooting - like I did.

To request and issue such a certificate, we'll need to create a certificate template. Do this by opening Certificate Authority, then right-click Certificate Templates, and choose Manage.



Find the Web Server template, right-click, and then click Duplicate Template.

You will be asked to choose Windows 2003 Server and Windows Server 2008. This seemingly innocuous dialog box is actually quite insidious.

IMPORTANT: I have no Windows 2003 servers left in my forest, so I normally would have no issue with picking the second option here. However, according to comments left here:

  "If you are generating certificates from AD-CS, make sure to request  the certificates using a template that supports a Windows Windows 2003 Enterprise CA. If you use a Windows Server 2008 CA template, the Federation server will fail to start and report a generic private key error message in the logs (Event ID 133)"


"ADFS2 is written in managed c#, using X509Certificates2 - X509Certificates2 don't support CNG (CAPI Next Generation) - this means (by extension) that you can't use certificates which rely on CNG - using 2003 templates as Ross suggests above will ensure you get CAPI keys, not CNG keys."

Actually, what I did here was to create one of each.

I never could get the 2008 version to work, so for the sake of this walkthrough, assume we are using the Legacy STS template, regardless of what you see in the screen capture. ;-)

Creating the 2008 Template: Secure Token Service


Pick a good name for the template, "Secure Token Server". It's definitely okay to publish this in AD.


Indicate that keys should be exportable, because we'll need this later.


Set 2048 bit key to meet ADFS minimum requirement. I have complained before that SHA-1 is a weak hash that should be destroyed. SHA-256 is expensive, but for my demo I don't really care.

Warning: DO NOT USE SHA-512!

From Microsoft: "AD FS 2.0 does not support the use of certificates with other hash methods, such as MD5 (the default hash algorithm that is used with the Makecert.exe command-line tool). As a security best practice, we recommend that you use SHA-256 (which is set by default) for all signatures."


Creating the 2003 Template: Legacy STS



Set 2048 bit key to meet ADFS minimum requirement. Notice there is no Cryptography tab and that you have no opportunity to select the hash algorithm.


The other tabs can be left as their default options.

Making the Template Available for Requests
Okay, now back in Certification Authority MMC:


Right-click Certificate Templates, once again. This time, click New > Certificate Template to Issue.


Choose the template(s) we just created.

If you have multiple CAs in your domain, you should do this for each one that you want to be able to issue this type of certificate.

And that's it. Now, you can request a certificate from your server that will meet the fickle needs of ADFS.

Step 4: Install SQL Server on MasterControl
The next step is to install SQL Server 2008 R2 with Reporting and Analysis (no PowerPivot... yet... maybe someday).


I wasn't sure if the ADFS installed a version of SQL Express that would mess with the SQL install, so I did the needful. The SKUUPGRADE=1 command line switch ensures the installer will not fail if it finds a conflict between existing and installing SQL versions. (Turns out it was totally unnecessary. Oh well.)

I got the usual expected warnings:

  • "Boo hoo! Installing SQL on a domain controller isn't recommended.", and
  • "Hey dipstick, don't forget to configure Windows Firewall so people can connect to your databases!"

Next, I picked the components that I thought we might need.

I created 3 new accounts in the OU I created earlier for service accounts:

  • DEMO\sql-servics
  • DEMO\sqlreports-service
  • DEMO\sqlanalysis-service

Next I chose Windows Authentication only, added my admin account, and provided credentials for the service accounts. Finally, I choose to "install but do not configure" Report Server. I want to save this for when I prepare the same machine as a BI demo server on some future date.

Click Next, Next, Next, and watch the blue bars grow!

As a preliminary step, I made some aliases and host records in DNS, in preparation for using this SQL Server with Kerberos and SharePoint. SPDB resolves to the name of the SQL server, in case we need to move the SQL databases later on. (But, because it's a CNAME, we should use SetSPN against the actual A record for the server itself. See more Kerberos stuff farther down in this article for details.)


I tested my DNS host names and CNAMEs to be sure they work.

We have to run these two commands to register Service Principal Names the SQL Server NetBIOS and FQDN names:

setspn -A MSSQLSvc/mastercontrol:1433 DEMO\sql-service
setspn -A MSSQLSvc/ DEMO\sql-service


And don't forget to visit AD afterwards and enable the DEMO\sql-service (SQL Server service account) for delegation. The DEMO\MASTERCONTROL$ (computer account) already has this right, because it's a domain controller but would need it to be set if you installed SQL on a separate server.

Step 5: Install OS on SmartyPants
Having completed the basic installation for our domain controller and database server, we can move on to our web server. This machine will run SharePoint 2010 and an ADFS Proxy.

It's a good thing I did this while I was waiting for other stuff to finish before, or I'd be taking a nap now. Steps are essentially identical to Step 1 above. Windows Server 2008 R2 Standard Edition is fine here too. Do your network configuration, machine renaming, and join the server to the DEMO domain.

And, for the love of God, Montresor! Change the time zone on your servers, before it's too late!

Step 6: Install ADFS 2.0 Proxy on SmartyPants
Same comatose installer, except this time we tell it we're installing a proxy instead of a server.

Unlike the domain controller, that had a certificate, No SSL certificate has been set up on the SharePoint box. We need to do that now in the usual way, by requesting a certificate from the Domain CA in IIS.



Here your Common Name needs to be the DNS name you will use for the web site. Fill in all the other information as required. (Note: the *correct* value for State is the full name, not the postal abbreviation.)

Little Known Fact(s): There's actually a "Johnson Cave" in the vicinity of Knoxville, TN
ASHPD = Aperture Science Handheld Portal Device



I had a little trouble getting the certificate issued, because my DC's CA wasn't set up to let the admin from the sub-domain request certificates. But, a quick jump over to the CA and I was able to issue the certificate manually and export it to a shared folder where I could use "Complete Certificate Request" (right click on the screen above) to bring it into IIS.

Set the bindings for Default Web Site in IIS to use the new certificate for SSL transactions on port 443.

Now, start the ADFS admin tool and the configuration wizard should begin automatically.


Remember, the ADFS 2.0 Management console is located in Start Menu > Administration Tools.


Here, enter the DNS name for the ADFS Server created earlier.


At this point, ADFS wants an account to establish a trust relationship. If you make sure that DEMO\adfs-service has admin on MasterControl, then you can use it here. If not, you'll have to fall back on the DEMO\Administrator account instead. :-(


I went into Services and changed the account for the ADFS proxy to run as DEMO/adfs.service instead of NETWORK SERVICE. This is just my preference.


After finishing the wizard, we still need to go into DNS configuration on the domain controller and create a DNS record for "login.aperturelabs.local"


Make sure you update Network adapter properties and set the DNS server for SMARTYPANTS to point to the IP for MASTERCONTROL. Do a couple ping tests to be sure that it works.

Okay. So far, so good.

A Special Note from Captain Hindsight: As I started using the ADFS proxy, I noticed some event messages in my Audit logs telling me that the firewall was blocking connections to the ADFS service. You can head this problem off at the pass by following a similar procedure to allow connections to ADFS service the way I describe for the SQL Service on the other box. You can read about this in detail under Pre-Requisites for Configuring SharePoint a few sections down form here.

Now, keep in mind that if you run SharePoint on SSL, you're going to need another IP address on SMARTYPANTS besides the one you already configured, and another SSL certificate to boot! But, we're going to kick that down the road a ways and figure it out later, when we really need it.


Note that now IIS has the /adfs and /adfs/ls virtual directories that we should expect.

One benefit to using proxies is that we can put custom branding on each separate proxy, even when we are using a single AD/ADFS server as our identity claims provider.

Step 7: Install SharePoint Server 2010 on SmartyPants

This screen should be familiar to everybody, right?


Install Pre-requisites. Even though we've installed every Windows Update and started with Service Pack 1, there are still components missing. Later on, we'll update WIF to the newer version.


Later on, I'll need to verify later that we have the latest and greatest WIF on here.

Run the SP2010 installer. Have your product key ready at this point.


Since we put SQL Server on MASTERCONTROL, we're technically doing a Farm install. I don't know about you, but I don't think I've ever actually hit that top button on this screen.


Once again, we need to specify that we are *not* using SQL Express in this scenario.


Beyond these steps, the actual installer itself is also quite boring. Tell you what – let me go get myself a cup of coffee while this thing runs.


Before we run the configuration wizard, we're going to install Service Pack 1 and the latest CU for SharePoint. So, we don't want to run the Configuration Wizard yet.

There was an update in June that came out right on the heels of SP1, and there may have been other ones since then. In any case the June CU had a bit of a rocky start and you may need to download a refresh. According to Microsoft, "If you installed a version of the June 2011 cumulative update that you downloaded prior to June 30, 2011, you need to download and install the update refresh from the download center."

The SharePoint Update Center reports the following as of this writing in early August 2011:

  • Latest Service Pack: SP1 (KB 2510690 and KB 2510766)
    • SP Foundation SP1 direct download
    • SP Server SP1 direct download
  • Latest Cumulative Update: June CU Refresh (KB 2553023)
    • SP Foundation CU direct download
    • SP Server CU direct download
  • Latest Public Update: July PU (KB 2582185) download from Windows Update(?)
    On the day I was setting this up, the hotfix request system was temporarily down. Fun!


So, a few hours later, I actually had all the files I needed.

There's one thing I see a lot of newbies mess up (and even some people with experience forget this occasionally), so I will underline it in flashing red double-bold typeface: you need to install the update(s) for SharePoint Foundation as well as the ones for SharePoint Server. There, now that I've gotten that out of system, I can continue.

Step 8: Pre-requisites for Configuring SharePoint
We need to make sure we meet some prerequisites in order for SharePoint to connect to SQL Server. Otherwise, you're going to get stuck at the database screen of the PSCONFIG wizard, shown below.


Correct DNS naming, permissions, and open ports are all needed for this to work correctly. (I can't tell you how often a SharePoint install has gone over its time budget because I found out too late that the network admins had everything tightly locked down.)

DNS Guidelines for SQL Server
Here are some tips on how to go about providing a name for the SQL server.

  • Earlier, when I installed SQL Server, I created an alias called SPDB. This was so we can redirect it later if needed - for example, if we want to create a third VM dedicated to SQL Server.
  • The SPNs for such DNS based pseudo-aliases should point to A (host) records, not CNAMEs. If you use a CNAME to define your pseudo-alias for SQL, set your SPN to the A (host) record. (See my notes about Kerberos below.)
  • In this case, since I'm not changing SQL port numbers, I can create this alias in DNS alone. If you use custom ports, you'll need to create a *real* SQL alias using the SQL Server Configuration Manager. To do so requires installing the SQL client connectivity tools on the SharePoint machine

 Creating Service Accounts in AD
I created more accounts in AD:

  • DEMO\spdba
  • DEMO\spservice
  • DEMO\spadmin

DEMO\spdba is my SharePoint database access account that I'll use when I run PSCONFIG. I'll use the other accounts later on for the default services and farm admin accounts.

Granting Correct Security Roles in SQL Server
For the install wizard to run, I need to give the database access account both dbcreator and dbsecurityadmin role based permissions in SQL Server. To add a login and grant the correct permissions, open SQL Management Studio on MASTERCONTROL, then connect to the server and expand Security > Logins.




Opening SQL Ports on the Firewall
We also need to make a rule in Windows Firewall on MASTERCONTROL to let our SQL traffic go from SharePoint to SQL Server. You'll recall that earlier we got a warning about this. Do this under Control Panel > Windows Firewall > Advanced Settings (look in the links on the left hand side).

We need to add a rule under Inbound Rules to let SQL traffic into the machine.



Choose All Programs and hit the Customize button next to Services.


Find the MSSQLSERVER service. Optionally, you can repeat this process to make rules for other SQL services you want open.


This is just a demo, so keep it simple, stupid.


Hit Add button for the second pick-list to add a range.


Limiting access to the local subnet reduces our exposure while requiring fewer configuration changes later on.


Allow all traffic to open this service completely. Since we're making this rule to allow just the local network acess, that should be secure enough.


Limiting access to the domain network should suffice.


Give your rule a name and explanation.

Ports may also need to be opened in your hardware firewall as well. The way I set up the Windows Firewall here will work regardless of the server's port settings.

Step 9: Configure SharePoint
Run the PSConfig.exe configuration wizard from Start > SharePoint 2010 Products and Technologies > SharePoint 2010 Configuration Wizard.



This is the essential screen I talked about earlier. The server name, firewalls, user account, and permissions have to be right in order to get past this point.


Don't forget to store your farm passphrase someplace safe, like in KeePass or an unencrypted text file on the root of C drive. ;-)


I want Kerberos to work, so I chose Negotiate and configured a custom port number (53281) instead of a random one. A fixed port makes it easier to assign an SPN to the Central Administration web site. However, before I do, I need to confirm that I know the account that'll be used as its application pool.

Little known fact: 53280 and 53281 are the addresses for the screen background and border colors on the Commodore 64 home computer. I use these because since early childhood I've had thousands of these now useless trivialities memorized, so I prefer to put them to work when assigning ports.


Continuing, you'll get the "well, duh" warning at this point. Umm, yeah. Pretty sure I just said basically the same thing a couple paragaphs ago. :-) I know we are doing things the hard way, as I'll explain later.



And it's time to refill my coffee!

Oh yeah, one other thing. You have to do an IISRESET at this point too. Although in a moment you'll see why we'll have to do a lot more than that. ;-)

Step 9(a): Configuring and Testing Kerberos
This is where you hit the roof, since you just locked yourself out of Central Admin. ;-) When the SharePoint configuration wizard finishes, it will report success. However, when it takes you to the Central Administration web site, you'll try to log in 3 times, and it'll fail into a blank browser page. This is because Kerberos is not properly set up for the Central Administration web site.

If you are desperate, one quick workaround that is *very* temporary, and also not a very good idea, is to turn on Kernel Mode Authentication in IIS for the Central Admin site. It'll get you into the site, and earn you a lecture from Spencer Harbar. ;-)

Another thing you can do is use powershell to turn off Negotiate/Kerberos and revert to NTLM. (At the time of this writing, I looked for such a script, and couldn't find one.) By the way, I also like the suggestion that some people have made, to set up Central Administration for the first time in NTLM mode, and then extend the web application into a new site that uses Kerberos. That way, you always have the NTLM version to fall back on if Kerberos fails, and you can use the extended application to configure Central Admin as a load balanced site. As cool as that is, it's totally uneccessary for this demo, so I'm saving it for some other time.

Configure the SPN for Central Admin
A better idea (at least in the long run) is to get Kerberos working, starting by doing the SPN set up.


Let's go into IIS and figure out the application pool account.


Go to Advanced Settings for the Central Administration web site, then look for Identity property.

So we have our answer there; it's the same account we put into the configuration wizard a few minutes ago for SharePoint database access.

I ran these commands to make an SPN for the CA web site:
setspn -A HTTP/smartypants:53281 DEMO\spdba
setspn -A HTTP/ DEMO\spdba
setspn -A HTTP/smartypants DEMO\spdba
setspn -A HTTP/ DEMO\spdba

The first time I did this, I only used the first two commands, and it didn't work the way I'd intended. What followed was an exercise in frustration that shouldn't surprise anyone who's ever configured Kerberos before – or tried. After installing KerbTray and WireShark on both servers, several reboots, and hours of lost productivity later, I finally got enough information out the system to tell me why I was unable to login to Central Admin. Ultimately, though I tried several things, I couldn't log in until I added the last two lines (underlined above), which correspond to port 80. Pretty weird, I must admit. (I should do some research to figure out why that might be.)


Once you finally do get into Central Admin, don't forget to add an AAM for the FQDN. :-)

In a little while, I'll have to configure more of these SPNs for the SharePoint web sites, but I haven't created those application pool acounts yet – all in good time.

Other Stuff I Tried That Helped - Maybe
As an additional step during my troubleshooting process, I changed the following as described on MSDN Blogs, in C:\Windows\System32\inetsrv\config\applicationHost.config under the system.webServices > security section:

<windowsAuthentication enabled="true" useAppPoolCredentials="true">
<add value="Negotiate" />
<add value="NTLM" />

Is it really necessary? I'm not sure, since by itself it didn't fix the problem I was trying to troubleshoot.

Note that in the above case, the command described in the MSDN blog article failed:

C:>c:\windows\system32\inetsrv\Appcmd set config "SharePoint Central Administration v4" /section:windowsauthentication /useAppPoolCredentials:true /commit:MACHINE
ERROR ( message:Configuration error
Filename: \\?\C:\inetpub\wwwroot\wss\VirtualDirectories\12592\web.config
Line Number: 0
Description: The configuration section 'system.webServer/security/authentication/windowsAuthentication' cannot be read because it is missing a section declaration. )

I also added reverse DNS entries for both machines. Maybe it helped, maybe not. But, certainly this is something you should do.

Also, if I haven't mentioned it yet (I'm pretty sure I did), make sure all your servers are set to the same time zone and have their time set correctly. Microsoft-centric Windows installs to Pacific Time, so if the rest of your domain is running in EST that won't help. Time synchronization issues are a common cause of Kerberos failures.

Don't forget to visit AD and trust the DEMO\spdba and DEMO\$SMARTYPANTS accounts for delegation like before. I'll note here that Spence says this isn't needed, and he's probably right. Frankly, I had enough trouble getting Kerberos working to begin with. This is just a demo environment! (Later, I plan to experiment with this and update this article accordingly.)

Another Side Note about Kerberos
Many folks - who are much more experienced than I am on this topic - report that use of CNAMEs causes problems with Kerberos. They might very well be right. However, I haven't had any issues come up yet. If I learn different, I'll let you know.

My rule of thumb is to assume that Kerberos (or maybe it's Internet Explorer) will resolve a CNAME and replace it with the underlying A record's DNS name *before* completing the process that involves looking up the SPN. So, from Kerberos' point of view, it's like the CNAME doesn't even exist. Thus, if you use a CNAME in DNS, don't use it when defining your SPNs; use the A record that it points to instead.

I've never tried this with IE 6; IE 6 sucks, so if this doesn't work that's honestly just one more reason to stop using it forever.

And, if it isn't obvious, I'm certainly not suggesting that you should point 10 SharePoint sites with host headers to a single A record, because then you'd either end up with 10 sites using one application pool - or duplicate SPNs that just won't work. Use A records for your web sites; my CNAME trick is something I do pretty much just for the SQL Server.

Further Reading for the Truly Masochistic
Getting Kerberos to work is a pretty common problem, and troubleshooting Kerberos is so far outside the scope of this article, it isn't even funny. If you need help, here are some resources I used to fix it.

  • Everything Spencer Harbar Has Ever Written on Kerberos (that man is a SharePoint god!)
  • Troubleshooting Kerberos in a SharePoint environment (Part 1)
  • Troubleshooting Kerberos in a SharePoint environment (Part 2)
  • Troubleshooting Kerberos in a SharePoint environment (Part3)
  • Troubleshooting the Kerberos error KRB_AP_ERR_MODIFIED

Step 10: Setting up SharePoint Services
Now, finally we can get to Central Administration to run the [second] configuration wizard.


Then, click on Launch the Farm Configuration Wizard (It's the only option shown, so IMHO it wasn't worth the screen shot.)


Here I entered the credentials for the "DEMO\spservice" account, and just left all the checkboxes in their default state.


<Yawn /> It's been so much time wasted in fixing Kerberos, that now it's dark outside - time to grab a cold beer and soldier on into the night.


Success! But I bet that User Profile Synchronization Service probably *still* won't work ;-)

We've had a long day installing a whole bunch of software and dealing with the little issues that came up along the way. But, we've got all the ground work laid out for the good stuff to follow! Tomorrow, I'll go into detail on how to provision the SharePoint web application(s) needed for the demo to work.

Real World Claims Part 4: Configuring ADFS and SharePoint STS

This post is part 4 of a series, and is a companion to my presentation titled Real World Claims in ADFS and SharePoint 2010. This presentation will be given Saturday, April 13th, 12 noon at SharePoint Saturday, The Conference, Washington, DC April 11-13, 2011. Table of contents, additional links, slides, video recording, and other funny liner notes will be posted in Part 1 as they become available.


In the last chapter, we set up the SharePoint web application to accommodate our ADFS deployment. We created three sites, one original and two extended, provide an anonymous access via HTTP, a secure HTTPS access for logged in users, and a safety net site that we can use internally for services that don't support claims login – or in the [oh-so-unlikely] event that ADFS malfunctions at some point.

Now, we need to do some substantial configuration to get ADFS working with SharePoint. SharePoint actually ships with its own Secure Token Service. If you've set things up like we have and configured your web applications to use claims authentication (as opposed to classic mode), then you're already using the SharePoint STS. What we need to do now is to configure SharePoint to use ADFS as a Trusted Identity Provider – and conversely set up ADSFS to allow our SharePoint web sites as a Relying Parties.

For the short run, we'll just configure ADFS to use Active Directory. Later, I'll add additional identity providers to ADFS to allow users to log in with accounts that come from other sources.

Allow me a final word about the architecture we're using here. Strictly speaking it is not really necessary to use ADFS in this way; you could set up your own custom STS web site(s) and tie directly into the SharePoint STS. You can write your own custom claim provider in SharePoint that ties directly into its STS, and if you want a custom user picker you'll actually need to. But doing these things requires lots of code and lots of PowerShell. Putting ADFS in the position of being the claims broker for SharePoint can greatly simplify your overall configuration, improve reliability, and provide a path for load balancing and enhanced performance. This choice is a topic I plan to cover in more detail during my presentation.

Generate Certificates for ADFS Token Signing

Let's get started. The ADFS server installs with its own self-signed certificate. You can view these from the ADFS Management Console.



Viewing this certificate, you can clearly see that there is something wrong with it. The problem is that it's self-signed. We could add the certificate to Trusted Root Certificates store like they suggest in the warning, but we want to try to learn to do this the right way. So, let's create a certificate that has the correct chain of authority for our domain.

On the ADFS computer (DEMO\MasterControl), click on Start > Run and type "mmc". This will bring up the management console.


In the management console, go to File > Add/Remove Snap In.


Click Certificates, then the Add button. A pop-up will appear.


Pick "Computer account" to show the machine certificate store.


...for this computer, not another one. :-/


It'll look like this, so hit OK.

This brings us into the computer's certificate store. Leave this open as we'll get a lot of use out of this as we continue. Assuming all went well, we'll request a certificate to use for ADFS encryption and signing next.


A successfully created certificate manager snap-in will look like this.


Let's do a File > Save As and store this MSC file someplace so we don't have to do all these steps again the next time we need it.


Request a certificate by expanding Personal > Certificates, then right-click and choose All Tasks > Request New Certificate.


Request templates come from Active Directory. Sometimes an external partner may give you a URL that you can use to add additional Certificate Enrollment Policy servers to this list manually.


Check the box for "Legacy STS" then click the link to provide the additional information. (Yes, the screen shot is wrong. See the section in Part 2 on setting up the certificate template to find out why.)

A Note from Captain Hindsight: When I tried this, I found first that it took a while for my certificate template to replicate into my DEMO domain - I had some health issues in both domain replication and the enterprise CA, and secondly that the rights I had given for the template weren't enough to request the certificate in this way. In this walkthrough, I've gone back in time and retroactively corrected my instructions.


Provide just the information that follows. I have seen that providing too much information may cause ADFS to reject the certificate later.

O=Colossus Consulting LLC
OU=Liquid Mercury Solutions
Alternative name – DNS:
The last item is optional. I wanted to try an experiment using SANs (Subject Alternative Names). (Again, the screenshots are wrong; I reversed SAN and CN and used a different DNS in my SAN.)


It should look like this when you're done. (Again, SAN and CN reversed.)


Verify we meet the requirements for what we're trying to do. 2048 bits and exportable keys.


Captain Hindsight: Now would be a good time to add permissions to the DEMO\adfs.service account too! More on this step later.


Note that each box you check here will ultimately have to be added to a list of trusted authorities we'll provide to the SharePoint STS.


Provide everything it wants and the link should disappear. (Again, we're using "Legacy STS" template not "Secure Token Server".)


Click Enroll to send the request to the CA. Assuming you have permission to enroll on the CA, this should succeed. If not, you can manually Issue the certificate at using the CA's MMC snap-in.

Changing the Certificates Used by ADFS Server

So, let's take the new certificate we created and set up ADFS to work with it instead.


Here's a little PowerShell script that we use to do just that.

Add-PSSnapIn Microsoft.Adfs.PowerShell
Set-ADFSProperties -AutoCertificateRollover $tf

Note: to get scripts to run, I had to do this:

Set-ExecutionPolicy Unrestricted
c:\TEMP\ADFSSetEditCerts $false

But there are certainly more secure ways to get your scripts to work, like actually signing them. When you're done, you can run the same script with $true to restore the lock. It will throw an error, but you can safely ignore it. Here's the screenshot:


Going back to the ADFS console, when you click Add Token Signing Certificate and Add Token Decription Certificate, you'll be prompted with a menu like this one.


Choose your desired certificate and click OK.

For both new certificate entries, right-click and choose "Set as Primary".


You might be given a warning like this one. We haven't created any Relying Party trusts yet though, so don't worry about it.

You'll be greeted with this reminder.



This is a really important step, and if DEMO\adfs-service can't access the private keys, you'll get error 133 in the event logs. This particular event happens for lots of reasons, so troubleshooting it is a pain. Best not to omit this step, as its one more thing you'll have to troubleshoot later. Assuming you didn't add these rights when you created the certificate in the first place, let's take care of this now before we forget. Back to Certificate Manager!



Give Read access to both NETWORK SERVICE and DEMO\adfs-service accounts.

Test your changes by restarting the ADFS service after you've added new certificates, to make sure they are compatible before your move forward.

After you successfully restart the ADFS service without any 133 events, you can safely delete the two self-signed certificates that ADFS included when it installed.


When you've finished, it should look like this. And, we got no warnings about the key strength of the certificates we chose.


You can view the certificate and see there are no warnings or errors.

Configure ADFS Relying Party Trust

With the correct certificate in place, we can configure ADFS to trust SharePoint as a Relying Party. This means that SharePoint will consume claims from ADFS – in other words, rely on it.

We do this in the ADFS Management Console on MASTERCONTROL.


Above are a couple places you can click to get started.


Step 1: Enter the RP information manually. SharePoint does not provide a FederationMetadata.xml file. However, you could choose to create and maintain such a file yourself - and publish it in a document library or by some other means.


Step 2: Just a description that will help you remember what this RP is for will be fine.


Step 3: Choose the ADFS 2.0 profile.


Step 4: We're not setting up token signing and encryption at this time, but we can [and should] revisit this later.


Step 5: The URL for the passive endpoint in SharePoint takes a standard format.


Step 6: It's okay to leave the default identifier in place, but later we'll configure a custom realm identifier in SharePoint. We add it here in anticipation of doing this soon.


Step 7: In secure environments, you start by denying access to all then open it to some. I just want my demo to work; save security for another day.


Step 8: Confirm your settings.


Step 9: The last screen will take you directly into the Rules manager.


We'll need to create one rule for AD, and three rules to support other claim providers.


"Send LDAP Attributes as Claims" is used to pass through Active Directory claims.


We need 3 attributes from AD: E-mail Addresses, Token Groups, and User Principal Name. I used the qualified token groups, because I want to be able to make a distinction between different domains on my network. UPN also makes a distinction between domains, so if you want to merge sub-domains under a single identity you could do that with a rule or by using unqualified account name instead.


One down, three to go.


We need to pass through three claims. Each one must be done with a separate rule.


Passing through e-mail address is fairly straightforward.


Now, we do the same for Role.


And finally, UPN.


Some of my providers actually pass through even more claims than this. For the sake of the demo, I'll keep this simple for now. We can always add more later on if we want to.


And you now see our completed RP configuration.

Exporting the ADFS Certificates to SharePoint Server

Now, we need to tell SharePoint to trust the certificate that we're using in ADFS. Additionally, SharePoint will need to trust every certificate in its chain of authority, so any subordinate CA or root CA in the chain will need to be added as well. We can easily get to the certificate chain from the ADFS console.


View the certificate to see its chain of authority.


Starting with the certificate itself, under Details, you can Copy to File in order to export the certificate.


Note that you *do not must be exportable)* need to put the private key on SharePoint. This is an important aspect to federated security. While your ADFS server needs access to its own private keys (they must be exportable), you should not need to give your private key to any federating partner – even one inside your own organization.


Note: for SharePoint to encrypt tokens, it will need its own certificate with a private key. To show that we don't need (or want) to share private keys, we'll issue a separate certificate for the SharePoint server, and then bring the public key back to ADFS and configure it. This will be done a little later.


Any format that can be read by SharePoint and PowerShell should be fine.


Save the file to a location we can access from SMARTYPANTS.


Once we've exported the certificate, we can use the Certification Path to view each certificate in the chain of authority. For each one, export it in the same way as was just done above.


For the certificate authority's certificate, obviously we give it a different file name.


So, you can see now we have all the certificates we'll need to use in SharePoint STS.

Configure the Trusted Identity Provider in SharePoint

Now that we have these certs on the SharePoint server, we need to tell SharePoint to trust them. We can do this from the SharePoint 2010 Management Shell.

if ($args) {"'$args is $args"}
"Configuring SharePoint Root Certificate Authority ..."
$root = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("$certFilePath")
if ($root) {
    New-SPTrustedRootAuthority -Name "$name" -Certificate $root

File C:\TEMP\AddSPTrustedRootAuth.ps1

Table: parameters for AddSPTrustedRootAuth.ps1

We can call the file with a script like this one:

Set-ExecutionPolicy Unrestricted # Have to do this again, because we're on a different server.
.\AddSPTrustedRootAuth "C:\Temp\ADFS Keys\ADFS-Encryption.cer" "ADFS ("
.\AddSPTrustedRootAuth "C:\Temp\ADFS Keys\CA.cer" "Root CA ("

Of course, don't forget to lock down your execution policy later.

The output should look something like this:

PS C:\Users\Administrator.DEMO> Set-ExecutionPolicy Unrestricted # have to do th
is again, because we're on a different server

Execution Policy Change
The execution policy helps protect you from scripts that you do not trust.
Changing the execution policy might expose you to the security risks described
in the about_Execution_Policies help topic. Do you want to change the execution
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"): y
PS C:\Users\Administrator.DEMO> CD c:\TEMP
PS C:\TEMP> .\AddSPTrustedRootAuth "C:\Temp\ADFS Keys\ADFS-Encryption.cer" "ADFS
Configuring SharePoint Root Certificate Authority ...

Certificate : [Subject], OU=Liquid
Mercury Solutions, O=Colossus Consulting LLC, L=B
altimore, S=Maryland, C=US

CN=colossusconsulting-WHOPPER-CA, DC=colossusco
nsulting, DC=com

[Serial Number]

[Not Before]
8/10/2011 8:17:15 PM

[Not After]
8/9/2013 8:17:15 PM


Name : ADFS (
TypeName : Microsoft.SharePoint.Administration.SPTrustedRoot
DisplayName : ADFS (
Id : 9ab83a92-31d5-427d-bda2-b6aae4177fd9
Status : Online
Parent : SPTrustedRootAuthorityManager
Version : 15816
Properties : {}
Farm : SPFarm Name=SharePoint_Config
UpgradedPersistedProperties : {}


PS C:\TEMP> .\AddSPTrustedRootAuth "C:\Temp\ADFS Keys\CA.cer" "Root CA (whopper."
Configuring SharePoint Root Certificate Authority ...

Certificate : [Subject]
CN=colossusconsulting-WHOPPER-CA, DC=colossusco
nsulting, DC=com

CN=colossusconsulting-WHOPPER-CA, DC=colossusco
nsulting, DC=com

[Serial Number]

[Not Before]
2/11/2010 3:20:28 PM

[Not After]
2/11/2020 3:30:20 PM


Name : Root CA (
TypeName : Microsoft.SharePoint.Administration.SPTrustedRoot
DisplayName : Root CA (
Id : 048afda4-c072-4f04-995c-a51252e672d8
Status : Online
Parent : SPTrustedRootAuthorityManager
Version : 15818
Properties : {}
Farm : SPFarm Name=SharePoint_Config
UpgradedPersistedProperties : {}



Now, we need to tell SharePoint to use ADFS as its IdP-STS (Identity Provider Secure Token Service).


if ($args) {"'$args is $args"}

"Configuring SharePoint STS as RP for ADFS ..."

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("$certFilePath")

if ($cert) {

$map1 = New-SPClaimTypeMapping "" -IncomingClaimTypeDisplayName "Account ID" –SameAsIncoming

$map2 = New-SPClaimTypeMapping "" -IncomingClaimTypeDisplayName "Role" –SameAsIncoming

$map3 = New-SPClaimTypeMapping "" -IncomingClaimTypeDisplayName "Email Address" –SameAsIncoming

$realm = "urn:sp2010:adfs"

$signinurl = "https://$adfsDns/adfs/ls/"

$ap = New-SPTrustedIdentityTokenIssuer -Name "$name" -Description "$description" -Realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map1, $map2, $map3 -SignInUrl $signinurl -IdentifierClaim $map1.InputClaimType



File: SPConfigureADFS.ps1

Parameter Name
File path to the certificate we exported from ADFS.
DNS name of our ADFS server or an ADFS proxy if we are using one. Note that unless you configure multiple providers, all SharePoint sites will use the same one.
Name of provider. This will appear in SP-STS realm selector as well as prefix in all claims based user names.
A friendly description, in case the name doesn't tell the whole story.
Table: parameters for SPConfigureADFS.ps1

So, we can use a command like this to run the script:

C:\TEMP\SPConfigureADFS "C:\Temp\ADFS Keys\ADFS-Encryption.cer" "login.aperturelabs.local" "Aperture ADFS" "Point to ADFS Proxy server (login.aperturelabs.local) on SmartyPants"

And, get the results:

PS C:\Users\Administrator.DEMO> C:\TEMP\SPConfigureADFS "C:\Temp\ADFS Keys\ADFS-
Encryption.cer" "login.aperturelabs.local" "Aperture ADFS" "Point to ADFS Proxy
server (login.aperturelabs.local) on SmartyPants"
Configuring SharePoint STS as RP for ADFS ...
PS C:\Users\Administrator.DEMO> Get-SPSecurityTokenServiceConfig

SecurityTokenServicePublicUrlSuffix : /_vti_bin/spsecuritytokenservicea
SecurityTokenServiceMetadataPublicUrlSuffix : /_vti_bin/spsecuritytokenservicea
LocalLoginProvider : Microsoft.SharePoint.Administrati
TrustedLoginProviderNames : {Aperture ADFS}
TrustedLoginProviders : {Aperture ADFS}
TrustedAccessProviders : {}
UseSessionCookies : False
WindowsTokenLifetime : 10:00:00
FormsTokenLifetime : 10:00:00
ServiceTokenLifetime : 10:00:00
MaxLogonTokenCacheItems : 250
MaxLogonTokenOptimisticCacheItems : 100000
LogonTokenCacheExpirationWindow : 00:10:00
MaxServiceTokenCacheItems : 250
MaxServiceTokenOptimisticCacheItems : 100000
ServiceTokenCacheExpirationWindow : 00:10:00
Name : SecurityTokenServiceManager
TypeName : Microsoft.SharePoint.Administrati
DisplayName : SecurityTokenServiceManager
Id : d720f68c-e45c-4aae-bfe0-e11304fd4
Status : Online
Parent : SPSecurityTokenService Name=Secur
Version : 15907
Properties : {}
Farm : SPFarm Name=SharePoint_Config
UpgradedPersistedProperties : {}


PS C:\Users\Administrator.DEMO> Get-SPTrustedIdentityTokenIssuer

ProviderUri : https://login.aperturelabs.local/adfs/ls/
DefaultProviderRealm : urn:sp2010:adfs
ProviderRealms : {}
ClaimTypes : {
/06/identity/claims/role, http://schemas.xmlsoap
HasClaimTypeInformation : True
ClaimTypeInformation : {Account ID, Role, Email Address}
IdentityClaimTypeInformation : Microsoft.SharePoint.Administration.Claims.SPTru
ClaimProviderName :
UseWReplyParameter : False
UseWHomeRealmParameter : False
Description : Point to ADFS Proxy server (login.aperturelabs.l
ocal) on SmartyPants
SigningCertificate : [Subject], OU=Liquid
Mercury Solutions, O=Colossus Consulting LLC, L
=Baltimore, S=Maryland, C=US

CN=colossusconsulting-WHOPPER-CA, DC=colossusc
onsulting, DC=com

[Serial Number]

[Not Before]
8/10/2011 8:17:15 PM

[Not After]
8/9/2013 8:17:15 PM


Name : Aperture ADFS
TypeName : Microsoft.SharePoint.Administration.Claims.SPTru
DisplayName : Aperture ADFS
Id : c5b9ce06-7358-4c13-8d25-4c614f11a709
Status : Online
Parent : SPSecurityTokenServiceManager Name=SecurityToken
Version : 15901
Properties : {}
Farm : SPFarm Name=SharePoint_Config
UpgradedPersistedProperties : {}


PS C:\Users\Administrator.DEMO>


You might realize by this point that we can configure multiple Trusted Identity Token Issuers for multiple SharePoint web applications. If so, your insight would be correct, which would allow us to host several differently branded proxy servers for a variety of customers on the same farm. In reality though, this will probably not happen for very many folks. It is a really neat idea though.

We're almost done configuring SharePoint, but still missing something. Recall that back when we configured the Relying Party in ADFS, we added a couple of realm identifiers. Why did we do this exactly? The answer is simple. Say we want to use the same Trusted Identity Token Issuer for multiple web sites that have different URLs. Say for example that later we want to add https://aperturelabs.local as a synonym for https://www.aperturelabs.local, or possibly we want to make a secure site for employees like https://intranet.aperturelabs.local. Adding ProviderRealms in addition to the default realm is how we can accomplish this without sending ADFS into fits of confusion.

We can add one with a PowerShell Script like this:

$t = Get-SPTrustedIdentityTokenIssuer "Aperture ADFS"

$uri = New-Object System.Uri("https://www.aperturelabs.local/")

$t.ProviderRealms.Add($uri, "urn:sp2010:adfs:www-aperture")


Code Example: Script to add an item to ProviderRealms collection of a Trusted Identity Token Issuer

Configuring the SharePoint Web Applications to Use the Trusted Provider

Now, we should be able to configure the web applications to accept claims from ADFS.

Go to Central Administration > Application Management > Manage Web Applications.



Click the web application, then hit Authentication Providers in the Ribbon.


Click each of the three links in turn, and do the following for each Zone.


Enable the "Aperture ADFS" provider by checking the boxes, then hit Save.

It's All Downhill from Here!

So, we've done all the configuration for both ADFS and SharePoint. It's time to test things to see if they work.

Honestly, even though I have done maybe more than a dozen of these configurations before, this did not go well for me this time. Chalk it up to burning the midnight oil I guess. Several screwdrivers later, I was eventually able to get to the answer – and even finished before the sun came up. I'm assuming you value your sleep though, so I'm going ot share a little of the pain with you in the hopes that you'll have an easier time of it.

Testing the ADFS Proxy Login Page

Browsing to https://www.apertuelabs.local will give you SharePoint's realm selector prompt.


Well, at this point SharePoint did redirect me to the ADFS proxy URL. But, instead of getting the expected, I got a 404 Not Found. Turned out the Default Web Site hadn't been started. Started it and I get a different error instead. This time, the kind of error that is really annoying because it's under a locked filing cabinet in a disused bathroom at the bottom of the [collapsed] basement stairs! (The "Beware the Leopard" sign had apparently been stolen by someone who came before me.)


"Never you mind!" I says. "I knows me lotsa tricks fo' working an' lurking around thee ol' Aye Dee Eff Ess, I does! We'll sort this bugger out, we will!"

So I jump into the web.config in C:\inetpub\adfs\ls and make some changes. Uncomment a couple lines and make a little cosmetic modification while I'm there.

<add key="displayExceptions" />

<add key="logo" value="aperture_logo.png" />

Excerpt from file C:\inetpub\adfs\ls\web.config


Well now, that extra information was certainly very helpful, wasn't it? What do you mean, "no"?

This error happens because the ADFS Proxy can't talk to the ADFS Server. Well, that can happen for lots of reasons.

A Night Spent Shaving Yaks on the ADFS Server

Investigation into this error led me to some errors in the ADFS server event logs that were preventing ADFS Server from starting. My certificate s were set up incorrectly. Before I got to the heart of the problem, I went down a rabbit hole for a little while, thinking maybe my issue was insufficient rights for the service account. I was wrong about that, but I'll show you how to check for the permissions anyway.












Eventually, I figured out that my problem was that my certificates were just plain wrong. Specifically, I am talking about the settings for the certificate template. These are what led me to create the Legacy STS template I talked about previously. This was the point where I had to go back in time and do everything right from the beginning, thus leading to my recommendation that – well – that you do everything right from the beginning. :-)


Test #2 of the ADFS Login Page

Well, I finally got all of that sorted out. Looks like I'm not getting any sleep before heading to Virginia for SharePoint Saturday (The Conference). <arm-stretch><yawn /></arm-stretch>


Notice that the URL for the browser and the name as reported by ADFS reflect the fact that we're hitting the ADFS server through the proxy.

Later, I'll change the name of the ADFS Service to be something more cosmetically appealing. Note that this setting will be passed through to every proxy you create, in case this affects you in a multi-tenant situation.


Oh, yes? Is this another one of those really *helpful* error screens? Let me just see if I can find the answer here in Nuclear Reactors for Dummies. <pageflip/><pageflip/><pageflip/><pageflip/><pageflip/><pageflip/><pageflip/><pageflip/><pageflip/><pageflip/> Ahh, the re we go!

Jumping into web.config for SharePoint to expose the error. Refresh. And…


Aaagh! Okay, well maybe that one's my fault. I have kind of made a mess of things.

A little help from Jimmie's Sharings on MSDN Blogs, who had the same problem, and I was able to cobble together a PowerShell to fix myself up. Seems I'd forgotten to update the signing certificate for the trusted identity provider when I replaced the certificate for ADFS after switching templates.

Setting Right for Claims Based Users

Another try, and…


Okay, that's not so bad. It means I just have to add some rights for the claims-based version of DEMO\Administrator. SharePoint treats the ADFS and Windows Authentication versions of the same user as different identities.

But, in order to login as the other account, I have to delete my cookies.


Rights are granted in Site Actions > Site Settings > people and Groups just like for Windows users.


Click the address book icon to bring up the people picker.


This is a multi-step process: 1) Type the UPN for the user you want to add. 2) Click "Account" to show only account claims based on UPN, otherwise you'll see three identical claims. 3) Click the only remaining claim. 4) Click Add button to add it to the list. Optionally, you can add multiple users in the way before you continue. 5) Click OK when done.


Your resolved claims will appear in the list. Sometimes, a claim may be listed here with a red underline. In those cases, click the name to bring up a list of claims to choose that will resolve the ambiguity.

Final Test: 3rd Time is the Charm

Need to delete my cookies again, just to be sure. Let's try the federated login again.


Realm selector: That's getting old. :-|


Credentials entered, and... <drumroll />


All Right!! It works!

Adding Encryption on the SharePoint STS

Encryption and signing of certificate from the SharePoint server is handled entirely in the web.config for the SharePoint application. Let's give it a try, shall we?

Creating a Certificate for SharePoint STS Token Encryption

Start in the Certificate Management Console, as usual.


Choose the Legacy STS template to ensure ADFS won't choke on it.


Provide a subject name. Unlike an SSL certificate, I don't think it really matter what you provide.

O=Aperture Laboratories
OU=AS Enrichment Center

Give it a name and description so you can remember what it's for.

Other tabs should be okay with the default settings.





Setting up the Web Server

Once we have the certificate, we can configure SharePoint to start encrypting tokens. This has to be done for each web.config file on sites that leverage ADFS. So, that's three files in our case. Each config file is located in the root of the web site in IIS, under C:\inetpub\wwwroot\wss\VirtualDirectories.

Find the "microsoft.identityModel" section near the bottom of the file. You need to change the file to add the following extra elements and attributes.


<service saveBootstrapTokens="true">

<audienceUris />

<issuerNameRegistry type="Microsoft.SharePoint.IdentityModel.SPPassiveIssuerNameRegistry, Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />


<clear />

<add type="Microsoft.IdentityModel.Tokens.X509SecurityTokenHandler, Microsoft.IdentityModel, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

<add type="Microsoft.SharePoint.IdentityModel.SPSaml11SecurityTokenHandler, Microsoft.SharePoint.IdentityModel, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c">


<nameClaimType value="" />



<add type="Microsoft.SharePoint.IdentityModel.SPTokenCache, Microsoft.SharePoint.IdentityModel, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

<!-- added: must be added to support encrypted tokens from ADFS -->

<add type="Microsoft.IdentityModel.Tokens.EncryptedSecurityTokenHandler, Microsoft.IdentityModel, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

<!-- END added -->


<!-- added: must be added to support encrypted tokens from ADFS -->


<certificateReference x509FindType="FindBySubjectName" findValue="sts.aperturelabs.local" storeLocation="LocalMachine" storeName="My" />


<!-- END added -->


<wsFederation passiveRedirectEnabled="false" issuer="https://none" realm="https://none" />

<!-- added domain below so that other web sites can share cookies to this one -->

<cookieHandler mode="Custom" domain=".aperturelabs.local" path="/">

<customCookieHandler type="Microsoft.SharePoint.IdentityModel.SPChunkedCookieHandler, Microsoft.SharePoint.IdentityModel, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />





File excerpt: web.config

After making these changes, you need to adjust the settings in your ADFS Relying Party configuration to adjust to the change.

Export a copy of your certificate (without the private key) and place it on the ADFS server.

At this point, you also need to ensure the SharePoint application pool has access to the private key for this certificate. This is done on SMARTYPANTS using the Certificate Management console. Add DEMO\ap-aperture permissions in the usual way. (This was covered in an earlier section.)


I then imported the certificate to the machine store on MASTERCONTROL.

Now we can set the encryption certificate in ADFS Management Console. It turns out, you need the *.CER file to do this, so theoretically you can just skip putting the certificate into the machine store.





This configuration does not include a signature.

A Moment to Review

Now, you'll just have to take my word for it, but after I did all this, it worked great. I had a small error because I hadn't given the application pool the key access rights I described above, but that was easily fixed and everything continued to work fine.

What do we have now, and is it any different than it was yesterday? Well, instead of three separate sites that use Windows Authentication, we now have three separate sites that use can use either ADFS or Windows Authentication. We have the added nuisance of a realm selector page, every time we log in we now have to choose where we want to log in from.

I had assumed that logging in via our public (anonymous HTTP) web site still isn't supported. In past deployments, I have definitely had problems with this where I got the infamous cookie looping problem. Maybe I didn't face this because the DNA names for our two sites are identical. Maybe it worked well because we added the domain attribute to the cookie handler in web.config. I'll never know, because right now I'm not going to test it. There are definitely configurations where it's a problem, and solving that requires code – code that won't be needed today.

But, as it turns out, we also can't effectively log out of SharePoint anymore, or switch users. So, there are still problems with the configuration that need to be addressed. In the next section, we're going to introduce some code to solve these problems, and add some enhancements too.

As it happens, I'm also giving my presentation at SharePoint Saturday tomorrow, so it will probably be a day or two before the next installment in this series hit the web.

See you on the other side!

More Reading
Tags: SharePoint 2010, Configuration

World Claims Part 3: Setting Up the Demo Web Sites

This post is part 3 of a series, and is a companion to my presentation titled Real World Claims in ADFS and SharePoint 2010. This presentation will be given Saturday, April 13th, 12 noon at SharePoint Saturday, The Conference, Washington, DC April 11-13, 2011. Table of contents, additional links, slides, video recording, and other funny liner notes will be posted in Part 1 as they become available.


In the previous installment, I laid the groundwork for a two server demonstration environment. We installed the OS, Active Directory, ADFS, SQL Server, an ADFS Proxy, SharePoint, and even got Kerberos configured. We have almost everything needed to start demonstrating the real power of Claims Based Authentication.

However, our battle station is not yet quite fully operational. We need to configure some sites, and then deploy some custom code, and configure everything before we can pass the BBQ sauce.

Clearing the Way for the Future

Now, I have a personal grudge against the settings used by the wizard, so the first thing I'll do is delete the "SharePoint – 80" web application. I didn't have to. It just felt good.

Setting an Application Pool Account

I want to create a new managed account for the web site's application pool account, DEMO\ap-aperture. This time, I want SharePoint to manage the password for me.

But this blew up in my face. I got an error saying "Access denied. Only machine administrators are allowed to create administration service job definitions of type", which is funny because I was logged into DEMO\Administrator and Domain Admins are included on the SMARTYPANTS\Administrators group. C'est la vie! I add the account explicitly.

But, now I get "Account DEMO\ap-aperture has already been registered" and then the dreaded "Object reference not set to an instance of an object" error when I go to the managed accounts page! My managed account exists, and it's corrupted! We no worries I guess; been there done that. You need PowerShell to back it out.

$a = Get-SPManagedAccount -Identity "DEMO\ap-aperture"

Get back into the web page, and do my thing. And I get the error AGAIN. :-( I add DEMO\spdba and DEMO\spservice to the Administrators group and prepare to try again.

This is why I like creating these accounts in PowerShell to begin with. To heck with the managed accounts web page!

$cred = Get-Credential
New-SPManagedAccount -Credential $cred
$i = Get-SPManagedAccount -Identity "DEMO\ap-aperture"
Set-SPManagedAccount -Identity $i -AutoGeneratePassword

If you run this on a clean farm and domain you'll get the "The password does not meet the password policy requirements…" error. You need to make a new GPO for your service accounts OU in Active Directory to disable the "minimum password age" policy. Do a "gpupdate /force" on the servers to make this change take effect.





On yet another side note, for your managed accounts with automated password change, you need to make sure you leave these two boxes unchecked in Active Directory. If you don't, bad things will happen! Maybe not today, maybe not tomorrow, but soon, and when they do you'll have a hell of a time recovering your corrupted list of managed accounts.

More info at:

The Sean Blog Updating Passwords on SharePoint 2010
Configure Automatic Password Change (SharePoint Foundation 2010)

Planning the Site Configuration

Before we create a new site that will make use of ADFS, we need to make some configuration changes to our environment. Why? Because claims based authentication through any Secure Token Service whether it's SharePoint or ADFS will require SSL to be secure. We already used port 443 for the only IP we had when we set up the ADFS Proxy.

Let's take a step back for a second and think about the architecture we're trying to configure.

I want to demonstrate the purpose of using Claims in the real world. One such purpose is for extranets, where you don't necessarily want to give external users accounts in Active Directory – like that contractor guy, who's probably a spy sent over by Black Mesa to infiltrate your our network! Wait, maybe I'm getting a bit paranoid, but it'd be good at least to not have to manage accounts for all those people who don't even work here. All those "forgotten" passwords – let 'em be someone else's problem. Yeah!!

To accomplish this, I need a web site that will be exposed on the public Internet at the address http://www.aperturelabs.local (Yes, I know this address won't work in the real Internet, silly! It's a demo.) When the user logs into the site, I want them to be directed to the ADFS Proxy which will be hosted as https://login.aperturelabs.local and will act as the front facing web site for the ADFS server Once the user is logged in, they can't stay at the public, unencrypted, site anymore. At this point, I'd like them to be sent to https://www.aperturelabs.local.

Why do we start at an unencrypted public site and then move to a site that uses SSL after logging in? Well, there are two reasons. In this demo, I want to show that a single site can serve double duty as both an extranet site and a public facing web site. There are certainly times when you would not want to do this, and instead you can just build these two sites using completely separate content. The second reason is that claims based authentication is not secure unless the site uses SSL.

Also, I'd like to have a version of the site that doesn't rely on ADFS or SSL at all, so that older technologies (like WebDAV) can still work when needed, and so I can still access the site if everything in ADFS goes pear shaped at some future point. I'll host that one at http://internal.aperturelabs.local, and assume for this demo that the network is locked down to prevent access to it from outside the Aperture Science Enrichment Center.

Now, I understand this is the first time you're hearing any of this. That's because I only thought of it just now. Otherwise, I'd have set things up the right way to begin with. But I think you'll agree it helps to make what we're trying to cook here a bit more clear.

There are some problems with this design, like the fact that ADFS is going to light-your-lemons-on-fire-and-throw-them-back-at-you if you tell it to return the user to a site that's different than the one they left in the first place. That's a limitation of the architecture we had to overcome. But, I'm getting ahead of myself. I'll cover those details when we get to talking about the code.

Table 1: a chart showing what the general configuration of the sites will look like

In the Liquid Mercury Solutions web site, we happen to use a similar configuration. However, the SSL web site uses a noticeably different DNS name;, so it's much more obvious to the user that they've logged into a secure site. Here I'm favoring simplicity, or at least the appearance of it.

Okay. So remember in Part 2 when I said we'd need more IP addresses later? No? Well, too bad. Go to Control Panel > Network > Change Adapter Settings > Local Area Connection > Properties > TCP/IP IPv4 > Properties > Advanced. Here we need to add an additional IP address. For the time being I will use


Our plan also requires that we update DNS. Here is what it should look like now.

Creating Our New Web Applications

Before I begin, it'd be a good idea to create SPNs for this application pool account and DNS name, so Kerberos will work on the new site we're going to create.

setspn -A HTTP/www.aperturelabs.local DEMO\ap-aperture
setspn -A HTTPS/www.aperturelabs.local DEMO\ap-aperture

To create the web application, I go to Central Administration > Manage Web Applications > Ribbon > New. We're going to start by creating the secure site at "www". Why? I don't know exactly, but if I think of a reason I'll put it here… Oh yeah! I remember now; it's because you can't pick anything except the Default zone when you make the first site for a web application, and I want to make the authenticated site the default site.





And so on, and so on…. Ugh…


(From here down, the default values are fine.)


Thank you SharePoint. You broke SnagIt. :-(


Next, I created the site collection at the root of the application. I used the Enterprise Wiki publishing template. This seems like a likely scenario for a company portal. :-)


Of course you have to add this site to Trusted Sites in IE.


Next, I changed the master page from v4.master to nightandday.master. I'd really like to crank out some custom branding for my demo. For now, I'll have to make do with just a couple enhancements. We have a lot we still need to do.

To summarize the above in a copy-pasta friendly format:

  • New IIS Web Site Name: "SharePoint - www.aperturelabs.local (443)"
  • Port: "443"
  • Host Header: "www.aperturelabs.local"
  • Path: This should be auto-generated for you, ending in www.aperturelabs.local443
  • Allow Anonymous: No
  • Use SSL: Yes
  • Enable Windows Authentication: Checked (Yes, we're not going to let users log into this site, but I have a good reason to leave this active that I will share later.)
  • Integrated Windows Auth: Negotiate/Kerberos
  • Trusted Claims Providers: We have none to pick from yet. Return to this later.
  • Sign-in Page: Use the default sign-in page. We'll change this later on.
  • Public URL: "https://www.aperturelabs.local"
  • Zone: Default
    A few tweaks to the UI, and we have ourselves the beginning of a little corporate intranet!

I'll come back later and snazz it up a bit, time permitting.


Okay, obviously, I need to do something about that SSL certificate. We can't be getting a bunch of security warnings in our presentation.

After trying and failing to generate a domain certificate from IIS for the second time, I've decided to add DEMO\Domain Admins to the security settings for the Web Server certificate template on my domain controller for the root domain of the forest. Perhaps I should install a CA on the DEMO domain controller? Time will tell. I can always reissue my certificates if I need to.


The important setting here is that CN must match your web site's DNS name.

Changing the security setting works, and I change the certificate for the site in IIS. I realize too late I typed the wrong CN into the request, and have to remove it from IIS, revoke the erroneous cert, and re-request a correct one. Finally, the security warnings are gone.

I can't say this often enough. Public key infrastructure is the key to getting claims based solutions to work. If you can't figure out how to generate valid certificates, don't understand what a chain of authority is, or just generally are a bit fuzzy on PKI (the infrastructure behind SSL), then you are going to have a heckuva time working with Claims.

Now that I have the core web site set up, I need to do some work to set the other supporting sites up. This is done in Central Admin > Manage Web Applications, except instead of hitting New in the ribbon to create a new web application, we're going to click the link for the www.aperturelabs.local web application (so it's highlighted). Then, click Extend in the ribbon.

The dialog is very similar to the New Web Application dialog, but with fewer options, since many settings must be the same across all the web sites for a single web application.

  • New IIS Web Site Name: "SharePoint - www.aperturelabs.local (Public)"
  • Port: "80"
  • Host Header: "www.aperturelabs.local"
  • Path: This will be auto-generated for you.
  • Allow Anonymous: Yes
  • Use SSL: NoEnable Windows Authentication: Checked (Yes, we're not going to let users log into this site, but I have a good reason to leave this active that I will share later.)
  • Integrated Windows Auth: Negotiate/Kerberos
  • Trusted Claims Providers: We have none to pick from yet. Return to this later.
  • Sign-in Page: Use the default sign-in page. We'll change this later on.
  • Public URL: "http://www.aperturelabs.local"
  • Zone: Internet


And, the same process for the internal-only web site.

  • New IIS Web Site Name: "SharePoint - internal.aperturelabs.local"
  • Port: "80"
  • Host Header: "internal.aperturelabs.local"
  • Path: This will be auto-generated for you.
  • Allow Anonymous: No
  • Use SSL: No
  • Enable Windows Authentication: Checked
  • Integrated Windows Auth: Negotiate/Kerberos
  • Trusted Claims Providers: We have none to pick from yet. Return to this later.
  • Sign-in Page: Use the default sign-in page. We'll change this later on.
  • Public URL: "http://internal.aperturelabs.local"
  • Zone: Intranet

Now go into IIS and edit the bindings for www.aperturelabs.local and Default Web Site as follows:

Table 2: SSL enabled web site bindings


When you're done, it should look like this. You won't need to adjust any bindings for the other sites, because they will use the host headers defined when you created/extended the application.

Browse to each web site to test that it is working properly. You'll note the SSL web site takes you from IIS to instead of https://www.aperturelabs.local. That's okay. It's a normal thing that happens when IIS doesn't have any host headers configured for a web site, and you can ignore it. Just enter the URL into your browser manually.

But, our Public site still challenges us to log in. We need to do something about that.

Go to Web Application Management, click on the web application, and then click Anonymous Policy in the Ribbon. Change the settings for the Internet zone to Deny Write as shown.


You could leave this unrestricted, especially if you want to open up blog comments to the public or something similar. But doing so requires that you consider the security implications of what you're doing. Otherwise, some random Google surfer might inadvertently disable GlaDOS's morality core and enable her deadly neurotoxin emitters - and we can't have that.

Let's enable anonymous access to the public facing site. We can do this within the new web site itself from Site Action > Site Settings > People and Groups. Adding a user policy in CA would make it more difficult for the Site Collection Admins to accidentally revoke the permission, but the globally applied (non-override-able) permissions would be extremely dangerous. (Besides, I tried it in Central Admin, and IUSR wouldn't resolve properly there anyway.)

Here we enter the anonymous access account for IIS by typing IUSR and hitting the Check Names icon.


But, we're not completely done. We still need to go to Site Actions > Site Settings > Site Permissions to fully enable anonymous access. In order to get this button to appear in the ribbon, you actually have to log in to the public web site at http://www.aperturelabs.local. That's because anonymous access wasn't enabled on any of the other extended web sites.


Here I chose, Entire Web Site but you can lock it down more if your needs differ.


Now when I visit http://www.aperturelabs.local, I'm no longer asked for credentials.

For our partner portal, this is exactly what I am hoping for. If we were content to use Active Directory as our sole login option and have our users self-select their access level through the URL they put in the browser, we could leave everything just as it is. So far, we haven't really even started using Claims. What we have done is provision a single SharePoint application, with multiple ways of gaining access to it.

We're innovators - Aperture Science Innovators - and science marches on! We've built the foundation, so to speak, of a bright tomorrow.

And that is *exactly* when I'm gonna configure the rest of this crap – tomorrow.

(This is Thomas Carpe. We're done here!)

Real World Claims Part 1: Prelude to a SharePoint Presentation

This post is the first of a multi-part series, and is a companion to my presentation titled Real World Claims in ADFS and SharePoint 2010. This presentation was given Saturday, April 13th, 12 noon at SharePoint Saturday, The Conference, Washington, DC April 11-13, 2011. Additional links, slides, video recording, and other funny liner notes will be posted here as they become available.


I sit here at my computer on the Saturday only a week before the main event. It's been weeks, maybe even months, since I originally submitted my idea for a presentation at SharePoint Saturday. And while there were many things that prevented me from working on this presentation sooner, including my own nature as a chronic procrastinator, everything I've been doing for pretty much the whole year has been leading up to this moment.

The cursor blinks, expectantly. I imagine that it must be disappointed in me. Is it restless?

Where to begin? Do I start by trying to flush out my slides? Do I review the notes I've been carefully collecting all this time? Sometimes staring at a blank page and figuring out what to write first can be the hardest part.

I fix myself a rum'n'Coke, and I head out to the office. It's raining, drearily, producing an early dusk. Our office is a small earth-sheltered room with about 300 square feet, carved from the back half of our 3 car garage and fondly referred to as "The Bat Cave" by friends of the business. The garage was utterly useless for parking cars, and entirely too useful for collecting large piles of useless stuff. Now, it serves as the nerve center for Liquid Mercury Solutions. There's a large U shaped array of desks, comfortable chairs, monitor arrays connected to nothing. The people who're entirely too accustomed to sitting elbow to elbow – and their laptops – are all gone for the weekend.

I sit down at my desk and fire up Pandora – Daft Reactor Society channel. It plays Mad as Hell by The Vandals, and I turn it up to 11. Howard Beale's screams echo into the empty space around me. Next stop: "The Zone".

(Links to other parts of this series will be posted here as they become available.)