Windows Identity Foundation (WIF) is a hugely important part of the .NET Framework, enabling you to architect and develop relying parties (RP) and security token servers (STS) that use claims based identity models. For all of this goodness, WIF is surprisingly undocumented on MSDN for a release product (at the time of writing at least), and when developing against it, it won’t be long before you come across “ID” exceptions which have little or no explanation.
Having spent many hours of my life trawling through forums trying to understand the issues, I’ve decided to blog a list of every exception I have seen when using WIF to create a relying party ASP.NET website that uses WS-Federation to authenticate with a security token server. This is sometimes called “passive” authentication, where the browser is acting as a thin client “middle man” in the federation process between the RP and the STS.
Note that this blog is not a guide to developing with WIF, WS-Federation or its use with ASP.NET; I’ll assume you already know how the pieces fit together. If you want some good resources on how to get developing with WIF, I suggest you look here:
The following table describes several common Windows Identity Foundation exceptions associated with using WIF to build a relying party using WS-Federation:
| WIF Exception | Error Message | What does that mean? |
| ID1025 | Cannot find a unique certificate that matches the criteria. | The relying party is unable to read the security token which has been encrypted at a message level by the issuing STS. In order for the relying party to decrypt the token, it needs access to the x.509 certificate used to encrypt the token. This certificate is referenced in the relying party’s WIF configuration under the <serviceCertificate> element. This exception is stating that there is an issue identifying a unique certificate that matches the configuration. |
| ID4036 | The key needed to decrypt the encrypted security token could not be resolved from the following security key identifier | This exception follows on from the ID1025 exception above. We are still trying to decrypt an encrypted security token using the information contained in the <serviceCertificate> element. This time however, WIF has managed to uniquely identify the certificate, but it cannot access the certificates private key to execute decryption. Not being able to access the certificate’s private key may be either because the certificate is missing a private key, or because the service account the relying party website is using does not have permissions to read the private key. |
| ID4175 | The issuer of the security token was not recognized by the IssuerNameRegistry. To accept security tokens from this issuer, configure the IssuerNameRegistry to return a valid name for this issuer. | Security tokens are signed by the issuer (the IP-STS). This issuer is validated by the relying party so that the RP can be sure the tokens have been issued from a trusted source. The relying party’s WIF configuration contains an <issuerNameRegistry> element where the settings for the issuer’s signature are stored. This exception means that the configuration contained under the issuer name registry does not match the signature of the security token. |
| ID4291 | The security token 'Microsoft.IdentityModel.Tokens. SessionSecurityToken' is not scoped to the current endpoint. | Session security tokens are scoped to work only for a single relying party, based on the realm and audience configuration in WIF. This is demonstrated by the path of cookies created by the cookie handler. If you attempt to use this cookie for another RP of sub application of the RP, you will see this exception. |
| ID1073 | A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API | The cookie the message refers to is the session security token stored as a series of cookies named FedAuth1 to FedAuthX (based on the size of the SessionSecurityToken). The Session Authentication Module (SAM) is responsible for managing the reading and writing of the the session security token information between page requests, using a cookie handler to physically read and write the cookies in the request and response stream. This exception states that the encrypted session security token could not be decrypted by the SAM. The encryption method stated here is DPAPI. |
| ID1074 | A CryptographicException occurred when attempting to encrypt the cookie using the ProtectedData API | The cookie the message refers to is the session security token stored as a series of cookies named FedAuth1 to FedAuthX (based on the size of the SessionSecurityToken). The Session Authentication Module (SAM) is responsible for managing the reading and writing of the the session security token information between page requests, using a cookie handler to physically read and write the cookies in the request and response stream. This exception states that the session security token could not be encrypted by the SAM. The encryption method stated here is DPAPI. |
How do I fix ID1025?
There are several ways to identify a certificate (e.g. via a certificate’s thumbprint or subject name). Make sure the certificate is complete and installed correctly and the identifier is correct. For example
<certificateReference x509FindType="FindBySubjectName" findValue="mysubjectname" storeLocation="LocalMachine" storeName="My" />
This configuration references the certificate by subject name (called mysubjectname) in a store on the same machine. Note that storeName “My” actually refers to certificates stored under Personal certificates when viewed the certificates MMC snap in.
Be careful when using FindByThumbprint. I have seen issues with this because the thumbprint value has to be correct in hex and configuration file encoding can screw this up and cause much pain during configuration management.
How do I fix ID4036?
Firstly, ensure that your certificate is complete with all the required properties for use with WIF (see below).
Assuming that is the case, check which user account your web site is running under in IIS by:
-
Looking at the sites basic settings and checking which app pool the site is using.
-
Looking at the named app pool and checking the identity by selecting advanced settings of the app pool.
Next, open up MMC and add the certificate snap in and manage certificates for the computer account.
Navigate to Personal > Certificates. Select the appropriate certificate referenced by WIF, right click All Tasks > Manage Private Keys. Ensure that the identity account used by the app pool has read access to the private key.
How do I fix ID4291?
Check the path of the chunked cookie (using development tools in Firefox) and ensure they match your configuration as expected. Check if your application contains any sub web applications. If needed, you may need to force the cookie path by setting the <cookieHandler path="custompath" /> configuration attribute.
How do I fix ID1073?
Using DPAPI requires the app pool load user profile setting to be turned on for the app pool in IIS. To do this, go to the app pool > advanced settings and set Load User Profile to true.
This will now work fine for the default ApplicationPoolIdentity account, but in production systems running a custom windows account (on 64bit), you will still get the same exception when the app pool recycles (I don’t know why).
I solved this by switching the token format from DPAPI to an RSA cryptographic algorithm using the following WIF event handler in the global.asax:
protected void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
{
//
// Use the <serviceCertificate> to protect the cookies that are
// sent to the client.
//
List<CookieTransform> sessionTransforms =
new List<CookieTransform>(new CookieTransform[] {
new DeflateCookieTransform(),
new RsaEncryptionCookieTransform(e.ServiceConfiguration.ServiceCertificate),
new RsaSignatureCookieTransform(e.ServiceConfiguration.ServiceCertificate) });
SessionSecurityTokenHandler sessionHandler = new
SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
}
This code has the added benefit of working in a web farm without all nodes in your farm sharing the same machine key in configuration, which is much nicer (and what I needed).
How do I fix ID1074?
I have only seen one cause of this failure. Image your relying party is accessed at:
https://mysite.com/myapplication/
This is your audience URI used on the security token issued from the STS.
Now if your user access the relying party by:
https://mysite.com/myapplication
the lack of closing slash on the end of the URI gives this exception thrown by the FAM. This is surely a bug in WIF.
The workaround for me was to switch off passive redirect in the FAM configuration:
<federatedAuthentication>
<wsFederation passiveRedirectEnabled="false" issuer="https://close-brothers.dev/closests/identity/issue" realm="https://close-brothers.dev/closeasset/federation" homeRealm="https://close-brothers.dev/closests/identity/issue" requireHttps="true" />
<cookieHandler requireSsl="true" />
</federatedAuthentication>
and then write code to handle the redirect myself. Again, this workaround was something I think I would have needed regardless, because my site uses ASP.NET MVC and I want the routing engine to handle all requests and provide plumbing for home realm discovery.
WIF and x.509 certificate creation in the real world
When you develop with WIF, you are given a handy little tool called FedUtil.exe. It does a bunch of things, like change your application configuration, and generating self signed certificates under the covers.
As useful as this is for development, when it comes to deployment on production environments, you will want to have all the certificates signed with a certificate authority, and you will want control of certificate generation using MakeCert.
The lack of WIF documentation here is very tiring and is from my experience the reason for half of the exceptions I mention above. With the help of two platform architects (Thanks to James Dawson and Barry Feist) we figured out what our makecert commands need to be:
REM Root Certificate Authority
makecert.exe -pe -n "CN=My Root CA,O=MyOrg, OU=Dev, L=London, C=GB" -ss my -sr LocalMachine -sky exchange -a sha1 -r "MyRootCA.cer"
REM SSL Cert
makecert.exe -pe -n "CN=ssl.dev,O=MyOrg, OU=Dev, L=London, C=GB" -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2 -in "My Root CA" -is My -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 "MyRootCA.cer"
REM STS Cert
makecert.exe -pe -n "CN=STS.Web,O=MyOrg, OU=Dev, L=London, C=GB" -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -in "My Root CA" -is My -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 "MyRootCA.cer"
REM Relying Party Cert
REM makecert.exe -pe -n "CN=RelyingParty.Web,O=MyOrg, OU=Dev, L=London, C=GB" -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.2 -in "My Root CA" -is My -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 "MyRootCA.cer"
Here we are creating four certificates. The first is the root CA. The second is a certificate we using for SSL between the relying party and the STS. The third is a certificate used by the STS to sign tokens. The final certificate is used to encrypt the security token and decrypt the token by the relying party.