我正在使用 passport-wsfed-saml2 , WS-fed 和 SAML2 协议(protocol)的通行证策略。
逻辑的 WS-fed 部分似乎无法处理 RequestedSecurityToken
内容为 <xenc:EncryptedData>
的元素元素。
这使得该策略与指定了加密证书的 ADFS 2.0 依赖方不兼容。
我想猴子修补策略的 WsFederation.extractToken带有一些解密逻辑的方法。
下面是 RequestSecurityTokenResponse
的示例我想预处理的 xml。我应该如何解密 token ?具体来说,我如何使用 <KeyInfo>
中提供的信息?元素结合 <xenc:CipherData>
元素访问明文 token 数据。
<?xml version="1.0" encoding="UTF-8"?>
<t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<t:Lifetime>
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2017-01-05T21:02:07.193Z</wsu:Created>
<wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2017-01-05T22:02:07.193Z</wsu:Expires>
</t:Lifetime>
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://localhost</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<t:RequestedSecurityToken>
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
</e:EncryptionMethod>
<KeyInfo>
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<X509Data>
<X509IssuerSerial>
<X509IssuerName>CN=token-signing, OU=SomeOrg, O=EvilCorp, L=Williston, S=VT, C=US</X509IssuerName>
<X509SerialNumber>13135613350938963680</X509SerialNumber>
</X509IssuerSerial>
</X509Data>
</o:SecurityTokenReference>
</KeyInfo>
<e:CipherData>
<e:CipherValue>v6ueRi+G+s31b9RZxE1X8gfNWk6qC9EWimhmDQzLOl/9HQrToqcLRNVqpdocfAgAGp3RkyR9IcwED7PZkreNNzEYMN3pntqS1372Nk6EEYwJSVmWkXmsv4m+xeJvGPQrDIZOwlq22OBt0EAwXoq7LvkmF0s/uhB4TItD47iAsDOFThMpuPoYo0EDLgPWzHtrZqTsC33c10zKKgyynSJPAKaC/+a9mSc4uxq55njU4GLVP/p4FvubPF2U1j4I7ozRGGWsAD5iTGwIOIF7H/ftKoRGIoFen29Ud87mm00BrF0GSUzcxTX+isMfI+HWp8u9zaO1ZLge5+x12BJcVWOYwblTQ7IPWyCMmaUscGgQPZ82ROrMCbX2f6HcGHtl8rwzXbz/VfAZkkxXZAfq9NRjSIRcmVtwC4cjwPAAcwE6V8+lvFn/2dUgzSz9y5K4HpzWZc2jg91oyzhFV+5luC+NV2HPAtTshjWOWhAcVuZYdINfcU1rSHKirBtDPQjxEWcyxkGyrl6UfWq1sEDuaXBPVNWT9/jyjuf7Rzyxnype8SleTK197FnD+rq6NzG9H4MpTFwhgokiPx4/RONjog7I1qnNM5wFybJ5WvkSh+x1w1w7/CNGipJSXCy3swGuSgSF3LI1bUZSzL+JqhUmYq8EVxW31TPe7JbBwMdvnGl7e6Q=</e:CipherValue>
</e:CipherData>
</e:EncryptedKey>
</KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>.... whole bunch of base64 encoded data ....</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</t:RequestedSecurityToken>
<t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
<t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
</t:RequestSecurityTokenResponse>
最佳答案
<RequestedSecurityToken>
元素包含 <EncryptedData>
元素。 EncryptedData 元素由三部分组成:
aes256-cbc
:
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
2. KeyInfo,在我的例子中这是 AES 加密 key ,但该 key 已使用 ADFS 中配置的加密证书进行了加密。我们需要使用加密证书的 RSA 私钥解密 key ,为我们提供可用于解密 SAML 安全 token 的 AES 加密 key /密码:
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
</e:EncryptionMethod>
<KeyInfo>
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<X509Data>
<X509IssuerSerial>
<X509IssuerName>CN=token-signing, OU=SomeOrg, O=EvilCorp, L=Williston, S=VT, C=US</X509IssuerName>
<X509SerialNumber>13135613350938963680</X509SerialNumber>
</X509IssuerSerial>
</X509Data>
</o:SecurityTokenReference>
</KeyInfo>
<e:CipherData>
<e:CipherValue>v6ueRi+G+s31b9RZxE1X8gfNWk6qC9EWimhmDQzLOl/9HQrToqcLRNVqpdocfAgAGp3RkyR9IcwED7PZkreNNzEYMN3pntqS1372Nk6EEYwJSVmWkXmsv4m+xeJvGPQrDIZOwlq22OBt0EAwXoq7LvkmF0s/uhB4TItD47iAsDOFThMpuPoYo0EDLgPWzHtrZqTsC33c10zKKgyynSJPAKaC/+a9mSc4uxq55njU4GLVP/p4FvubPF2U1j4I7ozRGGWsAD5iTGwIOIF7H/ftKoRGIoFen29Ud87mm00BrF0GSUzcxTX+isMfI+HWp8u9zaO1ZLge5+x12BJcVWOYwblTQ7IPWyCMmaUscGgQPZ82ROrMCbX2f6HcGHtl8rwzXbz/VfAZkkxXZAfq9NRjSIRcmVtwC4cjwPAAcwE6V8+lvFn/2dUgzSz9y5K4HpzWZc2jg91oyzhFV+5luC+NV2HPAtTshjWOWhAcVuZYdINfcU1rSHKirBtDPQjxEWcyxkGyrl6UfWq1sEDuaXBPVNWT9/jyjuf7Rzyxnype8SleTK197FnD+rq6NzG9H4MpTFwhgokiPx4/RONjog7I1qnNM5wFybJ5WvkSh+x1w1w7/CNGipJSXCy3swGuSgSF3LI1bUZSzL+JqhUmYq8EVxW31TPe7JbBwMdvnGl7e6Q=</e:CipherValue>
</e:CipherData>
</e:EncryptedKey>
</KeyInfo>
3. CipherData:SAML 安全 token ,使用 AES 加密。
<xenc:CipherData>
<xenc:CipherValue>.... whole bunch of base64 encoded data ....</xenc:CipherValue>
</xenc:CipherData>
解决方案
这是猴子修补 passport-wsfed-saml2 库的 WsFederation.extractToken
的代码方法:
import WsFederation = require('passport-wsfed-saml2/lib/passport-wsfed-saml2/wsfederation');
import { createPrivateKey } from 'ursa-purejs';
import { createDecipheriv, randomBytes } from 'crypto';
import { DOMParser } from 'xmldom';
import { readFileSync } from 'fs';
const tokenSigningKey = createPrivateKey(readFileSync('./certs/token-signing.pem'));
const parser = new DOMParser();
WsFederation.prototype.standardExtractToken = WsFederation.prototype.extractToken;
WsFederation.prototype.extractToken = function (this: any, req: string) {
const token: Element | null = this.standardExtractToken(req);
// Is the SAML token encrypted?
if (!token || token.nodeName !== 'xenc:EncryptedData') {
// no. return it.
return token;
}
// We need to decrypt the SAML token...
// Grab the CipherValue elements. There will be two:
// 0. The encryption key for the SAML token, encrypted by ADFS using the rsa-oaep-mgf1p
// algo and the public key of the encryption certificate configured in the relying party.
// 1. The SAML token, encrypted using the aes-256-cbc algo with the key from #0 ^^^
const ciphers = token.getElementsByTagNameNS('http://www.w3.org/2001/04/xmlenc#', 'CipherValue');
const aesPasswordCipher = <string>ciphers[0].textContent;
const samlTokenCipher = <string>ciphers[1].textContent;
// Decrypt the password for the SAML token.
const aesPassword = tokenSigningKey.decrypt(aesPasswordCipher, 'base64');
// Decrypt the SAML token.
const decipher = createDecipheriv('aes-256-cbc', aesPassword, randomBytes(16));
let saml = decipher.update(new Buffer(samlTokenCipher, 'base64'), 'binary', 'utf8');
saml += decipher.final('utf8');
// Parse the XML and return the token.
return parser.parseFromString(saml);
};
有用的链接:https://coolaj86.com/articles/asymmetric-public--private-key-encryption-in-node-js/
关于javascript - Node .js/SAML : How to decrypt contents of RequestedSecurityToken,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41495684/