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. ASP.NET MVC搭建项目后台UI框架—4、tab多页签支持

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  2. SpringMVC Mybatis Shiro RestTemplate的实现客户端无状态验证及访问控制【转】

    A.首先需要搭建SpringMVC+Shiro环境 a1.pom.xml配置 spring: <dependency> <groupId>org.springframework ...

  3. highCharts提示框不显示的问题

    使用HighCharts插件进行数据展示的时候,鼠标放在数据处没有提示框,或者只有头尾2个提示框,其他提示框不显示,为什么会这样? 1.查看是否使用了tooltip属性,该属性的enabled默认为t ...

  4. CSS3D效果

    效果如本博客中右边呢个浅色框框,来自webpack首页(IE绕路0_0) github地址:http://wjf444128852.github.io/demo02/css3/css3d/ 思路: 1 ...

  5. js instanceof

    a instanceof b: 1,首先a不是对象,返回false,b的原型不是对象抛出TypeError 2,取得b的prototype标记为bp,对a的原型链做循环,令ap为当前原型,如果ap与b ...

  6. file_put_contents 错误:failed to open stream: Invalid argument 一种原因

    今天在测试nilcms系统的时候,出现了一个报错,导致缓存无法更新: file_put_contents(C:\UPUPW_AP5.4\vhosts\d.tv\NilCMS_APP\include_r ...

  7. css判断不同分辨率显示不同宽度布局实现自适应宽度

    一.CSS DIV网页布局中当分辨率小于等于1024px(像素)时,DIV布局对象显示1000px宽度,当分辨率大于1024px时候显示1200px宽度等需求.使用CSS实现改变浏览器显示宽度从而实现 ...

  8. ArcGIS 10.5新功能预览

    ArcGIS for Server产品线被重命名为ArcGIS Enterprise. 带来更多丰富的时空GIS功能. 分析地理大数据 捕捉和分析实时传感器数据 快速地理影像分析 ArcGIS Ent ...

  9. IOS开发基础知识--碎片47

    1:解决ios静态库中的类别(category)在工程中不能使用 解决方法为:找到 target 的图标,更改其 Other Linker Flags 为: -all_load 或 -force_lo ...

  10. MySQL错误日志总结

    MySQL错误日志是记录MySQL 运行过程中较为严重的警告和错误信息,以及MySQL每次启动和关闭的详细信息.错误日志的命名通常为hostname.err.其中,hostname表示服务器主机名. ...