Yes, the endpoint was there, but I noticed that location was missing the
port:

let loc = Location {uri: "grpc+tcp://127.0.0.1".to_string(),};

I will work with the arrow-rs team to add this as well! Thanks for the
help, very much appreciated!

On Thu, Apr 18, 2024 at 12:52 PM Diego Fernandez <[email protected]>
wrote:

> 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