This is an automated email from the ASF dual-hosted git repository.

kou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new 106568d5a7 GH-34074: [GLib][FlightRPC] Add support for authentication 
(#34090)
106568d5a7 is described below

commit 106568d5a742605f7e96eeeab73ca19dac7039e3
Author: Sutou Kouhei <[email protected]>
AuthorDate: Fri Feb 10 12:52:55 2023 +0900

    GH-34074: [GLib][FlightRPC] Add support for authentication (#34090)
    
    ### Rationale for this change
    
    Authentication related features are missing.
    
    ### What changes are included in this PR?
    
    New APIs:
    
    * `gaflight_client_authenticate_basic_token()`
    * `GAFlightServerAuthSender`
    * `GAFlightServerAuthReader`
    * `GAFlightServerAuthHandler`
    
    ### Are these changes tested?
    
    Yes.
    
    ### Are there any user-facing changes?
    
    Yes.
    * Closes: #34074
    
    Authored-by: Sutou Kouhei <[email protected]>
    Signed-off-by: Sutou Kouhei <[email protected]>
---
 c_glib/Gemfile                                     |   2 +-
 c_glib/arrow-flight-glib/client.cpp                |  47 ++
 c_glib/arrow-flight-glib/client.h                  |  10 +
 c_glib/arrow-flight-glib/server.cpp                | 485 ++++++++++++++++++++-
 c_glib/arrow-flight-glib/server.h                  |  95 ++++
 c_glib/arrow-flight-glib/server.hpp                |  15 +
 c_glib/arrow-glib/version.h.in                     |  23 +
 .../arrow-flight-glib/arrow-flight-glib-docs.xml   |   4 +
 c_glib/doc/arrow-glib/arrow-glib-docs.xml          |   4 +
 c_glib/test/flight/test-client.rb                  |   8 +
 c_glib/test/helper/flight-server.rb                |  13 +
 11 files changed, 704 insertions(+), 2 deletions(-)

diff --git a/c_glib/Gemfile b/c_glib/Gemfile
index 015f962de5..d32bc87ba7 100644
--- a/c_glib/Gemfile
+++ b/c_glib/Gemfile
@@ -20,4 +20,4 @@
 source "https://rubygems.org/";
 
 gem "test-unit"
-gem "gobject-introspection", ">= 3.4.9"
+gem "gobject-introspection", ">= 4.1.1"
diff --git a/c_glib/arrow-flight-glib/client.cpp 
b/c_glib/arrow-flight-glib/client.cpp
index 862cfe093e..960449abb9 100644
--- a/c_glib/arrow-flight-glib/client.cpp
+++ b/c_glib/arrow-flight-glib/client.cpp
@@ -404,6 +404,53 @@ gaflight_client_close(GAFlightClient *client,
                        "[flight-client][close]");
 }
 
+/**
+ * gaflight_client_authenticate_basic_token:
+ * @client: A #GAFlightClient.
+ * @user: User name to be used.
+ * @password: Password to be used.
+ * @options: (nullable): A #GAFlightCallOptions.
+ * @bearer_name: (out) (transfer full): Bearer token name on success.
+ * @bearer_value: (out) (transfer full): Bearer token value on success.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Authenticates to the server using basic HTTP style authentication.
+ *
+ * Returns: %TRUE on success, %FALSE if there was an error.
+ *
+ * Since: 12.0.0
+ */
+gboolean
+gaflight_client_authenticate_basic_token(GAFlightClient *client,
+                                         const gchar *user,
+                                         const gchar *password,
+                                         GAFlightCallOptions *options,
+                                         gchar **bearer_name,
+                                         gchar **bearer_value,
+                                         GError **error)
+{
+  auto flight_client = gaflight_client_get_raw(client);
+  arrow::flight::FlightCallOptions flight_default_options;
+  auto flight_options = &flight_default_options;
+  if (options) {
+    flight_options = gaflight_call_options_get_raw(options);
+  }
+  auto result = flight_client->AuthenticateBasicToken(*flight_options,
+                                                      user,
+                                                      password);
+  if (!garrow::check(error,
+                     result,
+                     "[flight-client][authenticate-basic-token]")) {
+    return FALSE;
+  }
+  auto bearer_token = *result;
+  *bearer_name = g_strndup(bearer_token.first.data(),
+                           bearer_token.first.size());
+  *bearer_value = g_strndup(bearer_token.second.data(),
+                            bearer_token.second.size());
+  return TRUE;
+}
+
 /**
  * gaflight_client_list_flights:
  * @client: A #GAFlightClient.
diff --git a/c_glib/arrow-flight-glib/client.h 
b/c_glib/arrow-flight-glib/client.h
index 30ddb0076c..42b18bfa60 100644
--- a/c_glib/arrow-flight-glib/client.h
+++ b/c_glib/arrow-flight-glib/client.h
@@ -105,6 +105,16 @@ gboolean
 gaflight_client_close(GAFlightClient *client,
                       GError **error);
 
+GARROW_AVAILABLE_IN_12_0
+gboolean
+gaflight_client_authenticate_basic_token(GAFlightClient *client,
+                                         const gchar *user,
+                                         const gchar *password,
+                                         GAFlightCallOptions *options,
+                                         gchar **bearer_name,
+                                         gchar **bearer_value,
+                                         GError **error);
+
 GARROW_AVAILABLE_IN_5_0
 GList *
 gaflight_client_list_flights(GAFlightClient *client,
diff --git a/c_glib/arrow-flight-glib/server.cpp 
b/c_glib/arrow-flight-glib/server.cpp
index 4af1bf60d4..62fe912ec7 100644
--- a/c_glib/arrow-flight-glib/server.cpp
+++ b/c_glib/arrow-flight-glib/server.cpp
@@ -41,6 +41,15 @@ G_BEGIN_DECLS
  * IPC payloads to be sent in `FlightData` protobuf messages by
  * #GArrowRecordBatchReader`.
  *
+ * #GAFlightServerAuthSender is a class for sending messages to the
+ * client during an authentication handshake.
+ *
+ * #GAFlightServerAuthReader is a class for reading messages from the
+ * client during an authentication handshake.
+ *
+ * #GAFlightServerAuthHandler is an abstract class to implement
+ * authentication for a Flight service.
+ *
  * #GAFlightServerOptions is a class for options of each server.
  *
  * #GAFlightServerCallContext is a class for context of each server call.
@@ -249,13 +258,402 @@ gaflight_record_batch_stream_new(GArrowRecordBatchReader 
*reader,
 }
 
 
+struct GAFlightServerAuthSenderPrivate {
+  arrow::flight::ServerAuthSender *sender;
+};
+
+enum {
+  PROP_SERVER_AUTH_SENDER = 1,
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GAFlightServerAuthSender,
+                           gaflight_server_auth_sender,
+                           G_TYPE_OBJECT)
+
+#define GAFLIGHT_SERVER_AUTH_SENDER_GET_PRIVATE(obj)        \
+  static_cast<GAFlightServerAuthSenderPrivate *>(           \
+    gaflight_server_auth_sender_get_instance_private(       \
+      GAFLIGHT_SERVER_AUTH_SENDER(obj)))
+
+static void
+gaflight_server_auth_sender_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec)
+{
+  auto priv = GAFLIGHT_SERVER_AUTH_SENDER_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_SERVER_AUTH_SENDER:
+    priv->sender =
+      static_cast<arrow::flight::ServerAuthSender 
*>(g_value_get_pointer(value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+gaflight_server_auth_sender_init(GAFlightServerAuthSender *object)
+{
+}
+
+static void
+gaflight_server_auth_sender_class_init(GAFlightServerAuthSenderClass *klass)
+{
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->set_property = gaflight_server_auth_sender_set_property;
+
+  GParamSpec *spec;
+  spec = g_param_spec_pointer("sender",
+                              "Sender",
+                              "The raw arrow::flight::ServerAuthSender *",
+                              static_cast<GParamFlags>(G_PARAM_WRITABLE |
+                                                       
G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_SERVER_AUTH_SENDER, 
spec);
+}
+
+/**
+ * gaflight_server_auth_sender_write:
+ * @sender: A #GAFlightServerAuthSender.
+ * @message: A #GBytes to be sent.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Writes a message to the client.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 12.0.0
+ */
+gboolean
+gaflight_server_auth_sender_write(GAFlightServerAuthSender *sender,
+                                  GBytes *message,
+                                  GError **error)
+{
+  auto flight_sender = gaflight_server_auth_sender_get_raw(sender);
+  gsize size;
+  auto data = g_bytes_get_data(message, &size);
+  const std::string flight_message(static_cast<const char *>(data), size);
+  auto status = flight_sender->Write(flight_message);
+  return garrow::check(error, status, "[flight-server-auth-sender][write]");
+}
+
+
+struct GAFlightServerAuthReaderPrivate {
+  arrow::flight::ServerAuthReader *reader;
+};
+
+enum {
+  PROP_SERVER_AUTH_READER = 1,
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GAFlightServerAuthReader,
+                           gaflight_server_auth_reader,
+                           G_TYPE_OBJECT)
+
+#define GAFLIGHT_SERVER_AUTH_READER_GET_PRIVATE(obj)        \
+  static_cast<GAFlightServerAuthReaderPrivate *>(           \
+    gaflight_server_auth_reader_get_instance_private(       \
+      GAFLIGHT_SERVER_AUTH_READER(obj)))
+
+static void
+gaflight_server_auth_reader_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec)
+{
+  auto priv = GAFLIGHT_SERVER_AUTH_READER_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_SERVER_AUTH_READER:
+    priv->reader =
+      static_cast<arrow::flight::ServerAuthReader 
*>(g_value_get_pointer(value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+gaflight_server_auth_reader_init(GAFlightServerAuthReader *object)
+{
+}
+
+static void
+gaflight_server_auth_reader_class_init(GAFlightServerAuthReaderClass *klass)
+{
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->set_property = gaflight_server_auth_reader_set_property;
+
+  GParamSpec *spec;
+  spec = g_param_spec_pointer("reader",
+                              "Reader",
+                              "The raw arrow::flight::ServerAuthReader *",
+                              static_cast<GParamFlags>(G_PARAM_WRITABLE |
+                                                       
G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_SERVER_AUTH_READER, 
spec);
+}
+
+/**
+ * gaflight_server_auth_reader_read:
+ * @reader: A #GAFlightServerAuthReader.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Reads a message from the client.
+ *
+ * Returns: (nullable) (transfer full): Read data as #GBytes on
+ *   success, %NULL on error.
+ *
+ * Since: 12.0.0
+ */
+GBytes *
+gaflight_server_auth_reader_read(GAFlightServerAuthReader *reader,
+                                 GError **error)
+{
+  auto flight_reader = gaflight_server_auth_reader_get_raw(reader);
+  std::string flight_message;
+  auto status = flight_reader->Read(&flight_message);
+  if (!garrow::check(error, status, "[flight-server-auth-reader][read]")) {
+    return nullptr;
+  }
+  return g_bytes_new(flight_message.data(), flight_message.size());
+}
+
+
+struct GAFlightServerAuthHandlerPrivate {
+  std::shared_ptr<arrow::flight::ServerAuthHandler> handler;
+};
+
+enum {
+  PROP_SERVER_AUTH_HANDLER = 1,
+};
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(GAFlightServerAuthHandler,
+                                    gaflight_server_auth_handler,
+                                    G_TYPE_OBJECT)
+
+#define GAFLIGHT_SERVER_AUTH_HANDLER_GET_PRIVATE(obj)        \
+  static_cast<GAFlightServerAuthHandlerPrivate *>(           \
+    gaflight_server_auth_handler_get_instance_private(       \
+      GAFLIGHT_SERVER_AUTH_HANDLER(obj)))
+
+static void
+gaflight_server_auth_handler_finalize(GObject *object)
+{
+  auto priv = GAFLIGHT_SERVER_AUTH_HANDLER_GET_PRIVATE(object);
+  priv->handler.~shared_ptr();
+  G_OBJECT_CLASS(gaflight_server_auth_handler_parent_class)->finalize(object);
+}
+
+static void
+gaflight_server_auth_handler_set_property(GObject *object,
+                                          guint prop_id,
+                                          const GValue *value,
+                                          GParamSpec *pspec)
+{
+  auto priv = GAFLIGHT_SERVER_AUTH_HANDLER_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_SERVER_AUTH_HANDLER:
+    if (g_value_get_pointer(value)) {
+      priv->handler =
+        *static_cast<std::shared_ptr<arrow::flight::ServerAuthHandler>*>(
+          g_value_get_pointer(value));
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+gaflight_server_auth_handler_init(GAFlightServerAuthHandler *object)
+{
+  auto priv = GAFLIGHT_SERVER_AUTH_HANDLER_GET_PRIVATE(object);
+  new(&priv->handler) std::shared_ptr<arrow::flight::ServerAuthHandler>;
+}
+
+static void
+gaflight_server_auth_handler_class_init(GAFlightServerAuthHandlerClass *klass)
+{
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->finalize = gaflight_server_auth_handler_finalize;
+  gobject_class->set_property = gaflight_server_auth_handler_set_property;
+
+  GParamSpec *spec;
+  spec = g_param_spec_pointer("handler",
+                              "Handler",
+                              "The raw std::shared_ptr<"
+                              "arrow::flight::ServerAuthHandler>",
+                              static_cast<GParamFlags>(G_PARAM_WRITABLE |
+                                                       
G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_SERVER_AUTH_HANDLER, 
spec);
+}
+
+
+G_END_DECLS
+namespace gaflight {
+  class ServerCustomAuthHandler : public arrow::flight::ServerAuthHandler {
+  public:
+    explicit ServerCustomAuthHandler(GAFlightServerCustomAuthHandler *handler)
+      : arrow::flight::ServerAuthHandler(),
+        handler_(handler) {
+    }
+
+    arrow::Status
+    Authenticate(arrow::flight::ServerAuthSender *sender,
+                 arrow::flight::ServerAuthReader *reader) override {
+      auto klass = GAFLIGHT_SERVER_CUSTOM_AUTH_HANDLER_GET_CLASS(handler_);
+      auto gsender = gaflight_server_auth_sender_new_raw(sender);
+      auto greader = gaflight_server_auth_reader_new_raw(reader);
+      GError *error = nullptr;
+      klass->authenticate(handler_, gsender, greader, &error);
+      g_object_unref(greader);
+      g_object_unref(gsender);
+      if (error) {
+        return garrow_error_to_status(error,
+                                      arrow::StatusCode::Invalid,
+                                      "[flight-server-custom-auth-handler]"
+                                      "[authenticate]");
+      } else {
+        return arrow::Status::OK();
+      }
+    }
+
+    arrow::Status
+    IsValid(const std::string &token,
+            std::string *peer_identity) override {
+      auto klass = GAFLIGHT_SERVER_CUSTOM_AUTH_HANDLER_GET_CLASS(handler_);
+      auto gtoken = g_bytes_new_static(token.data(), token.size());
+      GBytes *gpeer_identity = nullptr;
+      GError *error = nullptr;
+      klass->is_valid(handler_, gtoken, &gpeer_identity, &error);
+      g_bytes_unref(gtoken);
+      if (gpeer_identity) {
+        gsize gpeer_identity_size;
+        auto gpeer_identity_data = g_bytes_get_data(gpeer_identity,
+                                                    &gpeer_identity_size);
+        *peer_identity =
+          std::string(static_cast<const char *>(gpeer_identity_data),
+                      gpeer_identity_size);
+        g_bytes_unref(gpeer_identity);
+      }
+      if (error) {
+        return garrow_error_to_status(error,
+                                      arrow::StatusCode::Invalid,
+                                      "[flight-server-custom-auth-handler]"
+                                      "[is-valid]");
+      } else {
+        return arrow::Status::OK();
+      }
+    }
+
+  private:
+    GAFlightServerCustomAuthHandler *handler_;
+  };
+}
+G_BEGIN_DECLS
+
+G_DEFINE_TYPE(GAFlightServerCustomAuthHandler,
+              gaflight_server_custom_auth_handler,
+              GAFLIGHT_TYPE_SERVER_AUTH_HANDLER)
+
+static void
+gaflight_server_custom_auth_handler_init(GAFlightServerCustomAuthHandler 
*object)
+{
+  auto priv = GAFLIGHT_SERVER_AUTH_HANDLER_GET_PRIVATE(object);
+  priv->handler = std::make_shared<gaflight::ServerCustomAuthHandler>(object);
+}
+
+static void
+gaflight_server_custom_auth_handler_class_init(
+  GAFlightServerCustomAuthHandlerClass *klass)
+{
+}
+
+/**
+ * gaflight_server_custom_auth_handler_authenticate:
+ * @handler: A #GAFlightServerCustomAuthHandler.
+ * @sender: A #GAFlightServerAuthSender.
+ * @reader: A #GAFlightServerAuthReader.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Authenticates the client on initial connection. The server can send
+ * and read responses from the client at any time.
+ *
+ * Since: 12.0.0
+ */
+void
+gaflight_server_custom_auth_handler_authenticate(
+  GAFlightServerCustomAuthHandler *handler,
+  GAFlightServerAuthSender *sender,
+  GAFlightServerAuthReader *reader,
+  GError **error)
+{
+  auto flight_handler =
+    gaflight_server_auth_handler_get_raw(
+      GAFLIGHT_SERVER_AUTH_HANDLER(handler));
+  auto flight_sender = gaflight_server_auth_sender_get_raw(sender);
+  auto flight_reader = gaflight_server_auth_reader_get_raw(reader);
+  auto status = flight_handler->Authenticate(flight_sender, flight_reader);
+  garrow::check(error,
+                status,
+                "[flight-server-custom-auth-handler][authenticate]");
+}
+
+/**
+ * gaflight_server_custom_auth_handler_is_valid:
+ * @handler: A #GAFlightServerCustomAuthHandler.
+ * @token: The client token. May be the empty string if the client does not
+ *   provide a token.
+ * @peer_identity: (out): The identity of the peer, if this authentication
+ *   method supports it.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Validates a per-call client token.
+ *
+ * Since: 12.0.0
+ */
+void
+gaflight_server_custom_auth_handler_is_valid(
+  GAFlightServerCustomAuthHandler *handler,
+  GBytes *token,
+  GBytes **peer_identity,
+  GError **error)
+{
+  auto flight_handler =
+    gaflight_server_auth_handler_get_raw(
+      GAFLIGHT_SERVER_AUTH_HANDLER(handler));
+  gsize token_size;
+  auto token_data = g_bytes_get_data(token, &token_size);
+  std::string flight_token(static_cast<const char *>(token_data), token_size);
+  std::string flight_peer_identity;
+  auto status = flight_handler->IsValid(flight_token, &flight_peer_identity);
+  if (garrow::check(error,
+                    status,
+                    "[flight-server-custom-auth-handler]"
+                    "[is-valid]")) {
+    *peer_identity = g_bytes_new(flight_peer_identity.data(),
+                                 flight_peer_identity.size());
+  }
+}
+
+
 typedef struct GAFlightServerOptionsPrivate_ {
   arrow::flight::FlightServerOptions options;
   GAFlightLocation *location;
+  GAFlightServerAuthHandler *auth_handler;
 } GAFlightServerOptionsPrivate;
 
 enum {
   PROP_LOCATION = 1,
+  PROP_AUTH_HANDLER,
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE(GAFlightServerOptions,
@@ -274,7 +672,12 @@ gaflight_server_options_dispose(GObject *object)
 
   if (priv->location) {
     g_object_unref(priv->location);
-    priv->location = NULL;
+    priv->location = nullptr;
+  }
+
+  if (priv->auth_handler) {
+    g_object_unref(priv->auth_handler);
+    priv->auth_handler = nullptr;
   }
 
   G_OBJECT_CLASS(gaflight_server_options_parent_class)->dispose(object);
@@ -306,6 +709,21 @@ gaflight_server_options_set_property(GObject *object,
       new(&(priv->options)) 
arrow::flight::FlightServerOptions(*flight_location);
     }
     break;
+  case PROP_AUTH_HANDLER:
+    if (priv->auth_handler != g_value_get_object(value)) {
+      if (priv->auth_handler) {
+        g_object_unref(priv->auth_handler);
+      }
+      priv->auth_handler =
+        GAFLIGHT_SERVER_AUTH_HANDLER(g_value_dup_object(value));
+      if (priv->auth_handler) {
+        priv->options.auth_handler =
+          gaflight_server_auth_handler_get_raw(priv->auth_handler);
+      } else {
+        priv->options.auth_handler = nullptr;
+      }
+    }
+    break;
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     break;
@@ -324,6 +742,9 @@ gaflight_server_options_get_property(GObject *object,
   case PROP_LOCATION:
     g_value_set_object(value, priv->location);
     break;
+  case PROP_AUTH_HANDLER:
+    g_value_set_object(value, priv->auth_handler);
+    break;
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     break;
@@ -346,6 +767,13 @@ 
gaflight_server_options_class_init(GAFlightServerOptionsClass *klass)
   gobject_class->get_property = gaflight_server_options_get_property;
 
   GParamSpec *spec;
+  /**
+   * GAFlightServerOptions:location:
+   *
+   * The location to be listened.
+   *
+   * Since: 5.0.0
+   */
   spec = g_param_spec_object("location",
                              "Location",
                              "The location to be listened",
@@ -353,6 +781,20 @@ 
gaflight_server_options_class_init(GAFlightServerOptionsClass *klass)
                              static_cast<GParamFlags>(G_PARAM_READWRITE |
                                                       G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property(gobject_class, PROP_LOCATION, spec);
+
+  /**
+   * GAFlightServerOptions:auth-handler:
+   *
+   * The authentication handler.
+   *
+   * Since: 12.0.0
+   */
+  spec = g_param_spec_object("auth-handler",
+                             "Authentication handler",
+                             "The authentication handler",
+                             GAFLIGHT_TYPE_SERVER_AUTH_HANDLER,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE));
+  g_object_class_install_property(gobject_class, PROP_AUTH_HANDLER, spec);
 }
 
 /**
@@ -757,6 +1199,47 @@ gaflight_data_stream_get_raw(GAFlightDataStream *stream)
   return priv->stream;
 }
 
+GAFlightServerAuthSender *
+gaflight_server_auth_sender_new_raw(
+  arrow::flight::ServerAuthSender *flight_sender)
+{
+  return GAFLIGHT_SERVER_AUTH_SENDER(
+    g_object_new(GAFLIGHT_TYPE_SERVER_AUTH_SENDER,
+                 "sender", flight_sender,
+                 nullptr));
+}
+
+arrow::flight::ServerAuthSender *
+gaflight_server_auth_sender_get_raw(GAFlightServerAuthSender *sender)
+{
+  auto priv = GAFLIGHT_SERVER_AUTH_SENDER_GET_PRIVATE(sender);
+  return priv->sender;
+}
+
+GAFlightServerAuthReader *
+gaflight_server_auth_reader_new_raw(
+  arrow::flight::ServerAuthReader *flight_reader)
+{
+  return GAFLIGHT_SERVER_AUTH_READER(
+    g_object_new(GAFLIGHT_TYPE_SERVER_AUTH_READER,
+                 "reader", flight_reader,
+                 nullptr));
+}
+
+arrow::flight::ServerAuthReader *
+gaflight_server_auth_reader_get_raw(GAFlightServerAuthReader *reader)
+{
+  auto priv = GAFLIGHT_SERVER_AUTH_READER_GET_PRIVATE(reader);
+  return priv->reader;
+}
+
+std::shared_ptr<arrow::flight::ServerAuthHandler>
+gaflight_server_auth_handler_get_raw(GAFlightServerAuthHandler *handler)
+{
+  auto priv = GAFLIGHT_SERVER_AUTH_HANDLER_GET_PRIVATE(handler);
+  return priv->handler;
+}
+
 arrow::flight::FlightServerOptions *
 gaflight_server_options_get_raw(GAFlightServerOptions *options)
 {
diff --git a/c_glib/arrow-flight-glib/server.h 
b/c_glib/arrow-flight-glib/server.h
index b293c7408a..7218c8a69a 100644
--- a/c_glib/arrow-flight-glib/server.h
+++ b/c_glib/arrow-flight-glib/server.h
@@ -55,6 +55,101 @@ gaflight_record_batch_stream_new(GArrowRecordBatchReader 
*reader,
                                  GArrowWriteOptions *options);
 
 
+#define GAFLIGHT_TYPE_SERVER_AUTH_SENDER        \
+  (gaflight_server_auth_sender_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightServerAuthSender,
+                         gaflight_server_auth_sender,
+                         GAFLIGHT,
+                         SERVER_AUTH_SENDER,
+                         GObject)
+struct _GAFlightServerAuthSenderClass
+{
+  GObjectClass parent_class;
+};
+
+GARROW_AVAILABLE_IN_12_0
+gboolean
+gaflight_server_auth_sender_write(GAFlightServerAuthSender *sender,
+                                  GBytes *message,
+                                  GError **error);
+
+
+#define GAFLIGHT_TYPE_SERVER_AUTH_READER        \
+  (gaflight_server_auth_reader_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightServerAuthReader,
+                         gaflight_server_auth_reader,
+                         GAFLIGHT,
+                         SERVER_AUTH_READER,
+                         GObject)
+struct _GAFlightServerAuthReaderClass
+{
+  GObjectClass parent_class;
+};
+
+GARROW_AVAILABLE_IN_12_0
+GBytes *
+gaflight_server_auth_reader_read(GAFlightServerAuthReader *reader,
+                                 GError **error);
+
+
+#define GAFLIGHT_TYPE_SERVER_AUTH_HANDLER       \
+  (gaflight_server_auth_handler_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightServerAuthHandler,
+                         gaflight_server_auth_handler,
+                         GAFLIGHT,
+                         SERVER_AUTH_HANDLER,
+                         GObject)
+struct _GAFlightServerAuthHandlerClass
+{
+  GObjectClass parent_class;
+};
+
+#define GAFLIGHT_TYPE_SERVER_CUSTOM_AUTH_HANDLER       \
+  (gaflight_server_custom_auth_handler_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightServerCustomAuthHandler,
+                         gaflight_server_custom_auth_handler,
+                         GAFLIGHT,
+                         SERVER_CUSTOM_AUTH_HANDLER,
+                         GAFlightServerAuthHandler)
+/**
+ * GAFlightServerCustomAuthHandlerClass:
+ * @authenticate: Authenticates the client on initial connection. The server
+ *   can send and read responses from the client at any time.
+ * @is_valid: Validates a per-call client token.
+ *
+ * Since: 12.0.0
+ */
+struct _GAFlightServerCustomAuthHandlerClass
+{
+  GAFlightServerAuthHandlerClass parent_class;
+
+  void (*authenticate)(GAFlightServerCustomAuthHandler *handler,
+                       GAFlightServerAuthSender *sender,
+                       GAFlightServerAuthReader *reader,
+                       GError **error);
+  void (*is_valid)(GAFlightServerCustomAuthHandler *handler,
+                   GBytes *token,
+                   GBytes **peer_identity,
+                   GError **error);
+};
+
+GARROW_AVAILABLE_IN_12_0
+void
+gaflight_server_custom_auth_handler_authenticate(
+  GAFlightServerCustomAuthHandler *handler,
+  GAFlightServerAuthSender *sender,
+  GAFlightServerAuthReader *reader,
+  GError **error);
+
+GARROW_AVAILABLE_IN_12_0
+void
+gaflight_server_custom_auth_handler_is_valid(
+  GAFlightServerCustomAuthHandler *handler,
+  GBytes *token,
+  GBytes **peer_identity,
+  GError **error);
+
+
 #define GAFLIGHT_TYPE_SERVER_OPTIONS (gaflight_server_options_get_type())
 G_DECLARE_DERIVABLE_TYPE(GAFlightServerOptions,
                          gaflight_server_options,
diff --git a/c_glib/arrow-flight-glib/server.hpp 
b/c_glib/arrow-flight-glib/server.hpp
index 69aed8a059..4c70437da8 100644
--- a/c_glib/arrow-flight-glib/server.hpp
+++ b/c_glib/arrow-flight-glib/server.hpp
@@ -27,6 +27,21 @@
 arrow::flight::FlightDataStream *
 gaflight_data_stream_get_raw(GAFlightDataStream *stream);
 
+GAFlightServerAuthSender *
+gaflight_server_auth_sender_new_raw(
+  arrow::flight::ServerAuthSender *flight_sender);
+arrow::flight::ServerAuthSender *
+gaflight_server_auth_sender_get_raw(GAFlightServerAuthSender *sender);
+
+GAFlightServerAuthReader *
+gaflight_server_auth_reader_new_raw(
+  arrow::flight::ServerAuthReader *flight_reader);
+arrow::flight::ServerAuthReader *
+gaflight_server_auth_reader_get_raw(GAFlightServerAuthReader *reader);
+
+std::shared_ptr<arrow::flight::ServerAuthHandler>
+gaflight_server_auth_handler_get_raw(GAFlightServerAuthHandler *handler);
+
 arrow::flight::FlightServerOptions *
 gaflight_server_options_get_raw(GAFlightServerOptions *options);
 
diff --git a/c_glib/arrow-glib/version.h.in b/c_glib/arrow-glib/version.h.in
index bd67ed6b8b..7426e614cd 100644
--- a/c_glib/arrow-glib/version.h.in
+++ b/c_glib/arrow-glib/version.h.in
@@ -110,6 +110,15 @@
 #  define GARROW_UNAVAILABLE(major, minor) G_UNAVAILABLE(major, minor)
 #endif
 
+/**
+ * GARROW_VERSION_12_0:
+ *
+ * You can use this macro value for compile time API version check.
+ *
+ * Since: 12.0.0
+ */
+#define GARROW_VERSION_12_0 G_ENCODE_VERSION(12, 0)
+
 /**
  * GARROW_VERSION_11_0:
  *
@@ -319,6 +328,20 @@
 
 #define GARROW_AVAILABLE_IN_ALL
 
+#if GARROW_VERSION_MIN_REQUIRED >= GARROW_VERSION_12_0
+#  define GARROW_DEPRECATED_IN_12_0                GARROW_DEPRECATED
+#  define GARROW_DEPRECATED_IN_12_0_FOR(function)  
GARROW_DEPRECATED_FOR(function)
+#else
+#  define GARROW_DEPRECATED_IN_12_0
+#  define GARROW_DEPRECATED_IN_12_0_FOR(function)
+#endif
+
+#if GARROW_VERSION_MAX_ALLOWED < GARROW_VERSION_12_0
+#  define GARROW_AVAILABLE_IN_12_0 GARROW_UNAVAILABLE(12, 0)
+#else
+#  define GARROW_AVAILABLE_IN_12_0
+#endif
+
 #if GARROW_VERSION_MIN_REQUIRED >= GARROW_VERSION_11_0
 #  define GARROW_DEPRECATED_IN_11_0                GARROW_DEPRECATED
 #  define GARROW_DEPRECATED_IN_11_0_FOR(function)  
GARROW_DEPRECATED_FOR(function)
diff --git a/c_glib/doc/arrow-flight-glib/arrow-flight-glib-docs.xml 
b/c_glib/doc/arrow-flight-glib/arrow-flight-glib-docs.xml
index 397a8bec0d..e078b1c037 100644
--- a/c_glib/doc/arrow-flight-glib/arrow-flight-glib-docs.xml
+++ b/c_glib/doc/arrow-flight-glib/arrow-flight-glib-docs.xml
@@ -55,6 +55,10 @@
     <title>Index of deprecated API</title>
     <xi:include href="xml/api-index-deprecated.xml"><xi:fallback 
/></xi:include>
   </index>
+  <index id="api-index-12-0-0" role="12.0.0">
+    <title>Index of new symbols in 12.0.0</title>
+    <xi:include href="xml/api-index-12.0.0.xml"><xi:fallback /></xi:include>
+  </index>
   <index id="api-index-6-0-0" role="6.0.0">
     <title>Index of new symbols in 6.0.0</title>
     <xi:include href="xml/api-index-6.0.0.xml"><xi:fallback /></xi:include>
diff --git a/c_glib/doc/arrow-glib/arrow-glib-docs.xml 
b/c_glib/doc/arrow-glib/arrow-glib-docs.xml
index e6990af559..4abb364712 100644
--- a/c_glib/doc/arrow-glib/arrow-glib-docs.xml
+++ b/c_glib/doc/arrow-glib/arrow-glib-docs.xml
@@ -193,6 +193,10 @@
     <title>Index of deprecated API</title>
     <xi:include href="xml/api-index-deprecated.xml"><xi:fallback 
/></xi:include>
   </index>
+  <index id="api-index-12-0-0" role="12.0.0">
+    <title>Index of new symbols in 12.0.0</title>
+    <xi:include href="xml/api-index-12.0.0.xml"><xi:fallback /></xi:include>
+  </index>
   <index id="api-index-11-0-0" role="11.0.0">
     <title>Index of new symbols in 11.0.0</title>
     <xi:include href="xml/api-index-11.0.0.xml"><xi:fallback /></xi:include>
diff --git a/c_glib/test/flight/test-client.rb 
b/c_glib/test/flight/test-client.rb
index d2fb3cc682..7eb093d3ca 100644
--- a/c_glib/test/flight/test-client.rb
+++ b/c_glib/test/flight/test-client.rb
@@ -27,6 +27,7 @@ class TestFlightClient < Test::Unit::TestCase
     host = "127.0.0.1"
     location = ArrowFlight::Location.new("grpc://#{host}:0")
     options = ArrowFlight::ServerOptions.new(location)
+    options.auth_handler = Helper::FlightAuthHandler.new
     @server.listen(options)
     @location = ArrowFlight::Location.new("grpc://#{host}:#{@server.port}")
   end
@@ -43,6 +44,13 @@ class TestFlightClient < Test::Unit::TestCase
     client.close
   end
 
+  def test_authenticate_basic_token
+    client = ArrowFlight::Client.new(@location)
+    generator = Helper::FlightInfoGenerator.new
+    assert_equal([true, "", ""],
+                 client.authenticate_basic_token("user", "password"))
+  end
+
   def test_list_flights
     client = ArrowFlight::Client.new(@location)
     generator = Helper::FlightInfoGenerator.new
diff --git a/c_glib/test/helper/flight-server.rb 
b/c_glib/test/helper/flight-server.rb
index 238b2f4b58..3aa8f4dc21 100644
--- a/c_glib/test/helper/flight-server.rb
+++ b/c_glib/test/helper/flight-server.rb
@@ -18,6 +18,19 @@
 require_relative "flight-info-generator"
 
 module Helper
+  class FlightAuthHandler < ArrowFlight::ServerCustomAuthHandler
+    type_register
+
+    private
+    def virtual_do_authenticate(sender, reader)
+      true
+    end
+
+    def virtual_do_is_valid(token)
+      "identity"
+    end
+  end
+
   class FlightServer < ArrowFlight::Server
     type_register
 

Reply via email to