当前位置: 首页 > 知识库问答 >
问题:

当使用Smack 4.1.0 API作为谷歌GCM CCS的XMPP客户端时,SecurityMode.required不工作

水浩歌
2023-03-14

我正在一台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/控制响应。

不幸的是,只有在指定XMPPTCPConnectionConfiguration时,连接才能正常工作。建设者设置SecurityMode(SecurityMode.if可能)或(SecurityMode.disabled)。在进行XMPPTCP连接时。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有关。必修的。使用该选项时,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)

我已经试了两天,想弄明白为什么我不能建立一个安全模式。需要连接,但失败。

使用与上面相同的SSLContext/SSLSocketFactory,如果我在没有Smack API的情况下连接到GCM CCS,只需打开一个TLS加密连接,它就可以正常工作。与谷歌的上述评论一致,当将常规SocketFactory(而非SSLSocketFactory)传递给XMPPTCPConnectionConfiguration时,无法建立连接:

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

所以我猜测(如果我错了,请纠正我),GCM CCS确实只接受TLS连接。但如果是这样的话,为什么我的安全模式是这样的呢。所需的连接尝试被拒绝,原因是“客户端需要SSL/TLS,但服务器不支持”?

我还想知道SecurityMode。禁用/安全模式。如果可能,实际上成功地建立了TLS连接,但isSecureConnection()返回false?这有可能吗?为了验证这个假设,我想测试在Smack中创建的底层SSLsocket(使用SSLsocket.getSession()。完成握手后的getCipherSuite()和getProtocol()。为了做到这一点,我试图将一个定制的SSLSocketFactory传递给XMPPTCPConnectionConfiguration,该工厂生产一个定制的SSLSocket(在完成握手后只输出密码套件和协议)。但我似乎也没法让它工作。

如何使用SecurityMode连接到GCM CCS。必需已建立,IsSecureReconnection()为哪个返回true?

任何帮助都将不胜感激!

共有2个答案

华星剑
2023-03-14

我对Smack 4.1.6也有同样的问题。

>

  • SecurityMode不能设置为必需(https://community.igniterealtime.org/thread/55808)。

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

    我犯了一个愚蠢的错误,但仍然如此。当你为你的项目创建一个应用编程接口密钥时,仔细选择平台:出于某种神秘的原因,Android应用编程接口密钥不适用于普通的Java应用程序(哈哈)。

    看起来,服务名称可以是任何东西,只是不能为null。

  • 施俊远
    2023-03-14

    同样的问题在这里,我伤口关于这个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

     类似资料:
    • 我将appengine gcs客户端添加到我的Google appengine标准项目中: (此页上的说明如下:https://cloud.google.com/appengine/docs/standard/java/googlecloudstorageclient/setting-up-cloud-storage) 编译项目会引发以下错误(几天前没有问题): [错误]无法在项目myprojec

    • 我有一个谷歌云,我想推我的图像。 我的图片是Hello-world项目与节点快递谷歌云客户端libray 你可以在我的github上找到它 https://github.com/innostarterkit/language 当我试着推的时候,我有这个错误 推送是指存储库[eu.gcr.io/innovation xxx/hello]a419c4413fb0:推送[================

    • 我正在编写一个类,用于创建对BigQuery和Google云存储的授权。 在过去,我曾使用,但已被弃用。我试图使用,但我发现它只允许我使用,而我需要。 我知道可以从转换为,但我不知道如何将它们转换成相反的方向(转换为)。例如,我像这样创建连接: 有人能给我指明如何实现这一目标的方向吗? 谢谢!

    • 我有一个wsdl: 我想提交信息以获得回应。我创建了client.php如下: 但它在浏览器中显示错误: SoapFault对象([消息:受保护]= 我错在哪里?对此,可能的解决方案是什么? 编辑: 我已经创建了一个php文件:client。php 但它产生了这个错误: 调用错误:响应不是文本/xml类型:应用程序/wsdl xmlHTTP/1.1 200确定日期:星期二,9月17日2013 15

    • 当您使用Google Drive Web客户端时,您可以第一次选择要连接的Google帐户。完成后续调用后,跳过您可以选择帐户的步骤——您不必再次授权。有没有办法在不实际退出Google帐户的情况下再次触发帐户选择? 我正在使用文件选择器API,参见https://developers.google.com/picker/docs/

    • 问题内容: 建筑: 我们有一个使用2个pubsub主题/订阅对的架构: 定期由cronjob触发主题(例如,每5分钟触发一次)。订阅是我们云功能的触发器。 主题充当我们的一项服务发布的后台作业的队列。云功能在每次执行时读取订阅,以为排队的后台作业提供服务。 这使我们可以控制后台作业的服务频率,而与将它们添加到队列的时间无关。 云功能(由触发)通过pull读取消息。它决定准备好哪些后台作业,并在成功