Apache James使用者資訊的資料庫儲存和密碼問題
阿新 • • 發佈:2019-01-03
一、James簡介
Apache James(Java Apache Mail Enterprise Server)是Apache組織的子專案之一,完全採用純Java技術開發,實現了SMTP、POP3與NNTP等多種郵件相關協議。
James也是一個郵件應用平臺,可以通過Mailet擴充其功能,如Mail2SMS、Mail2Fax等。James提供了比較完善的配置方案,尤其是關於郵件內容儲存和使用者資訊儲存部分,可以選擇在檔案、資料庫或其他介質中儲存。
James效能穩定、可配置性強,還是開源專案,所有原始碼不存在版權問題,因此,James在專案中的應用日益廣泛,現在常用版本為2.1,但最新版本2.3已經推出,在本文中,我們將仍以James2.1作為介紹藍本。
二、一個假設的專案
假設我要以James為郵件伺服器,開發一套基於Web的郵件系統,就像263.net,163.net一樣,要求實現線上註冊、線上收發郵件等功能。
預設情況下,James的使用者資訊儲存在文字中,雖然加了密,但由於文字存檔不足,不便於查詢及相應處理,幸好James提供了多種使用者資訊儲存方案,如資料庫儲存,LDAP儲存等。
這裡我們將以資料庫儲存為例,講解使用者資訊的管理,資料庫採用MySQL。當然你也可以採用LDAP,比如免費的OpenLDAP,功能非常強大。
三、使用者資訊的資料庫儲存
James郵件使用者的使用者資訊預設儲存在apps/james/var/users目錄下,通過修改配置檔案apps/james/SAR-INF/config.xml,可以把使用者資訊儲存到資料庫中,配置方法如下:
第一步:在MySQL中新建一個數據庫mail,使用者名稱root,密碼為空;
第二步:開啟config.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/users"> <sqlFile>file://conf/sqlResources.xml</sqlFile> </repository> |
通過修改,我們就把使用者資訊的儲存介質從file改成了db,<sqlFile>是指明瞭在db中的資料表結構及相關資料庫資訊。
第三步:仍然是config.xml,找到<data-sources>項,預設內容為空,把此項內容修改為:
<data-source name="maildb" class="org.apache.james.util.mordred.JdbcDataSource"> <driver>org.gjt.mm.mysql.Driver</driver> <dburl>jdbc:mysql://127.0.0.1/mail</dburl> <user>root</user> <password></password> <max>20</max> </data-source> |
<driver>是指MySQL的JDBC驅動,<dburl>指資料庫的訪問路徑,IP後的mail即MySQL中新建資料庫名,接下來是使用者名稱、密碼及最大連線數。
至此,資料庫配置完成,啟動James,若正常無誤,請通過telnet新增一個新使用者,比如adduser holen 123456,然後檢查MySQL中的mail資料庫,下面將有一個表users,這是James根據file://conf/sqlResources.xml的內容建立的。
通過以上配置,James的使用者資訊就可以儲存在資料庫中了。
四、密碼問題
當你通過telnet新增新使用者時,比如adduser holen 123456,你可以檢視資料庫中的記錄,第一個欄位是holen,第二欄位是密碼,但密碼並非123456,而一串“亂碼”(zhwQUMTwdMqWfm/h0biB51Gf)??這是加密碼後的密碼內容,再看後面的欄位是“SHA”,顯然用的是SHA加密方式。
通過telnet方式新增新使用者,使用者密碼將自動加密,然後插入資料庫中。但通過telnet方式進行使用者管理有著諸多不便,儘管你可以藉助James的一個RMI工具包,提高效率,但仍然沒有本質改變,當需要用作商業用途時,你更不能要求你的客戶熟記那一堆命令符。
一般我們可以做一個Web前端,通過網頁形式,新增修改使用者,介面友好,傻瓜化使用,如263或163一樣。若這樣做,我們就需要直接操作資料庫,新增使用者記錄或修改刪除使用者記錄了。但別忘了,James預設對使用者密碼是加密的,既然我們要直接操作資料庫,那麼我們只有兩個選擇:要麼我們研究其密碼機制,新增記錄時,我們對新增使用者的密碼進行同樣加密,要麼我們去掉James的加密機制,使其明碼儲存。
幸好,這兩種選擇都是可行的。我們從Apache網站下載James的原始碼包,下載後的檔案為james-2.1-src.zip,接近8M,通過分析原始碼,我們發現,與使用者密碼相關的檔案是DefaultUser.java,部分原始碼如下:
package org.apache.james.userrepository; …… /** * Method to verify passwords. * * @param pass the String that is claimed to be the password for this user * @return true if the hash of pass with the current algorithm matches * the stored hash. */ public boolean verifyPassword(String pass) { try { String hashGuess = DigestUtil.digestString(pass, algorithm); return hashedPassword.equals(hashGuess); } catch (NoSuchAlgorithmException nsae) { throw new RuntimeException("Security error: " + nsae); } } /** * Sets new password from String. No checks made on guessability of * password. * * @param newPass the String that is the new password. * @return true if newPass successfuly hashed */ public boolean setPassword(String newPass) { try { hashedPassword = DigestUtil.digestString(newPass, algorithm); return true; } catch (NoSuchAlgorithmException nsae) { throw new RuntimeException("Security error: " + nsae); } } …… |
第一個方法verifyPassword()是用來做密碼認證,傳入的引數是明文密碼,通過DigestUtil.digestString()方法,轉換成密文密碼,然後與資料庫中密碼作比較,返回比較結果。請注意這裡的DigestUtil.digestString()方法,在後面還在提到。
第二個方法setPassword()是用於密碼轉換的,把明文轉成密文,用的同樣是DigestUtil.digestString()方法。
談到這裡,相信你應該知道怎麼在自己的程式中進行密碼轉換和密碼認證了吧!其實並不是要你自己去寫一個SHA的加密演算法,既然James已經提供了此功能,你呼叫便是了。
還有一種情況,開發者需要在資料庫中必須用明文儲存密碼,這樣就不必在自己寫的程式中進行密碼轉換了,而且當多個應用系統採用統一使用者模型時,最好只有一個使用者例項。要實現這個需求,就只能修改James原始碼了,把verifyPassword()方法和setPassword()改成:
public boolean verifyPassword(String pass) { return hashedPassword.equals(pass); } public boolean setPassword(String newPass) { hashedPassword = newPass; return true; } |
其實就是把轉換過程去掉,儲存和認證就都採用明文進行了。
你要是覺得SHA方式不妥,也可以掛接別的加密方式,同樣是修改這兩個方法。
注意,當你修改了James的原始碼後,你需要用Ant重新build James專案,build後將在james-2.1-src/dist/james-2.1/apps下面找到新生成的james.sar檔案。把該檔案覆蓋James原來james.sar,並刪除與james.sar同級的james目錄,重啟動james即可。建議保留原來的config.xml,免得又配一次。
通過以上探討,我們明白瞭如何通過Web方式進行使用者註冊和使用者登記等。需要說明一點是,James自動生成的users表中只有7個欄位,而且都是系統需要使用的。一般註冊時需要輸入的資訊項比較多,這時建議開發者自己再建一個新表USERINFO,用username把兩個表關聯起來,不建議修改users表的內容(如果想試試,請參考file://conf/sqlResources.xml)。
五、基於James的郵件系統開發方案簡述
James執行在Win2000上,客戶端採用Web介面(仿263風格)、Foxmail或OutLook Express,該系統主要面向1000人以下的中小企業。
基於James的郵件開發,主要包括兩個方面:一是郵件系統的後臺管理,另一個是客戶端應用系統。
後臺管理的功能主要包括使用者的新增、刪除、修改、使用者使用空間指配、郵件備份等。
Web客戶端功能包括收件箱、發郵件、發件箱、草稿箱、回收站、地址本、自定義資料夾、配置等。
使用者資訊儲存在MySQL資料庫中,郵件內容預設儲存在文件中。
系統採用Struts架構,執行環境為Apache1.3+Tomcat4.1,資料庫連線池採用Tomcat自帶的DBCP。
系統開發預計需60人天完成,開發人員需要掌握Struts和JavaMail。
壓力測試超過50個併發。
六、參考資料
James 2.1 Documentation