如何获取 ADFS Public 密钥并验证 JWT 令牌上的签名?
How to obtain the ADFS Public Key and validate the signature on a JWT Token?
我需要验证在 ADFS 服务器上签名的 JWT 令牌的签名。我可以验证 self-signed JWT 令牌,但不能验证从 ADFS 收到的令牌。我应该如何获得 public 密钥?
为了从 ADFS 服务器获取 public 密钥,我让我的同事导出
来自 ADFS 服务器的证书。在 ADFS 控制台上 他查看了
“服务”>“编辑联合身份验证服务属性”,
“常规”选项卡,他在其中找到了三个完整的选项卡。他们在标题下
“令牌签名”、“令牌解密”和“服务通信”。
他查看了每个证书,然后导出了 DER 证书
(没有私钥)。然后将它们转化为 PEM(使用
openssl x509 -inform der -in cert.cer -out cert.pem
) 但 none 这些键
允许我的代码验证嗅探到的 JWT 令牌。
我的 Java 代码采用 JWT 令牌和 Public 密钥,并验证令牌是否使用 Public 密钥签名。如果我使用 self-signed 密钥对和自生成的 JWT 令牌,那么代码似乎可以工作,并报告签名正常。当从来自 ADFS 的消息中的 HTTP Header 复制令牌时,相同的代码报告签名无效。
这是我用来加载 PEM public 密钥的代码:
FileInputStream fis = new FileInputStream(publicKeyFile)
Reader keyReader = new InputStreamReader(publicKeyStream);
PemReader pemReader = new PemReader(keyReader);
PEMParser pemParser = new PEMParser(pemReader);
Object pemObject = pemParser.readObject();
if (pemObject instanceof X509CertificateHolder) {
X509CertificateHolder x509CertificateHolder = (X509CertificateHolder) pemObject;
X509Certificate x509Certificate = new JcaX509CertificateConverter()
.setProvider("BC").getCertificate(x509CertificateHolder);
return x509Certificate.getPublicKey();
}
这是我用来验证签名的代码:
String signatureAlgorithm = publicKey.getAlgorithm();
Signature signatureInstance = Signature.getInstance(signatureAlgorithm);
signatureInstance.initVerify(publicKey);
byte[] messageBytes = Base64.encodeBase64(message.getBytes(UTF_8));
signatureInstance.update(messageBytes);
byte[] receivedSignature = Base64.decodeBase64URLSafe(signature);
return signatureInstance.verify(receivedSignature);
(为简洁起见,我在上面删除了异常处理和资源关闭。
我正在使用 tomcat 的 Base64 class。)
代码运行没有错误,但表明签名无效。在我看来,以下任何一项都可能是错误的:
从 ADFS 服务器提取的 - None 个 public 密钥是相关的 public 密钥。
- public 密钥从 .cer 到 .pem 的转换可能不正确。
- 验证签名或加载 public 密钥的代码可能有误。
我需要验证在 ADFS 服务器上签名的 JWT 令牌的签名。我可以验证 self-signed JWT 令牌,但不能验证从 ADFS 收到的令牌。我应该如何获得 public 密钥?
为了从 ADFS 服务器获取 public 密钥,我让我的同事导出
来自 ADFS 服务器的证书。在 ADFS 控制台上 他查看了
“服务”>“编辑联合身份验证服务属性”,
“常规”选项卡,他在其中找到了三个完整的选项卡。他们在标题下
“令牌签名”、“令牌解密”和“服务通信”。
他查看了每个证书,然后导出了 DER 证书
(没有私钥)。然后将它们转化为 PEM(使用
openssl x509 -inform der -in cert.cer -out cert.pem
) 但 none 这些键
允许我的代码验证嗅探到的 JWT 令牌。
我的 Java 代码采用 JWT 令牌和 Public 密钥,并验证令牌是否使用 Public 密钥签名。如果我使用 self-signed 密钥对和自生成的 JWT 令牌,那么代码似乎可以工作,并报告签名正常。当从来自 ADFS 的消息中的 HTTP Header 复制令牌时,相同的代码报告签名无效。
这是我用来加载 PEM public 密钥的代码:
FileInputStream fis = new FileInputStream(publicKeyFile)
Reader keyReader = new InputStreamReader(publicKeyStream);
PemReader pemReader = new PemReader(keyReader);
PEMParser pemParser = new PEMParser(pemReader);
Object pemObject = pemParser.readObject();
if (pemObject instanceof X509CertificateHolder) {
X509CertificateHolder x509CertificateHolder = (X509CertificateHolder) pemObject;
X509Certificate x509Certificate = new JcaX509CertificateConverter()
.setProvider("BC").getCertificate(x509CertificateHolder);
return x509Certificate.getPublicKey();
}
这是我用来验证签名的代码:
String signatureAlgorithm = publicKey.getAlgorithm();
Signature signatureInstance = Signature.getInstance(signatureAlgorithm);
signatureInstance.initVerify(publicKey);
byte[] messageBytes = Base64.encodeBase64(message.getBytes(UTF_8));
signatureInstance.update(messageBytes);
byte[] receivedSignature = Base64.decodeBase64URLSafe(signature);
return signatureInstance.verify(receivedSignature);
(为简洁起见,我在上面删除了异常处理和资源关闭。 我正在使用 tomcat 的 Base64 class。)
代码运行没有错误,但表明签名无效。在我看来,以下任何一项都可能是错误的:
-
从 ADFS 服务器提取的
- None 个 public 密钥是相关的 public 密钥。
- public 密钥从 .cer 到 .pem 的转换可能不正确。
- 验证签名或加载 public 密钥的代码可能有误。