我正在使用 Tomcat 8.5.59 并在 context.xml 中有以下领域:
<Realm className="org.apache.catalina.realm.LockOutRealm" >
<Realm className="org.apache.catalina.realm.DataSourceRealm" dataSourceName="jdbc/MyName" localDataSource="true">
<CredentialHandler className="org.apache.catalina.realm.NestedCredentialHandler">
<CredentialHandler className="org.apache.catalina.realm.SecretKeyCredentialHandler" />
<CredentialHandler className="org.apache.catalina.realm.MessageDigestCredentialHandler" algorithm="SHA-512" />
</CredentialHandler>
</Realm>
</Realm>
我想在我的 Java 应用程序中使用 CredentialHandler 来散列和存储密码。根据克里斯托弗·舒尔茨 (Christopher Schultz) 的演讲http://people.apache.org/~schultz/ApacheCon%20NA%202016/Seamless%20Upgrades%20for%20Credential%20Security%20in%20Apache%20Tomcat.pdf http://people.apache.org/%7Eschultz/ApacheCon%20NA%202016/Seamless%20Upgrades%20for%20Credential%20Security%20in%20Apache%20Tomcat.pdf我是这样理解的:
CredentialHandler ch = (CredentialHandler) application.getAttribute(Globals.CREDENTIAL_HANDLER);
问题是它返回一个空白/默认凭证处理程序,而不是我配置的凭证处理程序。
如果我删除 LockoutRealm 定义,它会正常工作,因此似乎有一个嵌套领域(LockoutRealm、DataSourceRealm)会导致它失败。翻看Tomcat代码,好像是调用的代码setAttribute(Globals.CREDENTIAL_HANDLER)
不需要CombinedRealm
考虑到。
如何在我的应用程序中获取配置的凭据处理程序,以便我可以调用 .matches() 和 .mutate() 方法?
我宁愿不删除锁定领域,因为这会损害安全性。
Edit:
此用例很常见:应用程序必须能够将变异的密码保存到数据库中,以便在用户登录时 tomcat 可以对其进行基于表单的身份验证。每次创建新的用户帐户时,用户的密码必须进行变异并保存到数据库中。
此外,当用户想要更改密码时,表单会询问当前密码和新密码 - .matches() 用于确认“当前”密码与现有密码匹配,然后再将其更改为新密码(这又是必须突变)。
使用上下文中定义的凭证处理程序对于确保密码按照 tomcat 所需的确切方式进行变异非常重要。另一种方法是为每个应用程序提供自己相应的库,鉴于 tomcat 已经拥有它们,这似乎很浪费且容易出错。
这一切都在我的问题开头的克里斯托弗·舒尔茨的链接中进行了描述。
我认为这都是相当标准的,Tomcat 提供了CredentialHandler ch = (CredentialHandler) application.getAttribute(Globals.CREDENTIAL_HANDLER)
以此目的。问题是该实现没有考虑使用 LockoutRealm - 它假设凭证处理程序是直接在顶级领域下定义的,所以我想知道这是否是 tomcat 中的监督/错误,或者它是否像那样工作通过设计,如果有某种方式我可以访问定义的 .mutate() 和 .matches() 函数CredentialHandler
同时还使用LockOutRealm
.
另外,tomcat曾经提供RealmBase.Digest(String credentials, String algorithm, String encoding)
对于这个用例,但该方法在 8.5 中已弃用并在 9 中删除,所以我明白CredentialHandler ch = (CredentialHandler) application.getAttribute(Globals.CREDENTIAL_HANDLER)
这是我们应该采取的新方式。
Edit 2:
getAttribute(Globals.CREDENTIAL_HANDLER)
返回默认值CredentialHandler
这根本不加密密码。调试器显示该类是StandardContext
。单步执行代码,一切似乎都是正确的,但它并没有深入到DataSourceRealm
得到定义的NestedCredentialHandler
,相反,它着眼于LockoutRealm
,没有找到直系子代CredentialHandler
,因此创建并返回一个默认值。我相信这是记录在https://tomcat.apache.org/tomcat-8.5-doc/config/credentialhandler.html https://tomcat.apache.org/tomcat-8.5-doc/config/credentialhandler.html:
CredentialHandler 元素必须嵌套在 Realm 组件内。如果未包含,则将使用 MessageDigestCredentialHandler 创建默认的 CredentialHandler。