pitrou commented on a change in pull request #123:
URL: https://github.com/apache/arrow-cookbook/pull/123#discussion_r797655109
##########
File path: python/source/flight.rst
##########
@@ -387,3 +387,214 @@ stream as it arrives, instead of reading them all into a
table:
# Shutdown the server
server.shutdown()
+
+Authentication with user/password
+=================================
+
+Often, services need a way to authenticate the user and identify who
+they are. Flight provides several ways to implement authentication;
+the simplest uses a user-password scheme. At startup, the client
+authenticates itself with the server using a username and
+password. The server returns an authorization token to include on
+future requests.
+
+.. warning:: Authentication should only be used over an encrypted
+ channel, i.e. TLS should be enabled.
+
+.. note:: While the scheme is described as "`(HTTP) basic
+ authentication`_", it does not actually implement HTTP
+ authentication (RFC 7325) per se.
+
+While Flight provides some interfaces to implement such a scheme, the
+server must provide the actual implementation, as demonstrated
+below. **The implementation here is not secure and is provided as a
+minimal example only.**
+
+.. testcode::
+
+ import base64
+ import pyarrow as pa
+ import pyarrow.flight
+
+
+ class EchoServer(pa.flight.FlightServerBase):
+ """A simple server that just echoes any requests from DoAction."""
+
+ def do_action(self, context, action):
+ return [action.type.encode("utf-8"), action.body]
+
+
+ class BasicAuthServerMiddlewareFactory(pa.flight.ServerMiddlewareFactory):
+ """Middleware that implements username-password authentication."""
+
+ def __init__(self, creds):
+ self.creds = creds
Review comment:
Perhaps indicate what `creds` should be?
##########
File path: python/source/flight.rst
##########
@@ -387,3 +387,214 @@ stream as it arrives, instead of reading them all into a
table:
# Shutdown the server
server.shutdown()
+
+Authentication with user/password
+=================================
+
+Often, services need a way to authenticate the user and identify who
+they are. Flight provides several ways to implement authentication;
Review comment:
Can we link to the "several ways" if they are documented or specified
somewhere?
##########
File path: python/source/flight.rst
##########
@@ -387,3 +387,214 @@ stream as it arrives, instead of reading them all into a
table:
# Shutdown the server
server.shutdown()
+
+Authentication with user/password
+=================================
+
+Often, services need a way to authenticate the user and identify who
+they are. Flight provides several ways to implement authentication;
+the simplest uses a user-password scheme. At startup, the client
+authenticates itself with the server using a username and
+password. The server returns an authorization token to include on
+future requests.
+
+.. warning:: Authentication should only be used over an encrypted
+ channel, i.e. TLS should be enabled.
+
+.. note:: While the scheme is described as "`(HTTP) basic
+ authentication`_", it does not actually implement HTTP
+ authentication (RFC 7325) per se.
+
+While Flight provides some interfaces to implement such a scheme, the
+server must provide the actual implementation, as demonstrated
+below. **The implementation here is not secure and is provided as a
+minimal example only.**
+
+.. testcode::
+
+ import base64
+ import pyarrow as pa
+ import pyarrow.flight
+
+
+ class EchoServer(pa.flight.FlightServerBase):
+ """A simple server that just echoes any requests from DoAction."""
+
+ def do_action(self, context, action):
+ return [action.type.encode("utf-8"), action.body]
+
+
+ class BasicAuthServerMiddlewareFactory(pa.flight.ServerMiddlewareFactory):
+ """Middleware that implements username-password authentication."""
+
+ def __init__(self, creds):
+ self.creds = creds
+
+ def start_call(self, info, headers):
+ """Validate credentials at the start of every call."""
+ # Search for the authentication header (case-insensitive)
+ token = None
+ for header in headers:
+ if header.lower() == "authorization":
+ token = headers[header]
+ break
+
+ if not token:
+ raise pa.flight.FlightUnauthenticatedError("No credentials
supplied")
+
+ # The header has the structure "AuthType TokenValue", e.g. "Basic
foo"
+ # or "Bearer bar".
+ values = token[0].split(" ", maxsplit=1)
+
+ if values[0] == "Basic":
+ # Initial "login". The user provided a username/password
+ # combination encoded in the same way as HTTP Basic Auth.
+ decoded = base64.b64decode(values[1])
+ username, password = decoded.decode("utf-8").split(':',
maxsplit=1)
+ if username not in self.creds or password !=
self.creds[username]:
+ raise pa.flight.FlightUnauthenticatedError("Unknown user or
invalid password")
+ # Return a bearer token to the user for future calls.
+ # Obviously, this is insecure and easily faked. This is for
+ # demonstration only.
+ bearer_token = username
+ return BasicAuthServerMiddleware(bearer_token)
+ elif values[0] == "Bearer":
+ # An actual call. Validate the bearer token returned to the
user.
+ # The token is just the username.
Review comment:
It shouldn't be difficult to generate an actual random token, actually.
Here is an example:
https://gist.github.com/pitrou/65083ea74fe75ee4f67b6a3e1040ed58
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]