(a)Smack:尝试使用 XMPP 登录时,TLS 套接字已关闭

Posted

技术标签:

【中文标题】(a)Smack:尝试使用 XMPP 登录时,TLS 套接字已关闭【英文标题】:(a)Smack: TLS socket is closed when trying to login with XMPP 【发布时间】:2013-01-31 10:51:09 【问题描述】:

我正在尝试将 asmack (android Gingerbread) 连接到 google talk。我已经设置了connectionConfig.setTruststoreType("BKS") - 所以我克服了证书问题。现在故障出在XMPPConnection.proceedTLSReceived() 函数中,该函数在服务器为“starttls”请求发送“proceed”后调用。

这个函数应该初始化 TSL 套接字。它失败并出现异常“java.net.SocketException: Socket closed”。

// Verify certificate presented by the server
context.init(kms,
    new javax.net.ssl.TrustManager[]new ServerTrustManager(getServiceName(), config),
    //new javax.net.ssl.TrustManager[]new OpenTrustManager(),
    new java.security.SecureRandom());
Socket plain = socket;
// Secure the plain connection
socket = context.getSocketFactory().createSocket(plain, plain.getInetAddress().getHostName(), plain.getPort(), false);
socket.setSoTimeout(0); ////// THIS LINE THROWS THE EXCEPTION

有什么线索吗?

套接字描述为: SSL socket over Socket[addr=talk.google.com/173.194.70.125,port=5222,localport=34840]

在模拟器和我的 Galaxy S I9000 上失败。

【问题讨论】:

【参考方案1】:

事实证明,SSL 连接存在超时问题。我的应用程序花费了很长时间来生成 SSL 套接字(通过普通套接字),而对方只是放弃了......这个,或者有一个关键问题(但我没有收到任何身份验证错误)。

我通过以下方式解决了问题:

    迁移到 API 级别 15 - 使用 AndroidCSStore,而不是 BKS(我用于 API 10)。 使用getAuthToken获取密码 - 它实际上是一个令牌,但后来​​在连接时用作密码。 我没有空闲时间来真正了解问题的根源。它现在可以工作了,这才是最重要的。

我在下面发布了我的代码。 SASLXOAuth2机制完成。但是 Main 中的代码是有条不紊的,并不完整。我从这个网站上的其他答案中提取了代码片段,我提前为我的抄袭道歉。

Main.java - 启动 asmack

// Init asmack, and register new mechanisms.
asmack = SmackAndroid.init(ctx);

SASLAuthentication.registerSASLMechanism("X-OAUTH2", SASLXOAuth2Mechanism.class);
SASLAuthentication.supportSASLMechanism("X-OAUTH2", 0);

ConnectionConfiguration connectionConfig = 
    new ConnectionConfiguration (getHost(), getPort(), getService());
connectionConfig.setSASLAuthenticationEnabled(true);
connectionConfig.setSecurityMode(true);
connectionConfig.setRosterLoadedAtLogin(true);
connectionConfig.setReconnectionAllowed(true);
connectionConfig.setSendPresence(false);
//connectionConfig.setCompressionEnabled(true);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) 
        connectionConfig.setTruststoreType("AndroidCAStore");
        connectionConfig.setTruststorePassword(null);
        connectionConfig.setTruststorePath(null);
 /*else 
        connectionConfig.setTruststoreType("BKS");
        String path = System.getProperty("javax.net.ssl.trustStore");
        if (path == null)
            path = System.getProperty("java.home") + File.separator + "etc"
                + File.separator + "security" + File.separator
                + "cacerts.bks";
        connectionConfig.setTruststorePath(path);
        connectionConfig.setTruststorePassword("changeit");
 // */

 XMPPConnection con = new XMPPConnection(connectionConfig);

SASLXOAuth2Mechanism.java - XOAuth2 机制

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.Base64;

import de.measite.smack.Sasl;

public class SASLXOAuth2Mechanism extends SASLMechanism

    static final String AUTHENTICATOR_URL = "http://www.google.com/talk/protocol/auth";
    protected String authenticationText = null;
    static final String TAG = "SASLXOAuth2Mechanism";

    public SASLXOAuth2Mechanism(SASLAuthentication saslAuthentication) 
        super(saslAuthentication);
    

    @Override
    protected String getName()
    
        return "X-OAUTH2";
    

    @Override
    public void authenticate(String username, String host, String password) throws IOException, XMPPException 
        this.password = password;
        this.authenticationId = username;

        StringBuilder credentials = new StringBuilder();
        credentials.append("\0");
        credentials.append(username);
        credentials.append("\0");
        credentials.append(password);
        authenticationText = Base64.encodeBytes(credentials.toString().getBytes("UTF-8"), Base64.DONT_BREAK_LINES);

        String[] mechanisms =  "PLAIN" ;
        Map<String,String> props = new HashMap<String,String>();
        sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, this);
        authenticate();
    

    protected void authenticate() throws IOException, XMPPException 
        // Send the authentication to the server
        getSASLAuthentication().send(new XOAuth2AuthMechanism(getName(), authenticationText));
    

    /**
     * Initiating SASL authentication by select a mechanism.
     */
    public class XOAuth2AuthMechanism extends Packet 
        final private String name;
        final private String authenticationText;

        public XOAuth2AuthMechanism(String name, String authenticationText) 
            super();
            this.name = name;
            this.authenticationText = authenticationText;
        

        public String toXML() 
            StringBuilder stanza = new StringBuilder();
            stanza.append("<auth mechanism=\"").append(name);
            stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" auth:service=\"oauth2\" xmlns:auth=\"").append(AUTHENTICATOR_URL);
            stanza.append("\">");
            if (authenticationText != null) 
                stanza.append(authenticationText);
            
            stanza.append("</auth>");
            return stanza.toString();
        
    

【讨论】:

以上是关于(a)Smack:尝试使用 XMPP 登录时,TLS 套接字已关闭的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Smack XMPP API 处理(失败的)登录尝试

XMPP 服务器不响应 Smack 登录请求

无法使用 java 中的 smack 库使用 xmpp 服务器登录

如何在 xmpp smack 或 asmack 中将文件发送给离线用户?

使用 smack 的 Android XMPP:服务器没有响应

XMPP Smack - 消息被修改