警告:这是一篇极其漫长的帖子,仅仅是因为我不知道如何以其他方式解释我们的具体问题(对不起)。
简短版本:
我们正在构建一个非常模块化的Java应用程序套件(包括客户端和服务器端)。某些客户端必须对服务器进行身份验证,并且服务器可以针对不同类型的用户存储进行身份验证。服务器还可以代表其经过身份验证的用户呼叫其他服务器,即使用其凭据。到目前为止,这已经使用简单的用户名/密码凭证工作正常,但现在我们必须通过Kerberos(以及后来的其他身份验证系统)选择性地支持SSO。到目前为止,我们失败了(部分悲惨)。
长版:
我们用于处理主体的中央Java库称为用户访问层(UAL)。该库由客户端和服务器应用程序使用,并提供三种类型的功能:
(2)和(3)可以使用调用者指定的凭据或(如果后端支持)作为技术用户执行。
对用户存储的实际访问权限由配置的后端处理。我们提供了许多后端(LDAP,WebDAV,自定义JDBC数据库,自定义XML文件),这些后端都可以通过统一的配置文件进行配置,通常名为useraccess.xml。该文件定义了应该使用哪个后端(或后端)以及如何配置它,例如: LDAP后端的LDAP服务器和结构数据,或数据库后端的数据库URL和数据库用户凭据。所有后端都实现相同的接口,因此应用程序代码独立于为特定安装配置的后端。
在我们的产品中,UAL由两种不同类型的应用程序使用:
客户端(用户在浏览器中打开的命令行/桌面客户端和Web前端应用程序)。这些应用程序使用UAL执行主要查询(例如,在修改WebDAV资源的ACL时我们的文件浏览器应用程序)或主要修改(我们有基于Web的用户管理应用程序)。根据应用程序,他们可以通过以下方式之一获取用于其UAL操作的凭据: 一个。用户在调用应用程序时在命令行上提供凭据 湾应用程序打开一个对话框,并在服务器访问需要时提示用户输入凭据 C。用户首次访问Web前端应用程序时显示的登录屏幕
服务器。哪个使用UAL: 一个。根据使用的协议(例如HTTP / WebDAV或SOAP / WSSE)提供的凭据对用户进行身份验证 湾根据用户(或用户的组')属性为用户执行授权 C。代表客户端执行UAL操作(查询/修改) d。代表客户端呼叫其他服务器,即将另一个服务器传递给用户的凭证(例如,通过HTTP / WebDAV或SOAP / WSSE)
到目前为止,我们所有的凭据都是用户名/密码对,只要我们确保将这些凭据保留在用户会话中,以便以后使用它们访问其他服务器,这些凭据就可以正常工作。我们可以这样做,每次检索凭据或将它们传递给服务器的调用都会通过我们的一些代码来存储/提供必要的凭据。
要求通过Kerberos支持SSO,一切都变得更加复杂。我们已经尝试了几种方法并多次修改了我们的代码库,但每次我们相信它们都在正确的轨道上时,我们意识到我们忽略了一个无法按照我们预期的方式工作的地方。
让事情变得如此令人困惑的是我们必须以几种不同的方式处理凭据。这些是我们向服务器提供凭据的一些方法:
我们必须从客户端接收和验证凭据的一些方法:
我们的一个非常常见的用例如下:
问题是:互联网上的信息似乎很少,无法帮助解决我们的具体问题。对于初学者,大多数资源仅描述如何为容器设置JAAS配置文件以使其Web应用程序执行用户身份验证。但是我们的代码必须在客户端和服务器上运行,并使用一个配置文件为身份验证和主要查询/修改指定用户存储配置。此外,这必须使用相同的代码,针对各种用户存储(其中一些是自定义编写的)和针对LDAP服务器的Kerberos(以及后来的其他)票证使用用户名/密码凭证。最后,它还不足以拥有一个可靠地告诉我们用户已提供正确凭据的身份验证库(正如许多JAAS登录模块似乎那样),因为我们实际上必须保留用户的凭据进一步的电话。
由于Apache Jackrabbit是我们的核心组件之一,它需要我们配置JAAS登录模块,并且已经有用于LDAP和Kerberos身份验证的JAAS登录模块,我们已成功修改UAL以执行其所有身份验证通过JAAS完成任务。为此我们有两个用于自定义后端的写入登录模块,我必须实现自己的LDAP登录模块,因为默认的JAAS会成功地针对LDAP服务器对用户进行身份验证,但随后丢弃了用户的凭据和LDAP上下文,因此我们无法使用相同的凭据执行进一步的LDAP查询。我们所有自己的登录模块都将凭证存储在经过身份验证的主题的私有凭证集中,这也是JAAS默认的Kerberos登录模块所做的事情。使用生成的主题,我们可以执行用户查询。这适用于我们所有的后端以及密码和Kerberos票证。
我们还能够修改SOAP服务以从SOAP消息中提取凭据。在密码凭证的情况下,我们可以在身份验证回调请求凭据时将它们简单地传递给JAAS。但是,似乎没有办法对Kerberos票证执行相同的操作。相反,我们的SOAP服务当前处理它们,通过必要的GSS API调用传递它们以验证票证,检索SOAP服务的配置服务用户的匹配票证,并创建包含凭证和用户的Subject。信息。使用此主题,我们可以通过UAL执行查询/修改。但是,这不仅意味着我们的SOAP服务在验证Kerberos票证时完全绕过UAL,除了useraccess.xml之外,它们还需要在自己的配置中使用一些Kerberos配置数据(服务用户名,领域和密钥表文件)。它已包含相同的数据(但不能直接访问通用UAL客户端,因为这些设置特定于UAL LDAP / Kerberos后端)。显然,当我们添加对其他基于票证的身份验证方法的支持时,事情只会变得更糟,除了实际处理用户存储访问的UAL后端之外,还必须在每个SOAP服务中手动实现。
最糟糕的是,我们仍然不确定如何将所有这些都放入基于Jackrabbit的WebDAV服务器中。 Jackrabbit需要一个登录模块,该模块应该可以处理用户名/密码凭证,但是(据我们所知)Kerberos票证失败。我们可以从HTTP头中手动获取这些内容,但是这不会让Jackrabbit停止调用登录模块和登录模块失败,因为它仍然会要求输入密码,然后在没有密码的情况下无法对Kerberos进行身份验证。 / p>
我不能动摇这种感觉,无论是我们的方法还是(很可能)我们对所有这些部件如何组合在一起的理解都存在根本缺陷,但我们在网上找不到的任何内容都足以满足我们的要求我们做错了什么(或者更重要的是,应该怎样做才能做到正确)。由于甚至描述我们的问题的复杂性,我到目前为止一直避免将这个问题作为一个问题发布,但如果您已经阅读了这篇文章并且可以给我们任何有关如何解决这个问题的指示,那么您可以将我们从挫折。
答案 0 :(得分:2)
您可以在
之后删除所有内容到目前为止,我们所有的凭据都是用户名/密码对,只要我们确保将这些凭据保存在用户的会话中,以便以后使用它们访问其他服务器,它们就可以正常工作。我们可以这样做,每次检索凭据或将它们传递给服务器的调用都会通过我们的一些代码来存储/提供必要的凭据。
您的问题很简单:您需要使用Kerberos进行凭据委派。基本技术非常简单。由于这里有多个问题区域,我建议将它们分解以解决问题:
由于您的入站频道是HTTP,因此以下是答案:
GSSContext.requestCredDeleg(true)
一样简单。详细说明其余部分。Principal
方法提供的HttpServletRequest#getPrincipal
实现中。GSSCredential
实例传递给客户端lib,其余的应该是。 (2)隐式:在PrivilegedAction
中包裹您的客户端操作,使用私有Subject
构建GSSCredential
并使用两者调用Subject.doAs
。 JAAS将使用线程主题中的隐式凭证,并代表您的用户执行操作。好像你还没有达到第2点或第3点。