Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Authentication changes to better support FlightSQL clients #6032

Merged
merged 11 commits into from
Oct 8, 2024

Conversation

niloc132
Copy link
Member

@niloc132 niloc132 commented Sep 8, 2024

Handshake calls previously required the client to send at least one message before sending a response, even if the required auth information was included in headers, now the server will respond and close the stream right away. This change could cause problems for older DH clients (specifically JS and Go clients), but the fix for this was released in 0.36.

Bearer authentication would fail if the token wasn't in the form of a UUID, even if an alternative authentication handler was going to accept the token.

Some Flight clients are unable to send auth types other than Basic and Bearer, our authentication interceptor can now support the auth type as a space-separated prefix of the auth token.

Fixes #5922

@niloc132 niloc132 added this to the 0.37.0 milestone Sep 8, 2024
@niloc132 niloc132 self-assigned this Sep 8, 2024
SessionState session = sessionService.getSessionForToken(uuid);
respondWithAuthTokenBin(session);
return;
} catch (IllegalArgumentException | InvalidUuidException ignored) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we expect IllegalArgumentException to ever get hit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this one is a real one - if session were null, respondWithAuthTokenBin would NPE (which inherts from IAE).

Probably better to wrap in a null check, in conjunction with the change below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, there's another way IAE can get hit here - if the req's payload isn't valid ascii, the String constructor will throw.

This is only an error in terms of "we cant read it as a uuid", this might be valid non-ascii bytes for some other auth handler.

@niloc132
Copy link
Member Author

Added another fix to handle v1 auth uuid being "invalid"

@@ -345,7 +346,7 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(final ServerCall<Re
if (altToken != null) {
try {
session = service.getSessionForToken(UUID.fromString(new String(altToken)));
} catch (IllegalArgumentException ignored) {
} catch (IllegalArgumentException | InvalidUuidException ignored) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We aren't using the f4b6a3 library for parsing here, so I don't think we should explicitly try to catch this exception; should we update to using f4b6a3 library? I guess wider Q: what's the difference between UUID and f4b6a3?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UuidCreator is capable of generating random uuids, unlike the default java impl.

According to its documentation, it is also substantially faster at parsing uuids than the default impl, so we're preferring it if we have the choice.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which case we should swap out the call from UUID.fromString to the UuidCreator?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to UuidCreator, and specified that the altToken bytes are ascii - but we need the IAE here as above in case the bytes aren't acsii? I'm not 100% that this is an invalid state though, just "we don't accept your token", so we move on?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think String throws IAE...

This method always replaces malformed-input and unmappable-character sequences with this charset's default replacement string

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is what the javadoc says, but doesn't quite match the bytecode I'm looking at (for Java 11, our default runtime for gradle). This might not strictly throw IAE for ascii, but there are paths to throw in this constructor:

String(byte[]) calls
String(byte[], int, int) calls
java.lang.StringCoding#decode(byte[], int, int)

  • For utf8 this can end up in
    java.lang.StringCoding#decodeUTF8_0 which clearly calls throwMalformed(), which will be a IAE
  • For ascii does seem to be safe
  • for latin1 also seems to be safe
  • for other charsets, this ends up in java.lang.StringCoding.StringDecoder#decode, which explicitly throws Error in response to CharacterEncodingExceptions

So I think you're right that this can't break, but I'm skeptical about trusting that it can't throw IAE at least in case we change our handling here (note that we used to decode as file.encoding, this patch fixes that to be ascii, and file.encoding defaults to utf-8 which according to the above can throw IAE) or Java weakens its implementation.

Copy link
Member

@nbauernfeind nbauernfeind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM aside from resolving existing conversation(s).

Copy link
Member

@devinrsmith devinrsmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not going to hold merge over IAE stuff, lgtm.

@@ -345,7 +346,7 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(final ServerCall<Re
if (altToken != null) {
try {
session = service.getSessionForToken(UUID.fromString(new String(altToken)));
} catch (IllegalArgumentException ignored) {
} catch (IllegalArgumentException | InvalidUuidException ignored) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think String throws IAE...

This method always replaces malformed-input and unmappable-character sequences with this charset's default replacement string

@niloc132 niloc132 merged commit 39a2fc0 into deephaven:main Oct 8, 2024
17 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Oct 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dremio odbc interpretation of flight auth
3 participants