-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
ARROW-11004: [FlightRPC][Python] Header-based auth in clients #8959
Changes from all commits
d241e50
206e1c8
c0dcca2
661a2a3
b999123
c162932
2cf5bbf
35e79e8
87043dd
ce33893
a861ac1
638113a
7c06d01
0ed06a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,7 +107,7 @@ cdef class FlightCallOptions(_Weakrefable): | |
cdef: | ||
CFlightCallOptions options | ||
|
||
def __init__(self, timeout=None, write_options=None): | ||
def __init__(self, timeout=None, write_options=None, headers=None): | ||
"""Create call options. | ||
|
||
Parameters | ||
|
@@ -118,12 +118,18 @@ cdef class FlightCallOptions(_Weakrefable): | |
write_options : pyarrow.ipc.IpcWriteOptions, optional | ||
IPC write options. The default options can be controlled | ||
by environment variables (see pyarrow.ipc). | ||
|
||
headers : List[Tuple[str, str]], optional | ||
A list of arbitrary headers as key, value tuples | ||
""" | ||
cdef IpcWriteOptions options = _get_options(write_options) | ||
cdef IpcWriteOptions c_write_options | ||
|
||
if timeout is not None: | ||
self.options.timeout = CTimeoutDuration(timeout) | ||
self.options.write_options = options.c_options | ||
if write_options is not None: | ||
c_write_options = _get_options(write_options) | ||
self.options.write_options = c_write_options.c_options | ||
if headers is not None: | ||
self.options.headers = headers | ||
|
||
@staticmethod | ||
cdef CFlightCallOptions* unwrap(obj): | ||
|
@@ -1150,6 +1156,38 @@ cdef class FlightClient(_Weakrefable): | |
self.client.get().Authenticate(deref(c_options), | ||
move(handler))) | ||
|
||
def authenticate_basic_token(self, username, password, | ||
options: FlightCallOptions = None): | ||
"""Authenticate to the server with HTTP basic authentication. | ||
|
||
Parameters | ||
---------- | ||
username : string | ||
Username to authenticate with | ||
password : string | ||
Password to authenticate with | ||
options : FlightCallOptions | ||
Options for this call | ||
|
||
Returns | ||
------- | ||
tuple : Tuple[str, str] | ||
A tuple representing the FlightCallOptions authorization | ||
header entry of a bearer token. | ||
""" | ||
cdef: | ||
CResult[pair[c_string, c_string]] result | ||
CFlightCallOptions* c_options = FlightCallOptions.unwrap(options) | ||
c_string user = tobytes(username) | ||
c_string pw = tobytes(password) | ||
|
||
with nogil: | ||
result = self.client.get().AuthenticateBasicToken(deref(c_options), | ||
user, pw) | ||
check_flight_status(result.status()) | ||
|
||
return GetResultValue(result) | ||
|
||
def list_actions(self, options: FlightCallOptions = None): | ||
"""List the actions available on a service.""" | ||
cdef: | ||
|
@@ -1871,7 +1909,6 @@ cdef CStatus _server_authenticate(void* self, CServerAuthSender* outgoing, | |
reader.poison() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a typo "poison"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a typo. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is to ensure a server doesn't use the Python reader beyond the lifetime of the C++ reader it wraps. |
||
return CStatus_OK() | ||
|
||
|
||
cdef CStatus _is_valid(void* self, const c_string& token, | ||
c_string* peer_identity) except *: | ||
"""Callback for implementing authentication in Python.""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -216,6 +216,7 @@ cdef extern from "arrow/flight/api.h" namespace "arrow" nogil: | |
CFlightCallOptions() | ||
CTimeoutDuration timeout | ||
CIpcWriteOptions write_options | ||
vector[pair[c_string, c_string]] headers | ||
|
||
cdef cppclass CCertKeyPair" arrow::flight::CertKeyPair": | ||
CCertKeyPair() | ||
|
@@ -307,6 +308,11 @@ cdef extern from "arrow/flight/api.h" namespace "arrow" nogil: | |
CStatus Authenticate(CFlightCallOptions& options, | ||
unique_ptr[CClientAuthHandler] auth_handler) | ||
|
||
CResult[pair[c_string, c_string]] AuthenticateBasicToken( | ||
CFlightCallOptions& options, | ||
const c_string& username, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the uninitiated, what are the coding standards on Class & variable names? I see a mixture of camel case and underscore separated names. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The mixture here is because this is a set of Cython type definitions for C++ code, which uses the C++ conventions (e.g. CResult), but the overall project is in Python, which uses Python conventions (e.g. c_string) |
||
const c_string& password) | ||
|
||
CStatus DoAction(CFlightCallOptions& options, CAction& action, | ||
unique_ptr[CResultStream]* results) | ||
CStatus ListActions(CFlightCallOptions& options, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't there be a FlightCallOption implementation to do this? How do you use HTTP basic auth without using authenticateBasicToken? (eg in Java you can directly call getFlightInfo without calling an authenticate function and supply a FlightCallOption with the basic auth info).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on how the C++ code was implemented , the Python wrapper can only wrap the AuthenticateBasicToken method in the C++ client. Seems like we would need to expand the C++ client implementation if we were to have C++/Python impl match the Java client implementation. #8724 -> C++ impl only exposed authenticateBasicToken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jduo are the changes in this PR sufficient?