繁体   English   中英

使用Smack 4.1.0 API作为Google GCM CCS的XMPP客户端时,SecurityMode.required无效

[英]When using Smack 4.1.0 API as a XMPP Client for Google’s GCM CCS, SecurityMode.required is not working

我正在开发一个Java服务器,它使用Smack 4.1.0 API作为XMPP客户端连接到Google Cloud Messaging Cloud Connection Server(GCM CCS),以便向Android应用程序发送消息。 我从这个例子开始( https://developer.android.com/google/gcm/ccs.html ),但随着Smack API的改变,我相应地调整了代码。 到目前为止,我的Smack客户端已成功连接到GCM CCS,发送消息并接收ack / nack / control响应。

不幸的是,如果我指定XMPPTCPConnectionConfiguration.Builder.setSecurityMode(SecurityMode.ifpossible)或(SecurityMode.disabled),则连接只能正常工作。 这样做时XMPPTCPConnection.isSecureConnection()返回false。 请参阅以下(相关)代码:

    static final String GCM_SERVER = "gcm.googleapis.com";
    static final int GCM_PORT = 5235;
    private XMPPTCPConnection connection;
    private SSLContext sslCtx;

    ...

    try {
        KeyStore windowsRootTruststore = KeyStore.getInstance("Windows-ROOT", "SunMSCAPI");
        windowsRootTruststore.load(null, null);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(windowsRootTruststore);
        sslCtx = SSLContext.getInstance("TLS");
        sslCtx.init(null, tmf.getTrustManagers(), null);
    } catch (KeyStoreException | NoSuchProviderException | NoSuchAlgorithmException
            | KeyManagementException | CertificateException e) {
        e.printStackTrace();
    }

    ...

    XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
        .setHost(GCM_SERVER)
        .setPort(GCM_PORT)
        .setServiceName(GCM_SERVER)
        .setUsernameAndPassword(GCM_SENDER_ID + "@gcm.googleapis.com", GCM_PASSWORD)
        .setCompressionEnabled(false)
        .setSecurityMode(SecurityMode.ifpossible)
        .setSendPresence(false)
        .setSocketFactory(sslCtx.getSocketFactory())
        .build();
    connection = new XMPPTCPConnection(config);
    Roster roster = Roster.getInstanceFor(connection);
    roster.setRosterLoadedAtLogin(false);
    connection.addConnectionListener(this);
    connection.addAsyncStanzaListener(this, new StanzaTypeFilter(Message.class));
    connection.addPacketInterceptor(new StanzaListener() {
            @Override
            public void processPacket(Stanza packet) throws NotConnectedException {
                System.out.println("CCS_Client sent the following message: " + packet.toXML());
            }
        }, new StanzaTypeFilter(Message.class));
    connection.connect();
    connection.login();
    System.out.println(connection.isSecureConnection());

根据谷歌“连接有两个重要的要求:1)您必须启动传输层安全性(TLS)连接。 ......“(见上面的链接)。 这听起来像是非TLS加密连接会被拒绝。 我的问题与SecurityMode.required发挥作用。 使用时,Smack会抛出以下错误代码:

org.jivesoftware.smack.SmackException$SecurityRequiredByClientException: SSL/TLS required by client but not supported by server 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.afterFeaturesReceived(XMPPTCPConnection.java:898) 
    at org.jivesoftware.smack.AbstractXMPPConnection.parseFeatures(AbstractXMPPConnection.java:1367) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$800(XMPPTCPConnection.java:139)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:998) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$200(XMPPTCPConnection.java:937) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:952) 
    at java.lang.Thread.run(Thread.java:744)

我已经尝试了两天来弄清楚为什么我无法建立SecurityMode.required连接但失败了。

使用与上面相同的SSLContext / SSLSocketFactory,它工作正常,如果我连接到没有Smack API的GCM CCS,只需打开TLS加密连接。 根据上面的Google评论,当将常规SocketFactory(不是SSLSocketFactory)传递给XMPPTCPConnectionConfiguration时,无法建立连接:

org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout

所以我猜测(如果我错了,请纠正我)GCM CCS确实只接受TLS连接。 但如果是这种情况,为什么我的SecurityMode.required连接尝试被拒绝,“客户端需要SSL / TLS但服务器不支持”?

我也想知道SecurityMode.disabled / SecurityMode.ifpossible是否实际上成功建立了TLS连接,但isSecureConnection()是否仍然返回false? 这有可能吗? 为了测试这个假设,我想测试在Smack中创建的底层SSLsocket(在完成Handshake之后使用SSLSocket.getSession()。getCipherSuite()和getProtocol())。 为了做到这一点,我试图传递一个自定义SSLSocketFactory,它生成一个自定义SSLSocket(它只会在完成握手后输出CipherSuite和Protocol)到XMPPTCPConnectionConfiguration。 但我似乎无法让这个工作。

如何建立与SecurityMode.required建立的GCM CCS连接,为什么isSecureConnection()返回true?

任何帮助,将不胜感激!

同样的问题,我对这个bug的伤害是:

https://groups.google.com/forum/#!topic/android-gcm/5mA7FImpTGo

这表示SSL会话缓存出错(由谷歌禁用)。 我没有运气在服务器端(我的身边)禁用它。

另一方面,您可能会看到更多类似的内容:

org.jivesoftware.smack.roster.Roster     : Exception reloading roster
org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 5000ms (~5s).

如果是这样,您可以在此处查看问题: https//jira.spring.io/browse/INT-3972

我现在的解决方法是: https//github.com/puel/training/blob/master/gcm/gcm-server/src/main/java/org/sterl/gcm/_example/server/config/GcmConfig.java

我和Smack 4.1.6有同样的问题。

  1. 不得将SecurityMode设置为requiredhttps://community.igniterealtime.org/thread/55808 )。

  2. 在编写用户名时,必须使用项目编号,而不是项目编号(可在https://console.cloud.google.com上找到)。

  3. 我的愚蠢错误,但仍然。 在为项目创建API密钥时,请仔细选择平台:出于某种神秘的原因,Android API密钥不适用于普通的Java应用程序(lol)。

  4. 看来,服务名称可以是任何东西,只是不为空。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM