]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: sasl-server-mech-oauth2 - Allow passing more detailed error fields to client
authorStephan Bosch <stephan.bosch@open-xchange.com>
Sat, 4 Nov 2023 00:50:13 +0000 (01:50 +0100)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Thu, 9 Oct 2025 08:41:22 +0000 (08:41 +0000)
src/auth/Makefile.am
src/auth/sasl-server-mech-oauth2.c
src/auth/sasl-server-oauth2.h [new file with mode: 0644]

index 939e84177a34a3a62f516c8b084788e586f84fe7..a36350d786037694e1ff8051f9e05eacc378dff2 100644 (file)
@@ -167,6 +167,7 @@ headers = \
        mech-otp.h \
        mech-digest-md5-private.h \
        sasl-server.h \
+       sasl-server-oauth2.h \
        sasl-server-protected.h \
        sasl-server-mech-plain-common.h \
        sasl-server-mech-scram.h \
index a83877410e9c2e79f9b53f22f4cbffbdc740baac..a492a9ddb7f06525e97f1f9595d034126932bbad 100644 (file)
@@ -12,6 +12,7 @@
 #include "oauth2.h"
 
 #include "sasl-server-protected.h"
+#include "sasl-server-oauth2.h"
 
 struct oauth2_auth_request {
        struct auth_request request;
@@ -24,31 +25,36 @@ struct oauth2_auth_request {
 static struct db_oauth2 *db_oauth2 = NULL;
 
 static void
-oauth2_fail(struct oauth2_auth_request *oauth2_req, const char *status)
+oauth2_fail(struct oauth2_auth_request *oauth2_req,
+           const struct sasl_server_oauth2_failure *failure)
 {
        struct auth_request *request = &oauth2_req->request;
-       const char *oidc_url = (oauth2_req->db == NULL ? "" :
-               db_oauth2_get_openid_configuration_url(oauth2_req->db));
        string_t *reply = t_str_new(256);
        struct json_ostream *joutput = json_ostream_create_str(reply, 0);
 
+       i_assert(failure->status != NULL);
        json_ostream_ndescend_object(joutput, NULL);
        if (strcmp(request->mech->mech_name, "XOAUTH2") == 0) {
-               if (strcmp(status, "invalid_token") == 0)
+               if (strcmp(failure->status, "invalid_token") == 0)
                        json_ostream_nwrite_string(joutput, "status", "401");
-               else if (strcmp(status, "insufficient_scope") == 0)
+               else if (strcmp(failure->status, "insufficient_scope") == 0)
                        json_ostream_nwrite_string(joutput, "status", "403");
                else
                        json_ostream_nwrite_string(joutput, "status", "400");
                json_ostream_nwrite_string(joutput, "schemes", "bearer");
        } else {
                i_assert(strcmp(request->mech->mech_name, "OAUTHBEARER") == 0);
-               json_ostream_nwrite_string(joutput, "status", status);
+               json_ostream_nwrite_string(joutput, "status", failure->status);
        }
-       json_ostream_nwrite_string(joutput, "scope", "mail");
-       if (*oidc_url != '\0') {
+       if (failure->scope == NULL)
+               json_ostream_nwrite_string(joutput, "scope", "mail");
+       else
+               json_ostream_nwrite_string(joutput, "scope", failure->scope);
+       if (failure->openid_configuration != NULL &&
+           *failure->openid_configuration != '\0') {
                json_ostream_nwrite_string(
-                       joutput, "openid-configuration", oidc_url);
+                       joutput, "openid-configuration",
+                       failure->openid_configuration);
        }
        json_ostream_nascend_object(joutput);
        json_ostream_nfinish_destroy(&joutput);
@@ -57,14 +63,24 @@ oauth2_fail(struct oauth2_auth_request *oauth2_req, const char *status)
        auth_request_fail_with_reply(request, str_data(reply), str_len(reply));
 }
 
+static void
+oauth2_fail_status(struct oauth2_auth_request *oauth2_req, const char *status)
+{
+       const struct sasl_server_oauth2_failure failure = {
+               .status = status,
+       };
+
+       oauth2_fail(oauth2_req, &failure);
+}
+
 static void oauth2_fail_invalid_request(struct oauth2_auth_request *oauth2_req)
 {
-       oauth2_fail(oauth2_req, "invalid_request");
+       oauth2_fail_status(oauth2_req, "invalid_request");
 }
 
 static void oauth2_fail_invalid_token(struct oauth2_auth_request *oauth2_req)
 {
-       oauth2_fail(oauth2_req, "invalid_token");
+       oauth2_fail_status(oauth2_req, "invalid_token");
 }
 
 static void
@@ -72,29 +88,38 @@ oauth2_verify_finish(enum passdb_result result, struct auth_request *request)
 {
        struct oauth2_auth_request *oauth2_req =
                container_of(request, struct oauth2_auth_request, request);
+       struct sasl_server_oauth2_failure failure;
+
+       i_zero(&failure);
 
        switch (result) {
        case PASSDB_RESULT_INTERNAL_FAILURE:
                auth_request_internal_failure(request);
-               break;
+               return;
        case PASSDB_RESULT_USER_DISABLED:
        case PASSDB_RESULT_PASS_EXPIRED:
                /* user is explicitly disabled, don't allow it to log in */
-               oauth2_fail(oauth2_req, "insufficient_scope");
+               failure.status = "insufficient_scope";
                break;
        case PASSDB_RESULT_USER_UNKNOWN:
        case PASSDB_RESULT_PASSWORD_MISMATCH:
-               oauth2_fail(oauth2_req, "invalid_token");
+               failure.status = "invalid_token";
                break;
        case PASSDB_RESULT_NEXT:
        case PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
        case PASSDB_RESULT_OK:
                /* sending success */
                auth_request_success(request, "", 0);
-               break;
+               return;
        default:
                i_unreached();
        }
+
+       if (oauth2_req->db != NULL) {
+               failure.openid_configuration =
+                       db_oauth2_get_openid_configuration_url(oauth2_req->db);
+       }
+       oauth2_fail(oauth2_req, &failure);
 }
 
 static void
diff --git a/src/auth/sasl-server-oauth2.h b/src/auth/sasl-server-oauth2.h
new file mode 100644 (file)
index 0000000..13a51e9
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SASL_SERVER_OAUTH2_H
+#define SASL_SERVER_OAUTH2_H
+
+#include "sasl-server.h"
+
+struct sasl_server_oauth2_failure {
+       const char *status;
+       const char *scope;
+       const char *openid_configuration;
+};
+
+#endif