Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Share an auth session between multiple dialogs/regc #4262

Merged
merged 9 commits into from
Feb 3, 2025
14 changes: 14 additions & 0 deletions pjsip/include/pjsip-ua/sip_regc.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,20 @@ PJ_DECL(pj_status_t) pjsip_regc_update_expires( pjsip_regc *regc,
PJ_DECL(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata);


/**
* set a shared auth session to be used by this register client.
* This will try to reuse authorization headers from another source
* (e.g. subscribe dialog).
*
* If available, the internal auth session will be ignored. To reset
* call with NULL for session parameter
*
* @param dlg The dialog
* @param session Pointer to the external session
*/
PJ_DECL(pj_status_t) pjsip_regc_set_auth_sess( pjsip_regc *regc,
pjsip_auth_clt_sess *session );

PJ_END_DECL

/**
Expand Down
3 changes: 2 additions & 1 deletion pjsip/include/pjsip/sip_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ typedef struct pjsip_auth_clt_sess
unsigned cred_cnt; /**< Number of credentials. */
pjsip_cred_info *cred_info; /**< Array of credential information*/
pjsip_cached_auth cached_auth; /**< Cached authorization info. */

pj_lock_t *lock; /**< Prevent concurrent usage when shared. should only used in parent */
struct pjsip_auth_clt_sess *parent; /**< allow a common parent for multiple sessions.*/
} pjsip_auth_clt_sess;


Expand Down
15 changes: 13 additions & 2 deletions pjsip/include/pjsip/sip_dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,19 @@ PJ_DECL(pj_status_t) pjsip_dlg_update_remote_cap(pjsip_dialog *dlg,
const pjsip_msg *msg,
pj_bool_t strict);


/**
* set a shared auth session to be used by this dialog.
* This will try to reuse authorization headers from another source
* (e.g. register).
*
* If available, the internal auth session will be ignored. To reset
* call with NULL for session parameter
*
* @param dlg The dialog
* @param session Pointer to the external session
*/
PJ_DECL(pj_status_t) pjsip_dlg_set_auth_sess(pjsip_dialog *dlg,
pjsip_auth_clt_sess *session);

/**
* @}
Expand All @@ -927,7 +939,6 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg,
pjsip_rx_data *rdata );



PJ_END_DECL


Expand Down
13 changes: 13 additions & 0 deletions pjsip/include/pjsua-lib/pjsua.h
Original file line number Diff line number Diff line change
Expand Up @@ -4661,6 +4661,19 @@ typedef struct pjsua_acc_config
*/
pj_bool_t enable_rtcp_xr;

/**
* Use a shared authorization session within this account.
* This will use the accounts credentials on outgoing requests,
* so that less 401/407 Responses will be returned.
*
* May need to have PJSIP_AUTH_AUTO_SEND_NEXT and PJSIP_AUTH_HEADER_CACHING
* enabled to work properly, and also will grow usage of the used pool for
* the cached headers.
*
* Default: PJ_FALSE
*/
pj_bool_t shared_auth;

} pjsua_acc_config;


Expand Down
1 change: 1 addition & 0 deletions pjsip/include/pjsua-lib/pjsua_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ typedef struct pjsua_acc
pjsip_transport_type_e tp_type; /**< Transport type (for local acc or
transport binding) */
pjsua_ip_change_op ip_change_op;/**< IP change process progress. */
pjsip_auth_clt_sess shared_auth_sess; /**< share one auth over all requests */
} pjsua_acc;


Expand Down
13 changes: 13 additions & 0 deletions pjsip/include/pjsua2/account.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,19 @@ struct AccountSipConfig : public PersistentObject
*/
pjsua_ipv6_use ipv6Use;

/**
* Use a shared authorization session within this account.
* This will use the accounts credentials on outgoing requests,
* so that less 401/407 Responses will be returned.
*
* May need to have PJSIP_AUTH_AUTO_SEND_NEXT and PJSIP_AUTH_HEADER_CACHING
* enabled to work properly, and also will grow usage of the used pool for
* the cached headers.
*
* Default is no
*/
bool sharedAuth;

public:
/**
* Read this object from a container node.
Expand Down
17 changes: 16 additions & 1 deletion pjsip/src/pjsip-ua/sip_reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ struct pjsip_regc

/* Authorization sessions. */
pjsip_auth_clt_sess auth_sess;
pjsip_auth_clt_sess *ext_auth_sess; /**< User defined auth session. */

/* Auto refresh registration. */
pj_bool_t auto_reg;
Expand Down Expand Up @@ -1555,4 +1556,18 @@ PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
return status;
}


PJ_DEF(pj_status_t) pjsip_regc_set_auth_sess( pjsip_regc *regc,
pjsip_auth_clt_sess *session ) {
PJ_ASSERT_RETURN(regc, PJ_EINVAL);
pj_status_t status = PJ_SUCCESS;
status = pj_lock_acquire(regc->auth_sess.lock);
if (status != PJ_SUCCESS) {
return status;
}
regc->auth_sess.parent = session;
status = pj_lock_release(regc->auth_sess.lock);
if (status != PJ_SUCCESS) {
return status;
}
return PJ_SUCCESS;
}
92 changes: 89 additions & 3 deletions pjsip/src/pjsip/sip_auth_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <pj/guid.h>
#include <pj/assert.h>
#include <pj/ctype.h>
#include <pj/lock.h>


#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
Expand Down Expand Up @@ -105,6 +106,26 @@ const pjsip_auth_algorithm pjsip_auth_algorithms[] = {
# define AUTH_TRACE_(expr)
#endif

#define DO_ON_PARENT_LOCKED(sess, call) \
do { \
pj_status_t on_parent, lock_status; \
pj_bool_t with_parent = PJ_FALSE; \
if (sess->parent) { \
lock_status = pj_lock_acquire(sess->parent->lock); \
if (lock_status != PJ_SUCCESS) { \
return lock_status; \
} \
with_parent = PJ_TRUE; \
on_parent = call; \
lock_status = pj_lock_release(sess->parent->lock); \
if (lock_status != PJ_SUCCESS) { \
return lock_status; \
} \
} \
if (with_parent) { \
return on_parent; \
} \
} while(0)

static void dup_bin(pj_pool_t *pool, pj_str_t *dst, const pj_str_t *src)
{
Expand Down Expand Up @@ -712,6 +733,24 @@ static pjsip_cached_auth *find_cached_auth( pjsip_auth_clt_sess *sess,
const pj_str_t *realm,
pjsip_auth_algorithm_type algorithm_type)
{
pj_status_t lock_status;
pj_bool_t with_parent = PJ_FALSE;
pjsip_cached_auth * pauth = NULL;
if (sess->parent) {
lock_status = pj_lock_acquire(sess->parent->lock);
if (lock_status != PJ_SUCCESS) {
return NULL;
}
pauth = find_cached_auth(sess->parent, realm, algorithm_type);
lock_status = pj_lock_release(sess->parent->lock);
if (lock_status != PJ_SUCCESS) {
return NULL;
}
}
if (pauth != NULL) {
return pauth;
}

pjsip_cached_auth *auth = sess->cached_auth.next;
while (auth != &sess->cached_auth) {
if (pj_stricmp(&auth->realm, realm) == 0
Expand All @@ -734,6 +773,24 @@ static const pjsip_cred_info* auth_find_cred( const pjsip_auth_clt_sess *sess,

PJ_UNUSED_ARG(auth_scheme);

pj_status_t lock_status;
pj_bool_t with_parent = PJ_FALSE;
const pjsip_cred_info * ptr = NULL;
if (sess->parent) {
lock_status = pj_lock_acquire(sess->parent->lock);
if (lock_status != PJ_SUCCESS) {
return NULL;
}
ptr = auth_find_cred(sess->parent, realm, auth_scheme, algorithm_type);
lock_status = pj_lock_release(sess->parent->lock);
if (lock_status != PJ_SUCCESS) {
return NULL;
}
}
if (ptr != NULL) {
return ptr;
}

for (i=0; i<sess->cred_cnt; ++i) {
switch(sess->cred_info[i].data_type) {
case PJSIP_CRED_DATA_PLAIN_PASSWD:
Expand Down Expand Up @@ -795,7 +852,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_init( pjsip_auth_clt_sess *sess,
sess->cred_info = NULL;
pj_list_init(&sess->cached_auth);

return PJ_SUCCESS;
sess->parent = NULL;
return pj_lock_create_simple_mutex(pool, "auth_clt_lock", &sess->lock);
}


Expand All @@ -812,7 +870,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_deinit(pjsip_auth_clt_sess *sess)
auth = auth->next;
}

return PJ_SUCCESS;
sess->parent = NULL;
return pj_lock_destroy(sess->lock);
}


Expand Down Expand Up @@ -849,6 +908,27 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_clone( pj_pool_t *pool,
}
}

pj_status_t status, lock_status;
if (sess->parent) {
lock_status = pj_lock_acquire(sess->parent->lock);
if (lock_status != PJ_SUCCESS) {
return lock_status;
}
sess->parent = PJ_POOL_ZALLOC_T(pool, pjsip_auth_clt_sess);
if (sess->parent == NULL) {
status = PJ_ENOMEM;
} else {
status = pjsip_auth_clt_clone(pool, sess->parent, rhs->parent);
}
lock_status = pj_lock_release(sess->parent->lock);
if (lock_status != PJ_SUCCESS) {
return lock_status;
}
}
if (status != PJ_SUCCESS) {
return status;
}

/* TODO note:
* Cloning the full authentication client is quite a big task.
* We do only the necessary bits here, i.e. cloning the credentials.
Expand All @@ -868,6 +948,7 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *sess,
const pjsip_cred_info *c)
{
PJ_ASSERT_RETURN(sess && c, PJ_EINVAL);
DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_set_credentials(sess->parent, cred_cnt, c));

if (cred_cnt == 0) {
sess->cred_cnt = 0;
Expand Down Expand Up @@ -943,6 +1024,7 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_set_prefs(pjsip_auth_clt_sess *sess,
const pjsip_auth_clt_pref *p)
{
PJ_ASSERT_RETURN(sess && p, PJ_EINVAL);
DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_set_prefs(sess->parent, p));

pj_memcpy(&sess->pref, p, sizeof(*p));
pj_strdup(sess->pool, &sess->pref.algorithm, &p->algorithm);
Expand All @@ -960,7 +1042,7 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_get_prefs(pjsip_auth_clt_sess *sess,
pjsip_auth_clt_pref *p)
{
PJ_ASSERT_RETURN(sess && p, PJ_EINVAL);

DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_get_prefs(sess->parent, p));
pj_memcpy(p, &sess->pref, sizeof(pjsip_auth_clt_pref));
return PJ_SUCCESS;
}
Expand Down Expand Up @@ -1197,6 +1279,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess,
PJ_ASSERT_RETURN(tdata->msg->type==PJSIP_REQUEST_MSG,
PJSIP_ENOTREQUESTMSG);


DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_init_req(sess->parent, tdata));
/* Init list */
pj_list_init(&added);

Expand Down Expand Up @@ -1548,6 +1632,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req( pjsip_auth_clt_sess *sess,
rdata->msg_info.msg->line.status.code == 407,
PJSIP_EINVALIDSTATUS);

DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_reinit_req(sess->parent, rdata, old_request, new_request));

tdata = old_request;
tdata->auth_retry = PJ_FALSE;

Expand Down
16 changes: 16 additions & 0 deletions pjsip/src/pjsip/sip_dialog.c
Original file line number Diff line number Diff line change
Expand Up @@ -2493,3 +2493,19 @@ PJ_DEF(pj_status_t) pjsip_dlg_remove_remote_cap_hdr(pjsip_dialog *dlg,

return PJ_SUCCESS;
}

PJ_DEF(pj_status_t) pjsip_dlg_set_auth_sess( pjsip_dialog *dlg,
pjsip_auth_clt_sess *session ) {
PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
pj_status_t status = PJ_SUCCESS;
status = pj_lock_acquire(dlg->auth_sess.lock);
if (status != PJ_SUCCESS) {
return status;
}
dlg->auth_sess.parent = session;
status = pj_lock_release(dlg->auth_sess.lock);
if (status != PJ_SUCCESS) {
return status;
}
return PJ_SUCCESS;
}
8 changes: 8 additions & 0 deletions pjsip/src/pjsua-lib/pjsua_acc.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ static pj_status_t initialize_acc(unsigned acc_id)
} else {
sip_reg_uri = NULL;
}
pjsip_auth_clt_init( &acc->shared_auth_sess, pjsua_var.endpt, acc->pool, 0);

if (sip_reg_uri) {
acc->srv_port = sip_reg_uri->port;
Expand Down Expand Up @@ -1297,6 +1298,9 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
unreg_first = PJ_TRUE;
}

/* Shared authentication session */
acc->cfg.shared_auth = cfg->shared_auth;

/* Registration */
if (acc->cfg.reg_timeout != cfg->reg_timeout) {
acc->cfg.reg_timeout = cfg->reg_timeout;
Expand Down Expand Up @@ -2754,6 +2758,10 @@ static pj_status_t pjsua_regc_init(int acc_id)
pjsua_init_tpselector(acc_id, &tp_sel);
pjsip_regc_set_transport(acc->regc, &tp_sel);

if (acc->cfg.shared_auth) {
pjsip_regc_set_auth_sess(acc->regc, &acc->shared_auth_sess);
}

/* Set credentials
*/
if (acc->cred_cnt) {
Expand Down
4 changes: 4 additions & 0 deletions pjsip/src/pjsua-lib/pjsua_call.c
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,10 @@ PJ_DEF(pj_status_t) pjsua_call_make_call(pjsua_acc_id acc_id,

dlg_set_via(dlg, acc);

if (acc->cfg.shared_auth) {
pjsip_dlg_set_auth_sess(dlg, &acc->shared_auth_sess);
}

/* Calculate call's secure level */
call->secure_level = get_secure_level(acc_id, dest_uri);

Expand Down
1 change: 1 addition & 0 deletions pjsip/src/pjsua-lib/pjsua_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
PJSUA_CALL_UPDATE_CONTACT |
PJSUA_CALL_UPDATE_VIA;
cfg->enable_rtcp_xr = (PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR);
cfg->shared_auth = PJ_FALSE;
}

PJ_DEF(void) pjsua_buddy_config_default(pjsua_buddy_config *cfg)
Expand Down
4 changes: 4 additions & 0 deletions pjsip/src/pjsua-lib/pjsua_pres.c
Original file line number Diff line number Diff line change
Expand Up @@ -2127,6 +2127,10 @@ static void subscribe_buddy(pjsua_buddy_id buddy_id,
pjsip_dlg_set_route_set(buddy->dlg, &acc->route_set);
}

if (acc->cfg.shared_auth) {
pjsip_dlg_set_auth_sess(buddy->dlg, &acc->shared_auth_sess);
}

/* Set credentials */
if (acc->cred_cnt) {
pjsip_auth_clt_set_credentials( &buddy->dlg->auth_sess,
Expand Down
Loading