Apache James数据库存储用户信息的密码加密问题

项目场景

Apache James邮件服务器使用数据库来存储用户信息的密码加密问题:

  1. 将James的用户改为数据库存储
  2. James密码是如何加密验证的

1.将James的用户改为数据库存储

1、修改存储方式

找到james-2.3.2\apps\james\SAR-INF\config.xml``

找到<users-store>标签,注释掉原来文件存储的方式,改为数据库的方式

maildb:是后面配置的数据源名称

mail_users:是存储用户信息的表名

XML 复制代码
<users-store>
  
  <!-- 注释掉原来文件存储的方式 -->
  <!--
  <repository name="LocalUsers" class="org.apache.james.userrepository.UsersFileRepository">
	 <destination URL="file://var/users/"/>
  </repository>
	 -->
  
  <!-- 改为数据库的方式 -->
  <repository name="LocalUsers" class="org.apache.james.userrepository.JamesUsersJdbcRepository" destinationURL="db://maildb/mail_users">
	 <sqlFile>file://conf/sqlResources.xml</sqlFile>
  </repository>

</users-store>

2.、配置数据库信息

找到<data-source>标签,根据具体数据库类型进行配置,下面已国产达梦数据库为例

maildb:数据源名称

XML 复制代码
<data-source name="maildb" class="org.apache.james.util.dbcp.JdbcDataSource">
	<driver>dm.jdbc.driver.DmDriver</driver>
	<dburl>jdbc:dm://127.0.0.1:5236/test_mail</dburl>
		<user>test</user>
	<password>test123</password>
	<max>50</max>
</data-source>

3、添加依赖包

因为我用的是达梦数据库,james里面没有这个数据库的依赖包,所以需要额外添加,如果是mysql、oracle常用的数据库就不需要再额外添加,因为james已经支持。

找到james-2.3.2\lib,然后把需要的依赖包放进去

4、创建用户表

正常情况下会自动创建,sql语句在james-2.3.2\apps\james\conf\sqlResources.xml

如果不会自动创建,那么自己把sql语句复制出来执行

sql 复制代码
CREATE TABLE "MAIL_USERS"
(
	"USERNAME" VARCHAR2(64) NOT NULL,
	"PWDHASH" VARCHAR2(50),
	"PWDALGORITHM" VARCHAR2(20),
	"USEFORWARDING" NUMBER(1,0),
	"FORWARDDESTINATION" VARCHAR2(255),
	"USEALIAS" NUMBER(1,0),
	"ALIAS" VARCHAR2(255),
	PRIMARY KEY("USERNAME")
);

COMMENT ON TABLE "MAIL_USERS" IS 'James邮件用户';
COMMENT ON COLUMN "MAIL_USERS"."PWDALGORITHM" IS '加密方式,默认SHA';
COMMENT ON COLUMN "MAIL_USERS"."PWDHASH" IS '加密后的密码';
COMMENT ON COLUMN "MAIL_USERS"."USERNAME" IS '邮箱帐号';

2.James密码是如何加密验证的

当你通过telnet添加新用户时,比如add user test 123456,你可以查看数据库中的记录,username字段是test,pwdhash是加密后的密码,pwdalgorithm字段是"SHA",显然用的是SHA加密方式。

让我们看下james源码是如何实现的,网上找到apache-james-2.3.2-src.zip源码文件,版本根据自己的来,然后用idea打开。

我们找到org.apache.james.userrepository.DefaultUser类

第一个方法verifyPassword()是用来做密码认证,传入的参数是明文密码,通过DigestUtil.digestString()方法,转换成密文密码,然后与数据库中密码作比较,返回比较结果。请注意这里的DigestUtil.digestString()方法,在后面还在提到。

第二个方法setPassword()是用于密码转换的,把明文转成密文,用的同样是DigestUtil.digestString()方法。

让我们再看下 org.apache.james.security.DigestUtil类,我们可以看到digestString加密的方法。

如果需要在自己的项目里去添加或修改用户的信息,这时候密码处理的逻辑肯定需要跟james一致,这时候我们把这个加密的方法拷贝用就行了 。

创建个DigestUtil类,然后调用DigestUtil.digestString()来获得加密后的密码。

java 复制代码
package com.mail;

import javax.mail.MessagingException;
import javax.mail.internet.MimeUtility;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class DigestUtil {

    public static String digestString(String pass, String algorithm )
            throws NoSuchAlgorithmException  {

        MessageDigest md;
        ByteArrayOutputStream bos;

        try {
            md = MessageDigest.getInstance(algorithm);
            byte[] digest = md.digest(pass.getBytes("iso-8859-1"));
            bos = new ByteArrayOutputStream();
            OutputStream encodedStream = MimeUtility.encode(bos, "base64");
            encodedStream.write(digest);
            return bos.toString("iso-8859-1");
        } catch (IOException ioe) {
            throw new RuntimeException("Fatal error: " + ioe);
        } catch (MessagingException me) {
            throw new RuntimeException("Fatal error: " + me);
        }
    }

    
    private DigestUtil() {}
}

加密支持的算法有MD5、SHA、SHA-256等 ,如果你想知道支持哪些算法,可以通过下面的代码列出所有支持的算法:

java 复制代码
import java.security.Security;
import java.security.Provider;
import java.security.Provider.Service;
 
public class ListAlgorithms {
    public static void main(String[] args) {
        for(Provider provider: Security.getProviders()) {
            for(Service service: provider.getServices()) {
                if ("MessageDigest".equals(service.getType())) {
                    System.out.println(service.getAlgorithm());
                }
            }
        }
    }
}

3.总结

集成java mail直接用明文帐号密码连接就行了,因为james会自己去加密验证,其他软件通过pop3配置,密码也是用明文就行了。

如果觉得这种连接方式不安全有两种解决方案:

  1. 修改james源码,比较麻烦。
  2. 密码在web端加密,传输到自己后台再解密,然后用解密后的密码连接james。
java 复制代码
import javax.mail.*;
import javax.mail.internet.*;
import java.util.*;
 
public class SendEmail {
    public static void main(String[] args) {
        String host = "smtp.example.com"; // SMTP服务器地址
        String username = "your-username"; // 用户名
        String password = "your-password"; // 密码
 
        Properties props = new Properties();
        props.put("mail.smtp.host", host);
        props.put("mail.smtp.auth", "true");
 
        Session session = Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        });
 
        try {
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress("from@example.com"));
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("to@example.com"));
            message.setSubject("Email Subject");
            message.setText("Email Body");
 
            Transport.send(message);
 
            System.out.println("Email sent successfully");
        } catch (MessagingException e) {
            throw new RuntimeException("Error sending email", e);
        }
    }
}
相关推荐
雾岛心情6 天前
【小铭邮件】小铭邮件管理工具箱之利用CSV同步日历
github·工具·邮件·小铭邮件工具箱·o365
袁煦丞 cpolar内网穿透实验室7 天前
MailHog邮件沙盒,本地邮件测试!cpolar内网穿透实验室第797个成功挑战
人工智能·远程工作·内网穿透·cpolar·邮件·安全内网连接·邮件沙盒
雾岛心情1 个月前
小铭邮件工具箱(公司版本)实现EML转PST文件
工具·邮件·小铭邮件工具箱·o365
雾岛心情1 个月前
小铭邮件工具箱之Office365邮件完全导出
工具·邮件·小铭邮件工具箱·小铭邮件工具箱(个人版)·o365
alwaysrun1 个月前
Python自动提取邮件订阅链接并解析
python·url·邮件·ai提取
潇凝子潇4 个月前
邮件中的链接偶尔会被自动点击 ,可能原因有哪些?以及对应的解决方案
邮件·超链接
玄同7654 个月前
Python 自动发送邮件实战:用 QQ/163 邮箱发送大模型生成的内容
开发语言·人工智能·python·深度学习·机器学习·邮件·邮箱
A-刘晨阳4 个月前
Prometheus + Grafana + Alertmanager 实现邮件监控告警及配置告警信息
运维·云计算·grafana·prometheus·监控·邮件
cws2004015 个月前
MFA双因素用户使用手册
运维·windows·网络安全·github·邮件·邮箱
一个帅气昵称啊5 个月前
.Net如何优雅的实现发送邮件服务
.net·mail·邮件