-
Notifications
You must be signed in to change notification settings - Fork 408
Workaround when WsFederationMessage.GetToken() returns a string with "
" in SAML that breaks signature validation.
White space is significant between elements when obtaining the C14n (https://www.w3.org/TR/xml-c14n/) octets that the signature is generated from. If the original xml had this whitespace, then the C14n octets which are used to generate the signature must have the octets.
Sometimes as the xml flows through nodes, whitespace is added (in this case carriage return \r). C14n removes whitespace inside elements, orders attributes, fixes namespaces, and other stuff. But does not remove the outer element whitespace. Removing whitespace automatically is breaking.
We plan on adding a switch that will allow control for ignoring whitespace between elements. In the meantime, the following logic is a suggested workaround for asp.net users.
In startup.cs replace the SamlSecurityTokenHandler with the code below that retries the validation if SecurityTokenInvalidSignatureException is thrown.
The same code would work Saml2 tokens.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication(options =>
{
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddWsFederation(options =>
{
options.SecurityTokenHandlers.Clear();
options.SecurityTokenHandlers.Add(new CustomSamlSecurityTokenHandler());
options.SecurityTokenHandlers.Add(new Saml2SecurityTokenHandler());
options.SecurityTokenHandlers.Add(new JwtSecurityTokenHandler());
options.MetadataAddress = "<METADATA address here: https://login.microsoftonline.com/<YOUR tenant>/FederationMetadata/2007-06/FederationMetadata.xml";
options.Wtrealm = "<YOUR ClientId>";
options.Wreply = "<Reply url registered with AAD>";
});
...
}
public class CustomSamlSecurityTokenHandler : SamlSecurityTokenHandler
{
public override ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
if (securityToken.Contains("
"))
{
string securityTokenTrimmed = securityToken.Replace("
", "");
try
{
return base.ValidateToken(securityTokenTrimmed, validationParameters, out validatedToken);
}
catch (Exception ex)
{
if (!(ex is SecurityTokenInvalidSignatureException))
throw;
}
}
return base.ValidateToken(securityToken, validationParameters, out validatedToken);
}
}
Conceptual Documentation
- Using TokenValidationParameters.ValidateIssuerSigningKey
- Scenarios
- Validating tokens
- Outbound policy claim type mapping
- How ASP.NET Core uses Microsoft.IdentityModel extensions for .NET
- Using a custom CryptoProvider
- SignedHttpRequest aka PoP (Proof-of-Possession)
- Creating and Validating JWEs (Json Web Encryptions)
- Caching in Microsoft.IdentityModel
- Resiliency on metadata refresh
- Use KeyVault extensions
- Signing key roll over