当前位置: 首页 > 知识库问答 >
问题:

在Java中验证、使用和重用密码和Kerberos凭据

鄂昌胤
2023-03-14

警告:这是一篇非常长的帖子,仅仅是因为我不知道如何以其他方式解释我们的具体问题(抱歉)。

短版:

我们正在构建一个非常模块化的Java应用程序套件(客户端和服务器端)。一些客户端必须针对服务器进行身份验证,服务器可以针对不同类型的用户存储进行身份验证。服务器还可以代表其经过身份验证的用户调用其他服务器,即使用其凭据。到目前为止,使用简单的用户名/密码凭据可以很好地工作,但现在我们必须通过Kerberos(以及稍后的其他身份验证系统)选择性地支持SSO。到目前为止,我们正在失败(部分是悲惨的)。

长版:

我们用于处理主体的中央Java库称为用户访问层(UAL)。该库被客户端和服务器应用程序使用,并提供三种类型的功能:

  1. 根据用户的凭据对用户进行身份验证(导致身份验证失败或有关用户的基本信息,即至少登录名或ID)
  2. 执行主体查询
  3. 在用户存储中执行主体修改,如果后端支持的话

(2)和(3)可以使用调用者指定的凭证或者(如果后端支持的话)作为技术用户来执行。

对用户存储的实际访问由配置的后端处理。我们提供了许多后端(LDAP、WebDAV、自定义JDBC数据库、自定义XML文件),它们都可以通过统一的配置文件进行配置,通常命名为useraccess.xml.该文件定义了应该使用哪个后端(或多个后端)以及如何配置,例如LDAP后端的LDAP服务器和结构数据或数据库后端的数据库URL和数据库用户凭据。所有后端实现相同的接口,因此应用程序代码独立于为特定安装配置的后端。

在我们的产品中,UAL用于两种不同类型的应用:

>

  • 客户端(用户在浏览器中打开的命令行/桌面客户端和web前端应用程序)。这些应用程序使用UAL来执行主要查询(例如,当修改WebDAV资源的ACL时,我们的文件浏览器应用程序)或主要修改(我们有一个基于web的用户管理应用程序)。根据应用程序的不同,他们通过以下方式之一获得用于其UAL操作的凭据:a.用户在调用应用程序时在命令行上提供凭据b.应用程序在服务器访问需要时打开对话框并提示用户输入凭据c.用户首次访问web前端应用程序时显示登录屏幕

    服务器。它们使用UAL来:a.根据通过所用协议提供的凭据对用户进行身份验证(例如HTTP/WebDAV或SOAP/WSSE)b.根据用户(或用户组)的属性对用户进行授权c.代表客户端执行UAL操作(查询/修改)d.代表客户端调用其他服务器,即,向另一台服务器传递用户凭据(例如,通过HTTP/WebDAV或SOAP/WSSE)

    到目前为止,我们所有的凭据都是用户名/密码对,只要我们确保在必要时将这些凭据保存在用户的会话中以便以后使用它们访问另一台服务器,就可以正常工作。我们可以做到,每个检索凭据或将它们传递到服务器的调用都会通过我们的一些代码来存储/提供必要的凭据。

    由于需要通过Kerberos支持SSO,一切都变得更加复杂。我们已经尝试了几种方法,并修改了我们的代码库几次,但每次我们相信是在正确的轨道上时,我们都会意识到有一个地方我们忽略了,不能按照我们预期的方式工作。

    让事情变得如此混乱的是,我们必须以几种不同的方式处理凭证。以下是我们向服务器提供凭证的一些方法:

      < li >访问HTTP/WebDAV服务器时通过Apache HTTP client < li >访问web服务时通过SOAP/WSSE < li >通过JNDI访问LDAP服务器(在UAL)

    以及我们必须从客户端接收和验证凭据的一些方法:

    1. 作为阿帕奇杰克兔的登录模块
    2. 在我们的某个 JAX-WS 网络服务中接收到 SOAP/WSE 消息时

    下面是我们的一个非常常见的使用案例:

    1. 客户端通过SOAP调用服务器A,提供凭据
    2. 服务器A从SOAP消息中检索凭据并验证它们(如果它们无效(身份验证错误)或用户无权执行所需操作(授权错误),则响应错误)
    3. 然后服务器A代表用户调用WebDAV服务器B,传递用户的凭据,以便可以使用该用户的权限(并使用该用户的名称和其他属性)执行WebDAV操作
    4. 服务器B从HTTP消息中检索凭据并验证它们
    5. 然后,服务器B对用户存储C执行主体查询,将用户的凭据传递给用户存储(取决于配置的UAL后端,这可能只是将用户的名称和密码与用户存储XML文件中的名称和密码进行比较,或者使用它们来建立LDAP连接并以该用户的身份查询LDAP存储)

    问题是:互联网上似乎没有什么信息可以帮助解决我们的具体问题。首先,大多数资源只是描述如何为容器设置JAAS配置文件,让其Web应用程序执行用户身份验证。但是我们的代码必须在客户端和服务器上运行,并使用一个配置文件来指定用于身份验证和主体查询/修改的用户存储配置。此外,这必须使用相同的代码,针对各种用户存储(其中一些是自定义编写的)使用用户名/密码凭据,并针对LDAP服务器使用Kerberos(以及后来的其他)票证。最后,仅仅有一个身份验证库是不够的,它可靠地告诉我们用户已经提供了正确的凭据(就像许多JAAS登录模块似乎做的那样),因为我们实际上必须保留用户的凭据以供进一步调用。

    由于我们的核心组件之一的底层 Apache 杰克兔需要我们配置一个 JAAS 登录模块,并且已经有用于 LDAP 和 Kerberos 认证的 JAAS 登录模块,因此我们已成功修改 UAL 以通过 JAAS 执行其所有认证任务。为此,我们有两个用于自定义后端的写入登录模块,我必须实现我自己的 LDAP 登录模块,因为默认的 JAAS 模块将针对 LDAP 服务器成功验证用户身份,但随后会丢弃用户的凭据和 LDAP 上下文,因此我们无法使用相同的凭据执行进一步的 LDAP 查询。我们自己的所有登录模块都将凭证存储在经过身份验证的使用者的私有凭证集中,这也是 JAAS 的默认 Kerberos 登录模块所做的。使用生成的主题,我们可以执行用户查询。这适用于我们所有的后端以及密码和 Kerberos 票证。

    我们还能够修改我们的SOAP服务,从SOAP消息中提取凭证。在密码凭证的情况下,当认证回调要求凭证时,我们可以简单地将它们传递给JAAS。然而,对于Kerberos票证,似乎没有一种方法可以做到这一点。相反,我们的SOAP服务目前自己处理这些,通过必要的GSS API调用传递它们以验证票证,为SOAP服务的已配置服务用户检索匹配的票证,并创建包含凭证和用户信息的主题。使用这个主题,我们可以通过UAL执行查询/修改。然而,这不仅意味着我们的SOAP服务在认证Kerberos票据时完全绕过UAL,它们还需要一些Kerberos配置数据(服务用户名、领域和keytab文件)在它们自己的配置中,除了已经包含相同数据的useraccess.xml(但是一般的UAL客户机不能直接访问,因为这些设置是特定于UAL LDAP/Kerberos后端的)。显然,当我们添加对其他基于票证的身份验证方法的支持时,事情只会变得更糟,除了实际处理用户存储访问的UAL后端之外,还必须在每个SOAP服务中手动实现这些方法。

    最糟糕的是,我们仍然不确定如何将所有这些内容纳入我们基于Jackrabbit的WebDAV服务器。Jackrabbit需要一个登录模块,该模块可以处理用户名/密码凭据,但对于Kerberos票证(据我们所知)失败。我们可能可以从HTTP头中手动获取这些信息,但这不会阻止Jackrabbit调用登录模块,登录模块也会失败,因为它仍然会要求输入密码,然后在没有密码的情况下无法根据Kerberos进行身份验证。

    我无法摆脱这样的感觉,我们的方法或者(很可能)我们对所有这些部分应该如何组合在一起的理解是有根本缺陷的,但是我们在网上找不到足够的需求来指出我们做错了什么(或者,更重要的是,应该如何做才能纠正它)。因为描述我们的问题很复杂,所以我一直避免把它作为一个问题提出来,但是如果你已经读到这里,并且可以给我们任何解决问题的建议,你可以让我们避免几个星期的沮丧。

  • 共有1个答案

    郎宏浚
    2023-03-14

    之后您可以删除所有内容

    到目前为止,我们所有的凭据都是用户名/密码对,只要我们确保在必要时将这些凭据保存在用户的会话中以便以后使用它们访问另一台服务器,就可以正常工作。我们可以做到,每个检索凭据或将它们传递到服务器的调用都会通过我们的一些代码来存储/提供必要的凭据。

    您的问题很简单:您需要Kerberos的凭证委托。基本技术很简单。由于您在这里有多个问题领域,我建议将它们分开来解决您的问题:

    1. Kerberos凭据委派的OS/环境配置
    2. 如何请求可委派服务令牌
    3. 如何从客户端检索委托的TGT
    4. 如何重用客户端的TGT并请求另一个服务令牌

    因为你的入站通道是HTTP,所以下面是答案:

      < li >如果您在Active Directory环境中,请要求您的管理员在将接受GSS安全上下文的机器帐户上设置"委托信任"。 < li >这有点棘手,因为它取决于客户端语言和库。在Java中,这就像设置< code > gsscontext . requestcreddeleg(true)一样简单。其余的用硼酸盐。 < li >检查我的Tomcat SPNEGO/AD验证器库的代码,我正在提取客户端的TGT,并将其存储在< code > http servlet request # get Principal 方法提供的< code>Principal实现中。 < li >假设您的后端客户端库正确支持GSS-API,基本上有两种方法:(1)显式凭据使用:将委托的< code>GSSCredential实例传递给客户端库,其余的由客户端库完成。(2)隐式:将您的客户端操作包装在一个< code>PrivilegedAction中,用private < code > GSS credential 构造一个< code>Subject,并用两者调用< code>Subject.doAs。JAAS将使用来自线程主题的隐式凭据,并代表您的用户执行操作。

    你好像还没到第2点或第3点。

     类似资料:
    • 在我的登录PHP文件中,我有这些 在我的注册PHP文件中,我有这个。 现在,基本上我使它哈希密码,并插入自己的数据库注册。确实如此。 然而,它无法核实。这两个结果给出了两个不同的哈希,我不知道我可能做错了什么。我也试着让它再次散列输入并检查数据库中的password_hash,但那不起作用... 正确的使用方法是什么? (另外,$passSign和$userInput是输入字段,它确实获取用户名/

    • 我用哈希法通过了一个密码 这将密码作为哈希值存储到数据库中。但是当我试图通过 无论密码是否正确,它都会告诉我密码是正确的。有没有办法解决这个问题,所以我可以散列密码,但登录时输入(非散列)密码。

    • 我正在使用以下代码创建哈希密码和salt: 我正在数据库中存储HashedPassword和Salt。 现在我要验证用户登录时的密码: 这不起作用,我得到了一个完全不同的哈希密码,而不是存储在数据库中的密码。据我所知,您应该在用户登录时输入的密码之前预置salt,然后运行相同的哈希密码函数。上面不是等价于那个吗?

    • 我正在尝试在SoapUI中发出SOAP请求,它需要使用用户名和密码进行身份验证。我让SoapUI基于wsdl文件生成一个测试,并尝试调用该服务。我按照SoapUI网站上的步骤使用身份验证(https://www.soapui.org/soap-and-wsdl/authenticating-soap-requests.html),但我不能让它工作。我不熟悉SOAP,所以我可能缺少一些基本的东西。我

    • 我有一个用户登录Html表单,我在其中获取用户的电子邮件和密码并根据数据库检查它们。到目前为止,我有以下代码,但当我提交表单时,它不会转到指定的JSP页面。我可以做些什么来改进我的代码,以及当用户按下提交但仍留在同一页面上时,我如何生成错误消息? 提前谢谢你。 //SERVLET doPost方法 //前向法 //HTML表单

    • 我对仅使用bcrypt的用户名和密码的用户注册验证有特定要求(没有设计!) 我目前正在工作: 我需要: 用户名: 只能包含字母、数字、短划线和下划线 必须至少包含一个大写字母、一个特殊字符、一个数字和一个小写字母