直接操作数据库数据来为Openfire注册新用户

众所周知,Openfire的注册方式一般有三种:

1.带内注册  ---- In-Band Registration. 即客户端通过匿名方式与Openfire 服务器端建立连接并验证,然后发起注册节点XML流,以XMPPStream的方法直接像服务器注册。code4app上有另外一个XMPP的带内注册demo详细的示范了这个方法(不是我写的)。

优点:不需假设额外的服务器端,适合对java一窍不通的开发者。

弊端:不容易管理用户账号。用户注册的JID无规律,不能够自增长。安全性低。

2.Openfire二次开发(为Openfire写插件)  ----- 这种方式是通过下载Openfire(JiveSoftware开放Openfire开源代码)的方式替代直接安装Openfire安装包来进行二次开发。二次开发非常强大,我后面会提到用这种方式获取用户的分组、在线信息、群体推送消息等都非常的方便。但是工作量相对较大,不建议java新手选择。

3.外接Openfire数据库至本机的数据库中,直接操作ofUser表并对其加密方式和字段规则进行模仿,可以达到与后台添加账号完全相同的功效。我的仿微信Demo即是采取的这种方式。

优点:可以使用比JDBC更好用的hibernate来操作openfire中的自带用户表来享受hibernate的性能。生成的jid中的用户名可以自增长的方式方便日后管理。

缺点:不同的电脑,或者重装Openfire都会让加密钥随之改变,所以如果遇到此情况需要将原有密文密码以旧秘钥解密后再使用新秘钥加密。

那么怎么做呢?
1.找到openfire默认数据库中的用户表 ofUser
plainPassword一般不会使用,openfire的用户名密码一般都是用后面的encryptedPassword来存储的,这里我保留了部分明文明码也是为了方便万一大家忘了密码我可以直接告诉他,因为这么多用户我也疏于管理,免费的开源事业不可能还要有客服帮你找回密码对吧。。。

仔细分析这个表的各个Colunm结构之后(如果你是新安装的,你观察amdin这个用户的信息就行了),我们发现如果我们要新建一个用户,很多字段都是可空的,但是为了尽量不影响openfire本身,我决定伪造时间戳与密文密码,然后自增长username来达到注册目的。你这里可以不使用自增长username。
注意 虽然只有3个非空字段,但是实质上你至少要有4个字段,即这3个字段加上 明文 or 密文密码,不然你没有密码怎么登陆。其次,注意看这里的CHAR(15)类型的时间戳,我们知道ios的时间戳是以秒为个位数的浮点数,java的时间戳是以毫秒为单位的13位的整数(至笔者写此博客为止是13位,不排除突破14位的可能,估计要等几百年吧),不难发现这个CHAR其实就是java时间戳的CHAR[]格式数据,这个就非常好办了。userName我们让他自增长,也好办。接下来就是密码了,这里大家最好不要使用明文密码,不然以后登陆出现问题,我不负责。

OK不啰嗦了,简单说下密文密码怎样伪造。首先我们需要研究openfire的加密原理,即他的加密方式。openfire使用其源码中的BlowFish.java 工具类来进行加密,简单的看看他的源码不难发现其加密方式实质为digest。
所以我们要成功伪造一个合格的密码,必须拿到这个文件并且调用他。大家可以到www.hcios.com:8080下载页面java源码中找到他。

这个加密类的工作原理很简单,以每个openfire安装出来后生成的passwordKey作为key,再以时间戳的某种形式作为变量拼接上用户的明文密码一起混合加密。其结果是同一密码不同openfire上加密后的结果不一样,同一密文密码解密后也不一样。即便是同一个server,不同时间加密后的密文密码也不一样,但是解密后的明文密码一样(因为时间戳和明文密码混合在一起加密,时间在变化)。

所以只要passwordKey不变,那么我们的对任意的明文密码在任意时候 进行加密,随时都可以解密回原明文密码。


这个秘钥大家可以在openfire控制台---服务器属性里找到,也可以在ofProperty表中找到他:
passwordKey属性的值(注意每个openfire的值不一样)。

找到他就好办了,
那么就可以写我们的代码:
Blowfish.java的下载地址:http://download.csdn.net/detail/zwdsmileface/8606315
注意:这个文件需要依赖一个slf4j的jar包,这个网上一搜就有。

public static void main(String[] args) {  
                //注意这里是你的openfire的秘钥
		Blowfish _encoder=new Blowfish("cDCTJGMyJv3E473");  
		  ResultSet rs = null;  
		  Statement stmt = null;  
		  Connection conn = null;  
		  try {  
		   Class.forName("oracle.jdbc.driver.OracleDriver");  
		   //new oracle.jdbc.driver.OracleDriver();  
		   conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.1.85:1521:ORCL", "test", "test");  
		   stmt = conn.createStatement(); 
		   String encodedStr=_encoder.encryptString("ccc");  
		   String time=String.format("00%d", System.currentTimeMillis());
		   String sql="insert into ofUser values('ccc','','"+encodedStr+"','','','"+time+"','"+time+"')";
		   stmt.execute(sql);
		  } catch (ClassNotFoundException e) {  
		   e.printStackTrace();  
		  } catch (SQLException e) {  
		   e.printStackTrace();  
		  } finally {  
		   try {  
		    if(rs != null) {  
		     rs.close();  
		     rs = null;  
		    }  
		    if(stmt != null) {  
		     stmt.close();  
		     stmt = null;  
		    }  
		    if(conn != null) {  
		     conn.close();  
		     conn = null;  
		    }  
		   } catch (SQLException e) {  
		    e.printStackTrace();  
		   }  
		  }  
		 }  

这个代码只是我用JDBC写的一个小的例子,大家可以用hibernate或者其他方法使用,有什么不会的请留言。

猜你喜欢

转载自zwdsmileface.iteye.com/blog/2203463
今日推荐