现在的位置: 首页 > 综合 > 正文

xmpp with openfire 之四 扩展AuthProvider

2011年02月10日 ⁄ 综合 ⁄ 共 30043字 ⁄ 字号 评论关闭
上一篇中提到jdbcAuthProvider.passwordType提供了三种方式

如果你的密码加密规则不是这三种方式,可以自己进行扩充

首先,下载openfire的源码
http://www.igniterealtime.org/downloads/source.jsp

打开org.jivesoftware.openfire.auth.JDBCAuthProvider

Java代码 复制代码
  1. package org.jivesoftware.openfire.auth;   
  2.   
  3. import org.jivesoftware.database.DbConnectionManager;   
  4. import org.jivesoftware.openfire.XMPPServer;   
  5. import org.jivesoftware.openfire.user.UserAlreadyExistsException;   
  6. import org.jivesoftware.openfire.user.UserManager;   
  7. import org.jivesoftware.openfire.user.UserNotFoundException;   
  8. import org.jivesoftware.util.JiveGlobals;   
  9. import org.jivesoftware.util.Log;   
  10. import org.jivesoftware.util.StringUtils;   
  11.   
  12. import java.sql.*;   
  13.   
  14. /**  
  15.  * The JDBC auth provider allows you to authenticate users against any database  
  16.  * that you can connect to with JDBC. It can be used along with the  
  17.  * {@link HybridAuthProvider hybrid} auth provider, so that you can also have  
  18.  * XMPP-only users that won't pollute your external data.<p>  
  19.  *  
  20.  * To enable this provider, set the following in the system properties:  
  21.  * <ul>  
  22.  * <li><tt>provider.auth.className = org.jivesoftware.openfire.auth.JDBCAuthProvider</tt></li>  
  23.  * </ul>  
  24.  *  
  25.  * You'll also need to set your JDBC driver, connection string, and SQL statements:  
  26.  *  
  27.  * <ul>  
  28.  * <li><tt>jdbcProvider.driver = com.mysql.jdbc.Driver</tt></li>  
  29.  * <li><tt>jdbcProvider.connectionString = jdbc:mysql://localhost/dbname?user=username&amp;password=secret</tt></li>  
  30.  * <li><tt>jdbcAuthProvider.passwordSQL = SELECT password FROM user_account WHERE username=?</tt></li>  
  31.  * <li><tt>jdbcAuthProvider.passwordType = plain</tt></li>  
  32.  * <li><tt>jdbcAuthProvider.allowUpdate = true</tt></li>  
  33.  * <li><tt>jdbcAuthProvider.setPasswordSQL = UPDATE user_account SET password=? WHERE username=?</tt></li>  
  34.  * </ul>  
  35.  *  
  36.  * The passwordType setting tells Openfire how the password is stored. Setting the value  
  37.  * is optional (when not set, it defaults to "plain"). The valid values are:<ul>  
  38.  *      <li>{@link PasswordType#plain plain}  
  39.  *      <li>{@link PasswordType#md5 md5}  
  40.  *      <li>{@link PasswordType#sha1 sha1}  
  41.  *  </ul>  
  42.  *  
  43.  * @author David Snopek  
  44.  */  
  45. public class JDBCAuthProvider implements AuthProvider {   
  46.   
  47.     private String connectionString;   
  48.   
  49.     private String passwordSQL;   
  50.     private String setPasswordSQL;   
  51.     private PasswordType passwordType;   
  52.     private boolean allowUpdate;   
  53.   
  54.     /**  
  55.      * Constructs a new JDBC authentication provider.  
  56.      */  
  57.     public JDBCAuthProvider() {   
  58.         // Convert XML based provider setup to Database based   
  59.         JiveGlobals.migrateProperty("jdbcProvider.driver");   
  60.         JiveGlobals.migrateProperty("jdbcProvider.connectionString");   
  61.         JiveGlobals.migrateProperty("jdbcAuthProvider.passwordSQL");   
  62.         JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");   
  63.         JiveGlobals.migrateProperty("jdbcAuthProvider.setPasswordSQL");   
  64.         JiveGlobals.migrateProperty("jdbcAuthProvider.allowUpdate");   
  65.   
  66.         // Load the JDBC driver and connection string.   
  67.         String jdbcDriver = JiveGlobals.getProperty("jdbcProvider.driver");   
  68.         try {   
  69.             Class.forName(jdbcDriver).newInstance();   
  70.         }   
  71.         catch (Exception e) {   
  72.             Log.error("Unable to load JDBC driver: " + jdbcDriver, e);   
  73.             return;   
  74.         }   
  75.         connectionString = JiveGlobals.getProperty("jdbcProvider.connectionString");   
  76.   
  77.         // Load SQL statements.   
  78.         passwordSQL = JiveGlobals.getProperty("jdbcAuthProvider.passwordSQL");   
  79.         setPasswordSQL = JiveGlobals.getProperty("jdbcAuthProvider.setPasswordSQL");   
  80.   
  81.         allowUpdate = JiveGlobals.getBooleanProperty("jdbcAuthProvider.allowUpdate",false);   
  82.   
  83.         passwordType = PasswordType.plain;   
  84.         try {   
  85.             passwordType = PasswordType.valueOf(   
  86.                     JiveGlobals.getProperty("jdbcAuthProvider.passwordType""plain"));   
  87.         }   
  88.         catch (IllegalArgumentException iae) {   
  89.             Log.error(iae);   
  90.         }   
  91.     }   
  92.   
  93.     public void authenticate(String username, String password) throws UnauthorizedException {   
  94.         if (username == null || password == null) {   
  95.             throw new UnauthorizedException();   
  96.         }   
  97.         username = username.trim().toLowerCase();   
  98.         if (username.contains("@")) {   
  99.             // Check that the specified domain matches the server's domain   
  100.             int index = username.indexOf("@");   
  101.             String domain = username.substring(index + 1);   
  102.             if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {   
  103.                 username = username.substring(0, index);   
  104.             } else {   
  105.                 // Unknown domain. Return authentication failed.   
  106.                 throw new UnauthorizedException();   
  107.             }   
  108.         }   
  109.         String userPassword;   
  110.         try {   
  111.             userPassword = getPasswordValue(username);   
  112.         }   
  113.         catch (UserNotFoundException unfe) {   
  114.             throw new UnauthorizedException();   
  115.         }   
  116.         // If the user's password doesn't match the password passed in, authentication   
  117.         // should fail.   
  118.         if (passwordType == PasswordType.md5) {   
  119.             password = StringUtils.hash(password, "MD5");   
  120.         }   
  121.         else if (passwordType == PasswordType.sha1) {   
  122.             password = StringUtils.hash(password, "SHA-1");   
  123.         }   
  124.         if (!password.equals(userPassword)) {   
  125.             throw new UnauthorizedException();   
  126.         }   
  127.   
  128.         // Got this far, so the user must be authorized.   
  129.         createUser(username);   
  130.     }   
  131.   
  132.     public void authenticate(String username, String token, String digest)   
  133.             throws UnauthorizedException   
  134.     {   
  135.         if (passwordType != PasswordType.plain) {   
  136.             throw new UnsupportedOperationException("Digest authentication not supported for "  
  137.                     + "password type " + passwordType);   
  138.         }   
  139.         if (username == null || token == null || digest == null) {   
  140.             throw new UnauthorizedException();   
  141.         }   
  142.         username = username.trim().toLowerCase();   
  143.         if (username.contains("@")) {   
  144.             // Check that the specified domain matches the server's domain   
  145.             int index = username.indexOf("@");   
  146.             String domain = username.substring(index + 1);   
  147.             if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {   
  148.                 username = username.substring(0, index);   
  149.             } else {   
  150.                 // Unknown domain. Return authentication failed.   
  151.                 throw new UnauthorizedException();   
  152.             }   
  153.         }   
  154.         String password;   
  155.         try {   
  156.             password = getPasswordValue(username);   
  157.         }   
  158.         catch (UserNotFoundException unfe) {   
  159.             throw new UnauthorizedException();   
  160.         }   
  161.         String anticipatedDigest = AuthFactory.createDigest(token, password);   
  162.         if (!digest.equalsIgnoreCase(anticipatedDigest)) {   
  163.             throw new UnauthorizedException();   
  164.         }   
  165.   
  166.         // Got this far, so the user must be authorized.   
  167.         createUser(username);   
  168.     }   
  169.   
  170.     public boolean isPlainSupported() {   
  171.         // If the auth SQL is defined, plain text authentication is supported.   
  172.         return (passwordSQL != null);   
  173.     }   
  174.   
  175.     public boolean isDigestSupported() {   
  176.         // The auth SQL must be defined and the password type is supported.   
  177.         return (passwordSQL != null && passwordType == PasswordType.plain);   
  178.     }   
  179.   
  180.     public String getPassword(String username) throws UserNotFoundException,   
  181.             UnsupportedOperationException   
  182.     {   
  183.   
  184.         if (!supportsPasswordRetrieval()) {   
  185.             throw new UnsupportedOperationException();   
  186.         }   
  187.         if (username.contains("@")) {   
  188.             // Check that the specified domain matches the server's domain   
  189.             int index = username.indexOf("@");   
  190.             String domain = username.substring(index + 1);   
  191.             if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {   
  192.                 username = username.substring(0, index);   
  193.             } else {   
  194.                 // Unknown domain.   
  195.                 throw new UserNotFoundException();   
  196.             }   
  197.         }   
  198.         return getPasswordValue(username);   
  199.     }   
  200.   
  201.     public void setPassword(String username, String password)   
  202.             throws UserNotFoundException, UnsupportedOperationException   
  203.     {   
  204.         if (allowUpdate && setPasswordSQL != null) {   
  205.             setPasswordValue(username, password);   
  206.         } else {    
  207.             throw new UnsupportedOperationException();   
  208.         }   
  209.     }   
  210.   
  211.     public boolean supportsPasswordRetrieval() {   
  212.         return (passwordSQL != null && passwordType == PasswordType.plain);   
  213.     }   
  214.   
  215.     /**  
  216.      * Returns the value of the password field. It will be in plain text or hashed  
  217.      * format, depending on the password type.  
  218.      *  
  219.      * @param username user to retrieve the password field for  
  220.      * @return the password value.  
  221.      * @throws UserNotFoundException if the given user could not be loaded.  
  222.      */  
  223.     private String getPasswordValue(String username) throws UserNotFoundException {   
  224.         String password = null;   
  225.         Connection con = null;   
  226.         PreparedStatement pstmt = null;   
  227.         ResultSet rs = null;   
  228.         if (username.contains("@")) {   
  229.             // Check that the specified domain matches the server's domain   
  230.             int index = username.indexOf("@");   
  231.             String domain = username.substring(index + 1);   
  232.             if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {   
  233.                 username = username.substring(0, index);   
  234.             } else {   
  235.                 // Unknown domain.   
  236.                 throw new UserNotFoundException();   
  237.             }   
  238.         }   
  239.         try {   
  240.             con = DriverManager.getConnection(connectionString);   
  241.             pstmt = con.prepareStatement(passwordSQL);   
  242.             pstmt.setString(1, username);   
  243.   
  244.             rs = pstmt.executeQuery();   
  245.   
  246.             // If the query had no results, the username and password   
  247.             // did not match a user record. Therefore, throw an exception.   
  248.             if (!rs.next()) {   
  249.                 throw new UserNotFoundException();   
  250.             }   
  251.             password = rs.getString(1);   
  252.         }   
  253.         catch (SQLException e) {   
  254.             Log.error("Exception in JDBCAuthProvider", e);   
  255.             throw new UserNotFoundException();   
  256.         }   
  257.         finally {   
  258.             DbConnectionManager.closeConnection(rs, pstmt, con);   
  259.         }   
  260.         return password;   
  261.     }   
  262.   
  263.     private void setPasswordValue(String username, String password) throws UserNotFoundException {   
  264.         Connection con = null;   
  265.         PreparedStatement pstmt = null;   
  266.         ResultSet rs = null;   
  267.         if (username.contains("@")) {   
  268.             // Check that the specified domain matches the server's domain   
  269.             int index = username.indexOf("@");   
  270.             String domain = username.substring(index + 1);   
  271.             if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {   
  272.                 username = username.substring(0, index);   
  273.             } else {   
  274.                 // Unknown domain.   
  275.                 throw new UserNotFoundException();   
  276.             }   
  277.         }   
  278.         try {   
  279.             con = DriverManager.getConnection(connectionString);   
  280.             pstmt = con.prepareStatement(setPasswordSQL);   
  281.             pstmt.setString(1, username);   
  282.             if (passwordType == PasswordType.md5) {   
  283.                 password = StringUtils.hash(password, "MD5");   
  284.             }   
  285.             else if (passwordType == PasswordType.sha1) {   
  286.                 password = StringUtils.hash(password, "SHA-1");   
  287.             }   
  288.             pstmt.setString(2, password);   
  289.   
  290.             rs = pstmt.executeQuery();   
  291.   
  292.         }   
  293.         catch (SQLException e) {   
  294.             Log.error("Exception in JDBCAuthProvider", e);   
  295.             throw new UserNotFoundException();   
  296.         }   
  297.         finally {   
  298.             DbConnectionManager.closeConnection(rs, pstmt, con);   
  299.         }   
  300.            
  301.     }   
  302.   
  303.     /**  
  304.      * Indicates how the password is stored.  
  305.      */  
  306.     @SuppressWarnings({"UnnecessarySemicolon"})  // Support for QDox Parser   
  307.     public enum PasswordType {   
  308.   
  309.         /**  
  310.          * The password is stored as plain text.  
  311.          */  
  312.         plain,   
  313.   
  314.         /**  
  315.          * The password is stored as a hex-encoded MD5 hash.  
  316.          */  
  317.         md5,   
  318.   
  319.         /**  
  320.          * The password is stored as a hex-encoded SHA-1 hash.  
  321.          */  
  322.         sha1;   
  323.     }   
  324.   
  325.     /**  
  326.      * Checks to see if the user exists; if not, a new user is created.  
  327.      *  
  328.      * @param username the username.  
  329.      */  
  330.     private static void createUser(String username) {   
  331.         // See if the user exists in the database. If not, automatically create them.   
  332.         UserManager userManager = UserManager.getInstance();   
  333.         try {   
  334.             userManager.getUser(username);   
  335.         }   
  336.         catch (UserNotFoundException unfe) {   
  337.             try {   
  338.                 Log.debug("JDBCAuthProvider: Automatically creating new user account for " + username);   
  339.                 UserManager.getUserProvider().createUser(username, StringUtils.randomString(8),   
  340.                         nullnull);   
  341.             }   
  342.             catch (UserAlreadyExistsException uaee) {   
  343.                 // Ignore.   
  344.             }   
  345.         }   
  346.     }   
  347. }  

看以看到通过读取PASSWORDTYPE配置

Java代码 复制代码
  1. JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");   
  2. 。。。。。   
  3. 。。。。。   
  4. 。。。。。   
  5. passwordType = PasswordType.plain;     
  6.         try {     
  7.             passwordType = PasswordType.valueOf(     
  8.                     JiveGlobals.getProperty("jdbcAuthProvider.passwordType""plain"));     
  9.         }     
  10.         catch (IllegalArgumentException iae) {     
  11.             Log.error(iae);     
  12.         }    

进行密码的验证

Java代码 复制代码
  1. if (passwordType == PasswordType.md5) {   
  2.            password = StringUtils.hash(password, "MD5");   
  3.        }   
  4.        else if (passwordType == PasswordType.sha1) {   
  5.            password = StringUtils.hash(password, "SHA-1");   
  6.        }   
  7.        if (!password.equals(userPassword)) {   
  8.            throw new UnauthorizedException();   
  9.        }  

这样完全可以仿照JDBCAuthProvider重新构造

Java代码 复制代码
  1. package org.yxsoft.openfire.plugin;   
  2.   
  3.   
  4. import org.jivesoftware.openfire.user.UserNotFoundException;   
  5. import org.jivesoftware.openfire.auth.*;   
  6. import org.jivesoftware.openfire.XMPPServer;   
  7. import org.jivesoftware.util.JiveGlobals;   
  8. import org.jivesoftware.util.Log;   
  9. import org.jivesoftware.util.StringUtils;   
  10. import org.jivesoftware.database.DbConnectionManager;   
  11.   
  12. import java.sql.*;   
  13. import java.security.MessageDigest;   
  14.   
  15. /**  
  16.  * Created by cl  
  17.  * Date: 2008-9-4  
  18.  * Time: 9:18:26  
  19.  * 仿照JDBCAuthProvider  
  20.  * 在数据库连接上 支持user/password  
  21.  * 密码验证 使用bfmp的机制  
  22.  */  
  23. public class BfmpAuthProvider implements AuthProvider {   
  24.     private String connectionString;   
  25.     private String user;   
  26.     private String password;   
  27.   
  28.     private String passwordSQL;   
  29.     private String setPasswordSQL;   
  30.     private PasswordType passwordType;   
  31.     private boolean allowUpdate;   
  32.   
  33.     /**  
  34.      * 初始化  
  35.      * 比JDBCAuthProvider多支持  
  36.      * JiveGlobals.migrateProperty("jdbcProvider.url");  
  37.         JiveGlobals.migrateProperty("jdbcProvider.user");  
  38.         JiveGlobals.migrateProperty("jdbcProvider.password");  
  39.      */  
  40.     public BfmpAuthProvider() {   
  41.         // Convert XML based provider setup to Database based   
  42.         JiveGlobals.migrateProperty("jdbcProvider.driver");   
  43.         JiveGlobals.migrateProperty("jdbcProvider.url");   
  44.         JiveGlobals.migrateProperty("jdbcProvider.user");   
  45.         JiveGlobals.migrateProperty("jdbcProvider.password");   
  46.   
  47.         JiveGlobals.migrateProperty("jdbcAuthProvider.passwordSQL");   
  48.         JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");   
  49.         JiveGlobals.migrateProperty("jdbcAuthProvider.setPasswordSQL");   
  50.         JiveGlobals.migrateProperty("jdbcAuthProvider.allowUpdate");   
  51.         JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");   
  52.   
  53.         // Load the JDBC driver and connection string.   
  54.         String jdbcDriver = JiveGlobals.getProperty("jdbcProvider.driver");   
  55.         try {   
  56.             Class.forName(jdbcDriver).newInstance();   
  57.         }   
  58.         catch (Exception e) {   
  59.             Log.error("Unable to load JDBC driver: " + jdbcDriver, e);   
  60.             return;   
  61.         }   
  62.         connectionString = JiveGlobals.getProperty("jdbcProvider.url");   
  63.         user = JiveGlobals.getProperty("jdbcProvider.user");   
  64.         password = JiveGlobals.getProperty("jdbcProvider.password");   
  65.   
  66.         // Load SQL statements.   
  67.         passwordSQL = JiveGlobals.getProperty("jdbcAuthProvider.passwordSQL");   
  68.         setPasswordSQL = JiveGlobals.getProperty("jdbcAuthProvider.setPasswordSQL");   
  69.   
  70.         allowUpdate = JiveGlobals.getBooleanProperty("jdbcAuthProvider.allowUpdate",false);   
  71.   
  72.         passwordType = PasswordType.plain;   
  73.         try {   
  74.             passwordType = PasswordType.valueOf(   
  75.                     JiveGlobals.getProperty("jdbcAuthProvider.passwordType""plain"));   
  76.             Log.error("PasswordType:"+ passwordType);   
  77.         }   
  78.         catch (IllegalArgumentException iae) {   
  79.             Log.error(iae);   
  80.         }   
  81.     }   
  82.   
  83.     public boolean isPlainSupported() {   
  84.         //default   
  85.         return true;   
  86.     }   
  87.   
  88.     public boolean isDigestSupported() {   
  89.         //default   
  90.         return true;   
  91.     }   
  92.   
  93.     public void authenticate(String username, String password) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {   
  94.         if (username == null || password == null) {   
  95.             throw new UnauthorizedException();   
  96.         }   
  97.         Log.error(username+":"+password);   
  98.         username = username.trim().toLowerCase();   
  99.         if (username.contains("@")) {   
  100.             Log.error(username+":"+XMPPServer.getInstance().getServerInfo().getXMPPDomain());   
  101.             // Check that the specified domain matches the server's domain   
  102.             int index = username.indexOf("@");   
  103.             String domain = username.substring(index + 1);   
  104.             if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {   
  105.                 username = username.substring(0, index);   
  106.             } else {   
  107.                 // Unknown domain. Return authentication failed.   
  108.                 throw new UnauthorizedException();   
  109.             }   
  110.         } else {   
  111.             Log.error("user name not contains ");   
  112.         }   
  113.         String userPassword;   
  114.         try {   
  115.             userPassword = getPasswordValue(username);   
  116.         }   
  117.         catch (UserNotFoundException unfe) {   
  118.             throw new UnauthorizedException();   
  119.         }   
  120.         // If the user's password doesn't match the password passed in, authentication   
  121.         // should fail.   
  122.         if (passwordType == PasswordType.bfmp) {   
  123.             //这里BfmpMD5 就是自己的密码规则   
  124.             password = BfmpMD5(password);   
  125.         }   
  126.   
  127.         if (!password.equals(userPassword)) {   
  128.             throw new UnauthorizedException();   
  129.         }   
  130.   
  131.         // Got this far, so the user must be authorized.   
  132.         //createUser(username);   
  133.     }   
  134.   
  135.     public void authenticate(String username, String token, String digest) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {   
  136.         if (passwordType != PasswordType.plain) {   
  137.             throw new UnsupportedOperationException("Digest authentication not supported for "  
  138.                     + "password type " + passwordType);   
  139.         }   
  140.         if (username == null || token == null || digest == null) {   
  141.             throw new UnauthorizedException();   
  142.         }   
  143.         username = username.trim().toLowerCase();   
  144.         if (username.contains("@")) {   
  145.             // Check that the specified domain matches the server's domain   
  146.             int index = username.indexOf("@");   
  147.             String domain = username.substring(index + 1);   
  148.             if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {   
  149.                 username = username.substring(0, index);   
  150.             } else {   
  151.                 // Unknown domain. Return authentication failed.   
  152.                 throw new UnauthorizedException();   
  153.             }   
  154.         }   
  155.         String password;   
  156.         try

抱歉!评论已关闭.