Java 中的简单 Kerberos 客户端?

发布于 2024-11-03 11:26:55 字数 346 浏览 4 评论 0 原文

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

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

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

Applications such a Google's Chrome and IE can transparently handle Kerberos authentication; however I can not find a "simple" Java solution to match this transparency. All of the solutions I have found require the presence of a krb5.conf file and a login.conf file which nether of the above apps seem to require.

What is the best way to build a Java application with Kerberos SSO capabilities that just work?

[update]: to be clear I need a CLIENT side solution for creating tickets not validating them. Also, it seems that SPNEGO is the default "wrapper" protocol that will eventually delegate to Kerberos but I need to be able to handle the SPNEGO protocol as well.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

凑诗 2024-11-10 11:26:55

现在有一个简单的解决方案,使用 Apache HTTP 组件客户端 4.5 或更高版本。这在 4.5 中仍然被标记为实验性的,因此您的情况可能会有所不同,但这对我来说在企业环境中工作得很好。

除了 HC 4.5 客户端 jar 之外,您还需要在类路径上拥有 httpclient-win、jna 和 jna-platform jar,如 http-component-client 提供的那样。然后,您可以按如下方式构建启用 Kerberos 的 HC 客户端:

CloseableHttpClient httpclient = WinHttpClients.createDefault();

或者使用构建器:

HttpClientBuilder clientBuilder = WinHttpClients.custom();

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

CloseableHttpClient client = clientBuilder.build();

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

示例来自 http-components 团队的代码

这一切都归功于 Daniel Doubrovkine 蒂莫西·沃尔
瑞恩·麦金利

There is now a simple solution for this using the Apache HTTP Components Client 4.5 or greater. This is still marked as experimental in 4.5 so your milage may vary, but this is working fine for me in an enterprise context.

In addition to the HC 4.5 client jars you will need to have the httpclient-win, jna and jna-platform jars on your classpath, as provided with http-component-client. You then construct a Kerberos enabled HC-client as follows:

CloseableHttpClient httpclient = WinHttpClients.createDefault();

Or using the builder:

HttpClientBuilder clientBuilder = WinHttpClients.custom();

Which can then be customised as required before building the client:

CloseableHttpClient client = clientBuilder.build();

This solution works without any external configuration, and most importantly solves the issue where the in-built JRE mechanism breaks for users with local Admin rights on Windows 7+. This is possible because the Kerberos ticket is being retrieved directly from the SSPI API via JNA, rather than going through the GSSAPI provided by the JRE.

Example code from the http-components team

This was all made possible by the good work of Daniel Doubrovkine Timothy Wall
and Ryan McKinley

痴者 2024-11-10 11:26:55

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

您的代码有效的原因是因为您的目标 SPN(服务器端主体)配置为 HTTP/[电子邮件受保护]。在这种情况下,它会起作用,因为您没有显式设置令牌。 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)

Adding to David Roussels answer on url specific http based kerberos authentication:-

The reason why your code works is because your target SPN(server side principal) is configured to with HTTP/[email protected]. In that case it will work because you are not explicitly setting the token. URLConnection internally sets a token with that SPN

1 Perform steps(from my previous answer) to get a subject

2 Use gss api init sec context to generate a context token. There are numerous tutorials out there for this step

3 Base 64 encode the token

4 Attach the token to urlconnection:-

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

5 Implement a priviledged action:-

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

6 Wrap the whole thing in Subject.doAs

//use prev answer instructions to get subject
Subject.doAs(subject, new PrivilegedGetInputStream(urlConnection)
2024-11-10 11:26:55

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

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

Oracle has an example using Java's SaslClient. I'm not a Java programmer, but when I pointed this out once to someone who is, they were able to make it work pretty quickly. It may still require a "conf" file somewhere (n.b. Kerberos uses environment variables, often starting with KRB5_, to know where to look for such files). Also note that Kerberos itself does not include a transport of any kind--your app needs to know how to send and receive the Kerberos payloads the way the server expects (and this is different depending on the server you are trying to authenticate with).

Edit: you edited your question, so here's a link related to SPNEGO in Java which might be of some use:
http://download.oracle.com/javase/6/docs/technotes/guides/security/jgss/lab/part5.html

君勿笑 2024-11-10 11:26:55

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

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

并且协商身份验证正常工作。至少对我来说是这样。而且我测试的服务器只支持Negotiate,不支持NTLM auth。

You don't actually need to do anything. In Java 6, on a Windows client machine you can do this:

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

And negotiate authentication just works. At least it does for me. And the server I tested on only supports Negotiate, not NTLM auth.

东北女汉子 2024-11-10 11:26:55

好的,如果您想避免使用 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 主题和基本上可以做大量的身份验证工作。

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

Ok if you want to avoid using a login.conf file you need to code differently:-

//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 };
}

Now once you are done with this definition you can use this in you use this to fetch tickets from kdc

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

Now from here on you can fetch jaas subject and can basically do a ton of authentication stuff.

In case you need further pointers just leave a comment.

北恋 2024-11-10 11:26:55

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

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

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

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

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

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

You can use system properties instead of config files to specify the KDC hostname and service name, but those things (at least) are mandatory....

Waffle will actually give you the information you need to set most of the properties, even if it won't get you a ticket. Look at the WindowsAuthProviderImpl class (the Waffle.chm help file shows the API).

I use JAAS do obtain a service ticket from Active Directory in two steps:

  1. Use Krb5LoginModule to retrieve the cached TGT and add it to the Subject.

  2. Use the Subject and GSS-API to retrieve a service ticket from the KDC.

There's a lot of good information and example code at The Java Way of Active Directory.

自演自醉 2024-11-10 11:26:55

我创建了一个小工具来简化 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);

I created a small tool to simplify connecting with httpclient to kerberos, you might want to give it a try.
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);
清风无影 2024-11-10 11:26:55

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

Here's a good blog post on having a java client to use with Kerberos
http://sachithdhanushka.blogspot.com/2014/02/kerberos-java-client-configuration.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文