You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-commits@axis.apache.org by ro...@apache.org on 2026/01/14 13:27:14 UTC

(axis-axis2-c-core) 04/04: AXIS2C-1312/1555: Add proxy authentication support for HTTPS CONNECT

This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git

commit e98d6364610929d15a8990427e3e843774658f8c
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Wed Jan 14 03:18:57 2026 -1000

    AXIS2C-1312/1555: Add proxy authentication support for HTTPS CONNECT
    
    When connecting to an HTTPS endpoint through a proxy, the HTTP client
    sends a CONNECT request to establish an SSL tunnel. This request may
    require proxy authentication (HTTP 407 response).
    
    Changes:
    - Add proxy_auth_username and proxy_auth_password fields to http_client struct
    - Add axis2_http_client_set_proxy_auth() function to set proxy credentials
    - Modify axis2_http_client_connect_ssl_host() to include Proxy-Authorization
      header with Basic auth in the CONNECT request when credentials are set
    - Return HTTP 407 status code (instead of generic failure) when proxy
      requires authentication, allowing caller to handle appropriately
    - Update axis2_http_sender_configure_proxy() to pass proxy credentials
      from message context to the HTTP client
    - Properly free proxy auth credentials in axis2_http_client_free()
    
    Co-Authored-By: Claude Opus 4.5 <no...@anthropic.com>
---
 include/axis2_http_client.h                  |  15 ++++
 src/core/transport/http/sender/http_client.c | 121 +++++++++++++++++++++++++--
 src/core/transport/http/sender/http_sender.c |  21 +++++
 3 files changed, 149 insertions(+), 8 deletions(-)

diff --git a/include/axis2_http_client.h b/include/axis2_http_client.h
index edbfc3f1f..27c936582 100644
--- a/include/axis2_http_client.h
+++ b/include/axis2_http_client.h
@@ -145,6 +145,21 @@ extern "C"
         const axis2_http_client_t * client,
         const axutil_env_t * env);
 
+    /**
+     * AXIS2C-1312/1555: Set proxy authentication credentials for HTTPS CONNECT
+     * @param client pointer to client
+     * @param env pointer to environment struct
+     * @param username proxy authentication username
+     * @param password proxy authentication password
+     * @return AXIS2_SUCCESS on success, else AXIS2_FAILURE
+     */
+    AXIS2_EXTERN axis2_status_t AXIS2_CALL
+    axis2_http_client_set_proxy_auth(
+        axis2_http_client_t * client,
+        const axutil_env_t * env,
+        const axis2_char_t * username,
+        const axis2_char_t * password);
+
     AXIS2_EXTERN axis2_status_t AXIS2_CALL
 
     axis2_http_client_connect_ssl_host(
diff --git a/src/core/transport/http/sender/http_client.c b/src/core/transport/http/sender/http_client.c
index 6eb1edff8..024cce315 100644
--- a/src/core/transport/http/sender/http_client.c
+++ b/src/core/transport/http/sender/http_client.c
@@ -54,6 +54,10 @@ struct axis2_http_client
     int req_body_size;
     axis2_bool_t validate_ssl_hostname;
 
+    /* AXIS2C-1312/1555: Proxy authentication for HTTPS CONNECT */
+    axis2_char_t *proxy_auth_username;
+    axis2_char_t *proxy_auth_password;
+
     /* These are for mtom case */
     axutil_array_list_t *mime_parts;
     axis2_bool_t doing_mtom;
@@ -119,6 +123,15 @@ axis2_http_client_free(
     {
         AXIS2_FREE(env->allocator, http_client->proxy_host_port);
     }
+    /* AXIS2C-1312/1555: Free proxy authentication credentials */
+    if(http_client->proxy_auth_username)
+    {
+        AXIS2_FREE(env->allocator, http_client->proxy_auth_username);
+    }
+    if(http_client->proxy_auth_password)
+    {
+        AXIS2_FREE(env->allocator, http_client->proxy_auth_password);
+    }
     if(http_client->url)
     {
         axutil_url_free(http_client->url, env);
@@ -815,6 +828,46 @@ axis2_http_client_get_proxy(
     return client->proxy_host_port;
 }
 
+/* AXIS2C-1312/1555: Set proxy authentication credentials for HTTPS CONNECT */
+AXIS2_EXTERN axis2_status_t AXIS2_CALL
+axis2_http_client_set_proxy_auth(
+    axis2_http_client_t * client,
+    const axutil_env_t * env,
+    const axis2_char_t * username,
+    const axis2_char_t * password)
+{
+    AXIS2_PARAM_CHECK(env->error, client, AXIS2_FAILURE);
+
+    if(client->proxy_auth_username)
+    {
+        AXIS2_FREE(env->allocator, client->proxy_auth_username);
+        client->proxy_auth_username = NULL;
+    }
+    if(client->proxy_auth_password)
+    {
+        AXIS2_FREE(env->allocator, client->proxy_auth_password);
+        client->proxy_auth_password = NULL;
+    }
+
+    if(username)
+    {
+        client->proxy_auth_username = axutil_strdup(env, username);
+        if(!client->proxy_auth_username)
+        {
+            return AXIS2_FAILURE;
+        }
+    }
+    if(password)
+    {
+        client->proxy_auth_password = axutil_strdup(env, password);
+        if(!client->proxy_auth_password)
+        {
+            return AXIS2_FAILURE;
+        }
+    }
+    return AXIS2_SUCCESS;
+}
+
 AXIS2_EXTERN axis2_status_t AXIS2_CALL
 axis2_http_client_connect_ssl_host(
     axis2_http_client_t * client,
@@ -851,9 +904,50 @@ axis2_http_client_connect_ssl_host(
         return AXIS2_FAILURE;
     }
 
-    connect_string = AXIS2_MALLOC(env->allocator, axutil_strlen(host) * sizeof(axis2_char_t) + 30
-        * sizeof(axis2_char_t));
-    sprintf(connect_string, "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
+    /* AXIS2C-1312/1555: Build CONNECT request with optional proxy authentication */
+    if(client->proxy_auth_username && client->proxy_auth_password)
+    {
+        /* Build Basic authentication header for proxy */
+        axis2_char_t *credentials = NULL;
+        axis2_char_t *encoded = NULL;
+        int credentials_len;
+        int encoded_len;
+
+        credentials_len = axutil_strlen(client->proxy_auth_username) +
+                          axutil_strlen(client->proxy_auth_password) + 2;
+        credentials = AXIS2_MALLOC(env->allocator, credentials_len);
+        sprintf(credentials, "%s:%s", client->proxy_auth_username, client->proxy_auth_password);
+
+        /* Base64 encode the credentials */
+        encoded_len = axutil_base64_encode_len(axutil_strlen(credentials));
+        encoded = AXIS2_MALLOC(env->allocator, encoded_len + 1);
+        if(encoded)
+        {
+            axutil_base64_encode(encoded, credentials, axutil_strlen(credentials));
+            encoded[encoded_len] = '\0';
+        }
+        AXIS2_FREE(env->allocator, credentials);
+
+        if(encoded)
+        {
+            int connect_len = axutil_strlen(host) + axutil_strlen(encoded) + 100;
+            connect_string = AXIS2_MALLOC(env->allocator, connect_len);
+            sprintf(connect_string, "CONNECT %s:%d HTTP/1.0\r\nProxy-Authorization: Basic %s\r\n\r\n",
+                    host, port, encoded);
+            AXIS2_FREE(env->allocator, encoded);
+        }
+        else
+        {
+            /* Fallback to no auth if encoding fails */
+            connect_string = AXIS2_MALLOC(env->allocator, axutil_strlen(host) + 30);
+            sprintf(connect_string, "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
+        }
+    }
+    else
+    {
+        connect_string = AXIS2_MALLOC(env->allocator, axutil_strlen(host) + 30);
+        sprintf(connect_string, "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
+    }
     axutil_stream_write(tmp_stream, env, connect_string, axutil_strlen(connect_string)
         * sizeof(axis2_char_t));
 
@@ -893,12 +987,23 @@ axis2_http_client_connect_ssl_host(
         axutil_stream_free(tmp_stream, env);
         return AXIS2_FAILURE;
     }
-    if(200 != axis2_http_status_line_get_status_code(status_line, env))
+    /* AXIS2C-1312/1555: Handle proxy authentication response */
     {
-        AXIS2_FREE(env->allocator, connect_string);
-        axis2_http_status_line_free(status_line, env);
-        axutil_stream_free(tmp_stream, env);
-        return AXIS2_FAILURE;
+        int status_code = axis2_http_status_line_get_status_code(status_line, env);
+        if(200 != status_code)
+        {
+            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
+                "Proxy CONNECT failed with status code %d", status_code);
+            AXIS2_FREE(env->allocator, connect_string);
+            axis2_http_status_line_free(status_line, env);
+            axutil_stream_free(tmp_stream, env);
+            /* Return 407 status code so caller can handle proxy auth */
+            if(AXIS2_HTTP_RESPONSE_PROXY_AUTHENTICATION_REQUIRED_CODE_VAL == status_code)
+            {
+                return AXIS2_HTTP_RESPONSE_PROXY_AUTHENTICATION_REQUIRED_CODE_VAL;
+            }
+            return AXIS2_FAILURE;
+        }
     }
     /* We need to empty the stream before we return
      */
diff --git a/src/core/transport/http/sender/http_sender.c b/src/core/transport/http/sender/http_sender.c
index 32a6f4a6e..6e1195784 100644
--- a/src/core/transport/http/sender/http_sender.c
+++ b/src/core/transport/http/sender/http_sender.c
@@ -1890,6 +1890,27 @@ axis2_http_sender_configure_proxy(
     if(proxy_port && proxy_host)
     {
         axis2_http_client_set_proxy(sender->client, env, proxy_host, AXIS2_ATOI(proxy_port));
+
+        /* AXIS2C-1312/1555: Set proxy authentication credentials for HTTPS CONNECT */
+        {
+            axutil_property_t *proxy_auth_un = NULL;
+            axutil_property_t *proxy_auth_pw = NULL;
+            axis2_char_t *proxy_uname = NULL;
+            axis2_char_t *proxy_passwd = NULL;
+
+            proxy_auth_un = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_PROXY_AUTH_UNAME);
+            proxy_auth_pw = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_PROXY_AUTH_PASSWD);
+
+            if(proxy_auth_un && proxy_auth_pw)
+            {
+                proxy_uname = (axis2_char_t *)axutil_property_get_value(proxy_auth_un, env);
+                proxy_passwd = (axis2_char_t *)axutil_property_get_value(proxy_auth_pw, env);
+                if(proxy_uname && proxy_passwd)
+                {
+                    axis2_http_client_set_proxy_auth(sender->client, env, proxy_uname, proxy_passwd);
+                }
+            }
+        }
     }
     return AXIS2_SUCCESS;
 }