您的位置:首页 > 运维架构

xmpp with openfire之四 扩展的AuthProvider

2015-03-31 02:52 465 查看
上一篇中提到jdbcAuthProvider.passwordType提供了三种方式

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

首先,下载openfire的源码

http://www.igniterealtime.org/downloads/source.jsp

打开org.jivesoftware.openfire.auth.JDBCAuthProvider

Java代码


package org.jivesoftware.openfire.auth;

import org.jivesoftware.database.DbConnectionManager;

import org.jivesoftware.openfire.XMPPServer;

import org.jivesoftware.openfire.user.UserAlreadyExistsException;

import org.jivesoftware.openfire.user.UserManager;

import org.jivesoftware.openfire.user.UserNotFoundException;

import org.jivesoftware.util.JiveGlobals;

import org.jivesoftware.util.Log;

import org.jivesoftware.util.StringUtils;

import java.sql.*;

/**

* The JDBC auth provider allows you to authenticate users against any database

* that you can connect to with JDBC. It can be used along with the

* {@link HybridAuthProvider hybrid} auth provider, so that you can also have

* XMPP-only users that won't pollute your external data.<p>

*

* To enable this provider, set the following in the system properties:

* <ul>

* <li><tt>provider.auth.className = org.jivesoftware.openfire.auth.JDBCAuthProvider</tt></li>

* </ul>

*

* You'll also need to set your JDBC driver, connection string, and SQL statements:

*

* <ul>

* <li><tt>jdbcProvider.driver = com.mysql.jdbc.Driver</tt></li>

* <li><tt>jdbcProvider.connectionString = jdbc:mysql://localhost/dbname?user=username&password=secret</tt></li>

* <li><tt>jdbcAuthProvider.passwordSQL = SELECT password FROM user_account WHERE username=?</tt></li>

* <li><tt>jdbcAuthProvider.passwordType = plain</tt></li>

* <li><tt>jdbcAuthProvider.allowUpdate = true</tt></li>

* <li><tt>jdbcAuthProvider.setPasswordSQL = UPDATE user_account SET password=? WHERE username=?</tt></li>

* </ul>

*

* The passwordType setting tells Openfire how the password is stored. Setting the value

* is optional (when not set, it defaults to "plain"). The valid values are:<ul>

* <li>{@link PasswordType#plain plain}

* <li>{@link PasswordType#md5 md5}

* <li>{@link PasswordType#sha1 sha1}

* </ul>

*

* @author David Snopek

*/

public class JDBCAuthProvider implements AuthProvider {

private String connectionString;

private String passwordSQL;

private String setPasswordSQL;

private PasswordType passwordType;

private boolean allowUpdate;

/**

* Constructs a new JDBC authentication provider.

*/

public JDBCAuthProvider() {

// Convert XML based provider setup to Database based

JiveGlobals.migrateProperty("jdbcProvider.driver");

JiveGlobals.migrateProperty("jdbcProvider.connectionString");

JiveGlobals.migrateProperty("jdbcAuthProvider.passwordSQL");

JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");

JiveGlobals.migrateProperty("jdbcAuthProvider.setPasswordSQL");

JiveGlobals.migrateProperty("jdbcAuthProvider.allowUpdate");

// Load the JDBC driver and connection string.

String jdbcDriver = JiveGlobals.getProperty("jdbcProvider.driver");

try {

Class.forName(jdbcDriver).newInstance();

}

catch (Exception e) {

Log.error("Unable to load JDBC driver: " + jdbcDriver, e);

return;

}

connectionString = JiveGlobals.getProperty("jdbcProvider.connectionString");

// Load SQL statements.

passwordSQL = JiveGlobals.getProperty("jdbcAuthProvider.passwordSQL");

setPasswordSQL = JiveGlobals.getProperty("jdbcAuthProvider.setPasswordSQL");

allowUpdate = JiveGlobals.getBooleanProperty("jdbcAuthProvider.allowUpdate",false);

passwordType = PasswordType.plain;

try {

passwordType = PasswordType.valueOf(

JiveGlobals.getProperty("jdbcAuthProvider.passwordType", "plain"));

}

catch (IllegalArgumentException iae) {

Log.error(iae);

}

}

public void authenticate(String username, String password) throws UnauthorizedException {

if (username == null || password == null) {

throw new UnauthorizedException();

}

username = username.trim().toLowerCase();

if (username.contains("@")) {

// Check that the specified domain matches the server's domain

int index = username.indexOf("@");

String domain = username.substring(index + 1);

if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {

username = username.substring(0, index);

} else {

// Unknown domain. Return authentication failed.

throw new UnauthorizedException();

}

}

String userPassword;

try {

userPassword = getPasswordValue(username);

}

catch (UserNotFoundException unfe) {

throw new UnauthorizedException();

}

// If the user's password doesn't match the password passed in, authentication

// should fail.

if (passwordType == PasswordType.md5) {

password = StringUtils.hash(password, "MD5");

}

else if (passwordType == PasswordType.sha1) {

password = StringUtils.hash(password, "SHA-1");

}

if (!password.equals(userPassword)) {

throw new UnauthorizedException();

}

// Got this far, so the user must be authorized.

createUser(username);

}

public void authenticate(String username, String token, String digest)

throws UnauthorizedException

{

if (passwordType != PasswordType.plain) {

throw new UnsupportedOperationException("Digest authentication not supported for "

+ "password type " + passwordType);

}

if (username == null || token == null || digest == null) {

throw new UnauthorizedException();

}

username = username.trim().toLowerCase();

if (username.contains("@")) {

// Check that the specified domain matches the server's domain

int index = username.indexOf("@");

String domain = username.substring(index + 1);

if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {

username = username.substring(0, index);

} else {

// Unknown domain. Return authentication failed.

throw new UnauthorizedException();

}

}

String password;

try {

password = getPasswordValue(username);

}

catch (UserNotFoundException unfe) {

throw new UnauthorizedException();

}

String anticipatedDigest = AuthFactory.createDigest(token, password);

if (!digest.equalsIgnoreCase(anticipatedDigest)) {

throw new UnauthorizedException();

}

// Got this far, so the user must be authorized.

createUser(username);

}

public boolean isPlainSupported() {

// If the auth SQL is defined, plain text authentication is supported.

return (passwordSQL != null);

}

public boolean isDigestSupported() {

// The auth SQL must be defined and the password type is supported.

return (passwordSQL != null && passwordType == PasswordType.plain);

}

public String getPassword(String username) throws UserNotFoundException,

UnsupportedOperationException

{

if (!supportsPasswordRetrieval()) {

throw new UnsupportedOperationException();

}

if (username.contains("@")) {

// Check that the specified domain matches the server's domain

int index = username.indexOf("@");

String domain = username.substring(index + 1);

if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {

username = username.substring(0, index);

} else {

// Unknown domain.

throw new UserNotFoundException();

}

}

return getPasswordValue(username);

}

public void setPassword(String username, String password)

throws UserNotFoundException, UnsupportedOperationException

{

if (allowUpdate && setPasswordSQL != null) {

setPasswordValue(username, password);

} else {

throw new UnsupportedOperationException();

}

}

public boolean supportsPasswordRetrieval() {

return (passwordSQL != null && passwordType == PasswordType.plain);

}

/**

* Returns the value of the password field. It will be in plain text or hashed

* format, depending on the password type.

*

* @param username user to retrieve the password field for

* @return the password value.

* @throws UserNotFoundException if the given user could not be loaded.

*/

private String getPasswordValue(String username) throws UserNotFoundException {

String password = null;

Connection con = null;

PreparedStatement pstmt = null;

ResultSet rs = null;

if (username.contains("@")) {

// Check that the specified domain matches the server's domain

int index = username.indexOf("@");

String domain = username.substring(index + 1);

if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {

username = username.substring(0, index);

} else {

// Unknown domain.

throw new UserNotFoundException();

}

}

try {

con = DriverManager.getConnection(connectionString);

pstmt = con.prepareStatement(passwordSQL);

pstmt.setString(1, username);

rs = pstmt.executeQuery();

// If the query had no results, the username and password

// did not match a user record. Therefore, throw an exception.

if (!rs.next()) {

throw new UserNotFoundException();

}

password = rs.getString(1);

}

catch (SQLException e) {

Log.error("Exception in JDBCAuthProvider", e);

throw new UserNotFoundException();

}

finally {

DbConnectionManager.closeConnection(rs, pstmt, con);

}

return password;

}

private void setPasswordValue(String username, String password) throws UserNotFoundException {

Connection con = null;

PreparedStatement pstmt = null;

ResultSet rs = null;

if (username.contains("@")) {

// Check that the specified domain matches the server's domain

int index = username.indexOf("@");

String domain = username.substring(index + 1);

if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {

username = username.substring(0, index);

} else {

// Unknown domain.

throw new UserNotFoundException();

}

}

try {

con = DriverManager.getConnection(connectionString);

pstmt = con.prepareStatement(setPasswordSQL);

pstmt.setString(1, username);

if (passwordType == PasswordType.md5) {

password = StringUtils.hash(password, "MD5");

}

else if (passwordType == PasswordType.sha1) {

password = StringUtils.hash(password, "SHA-1");

}

pstmt.setString(2, password);

rs = pstmt.executeQuery();

}

catch (SQLException e) {

Log.error("Exception in JDBCAuthProvider", e);

throw new UserNotFoundException();

}

finally {

DbConnectionManager.closeConnection(rs, pstmt, con);

}

}

/**

* Indicates how the password is stored.

*/

@SuppressWarnings({"UnnecessarySemicolon"}) // Support for QDox Parser

public enum PasswordType {

/**

* The password is stored as plain text.

*/

plain,

/**

* The password is stored as a hex-encoded MD5 hash.

*/

md5,

/**

* The password is stored as a hex-encoded SHA-1 hash.

*/

sha1;

}

/**

* Checks to see if the user exists; if not, a new user is created.

*

* @param username the username.

*/

private static void createUser(String username) {

// See if the user exists in the database. If not, automatically create them.

UserManager userManager = UserManager.getInstance();

try {

userManager.getUser(username);

}

catch (UserNotFoundException unfe) {

try {

Log.debug("JDBCAuthProvider: Automatically creating new user account for " + username);

UserManager.getUserProvider().createUser(username, StringUtils.randomString(8),

null, null);

}

catch (UserAlreadyExistsException uaee) {

// Ignore.

}

}

}

}

看以看到通过读取PASSWORDTYPE配置

Java代码


JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");

。。。。。

。。。。。

。。。。。

passwordType = PasswordType.plain;

try {

passwordType = PasswordType.valueOf(

JiveGlobals.getProperty("jdbcAuthProvider.passwordType", "plain"));

}

catch (IllegalArgumentException iae) {

Log.error(iae);

}

进行密码的验证

Java代码


if (passwordType == PasswordType.md5) {

password = StringUtils.hash(password, "MD5");

}

else if (passwordType == PasswordType.sha1) {

password = StringUtils.hash(password, "SHA-1");

}

if (!password.equals(userPassword)) {

throw new UnauthorizedException();

}

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

Java代码


package org.yxsoft.openfire.plugin;

import org.jivesoftware.openfire.user.UserNotFoundException;

import org.jivesoftware.openfire.auth.*;

import org.jivesoftware.openfire.XMPPServer;

import org.jivesoftware.util.JiveGlobals;

import org.jivesoftware.util.Log;

import org.jivesoftware.util.StringUtils;

import org.jivesoftware.database.DbConnectionManager;

import java.sql.*;

import java.security.MessageDigest;

/**

* Created by cl

* Date: 2008-9-4

* Time: 9:18:26

* 仿照JDBCAuthProvider

* 在数据库连接上 支持user/password

* 密码验证 使用bfmp的机制

*/

public class BfmpAuthProvider implements AuthProvider {

private String connectionString;

private String user;

private String password;

private String passwordSQL;

private String setPasswordSQL;

private PasswordType passwordType;

private boolean allowUpdate;

/**

* 初始化

* 比JDBCAuthProvider多支持

* JiveGlobals.migrateProperty("jdbcProvider.url");

JiveGlobals.migrateProperty("jdbcProvider.user");

JiveGlobals.migrateProperty("jdbcProvider.password");

*/

public BfmpAuthProvider() {

// Convert XML based provider setup to Database based

JiveGlobals.migrateProperty("jdbcProvider.driver");

JiveGlobals.migrateProperty("jdbcProvider.url");

JiveGlobals.migrateProperty("jdbcProvider.user");

JiveGlobals.migrateProperty("jdbcProvider.password");

JiveGlobals.migrateProperty("jdbcAuthProvider.passwordSQL");

JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");

JiveGlobals.migrateProperty("jdbcAuthProvider.setPasswordSQL");

JiveGlobals.migrateProperty("jdbcAuthProvider.allowUpdate");

JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");

// Load the JDBC driver and connection string.

String jdbcDriver = JiveGlobals.getProperty("jdbcProvider.driver");

try {

Class.forName(jdbcDriver).newInstance();

}

catch (Exception e) {

Log.error("Unable to load JDBC driver: " + jdbcDriver, e);

return;

}

connectionString = JiveGlobals.getProperty("jdbcProvider.url");

user = JiveGlobals.getProperty("jdbcProvider.user");

password = JiveGlobals.getProperty("jdbcProvider.password");

// Load SQL statements.

passwordSQL = JiveGlobals.getProperty("jdbcAuthProvider.passwordSQL");

setPasswordSQL = JiveGlobals.getProperty("jdbcAuthProvider.setPasswordSQL");

allowUpdate = JiveGlobals.getBooleanProperty("jdbcAuthProvider.allowUpdate",false);

passwordType = PasswordType.plain;

try {

passwordType = PasswordType.valueOf(

JiveGlobals.getProperty("jdbcAuthProvider.passwordType", "plain"));

Log.error("PasswordType:"+ passwordType);

}

catch (IllegalArgumentException iae) {

Log.error(iae);

}

}

public boolean isPlainSupported() {

//default

return true;

}

public boolean isDigestSupported() {

//default

return true;

}

public void authenticate(String username, String password) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {

if (username == null || password == null) {

throw new UnauthorizedException();

}

Log.error(username+":"+password);

username = username.trim().toLowerCase();

if (username.contains("@")) {

Log.error(username+":"+XMPPServer.getInstance().getServerInfo().getXMPPDomain());

// Check that the specified domain matches the server's domain

int index = username.indexOf("@");

String domain = username.substring(index + 1);

if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {

username = username.substring(0, index);

} else {

// Unknown domain. Return authentication failed.

throw new UnauthorizedException();

}

} else {

Log.error("user name not contains ");

}

String userPassword;

try {

userPassword = getPasswordValue(username);

}

catch (UserNotFoundException unfe) {

throw new UnauthorizedException();

}

// If the user's password doesn't match the password passed in, authentication

// should fail.

if (passwordType == PasswordType.bfmp) {

//这里BfmpMD5 就是自己的密码规则

password = BfmpMD5(password);

}

if (!password.equals(userPassword)) {

throw new UnauthorizedException();

}

// Got this far, so the user must be authorized.

//createUser(username);

}

public void authenticate(String username, String token, String digest) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {

if (passwordType != PasswordType.plain) {

throw new UnsupportedOperationException("Digest authentication not supported for "

+ "password type " + passwordType);

}

if (username == null || token == null || digest == null) {

throw new UnauthorizedException();

}

username = username.trim().toLowerCase();

if (username.contains("@")) {

// Check that the specified domain matches the server's domain

int index = username.indexOf("@");

String domain = username.substring(index + 1);

if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {

username = username.substring(0, index);

} else {

// Unknown domain. Return authentication failed.

throw new UnauthorizedException();

}

}

String password;

try {

password = getPasswordValue(username);

}

catch (UserNotFoundException unfe) {

throw new UnauthorizedException();

}

String anticipatedDigest = AuthFactory.createDigest(token, password);

if (!digest.equalsIgnoreCase(anticipatedDigest)) {

throw new UnauthorizedException();

}

// Got this far, so the user must be authorized.

//createUser(username);

}

public String getPassword(String username) throws UserNotFoundException, UnsupportedOperationException {

if (!supportsPasswordRetrieval()) {

throw new UnsupportedOperationException();

}

if (username.contains("@")) {

// Check that the specified domain matches the server's domain

int index = username.indexOf("@");

String domain = username.substring(index + 1);

if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {

username = username.substring(0, index);

} else {

// Unknown domain.

throw new UserNotFoundException();

}

}

return getPasswordValue(username);

}

private String getPasswordValue(String username) throws UserNotFoundException {

String password = null;

Connection con = null;

PreparedStatement pstmt = null;

ResultSet rs = null;

if (username.contains("@")) {

// Check that the specified domain matches the server's domain

int index = username.indexOf("@");

String domain = username.substring(index + 1);

if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {

username = username.substring(0, index);

} else {

// Unknown domain.

throw new UserNotFoundException();

}

}

try {

con = DriverManager.getConnection(connectionString, user, this.password);

pstmt = con.prepareStatement(passwordSQL);

pstmt.setString(1, username);

rs = pstmt.executeQuery();

// If the query had no results, the username and password

// did not match a user record. Therefore, throw an exception.

if (!rs.next()) {

throw new UserNotFoundException();

}

password = rs.getString(1);

}

catch (SQLException e) {

Log.error("Exception in JDBCAuthProvider", e);

throw new UserNotFoundException();

}

finally {

DbConnectionManager.closeConnection(rs, pstmt, con);

}

return password;

}

public void setPassword(String username, String password) throws UserNotFoundException, UnsupportedOperationException {

// unsupport

}

public boolean supportsPasswordRetrieval() {

return true;

}

/**

* Indicates how the password is stored.

*/

@SuppressWarnings({"UnnecessarySemicolon"}) // Support for QDox Parser

public enum PasswordType {

/**

* The password is stored as plain text.

*/

plain,

/**

* The password is stored as a bfmp passwrod.

*/

bfmp;

}

private String BfmpMD5 (String source) {

//在这里实现你的加密机制,返回生成的密码

return "";

}

}

编译后将此class加入到lib/openfire.jar中即可

当然不要忘记 将系统属性中

provider.auth.className,改成你自已的Provider

*上述代码例子中是org.yxsoft.openfire.plugin.BFMPAuthProvider

jdbcAuthProvider.passwordType,改成你自己定义的枚举值

*上述代码例子中是bfmp
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: