构造签名的SAML2 LogOut请求

Gau*_*cho 14 saml-2.0

我的目标是实现单一登出协议.首先,我理解标准是如何工作的以及我如何在我的场景中适应它:ADFS 2.0作为IdP,对我来说就像一个"黑匣子"

我现在正在做的是下一个:

  1. 发送<AuthnRequest>给我的IdP

  2. IdP要求我提供凭据,我提供这些凭据并成功登录.

  3. 获取SessionIndex值并构造一个 <LogoutRequest>

<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_135ad2fd-b275-4428-b5d6-3ac3361c3a7f" Version="2.0" Destination="https://idphost/adfs/ls/" IssueInstant="2008-06-03T12:59:57Z"><saml:Issuer>myhost</saml:Issuer><NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" NameQualifier="https://idphost/adfs/ls/">myemail@mydomain.com</NameID<samlp:SessionIndex>_0628125f-7f95-42cc-ad8e-fde86ae90bbe</samlp:SessionIndex></samlp:LogoutRequest>

  1. 取上面的内容<LogoutRequest>并在Base64中编码

  2. 构造下一个字符串: SAMLRequest=base64encodedRequest&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1

  3. 用上面的字符串生成签名

  4. 在base64中编码签名

  5. 发送请求: https://"https://idphost/adfs/ls/?SAMLRequest=base64encodedRequest&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature=base64EncodedSignature

但是IdP正在回答我:SAML消息签名的验证失败了.

对于签名我使用我的私钥(2048字节),并且用于验证它是否假设IdP正在使用我的公钥(我在注册我的主机时发送的那个)

签署请求的代码如下:

// Retrieve the private key
KeyStore keyStore = KeyStore.getInstance("JKS", "SUN");
FileInputStream stream;
stream = new FileInputStream("/path/to/my/keystore.jks");
keyStore.load(stream, "storepass".toCharArray());
PrivateKey key = (PrivateKey) keyStore.getKey("keyAlias","keyPass".toCharArray());

// Create the signature
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(key);
signature.update("SAMLRequest=jVJda8IwFH2e4H8ofW%2BbVmvboGWCDApusDn2sBdJm1sNtEmXmw7x1y92KDrY2Ov5uueEzJG1TUfXaqd68wIfPaBxDm0jkQ7Mwu21pIqhQCpZC0hNRTfLxzWNfEI7rYyqVONeWf52METQRijpOsVq4W7JoSzjJJnWAEAmwLMMpmRG0jCrYJICIcR13kCjdSxcG%2BA6K9tQSGYGZG9MhzQIGrUT0uPw6VegpV%2FtA8ZrDBq0ZxB7KCQaJo2NICT1yMwjk9cwonFG4%2BTdzceju%2FmpOx3EOu8qYThgGJ3j5sE1fZE%2F2X3FynlQumXm9%2BGhHw6I4F49SCm0TDRLzjWgrXiKee5ZI2oB%2Bj%2Bj8qYX6GvFtdj1cPRryzPJ4Xh%2F2%2Fe736VvRzf2nn24wmoP%2BZbMojSM4tpL6iz2plFVeYyn4NUc0hmDjJQlfCf9cI5HZ%2Fjm4%2BRf&RelayState=null&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1".getBytes());

String signatureBase64encodedString = (new BASE64Encoder()).encodeBuffer(signature.sign());
Run Code Online (Sandbox Code Playgroud)

Gau*_*cho 10

最后我得到了正确的食谱:

  1. 生成SAMLRequest值
  2. 在Base64中编码SAMLRequest值
  3. URL编码SAMLRequest值
  4. URL编码SigAlg值:http: //www.w3.org/2000/09/xmldsig#rsa-sha1
  5. 使用SAMLRequest = value和SigAlg =值提供算法签名(SHA1withRSA)
  6. 对生成的签名进行URL编码

我们可以使用SAML 2.0调试器(https://rnd.feide.no/simplesaml/module.php/saml2debug/debug.php)执行步骤2和3 .对于URL编码使用经典的w3schools(http://www.w3schools.com/tags/ref_urlencode.asp)

警告!确保ADFS2中依赖方的算法设置为SHA1!

最好的祝福,

路易斯

ps:现在我需要编码一点......

pps:你可以在这里找到代码:https://github.com/cerndb/wls-cern-sso/tree/master/saml2slo

  • 感谢有关哈希算法的提示!这让我感到高兴. (2认同)