فهرست منبع

http_async_client: added support for authentication

Federico Cabiddu 9 سال پیش
والد
کامیت
b1e8c2f007

+ 86 - 6
modules/http_async_client/async_http.c

@@ -213,7 +213,7 @@ void notification_socket_cb(int fd, short event, void *arg)
 	const async_http_worker_t *worker = (async_http_worker_t *) arg;
 
 	int received;
-	int i;
+	int i, len;
 	async_query_t *aq;
 
 	http_m_params_t query_params;
@@ -237,6 +237,8 @@ void notification_socket_cb(int fd, short event, void *arg)
 	query_params.timeout = aq->query_params.timeout;
 	query_params.tls_verify_peer = aq->query_params.tls_verify_peer;
 	query_params.tls_verify_host = aq->query_params.tls_verify_host;
+	query_params.authmethod = aq->query_params.authmethod;
+
 	query_params.headers = NULL;
 	for (i = 0 ; i < aq->query_params.headers.len ; i++) {
 		query_params.headers = curl_slist_append(query_params.headers, aq->query_params.headers.t[i]);
@@ -248,7 +250,7 @@ void notification_socket_cb(int fd, short event, void *arg)
 	if (aq->query_params.tls_client_cert.s && aq->query_params.tls_client_cert.len > 0) {
 		if (shm_str_dup(&query_params.tls_client_cert, &(aq->query_params.tls_client_cert)) < 0) {
 			LM_ERR("Error allocating query_params.tls_client_cert\n");
-			return;
+			goto done;
 		}
 	}
 
@@ -257,7 +259,7 @@ void notification_socket_cb(int fd, short event, void *arg)
 	if (aq->query_params.tls_client_key.s && aq->query_params.tls_client_key.len > 0) {
 		if (shm_str_dup(&query_params.tls_client_key, &(aq->query_params.tls_client_key)) < 0) {
 			LM_ERR("Error allocating query_params.tls_client_key\n");
-			return;
+			goto done;
 		}
 	}
 
@@ -266,7 +268,7 @@ void notification_socket_cb(int fd, short event, void *arg)
 	if (aq->query_params.tls_ca_path.s && aq->query_params.tls_ca_path.len > 0) {
 		if (shm_str_dup(&query_params.tls_ca_path, &(aq->query_params.tls_ca_path)) < 0) {
 			LM_ERR("Error allocating query_params.tls_ca_path\n");
-			return;
+			goto done;
 		}
 	}
 
@@ -275,9 +277,35 @@ void notification_socket_cb(int fd, short event, void *arg)
 	if (aq->query_params.body.s && aq->query_params.body.len > 0) {
 		if (shm_str_dup(&query_params.body, &(aq->query_params.body)) < 0) {
 			LM_ERR("Error allocating query_params.body\n");
-			return;
+			goto done;
 		}
 	}
+  
+	if (aq->query_params.username) {
+		len = strlen(aq->query_params.username);
+		query_params.username = shm_malloc(len+1);
+	
+		if(query_params.username == NULL) {
+			LM_ERR("error in shm_malloc\n");
+			goto done;
+		}
+
+		strncpy(query_params.username, aq->query_params.username, len);
+		query_params.username[len] = '\0';
+	}
+	
+	if (aq->query_params.password) {
+		len = strlen(aq->query_params.password);
+		query_params.password = shm_malloc(len+1);
+	
+		if(query_params.password == NULL) {
+			LM_ERR("error in shm_malloc\n");
+			goto done;
+		}
+
+		strncpy(query_params.password, aq->query_params.password, len);
+		query_params.password[len] = '\0';
+	}
 
 	LM_DBG("query received: [%.*s] (%p)\n", query.len, query.s, aq);
 
@@ -286,6 +314,7 @@ void notification_socket_cb(int fd, short event, void *arg)
 		free_async_query(aq);
 	}
 
+done:
 	if (query_params.tls_client_cert.s && query_params.tls_client_cert.len > 0) {
 		shm_free(query_params.tls_client_cert.s);
 		query_params.tls_client_cert.s = NULL;
@@ -307,6 +336,16 @@ void notification_socket_cb(int fd, short event, void *arg)
 		query_params.body.len = 0;
 	}
 
+	if (query_params.username) {
+		shm_free(query_params.username);
+		query_params.username = NULL;
+	}
+	
+	if (query_params.password) {
+		shm_free(query_params.password);
+		query_params.password = NULL;
+	}
+
 	return;
 }
 
@@ -324,6 +363,7 @@ int async_send_query(sip_msg_t *msg, str *query, cfg_action_t *act)
 	unsigned int tlabel = 0;
 	short suspend = 0;
 	int dsize;
+	int len;
 	tm_cell_t *t = 0;
 
 	if(query==0) {
@@ -375,7 +415,8 @@ int async_send_query(sip_msg_t *msg, str *query, cfg_action_t *act)
 	aq->query_params.timeout = ah_params.timeout;
 	aq->query_params.headers = ah_params.headers;
 	aq->query_params.method = ah_params.method;
-
+	aq->query_params.authmethod = ah_params.authmethod;
+	
 	q_idx++;
 	snprintf(q_id, MAX_ID_LEN+1, "%u-%u", (unsigned int)getpid(), q_idx);
 	strncpy(aq->id, q_id, strlen(q_id));
@@ -416,6 +457,34 @@ int async_send_query(sip_msg_t *msg, str *query, cfg_action_t *act)
 		}
 	}
 
+	aq->query_params.username = NULL;
+	if (ah_params.username) {
+		len = strlen(ah_params.username);
+		aq->query_params.username = shm_malloc(len+1);
+	
+		if(aq->query_params.username == NULL) {
+			LM_ERR("error in shm_malloc\n");
+			goto error;
+		}
+
+		strncpy(aq->query_params.username, ah_params.username, len);
+		aq->query_params.username[len] = '\0';
+	}
+
+	aq->query_params.password = NULL;
+	if (ah_params.password) {
+		len = strlen(ah_params.password);
+		aq->query_params.password = shm_malloc(len+1);
+	
+		if(aq->query_params.password == NULL) {
+			LM_ERR("error in shm_malloc\n");
+			goto error;
+		}
+
+		strncpy(aq->query_params.password, ah_params.password, len);
+		aq->query_params.password[len] = '\0';
+	}
+
 	set_query_params(&ah_params);
 
 	if(async_push_query(aq)<0) {
@@ -473,6 +542,7 @@ void set_query_params(struct query_params *p) {
 	p->suspend_transaction = 1;
 	p->timeout = http_timeout;
 	p->method = AH_METH_DEFAULT;
+	p->authmethod = default_authmethod;
 
 	if (p->tls_client_cert.s && p->tls_client_cert.len > 0) {
 		shm_free(p->tls_client_cert.s);
@@ -515,6 +585,16 @@ void set_query_params(struct query_params *p) {
 		p->body.s = NULL;
 		p->body.len = 0;
 	}
+	
+	if (p->username) {
+		shm_free(p->username);
+		p->username = NULL;
+	}
+	
+	if (p->password) {
+		shm_free(p->password);
+		p->password = NULL;
+	}
 }
 
 int header_list_add(struct header_list *hl, str* hdr) {

+ 15 - 0
modules/http_async_client/async_http.h

@@ -59,6 +59,7 @@ extern str tls_client_cert;
 extern str tls_client_key;
 extern str tls_ca_path;
 
+extern unsigned int default_authmethod;
 
 typedef struct async_http_worker {
 	int notication_socket[2];
@@ -92,6 +93,10 @@ struct query_params {
 	str tls_client_key;
 	str tls_ca_path;
 	str body;
+
+	unsigned int authmethod;
+	char* username;
+	char* password;
 };
 
 extern struct query_params ah_params;
@@ -162,6 +167,16 @@ static inline void free_async_query(async_query_t *aq)
 		aq->query_params.body.len = 0;
 	}
 
+	if (aq->query_params.username) {
+		shm_free(aq->query_params.username);
+		aq->query_params.username = NULL;
+	}
+
+	if (aq->query_params.password) {
+		shm_free(aq->query_params.password);
+		aq->query_params.password = NULL;
+	}
+
 	shm_free(aq);
 }
 

+ 19 - 0
modules/http_async_client/doc/http_async_client_admin.xml

@@ -589,6 +589,25 @@ xlog("L_INFO", "received reply for query $http_query_id\n");
 		<listitem><para><emphasis>tls_client_cert</emphasis>: sets the client certificate to use (see <emphasis>http_set_tls_client_cert()</emphasis>)</para></listitem>
 		<listitem><para><emphasis>tls_client_key</emphasis>: sets the client certificate key to use (see <emphasis>http_set_tls_client_key()</emphasis>)</para></listitem>
 		<listitem><para><emphasis>tls_ca_path</emphasis>: sets the CA certificate path to use (see <emphasis>http_set_tls_ca_path()</emphasis>)</para></listitem>
+		<listitem><para><emphasis>authmethod</emphasis>: 
+			Sets the preferred authentication mode for HTTP/HTTPS requests. The value is a bitmap
+                        and multiple methods can be used. Note that in this case, the CURL library will make an
+                        extra request to discover server-supported authentication methods. You may want to use
+                        a specific value.
+                        <para>
+                        Valid values are:
+                                <itemizedlist>
+                                <listitem><para>1 - BASIC authentication</para></listitem>
+                                <listitem><para>2 - HTTP Digest authentication</para></listitem>
+                                <listitem><para>4 - GSS-Negotiate authentication</para></listitem>
+                                <listitem><para>8 - NTLM authentication</para></listitem>
+                                <listitem><para>16 - HTTP Digest with IE flavour</para></listitem>
+                                </itemizedlist>
+                        Default value is 3 - BASIC and Digest authentication.
+                        </para>	
+		</para></listitem>
+		<listitem><para><emphasis>username</emphasis>: sets the username to use for authenticated requests</para></listitem>
+		<listitem><para><emphasis>password</emphasis>: sets the password to use for authenticated requests</para></listitem>
 		<listitem><para><emphasis>suspend</emphasis>: if set to 0 it doesn't suspend the current transaction before performing the query (see <emphasis>http_async_suspend()</emphasis>)</para></listitem>
 	</itemizedlist>
 	<example>

+ 4 - 0
modules/http_async_client/hm_hash.h

@@ -74,6 +74,10 @@ typedef struct hm_params {
 	str tls_client_key;
 	str tls_ca_path;
 	str body;
+	
+	unsigned int authmethod;
+	char* username;
+	char* password;
 } http_m_params_t;
 
 typedef struct http_m_cell

+ 83 - 12
modules/http_async_client/http_async_client_mod.c

@@ -75,6 +75,7 @@ str tls_client_key = STR_STATIC_INIT(""); // client SSL certificate key path, de
 str tls_ca_path = STR_STATIC_INIT(""); // certificate authority dir path, defaults to NULL
 static char *memory_manager = "shm";
 extern int curl_memory_manager;
+unsigned int default_authmethod = CURLAUTH_BASIC | CURLAUTH_DIGEST;
 
 static int  mod_init(void);
 static int  child_init(int);
@@ -128,7 +129,8 @@ enum http_req_name_t {
 	E_HRN_HDR, E_HRN_METHOD, E_HRN_TIMEOUT,
 	E_HRN_TLS_CA_PATH, E_HRN_TLS_CLIENT_KEY,
 	E_HRN_TLS_CLIENT_CERT, E_HRN_SUSPEND,
-	E_HRN_BODY
+	E_HRN_BODY, E_HRN_AUTHMETHOD, E_HRN_USERNAME,
+	E_HRN_PASSWORD
 };
 
 static cmd_export_t cmds[]={
@@ -156,17 +158,18 @@ static cmd_export_t cmds[]={
 };
 
 static param_export_t params[]={
-{"workers",					INT_PARAM,   &num_workers},
-	{"connection_timeout",	INT_PARAM,   &http_timeout},
-	{"hash_size",			INT_PARAM,   &hash_size},
-	{"tls_version",			INT_PARAM,   &tls_version},
-	{"tls_verify_host",		INT_PARAM,   &tls_verify_host},
-	{"tls_verify_peer",		INT_PARAM,   &tls_verify_peer},
-	{"curl_verbose",		INT_PARAM,   &curl_verbose},
-	{"tls_client_cert",		PARAM_STR,   &tls_client_cert},
-	{"tls_client_key",		PARAM_STR,   &tls_client_key},
-	{"tls_ca_path",			PARAM_STR,   &tls_ca_path},
-	{"memory_manager",	PARAM_STRING,&memory_manager},
+	{"workers",				INT_PARAM,		&num_workers},
+	{"connection_timeout",	INT_PARAM,		&http_timeout},
+	{"hash_size",			INT_PARAM,		&hash_size},
+	{"tls_version",			INT_PARAM,		&tls_version},
+	{"tls_verify_host",		INT_PARAM,		&tls_verify_host},
+	{"tls_verify_peer",		INT_PARAM,		&tls_verify_peer},
+	{"curl_verbose",		INT_PARAM,		&curl_verbose},
+	{"tls_client_cert",		PARAM_STR,		&tls_client_cert},
+	{"tls_client_key",		PARAM_STR,		&tls_client_key},
+	{"tls_ca_path",			PARAM_STR,		&tls_ca_path},
+	{"memory_manager",		PARAM_STRING,	&memory_manager},
+	{"authmethod",			PARAM_INT,		&default_authmethod },
 	{0, 0, 0}
 };
 
@@ -573,6 +576,33 @@ static int set_query_param(str* param, str input)
 	return 1;
 }
 
+/*
+ * Helper to copy input string parameter into a query char* parameter
+ */
+static int set_query_cparam(char** param, str input)
+{
+	if (*param) {
+		shm_free(*param);
+		*param = NULL;
+	}
+
+	if (input.s && input.len > 0) {
+		*param = shm_malloc(input.len+1);
+	
+		if(*param == NULL) {
+			LM_ERR("error in shm_malloc\n");
+			return -1;
+		}
+
+		strncpy(*param, input.s, input.len);
+		(*param)[input.len] = '\0';
+		
+		LM_DBG("param set to '%s'\n", *param);
+	}
+
+	return 1;
+}
+
 /**
  *
  */
@@ -678,6 +708,18 @@ static int ah_parse_req_name(pv_spec_p sp, str *in) {
 				sp->pvp.pvn.u.isname.name.n = E_HRN_SUSPEND;
 			else goto error;
 			break;
+		case 8:
+			if(strncmp(in->s, "username", 8)==0)
+				sp->pvp.pvn.u.isname.name.n = E_HRN_USERNAME;
+			else if(strncmp(in->s, "password", 8)==0)
+				sp->pvp.pvn.u.isname.name.n = E_HRN_PASSWORD;
+			else goto error;
+			break;
+		case 10:
+			if(strncmp(in->s, "authmethod", 10)==0)
+				sp->pvp.pvn.u.isname.name.n = E_HRN_AUTHMETHOD;
+			else goto error;
+			break;
 		case 11:
 			if(strncmp(in->s, "tls_ca_path", 11)==0)
 				sp->pvp.pvn.u.isname.name.n = E_HRN_TLS_CA_PATH;
@@ -808,6 +850,35 @@ static int ah_set_req(struct sip_msg* msg, pv_param_t *param,
 			set_query_param(&ah_params.body, tval->rs);
 		}
 		break;
+	case E_HRN_AUTHMETHOD:
+		if (tval) {
+			if (!(tval->flags & PV_VAL_INT)) {
+				LM_ERR("invalid value type for $http_req(authmethod)\n");
+				return -1;
+			}
+			ah_params.authmethod = tval->ri;
+		} else {
+			ah_params.authmethod = default_authmethod;
+		}
+		break;
+	case E_HRN_USERNAME:
+		if (tval) {
+			if (!(tval->flags & PV_VAL_STR)) {
+				LM_ERR("invalid value type for $http_req(username)\n");
+				return -1;
+			}
+			set_query_cparam(&ah_params.username, tval->rs);
+		}
+		break;
+	case E_HRN_PASSWORD:
+		if (tval) {
+			if (!(tval->flags & PV_VAL_STR)) {
+				LM_ERR("invalid value type for $http_req(password)\n");
+				return -1;
+			}
+			set_query_cparam(&ah_params.password, tval->rs);
+		}
+		break;
 	}
 
 	return 1;

+ 12 - 0
modules/http_async_client/http_multi.c

@@ -511,6 +511,18 @@ int new_request(str *query, http_m_params_t *query_params, http_multi_cbe_t cb,
 	default:
 		break;
 	}
+
+	if (cell->params.username) {
+		curl_easy_setopt(cell->easy, CURLOPT_USERNAME, cell->params.username);
+		curl_easy_setopt(cell->easy, CURLOPT_HTTPAUTH, cell->params.authmethod);
+
+		LM_DBG("set username to %s [authmethod %u]\n", cell->params.username, cell->params.authmethod);
+	}
+
+	if (cell->params.password) {
+		curl_easy_setopt(cell->easy, CURLOPT_PASSWORD, cell->params.password);
+	}
+
 	LM_DBG("Adding easy %p to multi %p (%.*s)\n", cell->easy, g->multi, query->len, query->s);
 	rc = curl_multi_add_handle(g->multi, cell->easy);
 	if (check_mcode(rc, cell->error) < 0) {