TheBestOrNothing / whispeer-kafka-oauth

OAuth2 support for Apache Kafka® to work with many OAuth2 authorization servers
Apache License 2.0
1 stars 0 forks source link

org.bouncycastle.tls.TlsFatalAlertReceived: handshake_failure #4

Open TheBestOrNothing opened 1 year ago

TheBestOrNothing commented 1 year ago

Sep 05, 2023 12:21:03 PM org.bouncycastle.jsse.provider.ProvTlsClient notifyAlertReceived INFO: [client #44 @2181a2c6] received fatal(2) handshake_failure(40) alert Sep 05, 2023 12:21:03 PM org.bouncycastle.jsse.provider.ProvTlsClient notifyConnectionClosed INFO: [client #44 @2181a2c6] disconnected from eth-goerli.g.alchemy.com:443 Sep 05, 2023 12:21:03 PM org.bouncycastle.jsse.provider.ProvTlsClient notifyHandshakeBeginning INFO: [client #45 @4df04033] opening connection to eth-goerli.g.alchemy.com:443 Sep 05, 2023 12:21:03 PM org.bouncycastle.jsse.provider.ProvTlsClient notifyAlertReceived INFO: [client #45 @4df04033] received fatal(2) handshake_failure(40) alert Sep 05, 2023 12:21:03 PM org.bouncycastle.jsse.provider.ProvTlsClient notifyConnectionClosed INFO: [client #45 @4df04033] disconnected from eth-goerli.g.alchemy.com:443 org.bouncycastle.tls.TlsFatalAlertReceived: handshake_failure(40)         at org.bouncycastle.tls.TlsProtocol.handleAlertMessage(TlsProtocol.java:245)         at org.bouncycastle.tls.TlsProtocol.processAlertQueue(TlsProtocol.java:740)         at org.bouncycastle.tls.TlsProtocol.processRecord(TlsProtocol.java:563)         at org.bouncycastle.tls.RecordStream.readRecord(RecordStream.java:247)         at org.bouncycastle.tls.TlsProtocol.safeReadRecord(TlsProtocol.java:879)         at org.bouncycastle.tls.TlsProtocol.blockForHandshake(TlsProtocol.java:427)         at org.bouncycastle.tls.TlsClientProtocol.connect(TlsClientProtocol.java:88)         at org.bouncycastle.jsse.provider.ProvSSLSocketWrap.startHandshake(ProvSSLSocketWrap.java:608)         at org.bouncycastle.jsse.provider.ProvSSLSocketWrap.startHandshake(ProvSSLSocketWrap.java:584)         at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:379)         at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)         at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)         at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)         at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)         at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)         at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)         at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)         at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)         at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)         at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)         at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)         at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)         at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)         at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)         at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)         at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)         at org.web3j.protocol.http.HttpService.performIO(HttpService.java:159)         at org.web3j.protocol.Service.send(Service.java:48)         at org.web3j.protocol.core.Request.send(Request.java:87)         at io.strimzi.kafka.oauth.validator.AccessValidator.ethValidate(AccessValidator.java:109)         at io.strimzi.kafka.oauth.server.JaasServerOauthValidatorCallbackHandler.handleCallback (JaasServerOauthValidatorCallbackHandler.java:343)         at io.strimzi.kafka.oauth.server.JaasServerOauthValidatorCallbackHandler.delegatedHandle (JaasServerOauthValidatorCallbackHandler.java:322)         at io.strimzi.kafka.oauth.server.JaasServerOauthValidatorCallbackHandler.handle(JaasServerOauthValidatorCallbackHandler.java:301)         at org.apache.kafka.common.security.oauthbearer.internals.OAuthBearerSaslServer.process(OAuthBearerSaslServer.java:156)         at org.apache.kafka.common.security.oauthbearer.internals.OAuthBearerSaslServer.evaluateResponse (OAuthBearerSaslServer.java:101)         at org.apache.kafka.common.security.authenticator.SaslServerAuthenticator.handleSaslToken(SaslServerAuthenticator.java:459)         at org.apache.kafka.common.security.authenticator.SaslServerAuthenticator.authenticate(SaslServerAuthenticator.java:288)         at org.apache.kafka.common.network.KafkaChannel.prepare(KafkaChannel.java:181)         at org.apache.kafka.common.network.Selector.pollSelectionKeys(Selector.java:543)         at org.apache.kafka.common.network.Selector.poll(Selector.java:481)         at kafka.network.Processor.poll(SocketServer.scala:1056)         at kafka.network.Processor.run(SocketServer.scala:960)         at java.base/java.lang.Thread.run(Thread.java:833)         Suppressed: org.bouncycastle.tls.TlsFatalAlertReceived: handshake_failure(40)         ... 43 more

TheBestOrNothing commented 1 year ago

handshake failed when the we3j use org.bouncycastle.jsse.provider to handsake. The failure happened when kafka broker start on docker container, but it is successful to runing on the host. Maybe the failure is related to the network configuration in the docker conainer. Maybe the failure reason is the time from org.bouncycastle.jsse.provider is not same as system's in container.

TheBestOrNothing commented 1 year ago

The workround is to adapt the code web3j.ethCall to AsyncHttpClient.

Orignal web3j.ethCall code:

        Web3j web3j = Web3j.build(new HttpService(provider)); 
        Function function = new Function(
                "getExpirationTime",
                Collections.singletonList(new Address(address)), // Function parameters

        String encodedFunction = FunctionEncoder.encode(function);

        //from = admin; to = whispeerAddress; data = encodedFunction;
        Transaction transaction = new Transaction(adminAdress, null, null, null, whispeerAdress, null, encodedFunction, null, null, null);

        EthCall response = null;
        try {
            response = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
        } catch (IOException e) {
            e.printStackTrace();
        }

the workwroud code with AsyncHttpClient :

        String body = null;
        AsyncHttpClient client = new DefaultAsyncHttpClient();

        // Create the innermost JSON object
        JSONObject innerObject = new JSONObject();
        innerObject.put("to", whispeerAdress);
        innerObject.put("from", adminAdress);
        innerObject.put("data", encodedFunction);

        // Create the JSON array for "params" and add the inner object and the string
        JSONArray paramsArray = new JSONArray();
        paramsArray.put(innerObject);
        paramsArray.put("latest");

        // Create the outer JSON object
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", 1);
        jsonObject.put("jsonrpc", "2.0");
        jsonObject.put("method", "eth_call");
        jsonObject.put("params", paramsArray);

        body = jsonObject.toString();
        System.out.println(jsonObject.toString());

        try {

            Response response = client.prepare("POST", provider)
                      .setHeader("accept", "application/json")
                      .setHeader("content-type", "application/json")
                      .setBody(body)
                      .execute()
                      .toCompletableFuture()
                      .join();

            if (response.getStatusCode() == 200) {
                String responseStr = response.getResponseBody();
                System.out.println("Response: " + responseStr);
                status = true;

                // Parse the JSON response using org.json.JSONObject
                JSONObject responseJson = new JSONObject(responseStr);

                // Get the "result" value as a hexadecimal string
                String resultHex = responseJson.getString("result");

                // Convert the hexadecimal string to a BigInteger
                expirationTime = new BigInteger(resultHex.substring(2), 16);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                client.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }