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

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