关于sasl
2014-08-14 00:00
85 查看
摘要: gsasl 使用demo
sasl(Simple Authentication and Security Layer)是一个用于网络通信协议的安全验证框架,它可以使网络协议在互相验证的阶段可以有多种验证方式可以选择。
现在实现sasl的协议主要有imap,smtp,pop,xmpp,subersion,….。举个smtp的例子说明一下sasl的验证流程:
1 和smtp sever建立连接后,server发送欢迎信息
2 server发送自己支持的验证方式DIGEST-MD5 CRAM-MD5 LOGIN PLAIN
3 client择使用LOGIN
4 server发送base64后的challenge code,base64解码后为Username:要求client回应一个用户名
5 client回应base64后的用户名
6 server发送base64后的challenge code,base64解码后为Password:要求client回应一个密码
7 client回应base64后的密码
8 server返回验证成功的信息
很简单的流程,服务端给出选择,客户端选一个,然后根据验证方式不同进行验证流程,由于sasl仅仅是个框架,具体怎么实现是由协议决定的,比如xmpp协议的sasl验证流程
当你实现一个协议的sasl部分时,如果你仅仅打算实现一两种验证方式,那么寥寥代码便可以搞定,但是如果希望提供尽可能多的验证方式,那么使用一些开源类库将是最好的选择。
对于C语言有两个成熟的lib:Cyrus SASL和libgsasl。以gsasl为例:
gsasl屏蔽了具体验证的细节,你要做的仅仅是为验证流程提供必要的信息,比如:用户名,密码,验证域等等
还是以上面的smtp验证为例,假设我们是client端,现在收到的server的mechlist,即验证方式列表,我们使用gsasl实现这次验证(虽然是我虚构的代码,但理论是可行的:)):
使用gsasl可以让我们用类似上面代码处理所有的验证方式,唯一不同的就在于使用gsasl_property_set设置不同的字段。
除了像上面一样直接设置验证字段,还可以通过回调函数设置,当gsasl需要某一字段时会触发回调函数
好了,不能够再详细了,我的主要目的是分析jabberd2的验证逻辑,关于gsasl的更多请参考:http://www.gnu.org/software/gsasl/manual/gsasl.html
其他参考:http://wiki.jabbercn.org/index.php?title=RFC3920&variant=zh-c
sasl(Simple Authentication and Security Layer)是一个用于网络通信协议的安全验证框架,它可以使网络协议在互相验证的阶段可以有多种验证方式可以选择。
现在实现sasl的协议主要有imap,smtp,pop,xmpp,subersion,….。举个smtp的例子说明一下sasl的验证流程:
1 2 3 4 5 6 7 8 | 250-mail.example.com Hello pc.example.org [192.168.1.42], pleased to meet you 250-AUTH DIGEST-MD5 CRAM-MD5 LOGIN PLAIN AUTH LOGIN 334 VXNlcm5hbWU6 eHh4eAo= 334 UGFzc3dvcmQ6 b294eAo= 235 2.0.0 OK Authenticated |
2 server发送自己支持的验证方式DIGEST-MD5 CRAM-MD5 LOGIN PLAIN
3 client择使用LOGIN
4 server发送base64后的challenge code,base64解码后为Username:要求client回应一个用户名
5 client回应base64后的用户名
6 server发送base64后的challenge code,base64解码后为Password:要求client回应一个密码
7 client回应base64后的密码
8 server返回验证成功的信息
很简单的流程,服务端给出选择,客户端选一个,然后根据验证方式不同进行验证流程,由于sasl仅仅是个框架,具体怎么实现是由协议决定的,比如xmpp协议的sasl验证流程
#client与server建立链接后发出一个strem头 C:<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'> #server回应一个steam头 S:<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'> #server发送自己支持的验证方式列表 S:<stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features> #client 说它要用DIGEST-MD5做验证 C: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/> #server 发送challenge code S:<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg== </challenge> #client 回应challenge C: <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo YXJzZXQ9dXRmLTgK </response> #server 回应验证结果 S: <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/> |
对于C语言有两个成熟的lib:Cyrus SASL和libgsasl。以gsasl为例:
gsasl屏蔽了具体验证的细节,你要做的仅仅是为验证流程提供必要的信息,比如:用户名,密码,验证域等等
还是以上面的smtp验证为例,假设我们是client端,现在收到的server的mechlist,即验证方式列表,我们使用gsasl实现这次验证(虽然是我虚构的代码,但理论是可行的:)):
Gsasl *ctx = NULL; char buffer[BUFSIZ] = ""; char *buf; Gsasl_session *session; int rc; char *p; //使用gsasl之前初始化 if ((rc = gsasl_init (&ctx)) != GSASL_OK) { printf ("Cannot initialize libgsasl (%d): %s", rc, gsasl_strerror (rc)); return; } //创建一个使用LOGIN验证方式的客户端session if ((rc = gsasl_client_start (ctx, "LOGIN", &session)) != GSASL_OK) { printf ("Cannot initialize client (%d): %s\n", rc, gsasl_strerror (rc)); return; } //设置用户名和密码 gsasl_property_set (session, GSASL_AUTHID, "username"); gsasl_property_set (session, GSASL_PASSWORD, "password"); //假设socket_fd为我们与server已经建立连接的描述字 //告诉server我们选择使用LOGIN做验证 buf = buffer; sprintf(buf, "AUTH LOGIN\r\n"); write(socket_fd, buf, strlen(buf)); do { buf = buffer; //从server读取一行, readline(buf, sizeof (buf) - 1, socket_fd); //334 是多余的 buf += 4; //将challenge code 交给gsasl处理 rc = gsasl_step64 (session, buf, &p); if (rc == GSASL_NEEDS_MORE || rc == GSASL_OK) { //将gsasl的处理结果发送给server write(socket_fd, p, strlen(p)); free (p); } } while (rc == GSASL_NEEDS_MORE); if (rc != GSASL_OK) { printf ("Authentication error (%d): %s\n", rc, gsasl_strerror (rc)); return; } printf("success!"); gsasl_finish (session); gsasl_done (ctx); |
除了像上面一样直接设置验证字段,还可以通过回调函数设置,当gsasl需要某一字段时会触发回调函数
int callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop) { char buf[BUFSIZ] = ""; int rc = GSASL_NO_CALLBACK; switch (prop) { case GSASL_AUTHID: gsasl_property_set (sctx, GSASL_AUTHID, "username"); rc = GSASL_OK; break; // .............. default: printf ("Unknown property! Don't worry.\n"); break; } return rc; } //................. gsasl_callback_set (ctx, callback); |
其他参考:http://wiki.jabbercn.org/index.php?title=RFC3920&variant=zh-c
相关文章推荐
- 关于SASL的介绍文档
- 关于SASL的介绍文档
- 关于java 的 Classpath全解
- 关于Windows中ActiveX控件注册
- 关于在linux下磁盘定额的实现
- 关于fvwm2的简单配置
- 关于制作 Linux 自启动光盘
- WIN32汇编: 5.学习更多的关于文本的知识
- 关于用VC,VB进行图像数据(二进制大对象)存储数据库的一点心得
- 关于Out Of Memory 的绝版回答
- 关于WEB应用程序的打印组件开发初探
- 关于Visual Basic 6.0类开发(一)
- 关于Delphi中预编译指令的使用方法
- 关于applet写入文件的处理
- 关于窗口的操作详谈
- 关于异常的使用心得
- J2EE与.NET平台关于电子企业的两种设想(1)
- 关于错误信息的显示
- 一个关于#include的问题