我根据Salesforce的OAuth JWT Bearer Token Flow编写了一个java客户端,但响应是“Invalid Assertion”。我上传到Salesforce组织的证书是自签名的,我发送的声明包含client_id(OAuth连接应用的用户密钥),用户的电子邮件地址/用户名(也是在证书和用户已经通过用户/密码OAuth流程成功使用Salesforce REST API,到期时间,并且受众设置为https://login.salesforce.com(aud)。我可以看到“数字签名”已在Salesforce中正确加载,我的代码正确签名。 Salesforce中的我的Oauth范围已设置为:
访问和管理您的数据(api)
通过Web(Web)提供对数据的访问
随时代表您执行请求(refresh_token,offline_access)
当我将JWT直接发布到/ services / oauth2 / token表单时,我得到相同的响应,如下所示:
grant_type =瓮%3Aietf%3Aparams%3Aoauth%3Agrant型%3Ajwt承载&安培;断言= k5ARCVFd1VgfOuM ...
我包含标题:
“内容类型”, “应用程序/ x WWW的形式进行了urlencoded”
使用以下方式生成JWT:
import com.payliquid.model.config.OAuthCredentials;
import org.apache.commons.codec.binary.Base64;
import org.joda.time.DateTime;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.cert.CertificateException;
public class JWTGenerator {
public static final String HEADER = "{\"alg\":\"RS256\"}";
public static final String CLAIM_TEMPLATE = "'{'\"iss\": \"%s\", \"prn\": \"%s\", \"aud\": \"%s\", \"exp\": \"%s\"'}'";
public static final String ALGORITHM = "SHA256withRSA";
private String audience;
private KeyStore keystore;
public JWTGenerator(String authServerURL, KeyStore keystore) {
this.audience = authServerURL;
this.keystore = keystore;
}
public String generateToken(OAuthCredentials oAuthCredentials, String clientId) {
final String certPassword = oAuthCredentials.getPassword();
final String principal = oAuthCredentials.getUserName();
final String certAlias = oAuthCredentials.getSecurityToken().get();
try {
StringBuilder jwTokenBuilder = new StringBuilder();
appendEncodedHeader(jwTokenBuilder);
appendSeparator(jwTokenBuilder);
final String joinedClaim = String.format(CLAIM_TEMPLATE, getClaimElements(clientId, principal));
appendEncodedClaim(jwTokenBuilder, joinedClaim);
PrivateKey privateKey = getPrivateKey(certPassword, certAlias);
String signedPayload = signPayload(jwTokenBuilder, privateKey);
appendSeparator(jwTokenBuilder);
jwTokenBuilder.append(signedPayload);
return jwTokenBuilder.toString();
} catch (Exception e) {
throw new OAuthRuntimeSystemException("Could not generate JWT Token", e);
}
}
private PrivateKey getPrivateKey(String certPassword, String certAlias) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
PrivateKey privateKey = loadPrivateKey(certAlias, certPassword);
if (privateKey == null) {
throw new OAuthRuntimeSystemException("Could not generate JWT Token as no private key available with " + certAlias);
}
return privateKey;
}
private String[] getClaimElements(String iss, String prn) {
return new String[]{
iss,
prn,
audience,
getExpirationTime()};
}
private String getExpirationTime() {
return new DateTime().plusMinutes(1).toDate().getTime() + "";
}
private void appendSeparator(StringBuilder token) {
token.append(".");
}
private PrivateKey loadPrivateKey(String certAlias, String privateKeyPassword) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
return (PrivateKey) keystore.getKey(certAlias, privateKeyPassword.toCharArray());
}
private String signPayload(StringBuilder token, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
Signature signature = Signature.getInstance(ALGORITHM);
signature.initSign(privateKey);
signature.update(getBytesInCharSet(token.toString()));
return encode(signature.sign());
}
private void appendEncodedClaim(StringBuilder token, String claim) throws UnsupportedEncodingException {
token.append(encode(claim));
}
private void appendEncodedHeader(StringBuilder token) throws UnsupportedEncodingException {
token.append(encode(HEADER));
}
private String encode(String payload) throws UnsupportedEncodingException {
final byte[] bytes = getBytesInCharSet(payload);
return encode(bytes);
}
private byte[] getBytesInCharSet(String s) throws UnsupportedEncodingException {
return s.getBytes("UTF-8");
}
private String encode(byte[] bytes) {
return Base64.encodeBase64URLSafeString(bytes);
}
}
有没有办法获得有关断言失败原因的更多信息,还是我需要对JWT或Salesforce Connected App或用户做更多的工作才能使其发挥作用?