Blame SOURCES/0053-LDAP-Only-authenticate-the-auth-connection-if-we-nee.patch

0d602d
From 7eb18ab68762d1b1ddbcbdc32dbcbd0df183d4f1 Mon Sep 17 00:00:00 2001
0d602d
From: Jakub Hrozek <jhrozek@redhat.com>
0d602d
Date: Thu, 22 Nov 2018 12:17:51 +0100
0d602d
Subject: [PATCH 53/54] LDAP: Only authenticate the auth connection if we need
0d602d
 to look up user information
0d602d
0d602d
Related:
0d602d
https://pagure.io/SSSD/sssd/issue/3451
0d602d
0d602d
Commit add72860c7a7a2c418f4d8b6790b5caeaf7dfb7b initially addressed #3451 by
0d602d
using the full sdap_cli_connect() request during LDAP authentication. This
0d602d
was a good idea as it addressed the case where the authentication connection
0d602d
must also look up some user information (typically with id_provider=proxy
0d602d
where you don't know the DN to bind as during authentication), but this
0d602d
approach also broke the use-case of id_provider=ldap and auth_provider=ldap
0d602d
with ldap_sasl_auth=gssapi.
0d602d
0d602d
This is because (for reason I don't know) AD doesn't like if you use
0d602d
both GSSAPI and startTLS on the same connection. But the code would
0d602d
force TLS during the authentication as a general measure to not transmit
0d602d
passwords in the clear, but then, the connection would also see that
0d602d
ldap_sasl_auth=gssapi is set and also bind with GSSAPI.
0d602d
0d602d
This patch checks if the user DN is already known and if yes, then
0d602d
doesn't authenticate the connection as the connection will then only be
0d602d
used for the user simple bind.
0d602d
0d602d
Reviewed-by: Sumit Bose <sbose@redhat.com>
0d602d
(cherry picked from commit 57fc60c9dc77698cf824813c36eb0f90d767b315)
0d602d
---
0d602d
 src/providers/ldap/ldap_auth.c | 53 +++++++++++++++++++++++++++-------
0d602d
 1 file changed, 42 insertions(+), 11 deletions(-)
0d602d
0d602d
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
0d602d
index c409353d9..b4d045a65 100644
0d602d
--- a/src/providers/ldap/ldap_auth.c
0d602d
+++ b/src/providers/ldap/ldap_auth.c
0d602d
@@ -664,6 +664,18 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx,
0d602d
         state->sdap_service = ctx->service;
0d602d
     }
0d602d
 
0d602d
+    ret = get_user_dn(state, state->ctx->be->domain,
0d602d
+                      state->ctx->opts, state->username, &state->dn,
0d602d
+                      &state->pw_expire_type, &state->pw_expire_data);
0d602d
+    if (ret == EAGAIN) {
0d602d
+        DEBUG(SSSDBG_TRACE_FUNC,
0d602d
+              "Need to look up the DN of %s later\n", state->username);
0d602d
+    } else if (ret != EOK) {
0d602d
+        DEBUG(SSSDBG_OP_FAILURE,
0d602d
+              "Cannot get user DN [%d]: %s\n", ret, sss_strerror(ret));
0d602d
+        goto fail;
0d602d
+    }
0d602d
+
0d602d
     if (auth_connect_send(req) == NULL) {
0d602d
         ret = ENOMEM;
0d602d
         goto fail;
0d602d
@@ -683,6 +695,8 @@ static struct tevent_req *auth_connect_send(struct tevent_req *req)
0d602d
     struct auth_state *state = tevent_req_data(req,
0d602d
                                                struct auth_state);
0d602d
     bool use_tls;
0d602d
+    bool skip_conn_auth = false;
0d602d
+    const char *sasl_mech;
0d602d
 
0d602d
     /* Check for undocumented debugging feature to disable TLS
0d602d
      * for authentication. This should never be used in production
0d602d
@@ -695,10 +709,33 @@ static struct tevent_req *auth_connect_send(struct tevent_req *req)
0d602d
                                "for debugging purposes only.");
0d602d
     }
0d602d
 
0d602d
+    if (state->dn != NULL) {
0d602d
+        /* In case the user's DN is known, the connection will only be used
0d602d
+         * to bind as the user to perform the authentication. In that case,
0d602d
+         * we don't need to authenticate the connection, because we're not
0d602d
+         * looking up any information using the connection. This might be
0d602d
+         * needed e.g. in case both ID and AUTH providers are set to LDAP
0d602d
+         * and the server is AD, because otherwise the connection would
0d602d
+         * both do a startTLS and later bind using GSSAPI which doesn't work
0d602d
+         * well with AD.
0d602d
+         */
0d602d
+        skip_conn_auth = true;
0d602d
+    }
0d602d
+
0d602d
+    if (skip_conn_auth == false) {
0d602d
+        sasl_mech = dp_opt_get_string(state->ctx->opts->basic,
0d602d
+                                      SDAP_SASL_MECH);
0d602d
+        if (sasl_mech && strcasecmp(sasl_mech, "GSSAPI") == 0) {
0d602d
+            /* Don't force TLS on if we're told to use GSSAPI */
0d602d
+            use_tls = false;
0d602d
+        }
0d602d
+    }
0d602d
+
0d602d
     subreq = sdap_cli_connect_send(state, state->ev, state->ctx->opts,
0d602d
                                    state->ctx->be,
0d602d
                                    state->sdap_service, false,
0d602d
-                                   use_tls ? CON_TLS_ON : CON_TLS_OFF, false);
0d602d
+                                   use_tls ? CON_TLS_ON : CON_TLS_OFF,
0d602d
+                                   skip_conn_auth);
0d602d
 
0d602d
     if (subreq == NULL) {
0d602d
         tevent_req_error(req, ENOMEM);
0d602d
@@ -739,15 +776,7 @@ static void auth_connect_done(struct tevent_req *subreq)
0d602d
         return;
0d602d
     }
0d602d
 
0d602d
-    ret = get_user_dn(state, state->ctx->be->domain,
0d602d
-                      state->ctx->opts, state->username, &state->dn,
0d602d
-                      &state->pw_expire_type, &state->pw_expire_data);
0d602d
-    if (ret == EOK) {
0d602d
-        /* All required user data was pre-cached during an identity lookup.
0d602d
-         * We can proceed with the bind */
0d602d
-        auth_do_bind(req);
0d602d
-        return;
0d602d
-    } else if (ret == EAGAIN) {
0d602d
+    if (state->dn == NULL) {
0d602d
         /* The cached user entry was missing the bind DN. Need to look
0d602d
          * it up based on user name in order to perform the bind */
0d602d
         subreq = get_user_dn_send(req, state->ev, state->ctx->be->domain,
0d602d
@@ -760,7 +789,9 @@ static void auth_connect_done(struct tevent_req *subreq)
0d602d
         return;
0d602d
     }
0d602d
 
0d602d
-    tevent_req_error(req, ret);
0d602d
+    /* All required user data was pre-cached during an identity lookup.
0d602d
+     * We can proceed with the bind */
0d602d
+    auth_do_bind(req);
0d602d
     return;
0d602d
 }
0d602d
 
0d602d
-- 
0d602d
2.19.1
0d602d