我正在开发一个Java服务器,使用Smack 4.1.0 API作为XMPP客户端连接到Google云消息传递云连接服务器(GCM CCS),以向Android应用程序发送消息。我从此示例开始(https://developer.android.com/google/gcm/ccs.html),但是由于Smack API已更改,因此我相应地适应了代码。现在,我的Smack客户端成功连接到GCM CCS,发送消息并接收确认/拒绝/控制响应。
不幸的是,只有当我指定XMPPTCPConnectionConfiguration.Builder.setSecurityMode(SecurityMode.ifpossible)或(SecurityMode.disabled)时,连接才能正常工作。这样做时,XMPPTCPConnection.isSecureConnection()返回false。请参见下面的(相关)代码:
根据Google的说法,“连接具有两个重要要求:1)必须启动传输层安全性(TLS)连接……”(请参见上面的链接)。这让我觉得非TLS加密连接会被拒绝。我的问题出现在使用SecurityMode.required时。当使用该模式时,Smack会抛出以下错误代码:
我猜测(如有错请纠正),GCM CCS只接受TLS连接。但如果是这样,为什么我的SecurityMode.required连接尝试被拒绝,并显示“客户端需要SSL/TLS但服务器不支持”?
我也想知道是否成功建立了TLS连接,但isSecureConnection()仍然返回false的情况下,SecurityMode.disabled/SecurityMode.ifpossible是否真实存在?这种可能性是否存在?为了测试这个假设,我想测试在Smack中创建的底层SSLsocket(使用完成握手后的SSLSocket.getSession().getCipherSuite()和getProtocol())。为此,我试图将自定义SSLSocketFactory传递给XMPPTCPConnectionConfiguration,以生成自定义SSLSocket(它只会在完成握手后输出CipherSuite和Protocol)。但我似乎也无法让它起作用。
如何使用SecurityMode.required与GCM CCS建立安全的连接,并使isSecureConnection()返回true?
非常感谢您的帮助!
不幸的是,只有当我指定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());
根据Google的说法,“连接具有两个重要要求: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,如果我连接到GCM CCS而没有Smack API,只是打开一个TLS加密的连接,它可以正常工作。根据Google的评论,当向XMPPTCPConnectionConfiguration传递一个常规SocketFactory(不是SSLSocketFactory)时,无法建立连接:
org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout
我猜测(如有错请纠正),GCM CCS只接受TLS连接。但如果是这样,为什么我的SecurityMode.required连接尝试被拒绝,并显示“客户端需要SSL/TLS但服务器不支持”?
我也想知道是否成功建立了TLS连接,但isSecureConnection()仍然返回false的情况下,SecurityMode.disabled/SecurityMode.ifpossible是否真实存在?这种可能性是否存在?为了测试这个假设,我想测试在Smack中创建的底层SSLsocket(使用完成握手后的SSLSocket.getSession().getCipherSuite()和getProtocol())。为此,我试图将自定义SSLSocketFactory传递给XMPPTCPConnectionConfiguration,以生成自定义SSLSocket(它只会在完成握手后输出CipherSuite和Protocol)。但我似乎也无法让它起作用。
如何使用SecurityMode.required与GCM CCS建立安全的连接,并使isSecureConnection()返回true?
非常感谢您的帮助!