title: How SAML Assertion/verification works with X509 public key
body: <p>In my asp.net MVC web-site, I have implemented SSO in which the IDP/ADFS sends the SAML response and I verify the SAML token to allow users to access the web-site.  I am using customized code (using System.IdentityModel.dll and System.IdentityModel.Services.dll libraries to verify the SAML response and token, instead of having.net framework do the checking with web.config settings).</p>
  
  <p>So far the code seems to be working fine, but since I am new to this domain have concern that hacker would able to bypass the validation with properly constructed SAML response. Recently I tried my hands on the SAML token generation part and I realized that my token verification code can be bypassed if the token is generated intelligently.</p>
  
  <p>At high level this is what I am doing to verify the token:</p>
  
  <ol>
  <li>Extract the security token from the request.</li>
  <li>Verify the token is valid and untouched by checking the digest value with the provided X509 public key(which is present in the SAML response) 
  
  <ol start="3">
  <li>Extract the claims/identity of the user and allow the access.</li>
  </ol></li>
  </ol>
  
  <p>My concern is that if hacker creates SAML token (like my own token generator code) and add public key in the response and post it to my web site, my web site will successfully validate the response as the response itself is well formed and signed. Is this a valid concern? I am missing some basic validations to handle this scenario?
  I can think of following options to mitigate the risk:</p>
  
  <ol>
  <li><p>Check the URLReferrer and make sure that the SAML response is posted from the expected entity.  I am not sure if there is a way to manipulate the URLReferrer.</p></li>
  <li><p>Avoid using the public key present in the response to validate the digest value.  I can store the X509 certificate on my end and use it to validate the response. The hacker won’t able to sign the response with the same certificate as he won’t have the private key. If this is the right way, can someone suggest me how to instruct “tokenhandler” to ignore the public key present in the response and use explicit public key?</p></li>
  <li><p>Is there a way by which I can make back-end call to IDP, May a web-service call, and check that the token received by my web site is indeed generated by the IDP?</p></li>
  </ol>
  
  <p>Since I am a newbie, I might be missing the basic SAML validation concept. So please let me know if my concern is legitimate.
  Here is the sample code I use to validate the response. </p>
  
  <pre><code>public ActionResult SAMLAssert()
      {
          var fam = new WSFederationAuthenticationModule();
          var request = this.HttpContext.Request;
  
          // Get the security token from the SAML response
          var securityToken = fam.GetSecurityToken(request);
  
          var config = new SecurityTokenHandlerConfiguration
          {
              CertificateValidator = X509CertificateValidator.None,
              IssuerNameRegistry = new CustomIssuerNameRegistry(),
  
          };
          config.AudienceRestriction.AudienceMode = AudienceUriMode.Never;
  
          var tokenHandler = new Saml2SecurityTokenHandler
          {
              CertificateValidator = X509CertificateValidator.None,
              Configuration = config,
  
          };
  
          //// validate the token and get the ClaimsIdentity out of it
          var identity = tokenHandler.ValidateToken(securityToken);
          bool isSuccess = identity[0].IsAuthenticated;
  
          // Code to retrieve the claims/user information from the token
          //....
          return View();
      }
  </code></pre>
  
  <p>And here is the custom "IssuerNameRegistry".</p>
  
  <pre><code>public class CustomIssuerNameRegistry : IssuerNameRegistry
      {
          public override string GetIssuerName(SecurityToken securityToken)
          {
              X509SecurityToken x509Token = securityToken as X509SecurityToken;
  
              return x509Token.Certificate.Subject;
          }
  
  
      }
  </code></pre>
  
  <p>I have suspicion that the custom class is the problematic part as it’s not doing any validation. </p>