有没有办法调查在Salesforce中尝试OAuth 2.0 JWT Bearer Token Flow时收到的“无效声明”

时间:2015-04-03 19:32:15

标签: java oauth-2.0 salesforce jwt

我根据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或用户做更多的工作才能使其发挥作用?

0 个答案:

没有答案