openfire源碼解讀--使用者登入,openfire源碼

來源:互聯網
上載者:User

openfire源碼解讀--使用者登入,openfire源碼

根據xmpp協議

用戶端發送:

<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>XXXXXXXXXXXXXXXXXXXXX=</auth>

其中,xmlns是命名空間,mechanism是使用者名稱密碼的加密方式,auth 標籤的text內容為使用者名稱密碼通過PLAIN方式加密的字串。

服務端接收:

  通過ConnectionHandler類的messageReceived方法接收,process中處理

     else if ("auth".equals(tag)) {            // User is trying to authenticate using SASL            startedSASL = true;            // Process authentication stanza            saslStatus = SASLAuthentication.handle(session, doc);        }

  判斷xml標籤為auth時進行登入驗證。

  下面來看SASLAuthentication的處理

  首先判斷加密方式,然後解密,通過下面這個方法來驗證登入。

final byte[] challenge = saslServer.evaluateResponse( decoded ); // Either a challenge or success data.

  根據加密方式不同,驗證處理方法不同。PLAIN加密的,那就看SaslServerPlainImpl中是怎麼實現的。

NameCallback ncb = new NameCallback("PLAIN authentication ID: ",principal);VerifyPasswordCallback vpcb = new VerifyPasswordCallback(password.toCharArray());cbh.handle(new Callback[]{ncb,vpcb});if (vpcb.getVerified()) {vpcb.clearPassword();AuthorizeCallback acb = new AuthorizeCallback(principal,username);cbh.handle(new Callback[]{acb});if(acb.isAuthorized()) {username = acb.getAuthorizedID();completed = true;} else {completed = true;username = null;throw new SaslException("PLAIN: user not authorized: "+principal);}} else {throw new SaslException("PLAIN: user not authorized: "+principal);}

  可以看到openfire是通過callback來驗證的,而且還進行了2層驗證。第一次是驗證使用者名稱密碼,第二次是載入使用者資訊

(自己有需要修改源碼時,這裡就可以最佳化了,第一步登入驗證時就可以擷取使用者資訊了,沒必要重新查詢一次)。

  callback是通過XMPPCallbackHandler實現的。

for (Callback callback : callbacks) {            if (callback instanceof RealmCallback) {                ((RealmCallback) callback).setText( XMPPServer.getInstance().getServerInfo().getXMPPDomain() );            }            else if (callback instanceof NameCallback) {                name = ((NameCallback) callback).getName();                if (name == null) {                    name = ((NameCallback) callback).getDefaultName();                }                //Log.debug("XMPPCallbackHandler: NameCallback: " + name);            }            else if (callback instanceof PasswordCallback) {                try {                    // Get the password from the UserProvider. Some UserProviders may not support                    // this operation                    ((PasswordCallback) callback)                            .setPassword(AuthFactory.getPassword(name).toCharArray());                    //Log.debug("XMPPCallbackHandler: PasswordCallback");                }                catch (UserNotFoundException | UnsupportedOperationException e) {                    throw new IOException(e.toString());                }            }            else if (callback instanceof VerifyPasswordCallback) {                //Log.debug("XMPPCallbackHandler: VerifyPasswordCallback");                VerifyPasswordCallback vpcb = (VerifyPasswordCallback) callback;                try {                    AuthToken at = AuthFactory.authenticate(name, new String(vpcb.getPassword()));                    vpcb.setVerified((at != null));                }                catch (Exception e) {                    vpcb.setVerified(false);                }            }            else if (callback instanceof AuthorizeCallback) {                //Log.debug("XMPPCallbackHandler: AuthorizeCallback");                AuthorizeCallback authCallback = ((AuthorizeCallback) callback);                // Principal that authenticated                String principal = authCallback.getAuthenticationID();                // Username requested (not full JID)                String username = authCallback.getAuthorizationID();                // Remove any REALM from the username. This is optional in the spec and it may cause                // a lot of users to fail to log in if their clients is sending an incorrect value                if (username != null && username.contains("@")) {                    username = username.substring(0, username.lastIndexOf("@"));                }                if (principal.equals(username)) {                    //client perhaps made no request, get default username                    username = AuthorizationManager.map(principal);                    if (Log.isDebugEnabled()) {                        //Log.debug("XMPPCallbackHandler: no username requested, using " + username);                    }                }                if (AuthorizationManager.authorize(username, principal)) {                    if (Log.isDebugEnabled()) {                        //Log.debug("XMPPCallbackHandler: " + principal + " authorized to " + username);                    }                    authCallback.setAuthorized(true);                    authCallback.setAuthorizedID(username);                }                else {                    if (Log.isDebugEnabled()) {                        //Log.debug("XMPPCallbackHandler: " + principal + " not authorized to " + username);                    }                    authCallback.setAuthorized(false);                }            }

  第一次驗證使用者名稱密碼是通過 AuthToken at = AuthFactory.authenticate(name, new String(vpcb.getPassword()));驗證的

根據資料庫配置provider.auth.className的類實現登入驗證。

第二次驗證AuthorizationManager.authorize(username, principal)會載入使用者資訊。
2次驗證通過就會返回用戶端 <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/> 表示登入成功。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.