Openfire 中SASL的认证方式之:PLAIN,DIGEST-MD5,anonymous

SASL  的认证方式包括:
    1. PLAIN: plain是最简单的机制,但同时也是最危险的机制,因为身份证书(登录名称与密码)是以base64字符串格式通过网络,没有任何加密保护措施。因此,使用plain机制时,你可能会想要结合tls。
     
     2.DIGEST-MD5:使用这种机制时,client与server共享同一个隐性密码,而且此密码不通过网络传输。验证过程是从服务器先提出challenge(质询)开始, 客户端使用此challenge与隐性密码计算出一个response(应答)。不同的challenge,不可能计算出相同的response;任何拥 有secret password的一方,都可以用相同的challenge算出相同的response。因此,服务器只要比较客户端返回的response是否与自己算 出的response相同,就可以知道客户端所拥有的密码是否正确。由于真正的密码并没有通过网络,所以不怕网络监测。
      3.   anonymous:   anonymous机制对smtp没有意义,因为smtp验证的用意在于限制转发服务的使用对象,而不是为了形成open relay,sasl之所以提供这种机制,主要是为了支持其他协议。
     

     PLAIN 方式的认证流程:
         由于是在SASL的认证方式,所以客户端必须要打开SASL认证的模式。
           config.setSecurityMode(SecurityMode. enabled );

    config.setSASLAuthenticationEnabled(  true );

  并且在客户端要声明,客户端必须支持PLAIN模式:
   
     SASLAuthentication.supportSASLMechanism( "PLAIN" );

   这样再客户端接下的来的认证过程中就会传输:
     <auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">c3lzYWRtaW4Ac3lzYWRtaW4AMTIz</auth> 数据包,接下来服务器端就会对这个数据包进贤处理。

   我的服务器端是结合中Openfire进行开发的,当数据包到达时,服务器端会进行如下处理:
    if  ( "auth"  .equals(tag)) {
                // User is trying to authenticate using SASL
                startedSASL  =  true ;
                // Process authentication stanza
                saslStatus  = SASLAuthentication.handle( session , doc);

  在服务器端接下来的处理过程中,就是通过SaslServer 来进行客户端用户名和密码的认证。SaslServer进行java.sercurity 中的类。
  

        SaslServer ss = Sasl. createSaslServer (mechanism,
                                        "xmpp" , session.getServerName(), props,
                                        new  XMPPCallbackHandler());

   这里主要使用SaslServer 创建SASL服务器端。
    制创建一个  SaslServer 。 此方法使用  JCA Security Provider Framework (在 "Java Cryptography Architecture API Specification & Reference" 中所有描述)来查找和选择  SaslServer  实现。 首先,它从 "SaslServerFactory" 服务的已注册安全提供者和指定的 SASL 机制中获得  SaslServerFactory  实例的有序列表。然后它在列表中的每个工厂实例上调用  createSaslServer() ,直到某个调用生成一个非 null 的  SaslServer  实例为止。此方法返回非 null 的  SaslServer  实例,如果搜索无法生成非 null 的 SaslServer  实例,则返回 null。

   在这里在Openfire中的:org.jivesoftware.openfire.sasl 中的SaslServerFactoryImpl 类实现了,javax.security.sasl.SaslServerFactory,这样在创建SaslServer的时候,就会调用这个具体的实现来进行创建。
     在这里在 SASLAuthentication 的初始化过程中,在initMechanisms 方法中,就初始化了 SaslServerFactory 的类的路径。
  在程序运行过程中,就会根据客户端发送的PLAIN 模式,创建SaslServer,并进行处理。
  在 SaslServerPlainImpl 类中,可以获得客户端发送过来的用户名和密码,这里都是明文进行了传输,可以获得客户端发送的数据。这样   在 XMPPCallbackHandler 中就可以获得客户端发送的用户名和密码,然后接下来就是对用户的用户名和密码进行认证。


  
DIGEST-MD5 :
    当服务器端支持   DIGEST-MD5 时,如果客户端不明确声明支持的认证方式,默认会使用  DIGEST-MD5 来进行客户端的认证。
    在认证过程中客户端发送: <auth mechanism="DIGEST-MD5" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></auth>
  服务器端,接收到消息后进行处理:
     if  ( mechanisms  .contains(mechanism)) {
                          // 被选的SASL的机制,需要服务器发送一个 challenge

                        System.  out .println(  "password------------call---back----"
                                  + mechanism);
                          try  {
                             Map<String, String> props =  new  TreeMap<String, String>();
                             props.put(Sasl.  QOP ,  "auth" );
                               if  (mechanism.equals( "GSSAPI"  )) {
                                  props.put(Sasl.  SERVER_AUTH ,  "TRUE" );
                             }
                             SaslServer ss = Sasl.createSaslServer(mechanism,
                                        "xmpp" , session.getServerName(), props,
                                        new  XMPPCallbackHandler());
                               // evaluateResponse doesn't like null parameter
                               byte [] token =  new  byte [0];
                               if  (doc.getText().length() > 0) {
                                    // If auth request includes a value then validate it
                                  token = StringUtils.decodeBase64(doc.getText()
                                           .trim());
                                    if  (token ==  null ) {
                                      token =  new  byte [0];
                                  }
                             }
                               if  (mechanism.equals( "DIGEST-MD5"  )) {
                                    // RFC2831 (DIGEST-MD5) says the client MAY provide
                                    // an initial response on subsequent
                                    // authentication. Java SASL does not (currently)
                                    // support this and thows an exception
                                    // if we try. This violates the RFC, so we just
                                    // strip any initial token.
                                  token =  new  byte [0];
                             }
                               byte [] challenge = ss.evaluateResponse(token);
                               if  (ss.isComplete()) {
                                  System.  out .println(  "ss------------------has---complete--------"  );
                                   authenticationSuccessful(session,
                                           ss.getAuthorizationID(), challenge);
                                  status = Status. authenticated ;
                             }  else  {
                                  System.  out .println(  "ss----------not--------has---complete--------"  );
                                    // Send the challenge
                                   sendChallenge(session, challenge);
                                  status = Status. needResponse ;
                             }
                             session.setSessionData(  "SaslServer" , ss);
 在这里服务器端接收客户端发送的数据信息,并且创建 SaslServer ,在创建  SaslServer server的时候,会在  java.security.Provider 中查询,服务器端设置的进行对认证方式实例化的类, ,在这里继承的 java.security.Provider 的类中,没有定义对   DIGEST-MD5 的具体实现,就采用系统默认的方式来实例化 SaslServer。接下来的过程就是服务器端向客户端发送 challenge 数据包,
      <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cmVhbG09InNtYXJ0Y29vbCIsbm9uY2U9Ind2aGNoTTFsS0dudXY0dFpOUDZxWlp3dG5WUENkTHRDUDdBNkVLcWoiLHFvcD0iYXV0aCIsY2hhcnNldD11dGYtOCxhbGdvcml0aG09bWQ1LXNlc3M=</challenge>

然后客户端发送,response 数据包进行匹配:
     <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">dXNlcm5hbWU9InN5c2FkbWluIixyZWFsbT0ic21hcnRjb29sIixjbm9uY2U9IjM3ZjJmNWUwMTQ3MWQ4ZWNkOWFmZWE1MjQyYWIyODMyMjE3MWNjOWNmNzU3MzczNTA1MGY2MjU1MjE2NTUzOTUiLG5jPTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvc21hcnRjb29sIixyZXNwb25zZT04ODBlMGU5YmYxZDYyMzI4Mjg5Nzg5MDYwNzAyNTQ5ZCxjaGFyc2V0PXV0Zi04LG5vbmNlPSJ3dmhjaE0xbEtHbnV2NHRaTlA2cVpad3RuVlBDZEx0Q1A3QTZFS3FqIg==</response>

  然后也会调用对应的 NameCallBack 和 PasswordCallBack 来验证登录用户的用户名和密码。

  当认证成功后,服务端发送:
      <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cnNwYXV0aD1iNWI4YmQ5Y2NjYjAyYjNiMDcxMDgzNzA5NDJiZDA4Yg==</success>
  这样客户端和服务器就认证成功了。

  3. anonymous 匿名登录:
       客户端在登录时,指明登录的方式, connection.loginAnonymously();
    客户端在认证时,发送数据包: <auth mechanism="ANONYMOUS" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></auth> 指明认证的方式为: ANONYMOUS。
     
      服务器端接收数据后,进行处理:
      

        在处理时:
  
         
     直接向客户端发送认证成功的数据包:
        
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值