gs: Add support for authenticating via Service Account Credentials

This allows authenticating directly with Server Account credentials
instead of having it configured on host system separately, and thus
allows using arbitrary accounts configured/selected at runtime.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/934>
This commit is contained in:
Sebastian Dröge 2021-09-27 15:30:25 +03:00 committed by GStreamer Marge Bot
parent c514f939c9
commit a12762a29a
4 changed files with 118 additions and 12 deletions

View file

@ -58,18 +58,35 @@ static inline gchar* g_date_time_format_iso8601(GDateTime* datetime) {
std::unique_ptr<google::cloud::storage::Client> gst_gs_create_client(
const gchar* service_account_email,
const gchar* service_account_credentials,
GError** error) {
if (service_account_email) {
// Meant to be used from a container running in the Cloud.
if (service_account_email || service_account_credentials) {
google::cloud::StatusOr<std::shared_ptr<gcs::oauth2::Credentials>> creds;
if (service_account_credentials) {
creds = gcs::oauth2::CreateServiceAccountCredentialsFromJsonContents(
service_account_credentials,
{{"https://www.googleapis.com/auth/devstorage.full_control"}},
absl::nullopt);
} else {
// Meant to be used from a container running in the Cloud.
creds =
gcs::oauth2::CreateComputeEngineCredentials(service_account_email);
}
google::cloud::StatusOr<std::shared_ptr<gcs::oauth2::Credentials>> creds(
std::make_shared<gcs::oauth2::ComputeEngineCredentials<>>(
service_account_email));
if (!creds) {
g_set_error(error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_AUTHORIZED,
"Could not retrieve credentials for the given service "
"account %s (%s)",
service_account_email, creds.status().message().c_str());
if (service_account_email) {
g_set_error(error, GST_RESOURCE_ERROR,
GST_RESOURCE_ERROR_NOT_AUTHORIZED,
"Could not retrieve credentials for the given service "
"account %s (%s)",
service_account_email, creds.status().message().c_str());
} else {
g_set_error(error, GST_RESOURCE_ERROR,
GST_RESOURCE_ERROR_NOT_AUTHORIZED,
"Could not retrieve credentials for the given service "
"account credentials JSON (%s)",
creds.status().message().c_str());
}
return nullptr;
}

View file

@ -30,6 +30,7 @@
std::unique_ptr<google::cloud::storage::Client> gst_gs_create_client(
const gchar* service_account_email,
const gchar* service_account_credentials,
GError** error);
gboolean gst_gs_get_buffer_date(GstBuffer* buffer,

View file

@ -110,6 +110,7 @@ enum {
PROP_NEXT_FILE,
PROP_SERVICE_ACCOUNT_EMAIL,
PROP_START_DATE,
PROP_SERVICE_ACCOUNT_CREDENTIALS,
};
class GSWriteStream;
@ -120,6 +121,7 @@ struct _GstGsSink {
std::unique_ptr<google::cloud::storage::Client> gcs_client;
std::unique_ptr<GSWriteStream> gcs_stream;
gchar* service_account_email;
gchar* service_account_credentials;
gchar* bucket_name;
gchar* object_name;
gchar* start_date_str;
@ -283,6 +285,22 @@ static void gst_gs_sink_class_init(GstGsSinkClass* klass) {
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
/**
* GstGsSink:service-account-credentials:
*
* Service Account Credentials as a JSON string to use for credentials.
*
* Since: 1.20
*/
g_object_class_install_property(
gobject_class, PROP_SERVICE_ACCOUNT_CREDENTIALS,
g_param_spec_string(
"service-account-credentials", "Service Account Credentials",
"Service Account Credentials as a JSON string to use for credentials",
NULL,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
/**
* GstGsSink:start-date:
*
@ -322,6 +340,7 @@ static void gst_gs_sink_init(GstGsSink* sink) {
sink->index = DEFAULT_INDEX;
sink->post_messages = DEFAULT_POST_MESSAGES;
sink->service_account_email = NULL;
sink->service_account_credentials = NULL;
sink->bucket_name = NULL;
sink->object_name = g_strdup(DEFAULT_OBJECT_NAME);
sink->start_date_str = NULL;
@ -341,6 +360,8 @@ static void gst_gs_sink_finalize(GObject* object) {
sink->gcs_stream = nullptr;
g_free(sink->service_account_email);
sink->service_account_email = NULL;
g_free(sink->service_account_credentials);
sink->service_account_credentials = NULL;
g_free(sink->bucket_name);
sink->bucket_name = NULL;
g_free(sink->object_name);
@ -427,6 +448,10 @@ static void gst_gs_sink_set_property(GObject* object,
g_free(sink->service_account_email);
sink->service_account_email = g_strdup(g_value_get_string(value));
break;
case PROP_SERVICE_ACCOUNT_CREDENTIALS:
g_free(sink->service_account_credentials);
sink->service_account_credentials = g_strdup(g_value_get_string(value));
break;
case PROP_START_DATE:
g_free(sink->start_date_str);
if (sink->start_date)
@ -472,6 +497,9 @@ static void gst_gs_sink_get_property(GObject* object,
case PROP_SERVICE_ACCOUNT_EMAIL:
g_value_set_string(value, sink->service_account_email);
break;
case PROP_SERVICE_ACCOUNT_CREDENTIALS:
g_value_set_string(value, sink->service_account_credentials);
break;
case PROP_START_DATE:
g_value_set_string(value, sink->start_date_str);
break;
@ -499,7 +527,8 @@ static gboolean gst_gs_sink_start(GstBaseSink* bsink) {
sink->content_type = "";
sink->gcs_client = gst_gs_create_client(sink->service_account_email, &err);
sink->gcs_client = gst_gs_create_client(
sink->service_account_email, sink->service_account_credentials, &err);
if (err) {
GST_ELEMENT_ERROR(sink, RESOURCE, OPEN_READ,
("Could not create client (%s)", err->message),

View file

@ -63,7 +63,12 @@ enum { LAST_SIGNAL };
#define DEFAULT_BLOCKSIZE 4 * 1024
enum { PROP_0, PROP_LOCATION, PROP_SERVICE_ACCOUNT_EMAIL };
enum {
PROP_0,
PROP_LOCATION,
PROP_SERVICE_ACCOUNT_EMAIL,
PROP_SERVICE_ACCOUNT_CREDENTIALS
};
class GSReadStream;
@ -74,6 +79,7 @@ struct _GstGsSrc {
std::unique_ptr<GSReadStream> gcs_stream;
gchar* uri;
gchar* service_account_email;
gchar* service_account_credentials;
std::string bucket_name;
std::string object_name;
guint64 read_position;
@ -166,6 +172,22 @@ static void gst_gs_src_class_init(GstGsSrcClass* klass) {
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
/**
* GstGsSrc:service-account-credentials:
*
* Service Account Credentials as a JSON string to use for credentials.
*
* Since: 1.20
*/
g_object_class_install_property(
gobject_class, PROP_SERVICE_ACCOUNT_CREDENTIALS,
g_param_spec_string(
"service-account-credentials", "Service Account Credentials",
"Service Account Credentials as a JSON string to use for credentials",
NULL,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
gobject_class->finalize = gst_gs_src_finalize;
gst_element_class_set_static_metadata(
@ -186,6 +208,7 @@ static void gst_gs_src_init(GstGsSrc* src) {
src->gcs_stream = nullptr;
src->uri = NULL;
src->service_account_email = NULL;
src->service_account_credentials = NULL;
src->read_position = 0;
src->object_size = 0;
@ -201,6 +224,8 @@ static void gst_gs_src_finalize(GObject* object) {
src->uri = NULL;
g_free(src->service_account_email);
src->service_account_email = NULL;
g_free(src->service_account_credentials);
src->service_account_credentials = NULL;
src->read_position = 0;
src->object_size = 0;
@ -294,6 +319,30 @@ static gboolean gst_gs_src_set_service_account_email(
return TRUE;
}
static gboolean gst_gs_src_set_service_account_credentials(
GstGsSrc* src,
const gchar* service_account_credentials) {
if (GST_STATE(src) == GST_STATE_PLAYING ||
GST_STATE(src) == GST_STATE_PAUSED) {
GST_WARNING_OBJECT(
src,
"Setting a new service account credentials not supported in "
"PLAYING or PAUSED state");
return FALSE;
}
GST_OBJECT_LOCK(src);
g_free(src->service_account_credentials);
src->service_account_credentials = NULL;
if (service_account_credentials)
src->service_account_credentials = g_strdup(service_account_credentials);
GST_OBJECT_UNLOCK(src);
return TRUE;
}
static void gst_gs_src_set_property(GObject* object,
guint prop_id,
const GValue* value,
@ -309,6 +358,10 @@ static void gst_gs_src_set_property(GObject* object,
case PROP_SERVICE_ACCOUNT_EMAIL:
gst_gs_src_set_service_account_email(src, g_value_get_string(value));
break;
case PROP_SERVICE_ACCOUNT_CREDENTIALS:
gst_gs_src_set_service_account_credentials(src,
g_value_get_string(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@ -334,6 +387,11 @@ static void gst_gs_src_get_property(GObject* object,
g_value_set_string(value, src->service_account_email);
GST_OBJECT_UNLOCK(src);
break;
case PROP_SERVICE_ACCOUNT_CREDENTIALS:
GST_OBJECT_LOCK(src);
g_value_set_string(value, src->service_account_credentials);
GST_OBJECT_UNLOCK(src);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@ -470,7 +528,8 @@ static gboolean gst_gs_src_start(GstBaseSrc* basesrc) {
GST_INFO_OBJECT(src, "Opening file %s", src->uri);
src->gcs_client = gst_gs_create_client(src->service_account_email, &err);
src->gcs_client = gst_gs_create_client(
src->service_account_email, src->service_account_credentials, &err);
if (err) {
GST_ELEMENT_ERROR(src, RESOURCE, OPEN_READ,
("Could not create client (%s)", err->message),