Blame SOURCES/0023-oidc_child-add-client-secret-stdin-option.patch

1c5238
From 2f3cd781879e7063fcd996389071458587623e1c Mon Sep 17 00:00:00 2001
1c5238
From: Sumit Bose <sbose@redhat.com>
1c5238
Date: Mon, 22 Aug 2022 11:37:07 +0200
1c5238
Subject: [PATCH 23/23] oidc_child: add --client-secret-stdin option
1c5238
MIME-Version: 1.0
1c5238
Content-Type: text/plain; charset=UTF-8
1c5238
Content-Transfer-Encoding: 8bit
1c5238
1c5238
Since there is the use-case of confidential client which requires that
1c5238
the client secret must be sent to the IdP we should handle it
1c5238
confidentially by not putting it on the command line but sending it via
1c5238
stdin.
1c5238
1c5238
Resolves: https://github.com/SSSD/sssd/issues/6146
1c5238
1c5238
Reviewed-by: Justin Stephenson <jstephen@redhat.com>
1c5238
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
1c5238
(cherry picked from commit 1a475e0c537c905c80406ceb88c7b34e6400bc40)
1c5238
1c5238
Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
1c5238
---
1c5238
 src/oidc_child/oidc_child.c | 89 ++++++++++++++++++++++++++++++++++---
1c5238
 1 file changed, 82 insertions(+), 7 deletions(-)
1c5238
1c5238
diff --git a/src/oidc_child/oidc_child.c b/src/oidc_child/oidc_child.c
1c5238
index c8d35d5d8..7758cdc25 100644
1c5238
--- a/src/oidc_child/oidc_child.c
1c5238
+++ b/src/oidc_child/oidc_child.c
1c5238
@@ -34,7 +34,7 @@
1c5238
 #include "util/atomic_io.h"
1c5238
 
1c5238
 #define IN_BUF_SIZE 4096
1c5238
-static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx)
1c5238
+static errno_t read_from_stdin(TALLOC_CTX *mem_ctx, char **out)
1c5238
 {
1c5238
     uint8_t buf[IN_BUF_SIZE];
1c5238
     ssize_t len;
1c5238
@@ -56,7 +56,7 @@ static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx)
1c5238
         return EINVAL;
1c5238
     }
1c5238
 
1c5238
-    str = talloc_strndup(dc_ctx, (char *) buf, len);
1c5238
+    str = talloc_strndup(mem_ctx, (char *) buf, len);
1c5238
     sss_erase_mem_securely(buf, IN_BUF_SIZE);
1c5238
     if (str == NULL) {
1c5238
         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
1c5238
@@ -65,21 +65,72 @@ static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx)
1c5238
     talloc_set_destructor((void *) str, sss_erase_talloc_mem_securely);
1c5238
 
1c5238
     if (strlen(str) != len) {
1c5238
-        DEBUG(SSSDBG_CRIT_FAILURE,
1c5238
-              "Input contains additional data, "
1c5238
-              "only JSON encoded device code expected.\n");
1c5238
+        DEBUG(SSSDBG_CRIT_FAILURE, "Input contains additional data.\n");
1c5238
         talloc_free(str);
1c5238
         return EINVAL;
1c5238
     }
1c5238
 
1c5238
+    *out = str;
1c5238
+
1c5238
+    return EOK;
1c5238
+}
1c5238
+
1c5238
+static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx,
1c5238
+                                           const char **out)
1c5238
+{
1c5238
+    char *str;
1c5238
+    errno_t ret;
1c5238
+    char *sep;
1c5238
+
1c5238
+    ret = read_from_stdin(dc_ctx, &str);
1c5238
+    if (ret != EOK) {
1c5238
+        DEBUG(SSSDBG_OP_FAILURE, "read_from_stdin failed.\n");
1c5238
+        return ret;
1c5238
+    }
1c5238
+
1c5238
+    if (out != NULL) {
1c5238
+        /* expect the client secret in the first line */
1c5238
+        sep = strchr(str, '\n');
1c5238
+        if (sep == NULL) {
1c5238
+            DEBUG(SSSDBG_CRIT_FAILURE,
1c5238
+                  "Format error, expecting client secret and JSON data.\n");
1c5238
+            talloc_free(str);
1c5238
+            return EINVAL;
1c5238
+        }
1c5238
+        *sep = '\0';
1c5238
+        *out = str;
1c5238
+        sep++;
1c5238
+    } else {
1c5238
+        sep = str;
1c5238
+    }
1c5238
+
1c5238
     clean_http_data(dc_ctx);
1c5238
-    dc_ctx->http_data = str;
1c5238
+    dc_ctx->http_data = talloc_strdup(dc_ctx, sep);
1c5238
 
1c5238
     DEBUG(SSSDBG_TRACE_ALL, "JSON device code: [%s].\n", dc_ctx->http_data);
1c5238
 
1c5238
     return EOK;
1c5238
 }
1c5238
 
1c5238
+static errno_t read_client_secret_from_stdin(struct devicecode_ctx *dc_ctx,
1c5238
+                                             const char **out)
1c5238
+{
1c5238
+    char *str;
1c5238
+    errno_t ret;
1c5238
+
1c5238
+    ret = read_from_stdin(dc_ctx, &str);
1c5238
+    if (ret != EOK) {
1c5238
+        DEBUG(SSSDBG_OP_FAILURE, "read_from_stdin failed.\n");
1c5238
+        return ret;
1c5238
+    }
1c5238
+
1c5238
+    *out = str;
1c5238
+
1c5238
+    DEBUG(SSSDBG_TRACE_ALL, "Client secret: [%s].\n", *out);
1c5238
+
1c5238
+    return EOK;
1c5238
+}
1c5238
+
1c5238
 static errno_t set_endpoints(struct devicecode_ctx *dc_ctx,
1c5238
                              const char *device_auth_endpoint,
1c5238
                              const char *token_endpoint,
1c5238
@@ -210,6 +261,7 @@ struct cli_opts {
1c5238
     const char *jwks_uri;
1c5238
     const char *scope;
1c5238
     const char *client_secret;
1c5238
+    bool client_secret_stdin;
1c5238
     const char *ca_db;
1c5238
     const char *user_identifier_attr;
1c5238
     bool libcurl_debug;
1c5238
@@ -253,6 +305,8 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts)
1c5238
         {"client-id", 0, POPT_ARG_STRING, &opts->client_id, 0, _("Client ID"), NULL},
1c5238
         {"client-secret", 0, POPT_ARG_STRING, &opts->client_secret, 0,
1c5238
                 _("Client secret (if needed)"), NULL},
1c5238
+        {"client-secret-stdin", 0, POPT_ARG_NONE, NULL, 's',
1c5238
+                _("Read client secret from standard input"), NULL},
1c5238
         {"ca-db", 0, POPT_ARG_STRING, &opts->ca_db, 0,
1c5238
                 _("Path to PEM file with CA certificates"), NULL},
1c5238
         {"libcurl-debug", 0, POPT_ARG_NONE, NULL, 'c',
1c5238
@@ -280,6 +334,9 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts)
1c5238
         case 'c':
1c5238
             opts->libcurl_debug = true;
1c5238
             break;
1c5238
+        case 's':
1c5238
+            opts->client_secret_stdin = true;
1c5238
+            break;
1c5238
         default:
1c5238
             fprintf(stderr, "\nInvalid option %s: %s\n\n",
1c5238
                   poptBadOption(pc, 0), poptStrerror(opt));
1c5238
@@ -324,6 +381,12 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts)
1c5238
         goto done;
1c5238
     }
1c5238
 
1c5238
+    if (opts->client_secret != NULL && opts->client_secret_stdin) {
1c5238
+        fprintf(stderr, "\n--client-secret and --client-secret-stdin are "
1c5238
+                        "mutually exclusive.\n\n");
1c5238
+        goto done;
1c5238
+    }
1c5238
+
1c5238
     poptFreeContext(pc);
1c5238
     print_usage = false;
1c5238
 
1c5238
@@ -454,6 +517,15 @@ int main(int argc, const char *argv[])
1c5238
     }
1c5238
 
1c5238
     if (opts.get_device_code) {
1c5238
+        if (opts.client_secret_stdin) {
1c5238
+            ret = read_client_secret_from_stdin(dc_ctx, &opts.client_secret);
1c5238
+            if (ret != EOK) {
1c5238
+                DEBUG(SSSDBG_OP_FAILURE,
1c5238
+                      "Failed to read client secret from stdin.\n");
1c5238
+                goto done;
1c5238
+            }
1c5238
+        }
1c5238
+
1c5238
         ret = get_devicecode(dc_ctx, opts.client_id, opts.client_secret);
1c5238
         if (ret != EOK) {
1c5238
             DEBUG(SSSDBG_OP_FAILURE, "Failed to get device code.\n");
1c5238
@@ -463,7 +535,10 @@ int main(int argc, const char *argv[])
1c5238
 
1c5238
     if (opts.get_access_token) {
1c5238
         if (dc_ctx->device_code == NULL) {
1c5238
-            ret = read_device_code_from_stdin(dc_ctx);
1c5238
+            ret = read_device_code_from_stdin(dc_ctx,
1c5238
+                                              opts.client_secret_stdin
1c5238
+                                                           ? &opts.client_secret
1c5238
+                                                           : NULL);
1c5238
             if (ret != EOK) {
1c5238
                 DEBUG(SSSDBG_OP_FAILURE,
1c5238
                       "Failed to read device code from stdin.\n");
1c5238
-- 
1c5238
2.37.3
1c5238