【问题标题】:Simple Kerberos client in Java?Java中的简单Kerberos客户端?
【发布时间】:2011-04-27 12:44:57
【问题描述】:

Google 的 Chrome 和 IE 等应用程序可以透明地处理 Kerberos 身份验证;但是我找不到与这种透明度相匹配的“简单”Java 解决方案。我发现的所有解决方案都需要存在 krb5.conf 文件和 login.conf 文件,上述应用似乎都不需要。

构建具有可正常工作的 Kerberos SSO 功能的 Java 应用程序的最佳方法是什么?

[更新]:需要明确的是,我需要一个 CLIENT 端解决方案来创建票证而不是验证票证。此外,似乎 SPNEGO 是默认的“包装器”协议,最终将委托给 Kerberos,但我也需要能够处理 SPNEGO 协议。

【问题讨论】:

标签: java kerberos


【解决方案1】:

现在有一个使用Apache HTTP Components Client 4.5 或更高版本的简单解决方案。这在 4.5 中仍然被标记为实验性的,所以你的里程可能会有所不同,但这在企业环境中对我来说很好用。

除了 HC 4.5 客户端 jar 之外,您还需要在类路径中包含 httpclient-win、jna 和 jna-platform jar,这些 jar 随 http-component-client 提供。然后构建一个启用 Kerberos 的 HC 客户端,如下所示:

CloseableHttpClient httpclient = WinHttpClients.createDefault();

或使用构建器:

HttpClientBuilder clientBuilder = WinHttpClients.custom();

然后可以在构建客户端之前根据需要进行自定义:

CloseableHttpClient client = clientBuilder.build();

此解决方案无需任何外部配置即可工作,最重要的是解决了在 Windows 7+ 上具有本地管理员权限的用户的内置 JRE 机制中断的问题。这是可能的,因为 Kerberos 票证是通过 JNA 直接从 SSPI API 检索的,而不是通过 JRE 提供的 GSSAPI。

Example code 来自 http-components 团队

这一切都归功于Daniel DoubrovkineTimothy Wall Ryan McKinley的出色工作

【讨论】:

  • 你确定这行得通吗?我检查了 4.4-SNAPSHOT 并在本地构建和安装它(到我的 Maven 存储库中)并尝试了上面的代码但无法进行身份验证。此示例中是否缺少某些内容,或者我只是做错了什么?
  • 它在我的环境中工作。出了什么问题?您是否打开了 HC 的调试输出?您确定要验证的服务具有正确的服务原则吗?
  • 我猜这个解决方案只有在您的 Windows/Active Directory 凭据(用户名/密码)与 Kerberos 服务器的用户名/密码相同时才有效。我有一个情况并非如此,上面的代码对我不起作用。有没有办法给它正确的用户名/密码?
  • 它在哪里被标记/记录为“实验性”?还是这样,你知道吗?
  • @NicholasDiPiazza 不需要用户名/密码,这就是重点!它通过 JNA 从操作系统获取当前登录用户的 Kerberos 令牌。
【解决方案2】:

添加到 David Roussels 关于 url 特定基于 http 的 kerberos 身份验证的答案:-

您的代码有效的原因是因为您的目标 SPN(服务器端主体)配置为使用 HTTP/serverhostname.realm.com@DOMAIN.COM。在这种情况下,它会起作用,因为您没有明确设置令牌。 URLConnection 在内部使用该 SPN 设置一个令牌

1 执行步骤(来自我之前的回答)以获取主题

2 使用 gss api init sec context 生成上下文令牌。这一步有很多教程

3 Base 64 编码令牌

4 将令牌附加到 urlconnection:-

URL url = new URL("http://myhost/myapp")
HttpURLConnection urlConn = (HttpURLConnection)url.openConnection(); = 
urlConn.setRequestProperty("Authorization", "Negotiate " + encodedToken);

5 实施特权操作:-

//this internally calls the getInputStream
public class PrivilegedGetInputStream implements PrivilegedExceptionAction<InputStream>

6 将整个内容包裹在 Subject.doAs 中

//use prev answer instructions to get subject
Subject.doAs(subject, new PrivilegedGetInputStream(urlConnection)

【讨论】:

【解决方案3】:

Oracle 有an example using Java's SaslClient。我不是 Java 程序员,但是当我向其他人指出这一点时,他们能够让它很快工作。它可能仍然需要某个地方的“conf”文件(n.b. Kerberos 使用环境变量,通常以 KRB5_ 开头,以了解在哪里查找此类文件)。另请注意,Kerberos 本身不包含任何类型的传输——您的应用程序需要知道如何以服务器期望的方式发送和接收 Kerberos 有效负载(这取决于您尝试进行身份验证的服务器)。

编辑:你编辑了你的问题,所以这里有一个与 Java 中的 SPNEGO 相关的链接,它可能有一些用处: http://download.oracle.com/javase/6/docs/technotes/guides/security/jgss/lab/part5.html

【讨论】:

    【解决方案4】:

    您实际上不需要做任何事情。在 Java 6 中,您可以在 Windows 客户端计算机上执行以下操作:

    new URL("http://myhost/myapp").openStream();
    

    协商身份验证就可以了。至少它对我有用。而且我测试的服务器只支持Negotiate,不支持NTLM auth。

    【讨论】:

    • 这与创建 Kerberos 票据有什么关系?
    • 最初的问题是“构建具有 Kerberos SSO 功能的 Java 应用程序的最佳方法是什么?”。我指出 Java 6 在 Windows 上为您执行 SPNEGO 身份验证,因此您不需要处理 krb5.conf。 Kerberos 在下面使用。它只是工作,比我预期的要好得多。请注意,这确实意味着您必须使用默认的 HTTP 客户端,并且不能使用 apache commons http 库。
    • 现在我明白你在说什么了。有时间我得试一试。
    • 我想我很密集,但 URL 似乎没有 getInputStream() 方法,你的意思是 openStream() (虽然在相同的设置下这对我不起作用描述。
    • 啊,是的,我的意思是 openStream()。您是使用安装程序安装 JRE,还是只是解压缩它?也许安装程序会采取一些措施使其正常工作。
    【解决方案5】:

    好的,如果您想避免使用 login.conf 文件,您需要进行不同的编码:-

    //define your own configuration
    import javax.security.auth.login.Configuration;
    public class CustomLoginConfiguration extends Configuration
    
    //pass certain parameters to its constructor
    //define an config entry
    import javax.security.auth.login.AppConfigurationEntry;
    private AppConfigurationEntry configEntry;
    
    //define a map of params you wish to pass and fill them up
    //the map contains entries similar to one you have in login.conf
    Map<String, String> params = new HashMap<String, String>();
    
    //define the configuration
    configEntry = new AppConfigurationEntry(
                "com.sun.security.auth.module.Krb5LoginModule",
                AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, params);
    
    //implement getappconfig method
    public AppConfigurationEntry[] getAppConfigurationEntry() {
        return new AppConfigurationEntry[] { configEntry };
    }
    

    现在,一旦你完成了这个定义,你就可以使用它来从 kdc 获取票证

    //get ticket in login context
    LoginContext lc = null;
        lc = new LoginContext("lc", null, callback, new CustomLoginConfiguration(argumentlist));
        lc.login();
    

    现在从这里开始,您可以获取 jaas 主题,并且基本上可以进行大量的身份验证工作。

    如果您需要进一步的指示,请发表评论。

    【讨论】:

      【解决方案6】:

      您可以使用系统属性而不是配置文件来指定 KDC 主机名和服务名,但这些东西(至少)是强制性的......

      Waffle 实际上会为您提供设置大多数属性所需的信息,即使它不会为您提供票证。查看 WindowsAuthProviderImpl 类(Waffle.chm 帮助文件显示了 API)。

      我使用 JAAS 确实分两步从 Active Directory 获取服务票证:

      1. 使用 Krb5LoginModule 检索缓存的 TGT 并将其添加到主题中。

      2. 使用主题和 GSS-API 从 KDC 检索服务票证。

      The Java Way of Active Directory 有很多很好的信息和示例代码。

      【讨论】:

        【解决方案7】:

        我创建了一个小工具来简化与 httpclient 到 kerberos 的连接,您可能想尝试一下。 https://github.com/DovAmir/httpclientAuthHelper

        DefaultHttpClient httpclient = new DefaultHttpClient();
        AuthUtils.securityLogging(SecurityLogType.KERBEROS,true);
        CredentialsUtils.setKerberosCredentials(client, new UsernamePasswordCredentials("xxx", "xxx"), "domain", "kdc");
        client.executeMethod(httpget);
        

        【讨论】:

        • 假设我有一个在 *nix 中运行的客户端应用程序,一个 Active Directory 令牌,现在我需要验证它,并从令牌/AD 服务器获取用户@域和组列表。这可能吗?
        【解决方案8】:

        使用WAFFLE

        【讨论】:

        • 那是服务器站点,不是客户端。
        • 它也支持客户端。
        【解决方案9】:

        这是一篇关于让 Java 客户端与 Kerberos 一起使用的好博文 http://sachithdhanushka.blogspot.com/2014/02/kerberos-java-client-configuration.html

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-16
          • 1970-01-01
          • 1970-01-01
          • 2015-08-16
          • 1970-01-01
          相关资源
          最近更新 更多