Openfire source code explanation-user logon and openfire source code
Based on xmpp protocol
Client sending:
<Auth xmlns = 'urn: ietf: params: xml: ns: xmpp-sasl 'mechanic = 'plain'> XXXXXXXXXXXXXXXXXXXXX = </auth>
Xmlns is the namespace, and mechanic is the encryption method of the user name and password. The text content of the auth tag is the string encrypted by the user name and password in PLAIN mode.
Received by the server:
Received through the messageReceived method of the ConnectionHandler class, Processed in process
else if ("auth".equals(tag)) { // User is trying to authenticate using SASL startedSASL = true; // Process authentication stanza saslStatus = SASLAuthentication.handle(session, doc); }
Logon verification is performed when the xml tag is auth.
The following describes how SASLAuthentication is handled.
First, determine the encryption method and decrypt it. Use the following method to verify logon.
final byte[] challenge = saslServer.evaluateResponse( decoded ); // Either a challenge or success data.
The verification method varies depending on the encryption method. PLAIN encryption, it depends on how SaslServerPlainImpl is implemented.
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);}
We can see that openfire is verified through callback, and two layers of verification are also performed. The first is to verify the user name and password, and the second is to load user information
(If you need to modify the source code, you can optimize it here. You can obtain the user information during the first step of login verification. You do not need to query it again ).
Callback is implemented through 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); } }
The username and password are verified by AuthToken at = AuthFactory. authenticate (name, new String (vpcb. getPassword ().
Perform logon Verification Based on the class of provider. auth. className configured in the database.
Second VerificationAuthorizationManager. authorize (username, principal) loads user information.
After two verification passes, the client <success xmlns = 'urn: ietf: params: xml: ns: xmpp-sasl '/> is returned, indicating that the logon is successful.