Thinktecture - Unable to handle an encrypted SAML security token in Web API

1.4k views Asked by At

In .net Web API, how can I configure Thinktechture Saml2SecurityTokenHandler to use a X509 Certificate to handle an encrypted SAML2 security token (decrypt it before validating).

The token was encrypted by Identity Server by configuring the RP to use the certificate for encrypting.

Below is the working configuration (without handling an encrypted token) taken from Thinktechture samples:

  #region IdentityServer SAML
  authentication.AddSaml2(
                issuerThumbprint: Constants.IdSrv.SigningCertThumbprint,
                issuerName: Constants.IdSrv.IssuerUri,
                audienceUri: Constants.Realm,
                certificateValidator: X509CertificateValidator.None,
                options: AuthenticationOptions.ForAuthorizationHeader(Constants.IdSrv.SamlScheme),
                scheme: AuthenticationScheme.SchemeOnly(Constants.IdSrv.SamlScheme));
  #endregion
2

There are 2 answers

3
JonathanN On BEST ANSWER

To enable encrypted tokens with Web API, I found this helpful: http://www.alexthissen.nl/blogs/main/archive/2011/07/18/using-active-profile-for.aspx

Towards the end you'll see code setting the ServiceTokenResolver property on the Configuration property of a SecurityTokenHandlerCollection using a X509 certificate from the LocalMachine store. The Configuration property is a SecurityTokenHandlerConfiguration, which is one of the parameters to an overload of the AddSaml2 extension method in AuthenticationConfigurationExtensionsCore.cs from the ThinkTecture.IdentityModel source. The below is what I ended up with.

var registry = new ConfigurationBasedIssuerNameRegistry();
registry.AddTrustedIssuer(Constants.IdSrv.SigningCertThumbprint, Constants.IdSrv.IssuerUri);

var handlerConfig = new SecurityTokenHandlerConfiguration();
handlerConfig.AudienceRestriction.AllowedAudienceUris.Add(new Uri(Constants.Realm));
handlerConfig.IssuerNameRegistry = registry;
handlerConfig.CertificateValidator = GetX509CertificateValidatorSetting();

X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificates = store.Certificates;
X509Certificate2Collection matchingCertificates = certificates.Find(
    X509FindType.FindBySubjectDistinguishedName,
    "CN=RPTokenCertificate", false);
X509Certificate2 certificate = certificates[0];

List<SecurityToken> serviceTokens = new List<SecurityToken>();
serviceTokens.Add(new X509SecurityToken(certificate));
SecurityTokenResolver serviceResolver =
    SecurityTokenResolver.CreateDefaultSecurityTokenResolver(
        serviceTokens.AsReadOnly(), false);
handlerConfig.ServiceTokenResolver = serviceResolver;

authentication.AddSaml2(handlerConfig, 
    AuthenticationOptions.ForAuthorizationHeader(SamlScheme), 
    AuthenticationScheme.SchemeOnly(SamlScheme));

Hope it helps.

0
Sam On

got this answer from someone:

    public ClaimsIdentity DecryptToken(string token)
    {
        XmlReader rdr = XmlReader.Create(new StringReader(token));

        SecurityTokenHandlerConfiguration config = new SecurityTokenHandlerConfiguration();
        config.AudienceRestriction.AllowedAudienceUris.Add(new Uri("urn:yourRP"));
        config.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
        config.RevocationMode = X509RevocationMode.NoCheck;

        ConfigurationBasedIssuerNameRegistry inr = new ConfigurationBasedIssuerNameRegistry();
        X509Certificate2 cert = new X509Certificate2(pathToSigningCert);
        inr.AddTrustedIssuer(cert.Thumbprint, "STS Name");

        config.IssuerNameRegistry = inr;
        config.CertificateValidator = System.IdentityModel.Selectors.X509CertificateValidator.None;

        SecurityTokenHandlerCollection handlers = System.IdentityModel.Tokens.SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection(config);

        if (handlers.CanReadToken(rdr))
        {
            var tmpToken = handlers.ReadToken(rdr);
            var claimsIds = handlers.ValidateToken(tmpToken);
            var id = claimsIds.FirstOrDefault();
        }
    }

not sure if this helps.

what did you use as the issuer name? the name of the website you setup in IIS? or the value you entered in the "Site ID" field in the "General Configuration" page of the IdentityServer's Administration section?