使用bcrypt编写自定义tomcat域

Mal*_*iel 5 java authentication tomcat hsqldb bcrypt

我正在使用Tomcat 7.0作为应用程序服务器开发基于Java的Web应用程序.在对先前问题的有用回答之后,我决定使用bcrypt在我的HSQLDB中安全地存储密码.但是Tomcat的默认Realm实现无法处理bcrypt,所以我需要编写自己的; 这是我写一个自定义领域的唯一原因,尽管在其他所有方面都可以使用JDBCRealm.我一直在谷歌搜索并查看示例,我对两点感到困惑.

首先,我应该扩展RealmBase还是JDBCRealm?我发现的大多数例子都使用了RealmBase,但到目前为止我已成功使用JDBCRealm作为应用程序(因为它仍在开发中,我开始将密码存储在纯文本中,只是使用JDBCRealm来处理身份验证),并且一个答案是关于Code Ranch的一个问题建议只是扩展它.不过,我不确定在这种情况下我需要覆盖哪些方法.只是验证方法,还是更多?如果这样做,JDBCRealm仍然能够处理和管理用户角色,getPrincipal,以及所有这些?

其次,在上面链接的CodeRanch示例中,除非我遗漏了某些内容,否则getPassword方法似乎返回了未加密的密码.因为我将要使用不可能的bcrypt,而且无论如何它似乎都是不可取的,我想.在此博客文章中的其他示例中,getPassword似乎只是直接从数据库返回密码.那么哪种方式是正确的?我找不到getPassword的用途; 文档没有说.为此可以返回存储在数据库中的加密值吗?

如果有人能告诉我应该扩展哪个类,我应该覆盖哪些方法,以及getPassword应该返回什么,我真的很感激.

Mal*_*iel 4

经过一番尝试和错误后,我想出了如何做到这一点。我扩展了 JDBCRealm,只覆盖了验证方法,它工作得很好。我将BCrypt.java放在与我的自定义领域相同的目录中,以下代码有效:

import java.security.Principal;
import org.apache.catalina.realm.JDBCRealm;
public class BCryptRealm extends JDBCRealm
{
  @Override
  public Principal authenticate(String username, String credentials)
  {
    String hashedPassword = getPassword(username);
    // Added this check after discovering checkpw generates a null pointer
    // error if the hashedPassword is null, which happens when the user doesn't
    // exist. I'm assuming returning null immediately would be bad practice as
    // it would let an attacker know which users do and don't exist, so I added
    // a call to hashpw. No idea if that completely solves the problem, so if
    // your application has more stringent security needs this should be
    // investigated further.
    if (hashedPassword == null)
    {
      BCrypt.hashpw("fakePassword", BCrypt.gensalt());
      return null;
    }
    if (BCrypt.checkpw(credentials, hashedPassword))
    {
      return getPrincipal(username);
    }
    return null;
  }
}
Run Code Online (Sandbox Code Playgroud)