Chapter 9:Authentication Framework
PJSIP提供客戶端和服務器的認證框架。認證框架支持缺省的http摘要認證,但是其他的認證方案也可以加到框架中。
下面的圖表描述了框架的類圖。
9.1 Client Authentication Framework
客戶端身份驗證框架管理客戶端到所下游服務器的身份驗證過程。它能以正確的憑證來響應服務器的認證(當有這種憑證提供),緩存認證信息,並且使用緩存的認證信息來初始化之後的請求。
9.1.1 Client Authentication Framework Reference
認證的API在頭文件 <pjsip/sip_auth.h>中聲明。下面是認證的數據結構和函數的文檔引用。
pjsip_cred_info
這個結構描述了特定範圍內的認證。一個客戶端在一個對話或者註冊期間有多個認證。每一種憑證都包含針對下游代理或服務器的認證信息。
比如,客戶端需要一個憑證來驗證的外發代理服務器,或者其他的憑證來驗證端服務器。
pjsip_cached_auth這個結構體保存特定服務器的最終鑑權。這個是必須的因爲這樣客戶端可以用最後的鑑權來初始化下一次的請求。
pjsip_auth_clt_sess這個結構體描述了客戶端認證會話。客戶端在對話或者註冊期間通常會保存這個結構體。
Function Reference
pj_status_t pjsip_auth_clt_init( pjsip_auth_clt_sess *sess,
pj_pool_t *pool, unsigned options);
初始化認證會話的數據結構,並設置會話使用pool來進行後續的內存分配。參數選項這個版本可以設置爲0。
pj_status_t pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *s,
int cred_cnt,
const pjsip_cred_info cred[]);
設置會話期間的憑證。使用客戶端的認證池來賦值指定的憑證。
pj_status_t pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess,
pjsip_tx_data *tdata );
這個函數根據會話緩存的信息爲新的發送請求tdata增加所有的認證頭。這個請求消息的請求行在調用這個函數前必須是有效的。
pj_status_t pjsip_auth_clt_reinit_req( pjsip_auth_clt_session *sess,
pjsip_endpoint *endpt,
const pjsip_rx_data *rdata,
pjsip_tx_data *old_request,
pjsip_tx_data **new_request )
調用這個函數在收到失敗的認證狀態(401.407)後重新初始化請求。這個函數根據 old_request重新創建 new_request,根據rdata響應中的鑑權添加合適的認證和代理認證頭。除此之外,這個函數還會在會話中添加相關信息。
如果鑑權缺少證書,這個函數會返回失敗。注意這個函數可以重用舊的請求而不是再創建一個新的。
9.1.2 Examples
Client Transaction Authentication
下面的例子說明了如何用認證信息初始化發出的請求以及處理來自服務器的鑑權。爲了簡單說明,例子裏沒有展示錯誤處理。一個好的應用程序應該有準備處理任何情形下的錯誤的能力。
pjsip_auth_client_session auth_sess;
// Initialize client authentication session with some credentials.
void init_auth(pj_pool_t *session_pool)
{
pjsip_cred_info cred;
pj_status_t status;
cred.realm = pj_str(“sip.example.com”);
cred.scheme = pj_str(“digest”);
cred.username = pj_str(“alice”);
cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
cred.data = pj_str(“secretpassword”);
Page 64
PJSIP Developer’s Guide
status = pjsip_auth_client_init( &auth_sess, session_pool, 0);
status = pjsip_auth_set_credentials( &auth_sess, 1, &cred );
}
// Initialize outgoing request with authorization information and
// send the request statefully.
void send_request(pjsip_tx_data *tdata)
{
pj_status_t status;
status = pjsip_auth_client_init_req( &auth_sess, tdata );
status = pjsip_endpt_send_request( endpt, tdata, -1, NULL, &on_complete);
}
// Callback when the transaction completes.
static void on_complete( void *token, pjsip_event *event )
{
int code;
pj_assert(event->type == PJSIP_EVENT_TSX_STATE);
code = event->body.tsx_state.tsx->status_code;
if (code == 401 || code == 407) {
pj_status_t status;
pjsip_tx_data *new_request;
status = pjsip_auth_client_reinit_req( &auth_sess, endpt,
event->body.tsx_state.src.rdata,
tsx->last_tx,
&new_request);
if (status == PJ_SUCCESS)
status = pjsip_endpt_send_request( endpt, new_request, -1, NULL,
&on_complete);
else
PJ_LOG(3,(“app”,”Authentication failed!!!”));
}
}
9.2 Server Authorization Framework
服務器認證框架提供了兩種服務器認證機制:
#無會話服務器認證爲認證的客戶端提供了通用API。 這個API在每個請求的基礎上提供了全局的服務器認證,通常用於代理認證服務器當它調用不是有狀態時。
#服務器認證會話,提供了特定對話或者註冊會話中的全局服務器認證機制。需要爲服務器的對話或者註冊會話建立服務器認證會話的實例。一個服務器認證會話要有一個初始設置的憑證,這個憑證在對話/註冊會話期間一直被客戶端使用。
9.2.1 Server Authorization Reference
Data Types Reference
typedef pj_status_t pjsip_auth_lookup_cred( pj_pool_t *pool,
const pj_str_t *realm,
const pj_str_t *acc_name,
pjsip_cred_info *cred_info );
在指定的realm中查找acc_name的憑證信息的要註冊到認證服務器的類型。當成功查找到憑證信息,函數用憑證填充cred_info並返回PJ_SUCCESS。否則就返回以下的 錯誤碼:
# PJSIP_EAUTHACCNOTFOUND :在指定的realm中未找到賬號
# PJSIP_EAUTHACCDISABLED:賬號找到了但是不可用
Functions Reference
pj_status_t pjsip_auth_srv_init( pj_pool_t *pool,
pjsip_auth_srv *auth_srv,
const pj_str_t *realm,
pjsip_auth_lookup_cred *lookup_func,
unsigned options );
初始化服務器認證會話數據結構以服務於指定的realm,並使用lookup_func函數查找憑證信息options參數是下面值的位掩碼組合:
# PJSIP_AUTH_SRV_IS_PROXY:指明服務器認證客戶端爲一個代理服務器(而不是作爲UAS),也就是說使用 Proxy-Authenticate代替 WWW-Authenticate。
pj_status_t pjsip_auth_srv_verify( pjsip_auth_srv *auth_srv,
pjsip_rx_data *rdata,
int *status_code );
請求認證服務區驗證rdata請求中的認證信息。如果status_code不是NULL,將適當的填充響應狀態(401/407等)。
如果請求中的認證信息可被接受,函數將返回PJ_SUCCESS,或者當認證失敗的時候,返回下面的錯誤:
# PJSIP_EAUTHNOAUTH:請求中未指明認證頭
# PJSIP_EINVALIDAUTHSCHEME:無效或不支持的認證方案(當前只支持摘要)
# PJSIP_EAUTHACCNOTFOUND or PJSIP_EAUTHACCDISABLED:查找函數返回的錯誤碼
# PJSIP_EAUTHINVALIDDIGEST:無效的摘要
#其他表示系統錯誤的非零值
pj_status_t pjsip_auth_srv_challenge( pjsip_auth_srv *auth_srv,
const pj_str_t *qop,
const pj_str_t *nonce,
const pj_str_t *opaque,
pj_bool_t stale,
pjsip_tx_data *tdata);
在發出的響應tdata中增加認證質詢頭。如果指定了qop,將該值放到質詢中,應用也可以指定nonce和qpaque,或者可以讓這些值爲NULL,以隨機字母填充。
9.3 Extending Authentication Framework
認證框架可以擴充來支持非http摘要的認證框架 (PGP)
TODO。