WIF: WIF10201: No valid key mapping found for securityToken:
Issue:
WIF10201: No valid key mapping found for securityToken:
This exception is observed on a federated application(web app / mvc / asmx / wcf) using WIF pipeline to authenticate the user.
Stack:
[SecurityTokenValidationException: WIF10201: No valid key mapping found for securityToken: 'System.IdentityModel.Tokens.X509SecurityToken' and issuer: 'LocalSTS'.]
System.IdentityModel.Tokens.SamlSecurityTokenHandler.ValidateToken(SecurityToken token) +987
System.IdentityModel.Tokens.SecurityTokenHandlerCollection.ValidateToken(SecurityToken token) +73
System.IdentityModel.Services.TokenReceiver.AuthenticateToken(SecurityToken token, Boolean ensureBearerToken, String endpointUri) +110
System.IdentityModel.Services.WSFederationAuthenticationModule.SignInWithResponseMessage(HttpRequestBase request) +527
System.IdentityModel.Services.WSFederationAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs args) +381
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +141
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69
Root cause:
This error is triggered because of the mandatory code validation in WIF module to check the incoming request Signing token.
// System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry
public override string GetIssuerName(SecurityToken securityToken)
{
if (securityToken == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityToken");
}
X509SecurityToken x509SecurityToken = securityToken as X509SecurityToken;
if (x509SecurityToken != null)
{
string thumbprint = x509SecurityToken.Certificate.Thumbprint; <----------------
if (this._configuredTrustedIssuers.ContainsKey(thumbprint))
{
string text = this._configuredTrustedIssuers[thumbprint];
text = (string.IsNullOrEmpty(text) ? x509SecurityToken.Certificate.Subject : text);
if (TD.GetIssuerNameSuccessIsEnabled())
{
TD.GetIssuerNameSuccess(EventTraceActivity.GetFromThreadOrCreate(false), text, securityToken.Id);
}
return text;
}
}
if (TD.GetIssuerNameFailureIsEnabled())
{
TD.GetIssuerNameFailure(EventTraceActivity.GetFromThreadOrCreate(false), securityToken.Id);
}
return null;
}
Summary:
So eventually we try to read the current token associated with the request
string thumbprint = x509SecurityToken.Certificate.Thumbprint
And then compare it with the config file entry for our project.
string text = this._configuredTrustedIssuers[thumbprint];
Two checks done:
===========
1. Validate if the existing request security token's thumbprint is already present inside the in memory dictionary object
this._configuredTrustedIssuers.
2. If it is not there, we return Null.
3. If it is there, we compare the subject name of incoming token with in memory value and pass from there..
All these check are to make sure that we receive the request signed from same issuer which was initially trusted on the main app.
Solution:
To solve this error we need to make sure we have added proper key inside the Federated app configuration file to respective issuer.
<system.identityModel>
<identityConfiguration>
<audienceUris>
<add value="localhost:1442/" />
</audienceUris>
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
<authority name="LocalSTS">
<keys>
<addthumbprint="9B74CB2F320F7AAFC156E1252270B1DC01EF40D1" />
</keys>
<validIssuers>
<add name="LocalSTS" />
</validIssuers>
</authority>
</issuerNameRegistry>
<certificateValidation certificateValidationMode="None" />
</identityConfiguration>
</system.identityModel>
If the thumbprint used here is invalid and does not match with the incoming Token - Base 4 encoded value. It fails!
Solution:
To get it working, we would need to extract and use the correct thumbprint.
1. Check the Base 64 encoded value of incoming request via fiddler or Freb logs and find the correct Signing Cert at STS. Get the thumbprint.
2. Use below code to create Thumbprint out of base 64 encoded value.
string _publicKey = "Base64encodedString";
var cert = new X509Certificate2(Convert.FromBase64String(_publicKey), "password", X509KeyStorageFlags.PersistKeySet);
if (cert != null)
{
//use Cert
}
I hope this helps everyone stuck with same error.
Thanks
Saurabh Somani