【问题标题】:Generate SPNEGO Token Failured生成 SPNEGO 令牌失败
【发布时间】:2019-09-25 04:39:40
【问题描述】:

我尝试生成可用作 HTTP 标头的令牌,以对 HDFS WebHDFS URL 和 Oozie REST API URL 进行身份验证。 我引用了下面的 url 以使用下面的代码生成 Negotiate 令牌。 https://www.ibm.com/support/knowledgecenter/en/SS7JFU_8.5.5/com.ibm.websphere.express.doc/ae/tsec_SPNEGO_token.html

public class TokenCreation {
  private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
  private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
  public static byte[] genToken(String principal) {
    System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
    byte[] spnegoToken = new byte[0];
    try {
      Oid spnegoMechOid = new Oid(SPNEGO_OID);
      Oid krb5MechOid = new Oid(KERBEROS_OID);
      GSSCredential clientGssCreds = null;
      GSSManager manager = GSSManager.getInstance();
      GSSName gssUserName = manager.createName(principal, GSSName.NT_USER_NAME, krb5MechOid);
      clientGssCreds = manager.createCredential(gssUserName.canonicalize(krb5MechOid),
          GSSCredential.INDEFINITE_LIFETIME,
          krb5MechOid,
          GSSCredential.INITIATE_ONLY);
      clientGssCreds.add(gssUserName,
          GSSCredential.INDEFINITE_LIFETIME,
          GSSCredential.INDEFINITE_LIFETIME,
          spnegoMechOid, GSSCredential.INITIATE_ONLY);
      GSSName gssServerName = manager.createName(principal, GSSName.NT_USER_NAME);
      GSSContext clientContext = manager.createContext(gssServerName.canonicalize(spnegoMechOid),
          spnegoMechOid,
          clientGssCreds,
          GSSContext.DEFAULT_LIFETIME);
      // optional enable GSS credential delegation
      clientContext.requestCredDeleg(true);
      // create a SPNEGO token for the target server
      spnegoToken = clientContext.initSecContext(spnegoToken, 0, spnegoToken.length);
    } catch (GSSException e) {
      e.printStackTrace();
    }
    return spnegoToken;
  }

但是运行上面的代码后,总是得到如下提示:

2019-09-25 14:12:51 760 [INFO] [pool-2-thread-1] c.s.n.c.u.security.KrbUtils - after loginUserFromKeytab............AtoimcUser:HTTP/host1.exmaple.com@EXAMPLE.COM
2019-09-25 14:12:51 760 [INFO] [pool-2-thread-1] c.s.n.app.oozie.OozieAppCaller - ->>>>>>User Name is HTTP/host1.exmaple.com@EXAMPLE.COM
2019-09-25 14:12:51 760 [INFO] [pool-2-thread-1] c.s.n.app.oozie.OozieAppCaller - ->>>>>>Mode is KERBEROS
>>>KinitOptions cache name is /tmp/krb5cc_0
Kerberos username [root]: ^C^C^C
Kerberos password for root:

您可以在上面的输出日志的末尾看到。 “Kerberos 用户名”总是提示询问用户名。

我还尝试手动运行 kinit keytab。 上面的类可以成功生成令牌。 但是手动运行 kinit 不是我想要的方式。

你能帮忙吗? 谢谢。

【问题讨论】:

  • 我做了一些搜索,发现上面的 TokenCreation 类在运行 UserGroupInformation.loginUserFromKeytab 后似乎无法生成令牌?
  • 你能解释一下为什么你搞乱了低级别的 Kerberos 凭据管理,而本机 Java HTTP 客户端支持开箱即用的 SPNego? (其他 HTTP 客户端,例如来自 Apache 的客户端可能存在错误)
  • Hadoop UserGroupInformation 使用自定义库(部分)覆盖 Kerberos 的默认 Java 实现(在 JAAS 内部),原因有好有坏(两种实现都有限且脆弱且难以无论如何调试)——当你使用 UGI 来“从 keytab 登录”时,它总是会创建一个 private 票证,该票证不会被推送到票证缓存中。因此,您不能从 JAAS 使用它。
  • 要在 JAAS 中启用调试跟踪(转储到 StdOut / StdErr),请使用 -Dsun.security.krb5.debug=true 和 -Djava.security.debug=gssloginconfig,configfile,configparser‌​,logincontext >> 输出并不漂亮,正如您可以从加密库中所期望的那样...
  • ...以及-Dsun.security.spnego.debug=true 使用本机 HTTP 客户端时

标签: kerberos spnego gssapi


【解决方案1】:

不幸的是,Java 中的 Kerberos 和 SPNEGO 支持很麻烦。

我创建了一个小型库来简化一些 Kerberos 用例:https://github.com/bedrin/kerb4j 您可以像这样使用它来生成 SPNEGO 令牌:

SpnegoClient spnegoClient = SpnegoClient.loginWithKeyTab("svc_consumer", "/opt/myapp/consumer.keytab");
URL url = new URL("http://api.provider.acme.com/api/operation1");
SpnegoContext context = spnegoClient.createContext("http://provider.acme.com"); // Will result in HTTP/provider.acme.com SPN
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization", context.createTokenAsAuthroizationHeader());

【讨论】:

  • 对不起,我是 kerberos 的新手,如果我想访问 httpfs url,例如http<:>,你代码中的哪一部分 URL 应该被替换?请问http<:>是什么意思?谢了。
  • 由于历史原因,我的项目中不得不依赖原始的 Jersey 客户端,所以我只想提取令牌,然后将其添加到请求头中,如“Authorization:Negotiate ",不确定它是否有效。
  • context.createTokenAsAuthroizationHeader() 将返回令牌。为了生成它,您需要提供在 Kerberos 服务器(Active Directory?)中注册的目标主机名 - 这就是 provider.acme.com 的含义
  • 我用你的方式生成token,但是发现我的代码中只有一个实例可以成功获得授权,而其他实例总是返回“Request is a replay 34”,你知道如何解决是吗?谢谢。
猜你喜欢
  • 2022-10-13
  • 2017-10-06
  • 2019-06-26
  • 2020-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多