TR069 Http Digest 认证流程

 

流程及流程图

1.1盒端主动发起Http Digest认证流程 

盒端CPE                                          ACS终端管理系统

1.------------------inform(http不带auth头)----------->

2.<------------------401(http不带auth头)--------------

3.------------------inform(http带auth头)------------->

4.<------------------200 OK---------------------------

5.------------------ Content-Length: 0--------------->

机顶盒(CPE)通过HTTP Digest Authentication发起与终端管理系统(ACS)的认证连接,连接方式遵循RFC 2617的规定。

机顶盒连接终端管理系统的地址由Device.ManagementServer.URL参数提供。

机顶盒主动想终端管理系统发起一个HTTP 连接请求,终端管理系统会要求进行HTTP Digest Authentication认证。并按照RFC2671规范,盒端和盒端管理系统在之后的请求和应答时信息均带有认证头信息。

认证中的用户名、密码为Device.ManagementServer.Username 及Device.ManagementServer.Password

1.2   ACS主动发起Http Digest认证流程

盒端CPE                                        ACS终端管理系统

1.<------------------http(不带auth头信息)-------------

2.------------------ 401 Unauthorized---------------->

3.<------------------http get(带auth头信息)-----------

4.------------------200 OK--------------------------->

5.<-----------------100 continue----------------------

6.------------------6 connect request---------------->

7.<------------------200 OK---------------------------

ACS终端管理系统主动发起一个HTTP 请求,CPE终端会要求进行HTTP Digest Authentication认证。并按照RFC2671规范,盒端和盒端管理系统在之后的请求和应答时信息均带有认证头信息。

认证中的用户名、密码为Device.ManagementServer.Connection.RequestUsername及Device.ManagementServer.ConnectionRequestPassword

 

二 详细交互流程:

2.1  盒端主动发起Http Digest认证报文 

 

CPE IP地址: 192.168.20.11

ACS IP地址: 192.168.20.36

1)盒端(CPE)首先发起不带认证头的Inform请求报文,内容如下:

POST /acs HTTP/1.1

Host: 192.168.20.36

Accept: */*

Connection: TE, Keep-Alive

Content-Type: text/xml; charset=utf-8

SOAPAction: ""

Content-Length: 3814

Expect: 100-continue

HTTP/1.1 100 Continue

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0">

<SOAP-ENV:Header>

<cwmp:ID SOAP-ENV:mustUnderstand="1">1</cwmp:ID>

</SOAP-ENV:Header>

<SOAP-ENV:Body>

<cwmp:Inform>

<DeviceId xsi:type="cwmp:DeviceIdStruct">

<Manufacturer>Test</Manufacturer>

<OUI>A1B2C4</OUI>

<ProductClass>Test_PC</ProductClass>

<SerialNumber>821281000054321</SerialNumber>

</DeviceId>

<Event SOAP-ENC:arrayType="cwmp:EventStruct[2]">

<EventStruct>

<EventCode>1 BOOT</EventCode>

<CommandKey></CommandKey>

</EventStruct>

<EventStruct>

……..

2) 盒端管理系统(ACS)收到上述报文后,发现没有认证消息(带有Authorization:标识的报文),然后发送401错误报文:

HTTP/1.1 401 Unauthorized

Date: Fri, 06 Jan 2017 02:47:12 GMT

Expires: Thu, 01 Jan 1970 00:00:00 GMT

Set-Cookie: JSESSIONID=12rxzt10p2rtb;Path=/

Content-Type: text/xml; charset=utf-8

WWW-Authenticate: Digest realm="XACS",qop="auth",nonce="fd171d5efcc65e79bfd8150af7f9cb21"

Content-Length: 0

Server: Jetty(6.1.20)

3 ) 盒端(cpe)收到报文后,经过分析得到报文错误为401,代码中通过分析报文中是否有WWW-Authenticate:  Digest 字段,如果具有那么通过设置函数

//设置鉴权参数

code=curl_easy_setopt(curl,CURLOPT_HTTPAUTH,CURLAUTH_BASIC|CURLAUTH_DIGEST);

(本地配置的realm必须与收到的realm一致否则验证不能通过)将本地文件配置的realm和从盒端管理系统(ACS)收到的nonce,opaque,qop等值通过函数http_da_calc_HA1,生成一个唯一的字符串并存入response字段,并将这些信息组合到报文的头部,最后发送给ACS的报文为:

POST /acs HTTP/1.1

Authorization: Digest username="cpe", realm="XACS", nonce="fd171d5efcc65e79bfd8150af7f9cb21", uri="/acs", cnonce="MDQ1NzA0", nc=00000001, qop="auth", response="5f6059675ea5da97e45be615c2466ff7"

Host: 192.168.20.36

Accept: */*

Cookie: JSESSIONID=12rxzt10p2rtb

Connection: TE, Keep-Alive

Content-Type: text/xml; charset=utf-8

SOAPAction: ""

Content-Length: 3814

Expect: 100-continue

HTTP/1.1 100 Continue

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0">

<SOAP-ENV:Header>

<cwmp:ID SOAP-ENV:mustUnderstand="1">1</cwmp:ID>

</SOAP-ENV:Header>

<SOAP-ENV:Body>

<cwmp:Inform>

<DeviceId xsi:type="cwmp:DeviceIdStruct">

<Manufacturer>Test</Manufacturer>

<OUI>A1B2C4</OUI>

<ProductClass>Test_PC</ProductClass>

<SerialNumber>821281000054321</SerialNumber>

</DeviceId>

<Event SOAP-ENC:arrayType="cwmp:EventStruct[2]">

<EventStruct>

<EventCode>1 BOOT</EventCode>

<CommandKey></CommandKey>

</EventStruct>……….

…….

4)盒端管理系统(ACS)收到上述报文后,确认其含Authorization:字段,并且Authorization:字段中的response的值正确,那么认证通过,并发送回复报文:

HTTP/1.1 200 OK

Date: Fri, 06 Jan 2017 02:47:12 GMT

Content-Type: text/xml; charset=utf-8

Content-Length: 526

Server: Jetty(6.1.20)

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><SOAP-ENV:Header><cwmp:ID SOAP-ENV:mustUnderstand="1">1</cwmp:ID><cwmp:NoMoreRequests>0</cwmp:NoMoreRequests></SOAP-ENV:Header><SOAP-ENV:Body><cwmp:InformResponse><MaxEnvelopes>1</MaxEnvelopes></cwmp:InformResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

5)  盒端(CPE)收到回复报文后,分析为认证通过报文后,发送一个inform内容为空的确认报文:——其实就是个空报文

POST /acs HTTP/1.1

Authorization: Digest username="cpe", realm="XACS", nonce="fd171d5efcc65e79bfd8150af7f9cb21", uri="/acs", cnonce="MDQ1NzA0", nc=00000002, qop="auth", response="1b58ed5321c916998e4af9de375177fc"

Host: 192.168.20.36

Accept: */*

Cookie: JSESSIONID=12rxzt10p2rtb

Connection: TE, Keep-Alive

Content-Length: 0

Content-Type: application/x-www-form-urlencoded

2.2   ACS主动发起Http Digest认证报文

略,和2.1流程类似,具体可以下载报文,自行分析。

2.3   同时开启双向认证 

即CPE终端认证ACS管理系统,和ACS管理系统认证CPE终端同时认证。成功后盒端和盒端管理系统在之后的请求和应答时信息均带有认证头信息,认证中的用户名、密码为Device.ManagementServer.Username 及Device.ManagementServer.Password

报文下载路径:

http://download.csdn.net/detail/eryunyong/9730525

代码片段:

1) CPE 认证ACS管理系统的代码

//初始化curl库,设置参数用于http 传输

 int http_init_curl(cwmp_context_t *cwmp_ctx, t_MemStruct *pmem, CURL **pcurl)

 {

     CURLcode    code;

     CURL          *curl = NULL;

     char           *acs_usr = NULL;

     char           *acs_passwd = NULL;

     char           error_buf[CURL_ERROR_SIZE];

     CURLcode   ret = FALSE;

     if(!cwmp_ctx || !pmem || !pcurl)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "some param is NULL\n");

         return FALSE;

     }

     curl = curl_easy_init();

     if (!curl)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "curl_easy_init fail\n");

         return FALSE;

     }

     memset(error_buf, , sizeof(error_buf));

     code = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buf);

     if (code != CURLE_OK)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set error buffer [%d]\n", code);

         return FALSE;

     }

     //设置回写函数

     code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cwmp_write_func_callback);

     if (code != CURLE_OK)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set writer [%s]\n", curl_easy_strerror(code));

         goto finish;

     }

     code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)pmem);

     if (code != CURLE_OK)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set write data [%s]\n", curl_easy_strerror(code));

         goto finish;

     }

     code = curl_easy_setopt(curl, CURLOPT_COOKIEFILE,  "");

     if (code != CURLE_OK)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set cookie file [%s]\n", curl_easy_strerror(code));

         goto finish;

     }

     //设置鉴权参数

     code = curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST);

     if (code != CURLE_OK)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set http auth [%s]\n", curl_easy_strerror(code));

         goto finish;

     }

     get_param_value_by_fullname(IGD_ManagementServer_Username, &acs_usr);

     get_param_value_by_fullname(IGD_ManagementServer_Password, &acs_passwd);

     if (acs_usr && acs_passwd)

     {

         //curl_easy_setopt(curl, CURLOPT_USERNAME, acs_usr);

         //curl_easy_setopt(curl, CURLOPT_PASSWORD, acs_passwd);

         code = curl_easy_setopt(curl, CURLOPT_USERNAME, acs_usr);

         if (code != CURLE_OK)

         {

             CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set username [%s]\n", curl_easy_strerror(code));

             goto finish;

         }

         code = curl_easy_setopt(curl, CURLOPT_PASSWORD, acs_passwd);

         if (code != CURLE_OK)

         {

             CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set password [%s]\n", curl_easy_strerror(code));

             goto finish;

         }

         CWMP_LOG_DEBUG(EVENT_MODULE, "acs usrname=%s, passwd=%s\n", acs_usr, acs_passwd);

     }

     else

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "get acs usrname or passwd fail\n");

         goto finish;

     }

     code = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, );

     if (code != CURLE_OK)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set follow location [%s]\n", curl_easy_strerror(code));

         goto finish;

     }

     code = curl_easy_setopt(curl, CURLOPT_MAXREDIRS, );

     if (code != CURLE_OK)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set max redirs [%s]\n", curl_easy_strerror(code));

         goto finish;

     }

     code = curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);

     if (code != CURLE_OK)

     {

         CWMP_LOG_ERROR(EVENT_MODULE, "Failed to set POSTREDIR [%s]\n", curl_easy_strerror(code));

         goto finish;

     }

     // http timeout 30 seconds

     curl_easy_setopt(curl, CURLOPT_TIMEOUT, );   

     // not support SSL

     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, );

     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, );

     (*pcurl) = curl;

     ret = TRUE;

 finish:

     if(ret == FALSE)

     {

         if(curl)

         {

             curl_easy_cleanup(curl);

         }

     }

     if (acs_usr)

     {

         free_check(acs_usr);

     }

     if (acs_passwd)

     {

         free_check(acs_passwd);

     }

     return ret;

 }

2) CPE处理来自ACS的socket连接报文

 //处理socket连接

 static void *handle_sock(void *data)

 {

     Http_request    *request = NULL;

     int             sock = (int)(long)data;

     int             len = ;

     const char      *auth_str = NULL;

     int             auth = ;   //是否需要校验

     int             status = ;

     char            *usrname = NULL;

     char            *passwd = NULL;

     char            resp[MAX_BUF_LEN+] = {};

     char            auth_opaque[] = {};

     CWMP_LOG_ERROR(ACS_CONN_MODULE, "handle_sock begin, sock=%d\n", sock);

     len = http_parse_request(sock, &request);

     if(len == )

     {

         CWMP_LOG_ERROR(ACS_CONN_MODULE, "socket:%d is closed\n", sock);

         return NULL;

     }

     if(len < )

     {

         CWMP_LOG_INFO(ACS_CONN_MODULE, "read data finish\n");

         goto finish;

     }

     if(!request)

     {

         CWMP_LOG_ERROR(ACS_CONN_MODULE, "http_parse_request fail\n");

         goto finish;

     }

     //判断是否需要验证

     if(g_pcwmp_ctx->dev_info.func_get_auth)

     {

         auth = g_pcwmp_ctx->dev_info.func_get_auth();

     }

     CWMP_LOG_ERROR(ACS_CONN_MODULE, "auth=%d\n", auth);

     if(auth <= )   //不需要校验

     {

         status = ;

         goto response;

     }

     auth_str = http_header_get(request->header, "Authorization");

     if(!auth_str)

     {

         status = ;

         CWMP_LOG_ERROR(ACS_CONN_MODULE, "have not Authorization\n");

         goto response;

     }

     //校验

     get_param_value_by_fullname(IGD_ManagementServer_ConnectionRequestUsername, &usrname);

     get_param_value_by_fullname(IGD_ManagementServer_ConnectionRequestPassword, &passwd);

     if(!usrname || !passwd)

     {

         status = ;

     }

     if (check_digest_auth(auth_str, usrname, passwd) == FALSE)

     {

         status = ;       

     }

     else

     {

         status = ;

         CWMP_LOG_INFO(ACS_CONN_MODULE, "auth pass\n");

     }

 response:

     if(status == )

     {

         strcpy(resp, RESPONSE_200);

     }

     else if(status == )

     {

         strcpy(resp, RESPONSE_400);

     }

     else if(status == )

     {

         char buffer[] = {};

         char nonce[];

         g_auth_nonce++;

         snprintf(buffer, ,  "%d", g_auth_nonce);

         MD5(nonce, buffer, NULL);

         nonce[] = ;

         MD5(auth_opaque, g_auth_realm, NULL);

         snprintf(resp, MAX_BUF_LEN+, RESPONSE_401, g_auth_realm, "auth", nonce, auth_opaque);

     }

     //发送回应

     if(status != )

     {

         write_all(sock, resp, strlen(resp));

         CWMP_LOG_DEBUG(ACS_CONN_MODULE, "response to acs ok, status=%d\n", status);

     }

 finish:

     close(sock);

     if(request)

     {

         http_destroy_request(request);

     }

     if(usrname)

     {

         free_check(usrname);

     }

     if(passwd)

     {

         free_check(passwd);

     }

     if(status == )

     {

         //6 Connected Request加入事件队列      

         increase_event_set(EVENT_CONNECTIONREQUEST, );

         sem_post(&g_pcwmp_ctx->sem_send_acs);

     }

     CWMP_LOG_DEBUG(ACS_CONN_MODULE, "handle_sock end\n");

     return NULL;

 }

总结

TR069 协议采用SSL/TLS、HTTP basic或者HTTP digest等加密认证方式可以保证数据的安全性;采用较多Web中成熟的技术,实现简单,降低了开发难度;采用HTTP协议,可以有效地穿越复杂的网络环境。因此,TR069协议比较适合对广域网内的设备进行管理。

参考

1)

http://wenku.baidu.com/link?url=w0eT-wBfONNGajF3mVOUL_KUOvZAwXnIBw7B6mBj48ySO7vXE6M7xtOo48-NEn60Dpy1pST1ATqWGleyMdLIRogQryLB72n9PJZAd5znfS3

2)TR069规范

CWMP开源代码研究4——认证流程的更多相关文章

  1. CWMP开源代码研究——git代码工程

    原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:40879506@qq.com 声明:本系列涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅 ...

  2. CWMP开源代码研究5——CWMP程序设计思想

    声明:本文涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅号:408797506) 本文介绍自己用过的ACS,其中包括开源版(提供下载包)和商业版(仅提供安装包下载 ...

  3. CWMP开源代码研究1——开篇之作

    原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:40879506@qq.com 声明:本系列涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅 ...

  4. CWMP开源代码研究2——easycwmp安装和学习

    声明:本文是对开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅号:408797506) 本文所有笔记和代码可以到csdn下载:http://download.csdn.n ...

  5. CWMP开源代码研究3——ACS介绍

    声明:本文涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅号:408797506) 本文介绍自己用过的ACS,其中包括开源版(提供下载包)和商业版(仅提供安装包下载 ...

  6. CWMP开源代码研究——cwmp移植

    原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:40879506@qq.com 声明:本系列涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅 ...

  7. CWMP开源代码研究6——libcwmp动态库开发

    原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:40879506@qq.com 为了使程序具有通用性,便于扩展和维护.采用了"模块"插入的思想.将设备业务相 ...

  8. CWMP开源代码研究7——cwmp移植

    原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:40879506@qq.com 声明:本系列涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅 ...

  9. CWMP开源代码研究——stun的NAT穿透

    原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:40879506@qq.com 参考: http://www.cnblogs.com/myblesh/p/6259765.htm ...

随机推荐

  1. 从零开始学 Java - Windows 下安装 Eclipse

    三观是什么鬼 当我们在讨论「三观一致」的时候是在讨论些什么? 我认为这个世界上本没有「三观」这一说法,说的人多了,也就有了「三观」这个词,当我们讨论「三观一致」其实并不是真的在说世界观.价值观.人生观 ...

  2. java泛型详解

    http://www.cnblogs.com/lwbqqyumidi/p/3837629.html

  3. js中this的绑定

    人们对于this的绑定常常有两个误解,一:指向函数本身,二:指向函数作用域.这两种想法都是错的,this并不指向函数本身,也不指向函数作用域. function foo(){ this.count++ ...

  4. angular源码分析:angular中入境检察官$sce

    一.ng-bing-html指令问题 需求:我需要将一个变量$scope.x = '<a href="http://www.cnblogs.com/web2-developer/&qu ...

  5. String类型的属性和方法

    × 目录 [1]属性 [2]对象通用方法 [3]访问字符方法[4]字符串拼接[5]创建子串方法[6]大小写转换[7]查找子串位置[8]正则匹配方法[9]去除首尾空格[10]字符串比较 前面的话 前面已 ...

  6. MyEclipse快捷键大全

    MyEclipse 快捷键1(CTRL)Ctrl+1 快速修复Ctrl+D: 删除当前行Ctrl+Q 定位到最后编辑的地方Ctrl+L 定位在某行Ctrl+O 快速显示 OutLineCtrl+T 快 ...

  7. sharepoint powershell 批量处理匿名访问

    配置Web Application启用匿名访问 Add-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyCont ...

  8. SQLite浅析

    对于iOS工程师有一道常考的面试题,即iOS数据存储的方式 标答如下: Plist(NSArray\NSDictionary) Preference (偏好设置\NSUserDefaults) NSC ...

  9. 使用VS2015开发跨平台APP

      VS2013开始就可以基于HTML5开发WEBAPP,并借助xamarin或者PHONEGAP实现原生APP 不过升级麻烦,直接下载VS2015CTP6,最好安装在同一个分区上,ANDROID S ...

  10. JVM-Class文件

    一个 Class 文件描述了类或接口的字段,方法,父类,访问权限等全部信息.其实,它只是一种能被 JVM 识别的数据格式,就和 UDP 8字节头部一样,这就是规范,标准!所谓"不闻不若闻之, ...