2015-05-18 69 views
3

我正在一個Java服務器上正在使用的Smack 4.1.0 API的XMPP客戶端連接到谷歌雲消息雲連接服務器(GCM CCS),以便將消息發送到Android應用程序。我從這個例子開始(https://developer.android.com/google/gcm/ccs.html),但隨着Smack API的改變,我相應地調整了代碼。到目前爲止,我的Smack客戶端已成功連接到GCM CCS,發送消息並接收ack/nack/control響應。使用的Smack 4.1.0 API的XMPP客戶端的谷歌的GCM CCS,SecurityMode.required不工作

不幸的是,如果我指定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有關。當使用,啪引發以下錯誤代碼:

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的如上,它工作正常,如果我連接到GCM CCS沒有啪API,只需打開一個TLS加密連接。在上面谷歌的註釋行,傳遞一個正的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?這可能嗎?爲了檢驗這一假設,我想測試所內拍擊產生的潛在的SSLSocket(與SSLSocket.getSession()。getCipherSuite()和的getProtocol()後完成握手)。爲了做到這一點,我試圖通過產生一個自定義的SSLSocket(這將只輸出的密文和協議的完成握手之後),以XMPPTCPConnectionConfiguration定製的SSLSocketFactory。但我似乎無法得到這個工作。

我如何與SecurityMode.required建立GCM CCS的連接,爲此isSecureConnection()返回true?

任何幫助,將不勝感激!

+0

可能是Truststore可以解決您的問題,我不確定與gcm css它會工作與否,但與xmpp服務器[openfire]它工作正常! http://stackoverflow.com/questions/24819441/certpathvalidatorexception-trust-anchor-for-certification-path-not-found-wit/26360672#26360672 – Dev

+1

感謝您的建議。正如您在代碼片段中看到的,我已經使用信任庫(「Windows-ROOT」)來提供所需的信任錨。我檢查了由此產生的TrustManagers,看看有什麼東西在這裏不起作用。但他們正確地「提取」了信任材料。我還使用默認的Java信任庫來測試整個事情。這兩個信任庫都可以正常使用與GCM CCS的常規TLS連接。所以我猜測信任商店應該按照預期工作。使用任一信任庫時,SecurityMode.required連接的Smack錯誤代碼保持不變。 – Skinner

回答

0

這裏同樣的問題,我的傷口就這個錯誤是:

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

0

我與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. 看來,服務名稱可以是任何東西,只是不爲空。

相關問題