当前位置: 首页 > 工具软件 > XMPP4R > 使用案例 >

php openfire xmpp,openfire xmpp sasl 浅析

孟泽宇
2023-12-01

SASL全称Simple Authentication and Security Layer,是一种用来扩充C/S模式验证能力的机制。在Postfix可以利用SASL来判断用户是否有权使用转发服务,或是辨认谁在使用你的服务器。

SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。

在xmpp协议下客户端和服务器端的交换报文如下:

1.客户端发送xmpp流

[client]:

2.服务端响应

[server]:<?xml version='1.0' encoding='UTF-8'?>

3.服务端发送支持链接的特性

[server]:DIGEST-MD5JIVE-SHAREDSECRETPLAINANONYMOUSCRAM-MD5zlib

4.客户端选择 tls (Transport Layer Security 传输层安全)协议

[client]:

5.服务器端开始处理 tls

[server]:

6.客户端重新发送开始流

[client]:

7.服务端响应

[server]:<?xml version='1.0' encoding='UTF-8'?>DIGEST-MD5JIVE-SHAREDSECRETPLAINANONYMOUSCRAM-MD5zlib

8.客户端发送 sasl认证请求

[client]:

9.服务端发送 询问 询问内容使用base64进行编码

[server]:cmVhbG09IjE5Mi4xNjguMS4yMTIiLG5vbmNlPSJNODU5ZE9PT3R6b21CVHA3S25zSlg2YTJIS0ZEcGdSZ0FWQ3hHY2twIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz

realm="192.168.1.212",nonce="M859dOOOtzomBTp7KnsJX6a2HKFDpgRgAVCxGckp",qop="auth",charset=utf-8,algorithm=md5-sess

10.客户端应答询问,应答内容使用base64进行编码

[client]:Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iamltbXkiLHJlYWxtPSIxOTIuMTY4LjEuMjEyIixub25jZT0iTTg1OWRPT090em9tQlRwN0tuc0pYNmEySEtGRHBnUmdBVkN4R2NrcCIsbmM9MDAwMDAwMDEsY25vbmNlPSJDRU9ienFnMTVJV1JSNkcrOFBLS2ZtbG81MUI2UzZaU040WXBHNXFxIixkaWdlc3QtdXJpPSJ4bXBwLzE5Mi4xNjguMS4yMTIiLG1heGJ1Zj02NTUzNixyZXNwb25zZT1iYjFkOWEwMWQ5NTBkYTFhOTIxNTI2ODMzYmUyZjE3Mixxb3A9YXV0aCxhdXRoemlkPSJqaW1teSI=

charset=utf-8,username="jimmy",realm="192.168.1.212",nonce="M859dOOOtzomBTp7KnsJX6a2HKFDpgRgAVCxGckp",nc=00000001,cnonce="CEObzqg15IWRR6G+8PKKfmlo51B6S6ZSN4YpG5qq",digest-uri="xmpp/192.168.1.212",maxbuf=65536,response=bb1d9a01d950da1a921526833be2f172,qop=auth,authzid="jimmy"

11.服务端验证成功

[server]:cnNwYXV0aD1kZGZiZmVmYmRiZjZlYmZjOTQ4M2U0MWMyMDM4MTA5YQ==

rspauth=ddfbfefbdbf6ebfc9483e41c2038109a

12.客户端第三次重新建立流

[client]:

13.服务端响应

[server]:<?xml version='1.0' encoding='UTF-8'?>zlib

下面就是一些流程性的东西了

在sasl 是怎样进行challenge、response、success的呢?

在服务端

先生成saslserver,由server生成challenge,发送给client。

Map props=new TreeMap();

props.put(Sasl.QOP, "auth");

SaslServer ss=Sasl.createSaslServer("DIGEST-MD5", "xmpp", "java.com", props, new ServerCallbackHandler());

byte[] token=new byte[0];

byte[] challenge=ss.evaluateResponse(token);

在客户端收到 challenge后生, 生成saslclient 处理challenge 生成response 在发给server

SaslClient sc=Sasl.createSaslClient(new String[]{"DIGEST-MD5"}, "x", "xmpp", "java.com", null, new ClientCallbackHandler());

byte response[];

response=sc.evaluateChallenge(challenge);

server收到 应答后进行验证,验证通过后给客户端一个响应。

ss.evaluateResponse(response);

if(ss.isComplete()) {

System.out.println("auth success");

}

下面是sasl 的一个小例子,希望有助于理解sasl协议

package test.com.jimmy.tls;

import java.io.IOException;

import java.util.Map;

import java.util.TreeMap;

import javax.security.auth.callback.Callback;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.NameCallback;

import javax.security.auth.callback.PasswordCallback;

import javax.security.auth.callback.UnsupportedCallbackException;

import javax.security.sasl.AuthorizeCallback;

import javax.security.sasl.RealmCallback;

import javax.security.sasl.Sasl;

import javax.security.sasl.SaslClient;

import javax.security.sasl.SaslException;

import javax.security.sasl.SaslServer;

public class AuthMain {

/**

* @param args

* @throws SaslException

*/

public static void main(String[] args) throws SaslException {

Map props=new TreeMap();

props.put(Sasl.QOP, "auth");

/**

* 为指定机制创建一个 SaslServer。 Sasl.createSaslServer(String mechanism, String protocol, String serverName, Map props,

* CallbackHandler cbh)

*  参数 mechanism - 非 null 的机制名。它必须是 SASL 机制的 IANA 注册名。(例如 "GSSAPI"、"CRAM-MD5")。

*  protocol - 非 null 的协议(例如 "ldap")字符串名,将为它执行身份验证。

*  serverName - 服务器的非 null 完全限定主机名。

*   props - 可能为 null 的属性集,用于选择 SASL 机制并配置所选机制的身份验证交换。例如,如果 props 包含

* Sasl.POLICY_NOPLAINTEXT 属性,且属性值为 "true",则所选的 SASL 机制必须不易受到简单被动式攻击的危害。除了在此类中所声明的标准属性外,也可以包括其他的可能特定于机制的属性。忽略与所选机制无关的属性。 cbh

* - SASL 机制使用的回调处理程序(可能为 null),以便为完成身份验证而从应用程序/库获得更多的信息。例如,SASL 机制可能需要从调用方获得身份验证 ID、密码和域。使用 NameCallback 来请求身份验证 ID。使用

* PasswordCallback 来请求密码。如果要从域列表中选择,则使用 RealmChoiceCallback 来请求域,如果必须输入域,则使用 RealmCallback 来请求域。

*/

SaslServer ss=Sasl.createSaslServer("DIGEST-MD5", "xmpp", "java.com", props, new ServerCallbackHandler());

byte[] token=new byte[0];

byte[] challenge=ss.evaluateResponse(token);

SaslClient sc=

Sasl.createSaslClient(new String[]{"DIGEST-MD5"}, "x", "xmpp", "java.com", null, new ClientCallbackHandler());

byte response[];

if(challenge != null) {

response=sc.evaluateChallenge(challenge);

} else {

response=sc.evaluateChallenge(null);

}

ss.evaluateResponse(response);

if(ss.isComplete()) {

System.out.println("auth success");

}

}

}

class ClientCallbackHandler implements CallbackHandler {

public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

for(int i=0; i < callbacks.length; i++) {

if(callbacks[i] instanceof NameCallback) {

NameCallback ncb=(NameCallback)callbacks[i];

ncb.setName("tony1");

} else if(callbacks[i] instanceof PasswordCallback) {

PasswordCallback pcb=(PasswordCallback)callbacks[i];

pcb.setPassword("admin1s".toCharArray());

} else if(callbacks[i] instanceof RealmCallback) {

RealmCallback rcb=(RealmCallback)callbacks[i];

rcb.setText("java.com");

} else {

throw new UnsupportedCallbackException(callbacks[i]);

}

}

}

}

class ServerCallbackHandler implements CallbackHandler {

public ServerCallbackHandler() {

}

public void handle(final Callback[] callbacks) throws IOException,

UnsupportedCallbackException {

for(Callback callback: callbacks) {

if(callback instanceof RealmCallback) {

System.out.println("RealmCallback" + ((RealmCallback)callback).getDefaultText());

} else if(callback instanceof NameCallback) {

System.out.println("NameCallback" + ((NameCallback)callback).getDefaultName());

} else if(callback instanceof PasswordCallback) {

((PasswordCallback)callback).setPassword("admin1s".toCharArray());

} else if(callback instanceof AuthorizeCallback) {

AuthorizeCallback authCallback=((AuthorizeCallback)callback);

authCallback.setAuthorized(true);

} else {

System.out.println(callback.getClass().getName());

throw new UnsupportedCallbackException(callback, "Unrecognized Callback");

}

}

}

}

 类似资料: