2017-10-02 10 views
1

私は署名付きアサーションを持つSAMLResponseを生成するIDPを持っています。私は生成されたXMLファイルの例を追加するつもりはありません。なぜなら、それは質問をあまりにも長くするからです。しかし、それが本当に役立つなら、私に知らせてください、私はそれを追加します。SAMLResponseに署名し、C#でアサーションを暗号化する方法は?

SPは、アサーションを暗号化して応答することを要求しています(現時点ではそうではありません)。研究の後、私はそれを行う方法を見つけることができませんでした、私は試したコードを投稿するだろうが、私は正直であるためにちょっと無責任です、そして私が試したものはどこにもありません。

質問:私はどのように応答に署名し、アサーションを暗号化するのですか?ここで

は、応答が作成され、署名されている方法は次のとおりです。

public class SAML 
{ 
    private const int tokenLifetime = 30; 
    private const string issuer = "https://some.domain/IdP"; 
    private const string CertificateSerialNumber = "XXXXXXXXXXXXX"; 

    private static string _RequestId; 
    private static string _RequestIssueInstant; 
    private static string _RequestProviderName; 
    private static string _RequestACS; 
    private static Dictionary<string, string> _claimDescriptors = new Dictionary<string, string>(); 


    public static string CreateSamlResponse(string RequestId, string RequestIssueInstant, string RequestProviderName, string RequestACS, Dictionary<string,string> claimDescriptors) 
    { 
     _RequestId = RequestId; 
     _RequestIssueInstant = RequestIssueInstant; 
     _RequestProviderName = RequestProviderName; 
     _RequestACS = RequestACS; 
     _claimDescriptors = claimDescriptors; 

     var claims = CreateClaims(); 
     var tokenHandler = new Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler(); 
     var token = CreateToken(claims, tokenHandler); 

     return CreateSamlResponseXml(tokenHandler, token); 
    } 

    private static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken CreateToken(IEnumerable<Microsoft.IdentityModel.Claims.Claim> claims, 
     Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler tokenHandler) 
    { 
     var descriptor = CreateTokenDescriptor(claims); 
     var token = tokenHandler.CreateToken(descriptor) as Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken; 

     AddAuthenticationStatement(token); 
     AddConfirmationData(token); 

     return token; 
    } 

    private static void AddConfirmationData(Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken token) 
    { 
     var confirmationData = new Microsoft.IdentityModel.Tokens.Saml2.Saml2SubjectConfirmationData 
     { 
      Recipient = new Uri(_RequestACS), 
      NotOnOrAfter = DateTime.UtcNow.AddSeconds(tokenLifetime), 
      InResponseTo = new Microsoft.IdentityModel.Tokens.Saml2.Saml2Id(_RequestId), 
     }; 

     token.Assertion.Subject.SubjectConfirmations.Add(new Microsoft.IdentityModel.Tokens.Saml2.Saml2SubjectConfirmation(
      Microsoft.IdentityModel.Tokens.Saml2.Saml2Constants.ConfirmationMethods.Bearer, confirmationData)); 
    } 

    private static void AddAuthenticationStatement(Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken token) 
    { 
     var authenticationMethod = "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"; 
     var authenticationContext = new Microsoft.IdentityModel.Tokens.Saml2.Saml2AuthenticationContext(new Uri(authenticationMethod)); 
     var authenticationStatement = new Microsoft.IdentityModel.Tokens.Saml2.Saml2AuthenticationStatement(authenticationContext); 
     token.Assertion.Statements.Add(authenticationStatement); 
    } 

    private static string CreateSamlResponseXml(Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler tokenHandler, Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken token) 
    { 
     var buffer = new StringBuilder(); 

     using (var stringWriter = new StringWriter(buffer)) 
     using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings())) 
     { 
      xmlWriter.WriteStartElement("Response", "urn:oasis:names:tc:SAML:2.0:protocol"); 
      xmlWriter.WriteAttributeString("IssueInstant", DateTime.UtcNow.ToString("o")); 
      xmlWriter.WriteAttributeString("ID", "_" + Guid.NewGuid()); 
      xmlWriter.WriteAttributeString("Version", "2.0"); 

      xmlWriter.WriteStartElement("Status"); 
      xmlWriter.WriteStartElement("StatusCode"); 
      xmlWriter.WriteAttributeString("Value", "urn:oasis:names:tc:SAML:2.0:status:Success"); 
      xmlWriter.WriteEndElement(); 
      xmlWriter.WriteEndElement(); 

      tokenHandler.WriteToken(xmlWriter, token); 

      xmlWriter.WriteEndElement(); 
     } 
     return buffer.ToString(); 
    } 

    private static Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor CreateTokenDescriptor(IEnumerable<Microsoft.IdentityModel.Claims.Claim> claims) 
    { 
     var descriptor = new Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor() 
     { 
      TokenType = Microsoft.IdentityModel.Tokens.SecurityTokenTypes.OasisWssSaml2TokenProfile11, 
      Lifetime = new Microsoft.IdentityModel.Protocols.WSTrust.Lifetime(DateTime.UtcNow, DateTime.UtcNow.AddMinutes(1)), 
      //AppliesToAddress = appliesTo, 
      AppliesToAddress = _RequestACS, 
      TokenIssuerName = issuer, 
      Subject = new Microsoft.IdentityModel.Claims.ClaimsIdentity(claims), 
      SigningCredentials = GetSigningCredentials() 
     }; 

     return descriptor; 
    } 

    private static System.IdentityModel.Tokens.SigningCredentials GetSigningCredentials() 
    {  
     System.Security.Cryptography.X509Certificates.X509Certificate2 myCertificate = null; 

     X509Certificate2Collection selectedCerts = new X509Certificate2Collection(); 

     X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); 
     store.Open(OpenFlags.ReadOnly); 

     foreach (System.Security.Cryptography.X509Certificates.X509Certificate2 cert in store.Certificates) 
     { 
      if (cert.SerialNumber.Trim().ToLower().Equals(CertificateSerialNumber.ToLower())){ myCertificate = cert; } 
     } 
     return new Microsoft.IdentityModel.SecurityTokenService.X509SigningCredentials(myCertificate, System.IdentityModel.Tokens.SecurityAlgorithms.RsaSha1Signature, System.IdentityModel.Tokens.SecurityAlgorithms.Sha1Digest); 
    } 

    private static IEnumerable<Microsoft.IdentityModel.Claims.Claim> CreateClaims() 
    { 
     foreach (var claimDescriptor in _claimDescriptors) 
     { 
      yield return new Microsoft.IdentityModel.Claims.Claim(claimDescriptor.Key, claimDescriptor.Value); 
     } 
    } 

} 

答えて

0

SecurityTokenDescriptorとSaml2SecurityTokenクラスは、SigningCredentialsプロパティに加えて、EncryptingCredentials性質を持っています。これを設定すると、アサーションが暗号化されます。

署名の応答が難しいかもしれません。暗号化されたアサーションを持つ応答xmlを取得したら、その目的でSignedXml classを使用できます。一例はhttps://github.com/Safewhere/CHTestSigningService/blob/86a66950d1ffa5208b8bf80d03868a073ba29f12/Kombit.Samples.CHTestSigningService/Code/TokenSigningService.cs#L344

+0

トゥアンです!これは本当に役に立ちました!私は1つの問題を抱えています。あなたが言及したようにEncryptingCredentialsプロパティを使用していますが、アサーションが暗号化されていますが、X509Certificate要素がX509Dataセクションに追加されていないため、理由がわかりません。助言がありますか? – Naner

+0

SecurityKeyIdentifierプロパティを確認することができます:https://msdn.microsoft.com/en-us/library/system.identitymodel.tokens.x509encryptingcredentials(v=vs.110).aspx IIRC、それはkeyinfoの追加を担当します。 – Thuan

関連する問題