我正在一個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?
任何幫助,將不勝感激!
可能是Truststore可以解決您的問題,我不確定與gcm css它會工作與否,但與xmpp服務器[openfire]它工作正常! http://stackoverflow.com/questions/24819441/certpathvalidatorexception-trust-anchor-for-certification-path-not-found-wit/26360672#26360672 – Dev
感謝您的建議。正如您在代碼片段中看到的,我已經使用信任庫(「Windows-ROOT」)來提供所需的信任錨。我檢查了由此產生的TrustManagers,看看有什麼東西在這裏不起作用。但他們正確地「提取」了信任材料。我還使用默認的Java信任庫來測試整個事情。這兩個信任庫都可以正常使用與GCM CCS的常規TLS連接。所以我猜測信任商店應該按照預期工作。使用任一信任庫時,SecurityMode.required連接的Smack錯誤代碼保持不變。 – Skinner