简体   繁体   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

I'm working on a Java Server that is using the Smack 4.1.0 API as a XMPP Client to connect to Google Cloud Messaging Cloud Connection Server (GCM CCS) in order to send messages to an Android app. 我正在开发一个Java服务器,它使用Smack 4.1.0 API作为XMPP客户端连接到Google Cloud Messaging Cloud Connection Server(GCM CCS),以便向Android应用程序发送消息。 I started with this example ( https://developer.android.com/google/gcm/ccs.html ), but as the Smack API has changed I adapted the code accordingly. 我从这个例子开始( https://developer.android.com/google/gcm/ccs.html ),但随着Smack API的改变,我相应地调整了代码。 By now my Smack Client is connecting successfully to GCM CCS, sends messages and receives ack/nack/control responses. 到目前为止,我的Smack客户端已成功连接到GCM CCS,发送消息并接收ack / nack / control响应。

Unfortunately, the connection is only working properly, if I specify XMPPTCPConnectionConfiguration.Builder.setSecurityMode(SecurityMode.ifpossible) or (SecurityMode.disabled). 不幸的是,如果我指定XMPPTCPConnectionConfiguration.Builder.setSecurityMode(SecurityMode.ifpossible)或(SecurityMode.disabled),则连接只能正常工作。 When doing that XMPPTCPConnection.isSecureConnection() returns false. 这样做时XMPPTCPConnection.isSecureConnection()返回false。 See the (relevant) code below: 请参阅以下(相关)代码:

    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());

According to Google “The connection has two important requirements: 1) You must initiate a Transport Layer Security (TLS) connection. 根据谷歌“连接有两个重要的要求:1)您必须启动传输层安全性(TLS)连接。 …” (see link above). ......“(见上面的链接)。 This sounds to me like a non-TLS encrypted connection would be refused. 这听起来像是非TLS加密连接会被拒绝。 My problem comes into play with SecurityMode.required. 我的问题与SecurityMode.required发挥作用。 When using that, Smack throws the following error code: 使用时,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)

I have been trying for two days to figure out why I can't establish a SecurityMode.required connection but failed. 我已经尝试了两天来弄清楚为什么我无法建立SecurityMode.required连接但失败了。

Using the same SSLContext/SSLSocketFactory as above, it works fine, if I connect to GCM CCS without the Smack API, just opening a TLS encrypted connection. 使用与上面相同的SSLContext / SSLSocketFactory,它工作正常,如果我连接到没有Smack API的GCM CCS,只需打开TLS加密连接。 In line with Google's comment above, when passing a regular SocketFactory (not SSLSocketFactory) to the XMPPTCPConnectionConfiguration, the connection cannot be established: 根据上面的Google评论,当将常规SocketFactory(不是SSLSocketFactory)传递给XMPPTCPConnectionConfiguration时,无法建立连接:

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

So I am guessing (correct me if I'm wrong) that GCM CCS is indeed only accepting TLS connections. 所以我猜测(如果我错了,请纠正我)GCM CCS确实只接受TLS连接。 But if that is the case, why is my SecurityMode.required connection attempt rejected with “SSL/TLS required by client but not supported by server”? 但如果是这种情况,为什么我的SecurityMode.required连接尝试被拒绝,“客户端需要SSL / TLS但服务器不支持”?

I am also wondering if SecurityMode.disabled/SecurityMode.ifpossible is actually successfully establishing a TLS connection but isSecureConnection() is returning false nonetheless? 我也想知道SecurityMode.disabled / SecurityMode.ifpossible是否实际上成功建立了TLS连接,但isSecureConnection()是否仍然返回false? Is that possible at all? 这有可能吗? In order to test this hypothesis, I wanted to test the underlying SSLsocket that is created within Smack (with SSLSocket.getSession().getCipherSuite() and getProtocol() after the completed Handshake). 为了测试这个假设,我想测试在Smack中创建的底层SSLsocket(在完成Handshake之后使用SSLSocket.getSession()。getCipherSuite()和getProtocol())。 In order to do that, I was trying to pass a custom SSLSocketFactory which produces a custom SSLSocket (which would just output the CipherSuite and Protocol after the completed Handshake) to XMPPTCPConnectionConfiguration. 为了做到这一点,我试图传递一个自定义SSLSocketFactory,它生成一个自定义SSLSocket(它只会在完成握手后输出CipherSuite和Protocol)到XMPPTCPConnectionConfiguration。 But I can't seem to get this working either. 但我似乎无法让这个工作。

How do I get a connection to GCM CCS with SecurityMode.required established, for which isSecureConnection() returns true? 如何建立与SecurityMode.required建立的GCM CCS连接,为什么isSecureConnection()返回true?

Any help would be appreciated! 任何帮助,将不胜感激!

Same issue here, what I wound concerning this bug was: 同样的问题,我对这个bug的伤害是:

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

Which indicates that something is wrong with the SSL Session Cache (disabled by google). 这表示SSL会话缓存出错(由谷歌禁用)。 I had no luck to disable it on the server side (my side). 我没有运气在服务器端(我的身边)禁用它。

On the other side you may see more something like this: 另一方面,您可能会看到更多类似的内容:

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

If so you can see the issue here: https://jira.spring.io/browse/INT-3972 如果是这样,您可以在此处查看问题: https//jira.spring.io/browse/INT-3972

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

I had the very same problem with Smack 4.1.6. 我和Smack 4.1.6有同样的问题。

  1. SecurityMode mustn't be set to required ( https://community.igniterealtime.org/thread/55808 ). 不得将SecurityMode设置为requiredhttps://community.igniterealtime.org/thread/55808 )。

  2. When making up the username, project NUMBER, not project ID must be used (can be found at https://console.cloud.google.com ). 在编写用户名时,必须使用项目编号,而不是项目编号(可在https://console.cloud.google.com上找到)。

  3. My stupid mistake, but still. 我的愚蠢错误,但仍然。 When creating an API key for your project, choose carefully the platform: for some mysterious reason Android API keys don't work for a plain Java app (lol). 在为项目创建API密钥时,请仔细选择平台:出于某种神秘的原因,Android API密钥不适用于普通的Java应用程序(lol)。

  4. It seems, the service name can be anything, just not null. 看来,服务名称可以是任何东西,只是不为空。

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

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