让apple推送http/2在Java7上工作

gj3fmq9x  于 2021-07-06  发布在  Java
关注(0)|答案(0)|浏览(287)

我们的客户有一个运行在Java7U80上的JBoss7.1.1应用程序,该应用程序使用apple推送通知框架发送推送通知。它一直在为此使用javapns库。到目前为止,它的工作效果很好,但是现在苹果正在切换到http/2,并且可用的第三方push-lib是为java8+构建的。
它不是升级服务器或java运行时的选项(JBoss7.1.1不在Java8上运行)。
我正在尝试让push与okhttp3.12.12(在它也转移到java 8之前的最后一个okhttp版本)一起工作,并且我添加了对bouncycastle的依赖性,以便升级到tls1.2和所需的密码,对于apple push,我相信:
tls\u ecdhe\u rsa\u带\u aes\u 256\u gcm\u sha384
tls\u ecdhe\u rsa\u带\u chacha20\u poly1305\u sha256
tls\U ecdhe\U rsa\U带\U aes\U 128\U gcm\U sha256
我的bouncycastle依赖项:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bctls-jdk15to18</artifactId>
    <version>1.67</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-ext-jdk15to18</artifactId>
    <version>1.67</version>
</dependency>

我有一个创业班,看起来像:

@Singleton
@Startup
public class MCPStartUp {
    @PostConstruct
    public void init() {
        System.setProperty("https.protocols", "TLSv1.2");

        Security.addProvider(new BouncyCastleJsseProvider());
        Security.addProvider(new BouncyCastleProvider());

        try {
            SSLContext context = SSLContext.getInstance("TLSv1.2", "BCJSSE");
            context.init(null, null, new SecureRandom());
            SSLContext.setDefault(context);

            SSLSocketFactory factory = (SSLSocketFactory) context.getSocketFactory();
            SSLSocket socket = (SSLSocket) factory.createSocket();

            String[] protocols = socket.getEnabledProtocols();
            for (String string : protocols)
                System.out.println("protocol:" + string);
            for (String string2 : socket.getEnabledCipherSuites())
                System.out.println("enabled cipher: " + string2);
            for (String string2 : socket.getSupportedCipherSuites())
                System.out.println("supported cipher: " + string2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

当我查看输出时,我发现我需要的密码已经启用了。

enabled cipher: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

到现在为止,一直都还不错。
我用于发送推送通知的测试类如下所示:

public void test(String deviceToken) {
    // load push certificate
    FileInputStream certificate = new FileInputStream(APNS_CERT_PATH);
    KeyStore ks = KeyStore.getInstance("PKCS12");
    ks.load(certificate, APNS_CERT_PASS.toCharArray());

    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(ks, APNS_CERT_PASS.toCharArray());

    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(ks);

    KeyManager[] keyManagers = kmf.getKeyManagers();

    SSLContext sslContext = SSLContext.getDefault();
    sslContext.init(keyManagers, tmf.getTrustManagers(), new SecureRandom());

    final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

    OkHttpClient client = new OkHttpClient.Builder()
            .sslSocketFactory(sslSocketFactory, (X509TrustManager) tmf.getTrustManagers()[0])
            .build();

    final Notification notification = new Notification.Builder(deviceToken).alertBody("Hello").build();

    Request.Builder rb = new Request.Builder().url("https://api.development.push.apple.com/3/device/" + deviceToken)
            .post(new RequestBody() {
                @Override
                public MediaType contentType() {
                    return MediaType.parse("application/json");
                }

                @Override
                public void writeTo(BufferedSink sink) throws IOException {
                    sink.write(notification.getPayload().getBytes(Charset.forName("UTF-8")));
                }
            })
            .header("apns-topic", "XXX")
            .header("content-length", notification.getPayload().getBytes(Charset.forName("UTF-8")).length + "");

    Request request = rb.build();
    Response response = client.newCall(request).execute();
    return response.code() == 200;
}

当我运行测试类(从rest服务调用)时,我可以在wireshark中看到客户端hello握手不包括所需的密码:

(我对tls版本也有点困惑,因为TLS1.0(蓝色框)和TLS1.2字段(红色框)都有。我假设它正确地使用了tls1.2。)
我收到以下答复:

这是意料之中的,因为我的初始请求不包括所需的密码。但在启动过程中,我已经验证了它们在我的Java7U80运行时中确实可用。
我尝试过更改代码以显式使用密码:

ConnectionSpec connectionSpec = new ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS)
                .cipherSuites(
                        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
                        "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
                        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
                .build();

OkHttpClient client = new OkHttpClient.Builder()
                .sslSocketFactory(sslSocketFactory, (X509TrustManager) tmf.getTrustManagers()[0])
                .connectionSpecs(Arrays.asList(connectionSpec))
                .build();

但这给了我一个例外:

Caused by: java.lang.IllegalStateException: No usable cipher suites enabled
at org.bouncycastle.jsse.provider.ProvSSLContextSpi.getActiveCipherSuites(Unknown Source) [bctls-jdk15to18-1.67.jar:1.67.00.0]
at org.bouncycastle.jsse.provider.ProvTlsClient.getSupportedCipherSuites(Unknown Source) [bctls-jdk15to18-1.67.jar:1.67.00.0]
at org.bouncycastle.tls.AbstractTlsClient.init(Unknown Source) [bctls-jdk15to18-1.67.jar:1.67.00.0]
at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source) [bctls-jdk15to18-1.67.jar:1.67.00.0]
at org.bouncycastle.jsse.provider.ProvSSLSocketWrap.startHandshake(Unknown Source) [bctls-jdk15to18-1.67.jar:1.67.00.0]
at org.bouncycastle.jsse.provider.ProvSSLSocketWrap.startHandshake(Unknown Source) [bctls-jdk15to18-1.67.jar:1.67.00.0]
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:320) [okhttp-3.12.12.jar:]

为了让这一切顺利进行,我还缺什么?如果你需要更多信息,请告诉我。希望你们能帮忙!
向拉斯姆斯致意

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题