Glad that solved the header issue!

Honestly, I didn't even know that the driver had retries built in. We've
never seen a retry hit the server.

My guess is that something is failing server side, causing the driver to
retry. Is the server returning the correct results for each of the requests
in the PreparedStatement flow?

Are you correctly specifying the location on the FlightEndpoints for
FlightIinfo?

Something to note is that both ADBC and JDBC `.execute` calls actually use
PreparedStatements under the covers.

On Thu, Apr 18, 2024 at 10:15 AM Istvan Fodor <[email protected]> wrote:

> Thank you Diego, this is super helpful!
>
> I just added the headers to the do_handshake response, and now I get past
> the authentication issue. I'll follow up with the arrow-rs guys to see if
> we can add this change in the repo, it certainly seems to me it would make
> sense.
>
> I see another issue, not sure if it is driver related or more on the
> server side, but through you might have some ideas. When I try to run a
> query, the driver seems to call the server in a loop, roughly these are the
> service calls:
>
> arrow.flight.protocol.FlightService/Handshake
> arrow.flight.protocol.sql.ActionCreatePreparedStatementRequest
>
> (
> arrow.flight.protocol.sql.CreatePreparedStatement
> arrow.flight.protocol.sql.CommandPreparedStatementQuery
> arrow.flight.protocol.sql.FetchResults
> ) x5
>
> The driver eventually bombs out with the following error:
>
> java.sql.SQLException: Error while executing SQL "SELECT 1": Failed to
> successfully execute query after 5 attempts.
> at cfjd.org.apache.calcite.avatica.Helper.createException(Helper.java:56)
> at cfjd.org.apache.calcite.avatica.Helper.createException(Helper.java:41)
> at
> cfjd.org.apache.calcite.avatica.AvaticaStatement.executeQuery(AvaticaStatement.java:235)
> at com.fusiongrid.App.main(App.java:29)
> at org.codehaus.mojo.exec.ExecJavaMojo.doMain(ExecJavaMojo.java:385)
> at org.codehaus.mojo.exec.ExecJavaMojo.doExec(ExecJavaMojo.java:374)
> at
> org.codehaus.mojo.exec.ExecJavaMojo.lambda$execute$0(ExecJavaMojo.java:296)
> at java.base/java.lang.Thread.run(Thread.java:1570)
> Caused by: java.lang.RuntimeException: Failed to successfully execute
> query after 5 attempts.
> at
> cfjd.org.apache.calcite.avatica.AvaticaStatement.executeInternal(AvaticaStatement.java:168)
> at
> cfjd.org.apache.calcite.avatica.AvaticaStatement.executeQuery(AvaticaStatement.java:228)
> ... 5 more
>
> Have you seen anything like this on other server implementations?
>
>
>
> On Thu, Apr 18, 2024 at 11:31 AM Diego Fernandez <
> [email protected]> wrote:
>
>> Interesting... so the Rust AFS server is returning the token in the
>> payload? I believe it should be setting it on the returning headers instead.
>>
>> In the Java server, you decide on the authentication mechanism. The
>> equivalent of what you're trying to do is `BearerTokenAuthenticator`, which
>> allows you to validate the incoming Basic auth header and set the Bearer
>> token header in the response headers.
>>
>> After a quick look at the JDBC code, it seems like it's looking for the
>> header `authorization=Bearer <token>` in the response to set it for
>> following requests.
>>
>> Maybe the Rust server has a similar auth mechanism to
>> `BearerTokenAuthenticator`?
>>
>> On Thu, Apr 18, 2024 at 9:11 AM Istvan Fodor <[email protected]>
>> wrote:
>>
>>> Hi Jordan,
>>> I was testing with the example code in the Apache Arrow Rust repo:
>>> https://github.com/apache/arrow-rs/blob/master/arrow-flight/examples/flight_sql_server.rs
>>>
>>>
>>> To the best of my knowledge, it returns a token in the payload. I can
>>> see in ngrep that do_handshake is called and this is what it returns:
>>>
>>> let result = HandshakeResponse {
>>>             protocol_version: 0,
>>>             payload: FAKE_TOKEN.into(),
>>>         };
>>> let result = Ok(result);
>>> let output = futures::stream::iter(vec![result]);
>>> return Ok(Response::new(Box::pin(output)));
>>>
>>> In the Java code it looks like the authorization header is not part of
>>> the metadata that is passed:
>>>
>>> No authorization header! metadata = MetadataMap { headers:
>>> {"content-type": "application/grpc", "te": "trailers", "user-agent":
>>> "grpc-java-netty/1.60.0", "username": "admin", "grpc-accept-encoding":
>>> "gzip"} }
>>>
>>> I logged the metadata on the Rust side and the authorization header was
>>> missing indeed.
>>>
>>> IN the Netty logs it looks like the right Basic auth is passed in on
>>> getConnection, and the token comes back fine:
>>>
>>> 10:50:53.890 [grpc-nio-worker-ELG-1-2] DEBUG
>>> cfjd.io.grpc.netty.NettyClientHandler -- [id: 0x53dab587, L:/
>>> 127.0.0.1:59757 - R:/127.0.0.1:50050] OUTBOUND HEADERS: streamId=3
>>> headers=GrpcHttp2OutboundHeaders[:authority: 0.0.0.0:50050, :path:
>>> /arrow.flight.protocol.FlightService/Handshake, :method: POST, :scheme:
>>> http, content-type: application/grpc, te: trailers, user-agent:
>>> grpc-java-netty/1.60.0, username: admin, grpc-accept-encoding: gzip,
>>> authorization: Basic YWRtaW46cGFzc3dvcmQ=] streamDependency=0 weight=16
>>> exclusive=false padding=0 endStream=false
>>> 10:50:53.895 [grpc-nio-worker-ELG-1-2] DEBUG
>>> cfjd.io.grpc.netty.NettyClientHandler -- [id: 0x53dab587, L:/
>>> 127.0.0.1:59757 - R:/127.0.0.1:50050] OUTBOUND DATA: streamId=3
>>> padding=0 endStream=true length=5 bytes=0000000000
>>> 10:50:53.898 [grpc-nio-worker-ELG-1-2] DEBUG
>>> cfjd.io.grpc.netty.NettyClientHandler -- [id: 0x53dab587, L:/
>>> 127.0.0.1:59757 - R:/127.0.0.1:50050] INBOUND HEADERS: streamId=3
>>> headers=GrpcHttp2ResponseHeaders[:status: 200, content-type:
>>> application/grpc, date: Thu, 18 Apr 2024 15:50:53 GMT] padding=0
>>> endStream=false
>>> 10:50:53.899 [grpc-nio-worker-ELG-1-2] DEBUG
>>> cfjd.io.grpc.netty.NettyClientHandler -- [id: 0x53dab587, L:/
>>> 127.0.0.1:59757 - R:/127.0.0.1:50050] INBOUND DATA: streamId=3
>>> padding=0 endStream=false length=17 bytes=000000000c120a757569645f746f6b656e
>>>
>>> Subsequent calls in the JDBC/Netty log don't show the authorization
>>> header.
>>>
>>>
>>> On Wed, Apr 17, 2024 at 2:16 PM Istvan Fodor <[email protected]>
>>> wrote:
>>>
>>>> Hi All,
>>>>
>>>> I am trying to write a basic example of a Java/JDBC code querying from
>>>> the Arrow Rust example implementation of the Arrow Flight SQL server (
>>>> https://github.com/apache/arrow-rs/blob/master/arrow-flight/examples/flight_sql_server.rs).
>>>> My impression was that based on the interoperability goals of the Arrow
>>>> project, these should work together just fine.
>>>>
>>>> It turns out the in my Java code, I can authenticate (getConnection())
>>>> fine against the Rust server. User/password goes in, and a token comes
>>>> back, but subsequent calls (executeQuery() for example) don't include the
>>>> authorization token at all (it should look like authorization=Bearer
>>>> <token>), whereas I expected the token to just propagate to subsequent
>>>> calls as it should.
>>>>
>>>> I am using the 15.0.2 flight-sql-jdbc-driver. Any ideas what my issue
>>>> could be? Is there any extra setup that we need to do to get JDBC + Basic
>>>> auth to work besides supplying user and password parameters?
>>>>
>>>> Thanks,
>>>> Istvan Fodor
>>>>
>>>

Reply via email to