2014-02-17 23:58:40 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Copyright 2003-2007 Jive Software.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.jivesoftware.smack;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
2014-03-24 19:30:34 +01:00
|
|
|
import java.util.ArrayList;
|
2014-08-01 10:34:47 +02:00
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.Iterator;
|
2017-03-18 12:59:52 +01:00
|
|
|
import java.util.LinkedHashMap;
|
2014-03-24 19:30:34 +01:00
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
2014-08-01 10:34:47 +02:00
|
|
|
import java.util.Set;
|
2014-11-16 19:03:03 +01:00
|
|
|
import java.util.logging.Logger;
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2017-06-14 17:12:43 +02:00
|
|
|
import javax.net.ssl.SSLSession;
|
|
|
|
import javax.security.auth.callback.CallbackHandler;
|
|
|
|
|
|
|
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
2019-02-10 19:50:46 +01:00
|
|
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
|
|
|
import org.jivesoftware.smack.SmackException.SmackSaslException;
|
2017-06-14 17:12:43 +02:00
|
|
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
|
|
|
import org.jivesoftware.smack.packet.Mechanisms;
|
|
|
|
import org.jivesoftware.smack.sasl.SASLErrorException;
|
|
|
|
import org.jivesoftware.smack.sasl.SASLMechanism;
|
|
|
|
import org.jivesoftware.smack.sasl.core.ScramSha1PlusMechanism;
|
|
|
|
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.SASLFailure;
|
|
|
|
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.Success;
|
|
|
|
|
|
|
|
import org.jxmpp.jid.DomainBareJid;
|
|
|
|
import org.jxmpp.jid.EntityBareJid;
|
|
|
|
|
2014-02-17 23:58:40 +01:00
|
|
|
/**
|
|
|
|
* <p>This class is responsible authenticating the user using SASL, binding the resource
|
|
|
|
* to the connection and establishing a session with the server.</p>
|
|
|
|
*
|
|
|
|
* <p>Once TLS has been negotiated (i.e. the connection has been secured) it is possible to
|
2014-08-01 10:34:47 +02:00
|
|
|
* register with the server or authenticate using SASL. If the
|
|
|
|
* server supports SASL then Smack will try to authenticate using SASL..</p>
|
2014-02-17 23:58:40 +01:00
|
|
|
*
|
|
|
|
* <p>The server may support many SASL mechanisms to use for authenticating. Out of the box
|
|
|
|
* Smack provides several SASL mechanisms, but it is possible to register new SASL Mechanisms. Use
|
2014-08-01 10:34:47 +02:00
|
|
|
* {@link #registerSASLMechanism(SASLMechanism)} to register a new mechanisms.
|
2014-02-17 23:58:40 +01:00
|
|
|
*
|
|
|
|
* @see org.jivesoftware.smack.sasl.SASLMechanism
|
|
|
|
*
|
|
|
|
* @author Gaston Dombiak
|
|
|
|
* @author Jay Kline
|
|
|
|
*/
|
2015-05-18 18:21:05 +02:00
|
|
|
public final class SASLAuthentication {
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2014-11-16 19:03:03 +01:00
|
|
|
private static final Logger LOGGER = Logger.getLogger(SASLAuthentication.class.getName());
|
|
|
|
|
2017-12-13 23:10:11 +01:00
|
|
|
private static final List<SASLMechanism> REGISTERED_MECHANISMS = new ArrayList<>();
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2017-12-13 23:10:11 +01:00
|
|
|
private static final Set<String> BLACKLISTED_MECHANISMS = new HashSet<>();
|
2014-03-12 11:50:05 +01:00
|
|
|
|
2016-11-20 19:32:26 +01:00
|
|
|
static {
|
|
|
|
// Blacklist SCRAM-SHA-1-PLUS for now.
|
|
|
|
blacklistSASLMechanism(ScramSha1PlusMechanism.NAME);
|
|
|
|
}
|
|
|
|
|
2014-02-17 23:58:40 +01:00
|
|
|
/**
|
2015-03-29 12:15:32 +02:00
|
|
|
* Registers a new SASL mechanism.
|
2014-08-01 10:34:47 +02:00
|
|
|
*
|
|
|
|
* @param mechanism a SASLMechanism subclass.
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2014-08-01 10:34:47 +02:00
|
|
|
public static void registerSASLMechanism(SASLMechanism mechanism) {
|
|
|
|
synchronized (REGISTERED_MECHANISMS) {
|
|
|
|
REGISTERED_MECHANISMS.add(mechanism);
|
|
|
|
Collections.sort(REGISTERED_MECHANISMS);
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-08-01 10:34:47 +02:00
|
|
|
* Returns the registered SASLMechanism sorted by the level of preference.
|
2014-02-17 23:58:40 +01:00
|
|
|
*
|
2014-08-01 10:34:47 +02:00
|
|
|
* @return the registered SASLMechanism sorted by the level of preference.
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2014-08-01 10:34:47 +02:00
|
|
|
public static Map<String, String> getRegisterdSASLMechanisms() {
|
2017-12-13 23:10:11 +01:00
|
|
|
Map<String, String> answer = new LinkedHashMap<>();
|
2014-08-01 10:34:47 +02:00
|
|
|
synchronized (REGISTERED_MECHANISMS) {
|
|
|
|
for (SASLMechanism mechanism : REGISTERED_MECHANISMS) {
|
2017-03-18 13:18:44 +01:00
|
|
|
answer.put(mechanism.getClass().getName(), mechanism.toString());
|
2014-08-01 10:34:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return answer;
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
2015-05-03 22:00:41 +02:00
|
|
|
public static boolean isSaslMechanismRegistered(String saslMechanism) {
|
|
|
|
synchronized (REGISTERED_MECHANISMS) {
|
|
|
|
for (SASLMechanism mechanism : REGISTERED_MECHANISMS) {
|
|
|
|
if (mechanism.getName().equals(saslMechanism)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-02-17 23:58:40 +01:00
|
|
|
/**
|
2014-08-01 10:34:47 +02:00
|
|
|
* Unregister a SASLMechanism by it's full class name. For example
|
|
|
|
* "org.jivesoftware.smack.sasl.javax.SASLCramMD5Mechanism".
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2014-08-01 10:34:47 +02:00
|
|
|
* @param clazz the SASLMechanism class's name
|
|
|
|
* @return true if the given SASLMechanism was removed, false otherwise
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2014-08-01 10:34:47 +02:00
|
|
|
public static boolean unregisterSASLMechanism(String clazz) {
|
|
|
|
synchronized (REGISTERED_MECHANISMS) {
|
|
|
|
Iterator<SASLMechanism> it = REGISTERED_MECHANISMS.iterator();
|
|
|
|
while (it.hasNext()) {
|
|
|
|
SASLMechanism mechanism = it.next();
|
|
|
|
if (mechanism.getClass().getName().equals(clazz)) {
|
|
|
|
it.remove();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
2017-12-13 23:10:11 +01:00
|
|
|
public static boolean blacklistSASLMechanism(String mechanism) {
|
2017-05-23 16:45:04 +02:00
|
|
|
synchronized (BLACKLISTED_MECHANISMS) {
|
2017-12-13 23:10:11 +01:00
|
|
|
return BLACKLISTED_MECHANISMS.add(mechanism);
|
2014-08-01 10:34:47 +02:00
|
|
|
}
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2014-08-01 10:34:47 +02:00
|
|
|
public static boolean unBlacklistSASLMechanism(String mechanism) {
|
2017-05-23 16:45:04 +02:00
|
|
|
synchronized (BLACKLISTED_MECHANISMS) {
|
2014-08-01 10:34:47 +02:00
|
|
|
return BLACKLISTED_MECHANISMS.remove(mechanism);
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
2014-08-01 10:34:47 +02:00
|
|
|
public static Set<String> getBlacklistedSASLMechanisms() {
|
2016-11-20 19:32:26 +01:00
|
|
|
return Collections.unmodifiableSet(BLACKLISTED_MECHANISMS);
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
2014-08-01 10:34:47 +02:00
|
|
|
private final AbstractXMPPConnection connection;
|
2015-05-03 22:00:41 +02:00
|
|
|
private final ConnectionConfiguration configuration;
|
2014-08-01 10:34:47 +02:00
|
|
|
private SASLMechanism currentMechanism = null;
|
|
|
|
|
2014-02-17 23:58:40 +01:00
|
|
|
/**
|
2014-08-01 10:34:47 +02:00
|
|
|
* Boolean indicating if SASL negotiation has finished and was successful.
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2014-09-11 09:49:16 +02:00
|
|
|
private boolean authenticationSuccessful;
|
2014-02-17 23:58:40 +01:00
|
|
|
|
|
|
|
/**
|
2014-08-01 10:34:47 +02:00
|
|
|
* Either of type {@link SmackException} or {@link SASLErrorException}
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2014-08-01 10:34:47 +02:00
|
|
|
private Exception saslException;
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2015-05-03 22:00:41 +02:00
|
|
|
SASLAuthentication(AbstractXMPPConnection connection, ConnectionConfiguration configuration) {
|
|
|
|
this.configuration = configuration;
|
2014-02-17 23:58:40 +01:00
|
|
|
this.connection = connection;
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Performs SASL authentication of the specified user. If SASL authentication was successful
|
|
|
|
* then resource binding and session establishment will be performed. This method will return
|
|
|
|
* the full JID provided by the server while binding a resource to the connection.<p>
|
|
|
|
*
|
|
|
|
* The server may assign a full JID with a username or resource different than the requested
|
|
|
|
* by this method.
|
|
|
|
*
|
|
|
|
* @param username the username that is authenticating with the server.
|
|
|
|
* @param password the password to send to the server.
|
2015-06-16 18:50:30 +02:00
|
|
|
* @param authzid the authorization identifier (typically null).
|
2016-11-20 19:32:26 +01:00
|
|
|
* @param sslSession the optional SSL/TLS session (if one was established)
|
2019-02-04 08:59:39 +01:00
|
|
|
* @return the used SASLMechanism.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws SASLErrorException if a SASL protocol error was returned.
|
|
|
|
* @throws IOException if an I/O error occured.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
|
|
|
* @throws SmackSaslException if a SASL specific error occured.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2019-02-04 08:59:39 +01:00
|
|
|
public SASLMechanism authenticate(String username, String password, EntityBareJid authzid, SSLSession sslSession)
|
2014-08-01 10:34:47 +02:00
|
|
|
throws XMPPErrorException, SASLErrorException, IOException,
|
2019-02-10 19:50:46 +01:00
|
|
|
InterruptedException, SmackSaslException, NotConnectedException, NoResponseException {
|
2015-06-16 18:50:30 +02:00
|
|
|
currentMechanism = selectMechanism(authzid);
|
2015-05-03 22:00:41 +02:00
|
|
|
final CallbackHandler callbackHandler = configuration.getCallbackHandler();
|
|
|
|
final String host = connection.getHost();
|
2015-05-18 16:48:23 +02:00
|
|
|
final DomainBareJid xmppServiceDomain = connection.getXMPPServiceDomain();
|
2014-02-17 23:58:40 +01:00
|
|
|
|
|
|
|
synchronized (this) {
|
2015-05-03 22:00:41 +02:00
|
|
|
if (callbackHandler != null) {
|
2016-11-20 19:32:26 +01:00
|
|
|
currentMechanism.authenticate(host, xmppServiceDomain, callbackHandler, authzid, sslSession);
|
2015-05-03 22:00:41 +02:00
|
|
|
}
|
|
|
|
else {
|
2016-11-20 19:32:26 +01:00
|
|
|
currentMechanism.authenticate(username, host, xmppServiceDomain, password, authzid, sslSession);
|
2015-05-03 22:00:41 +02:00
|
|
|
}
|
2017-01-12 20:57:19 +01:00
|
|
|
final long deadline = System.currentTimeMillis() + connection.getReplyTimeout();
|
2015-09-13 18:12:33 +02:00
|
|
|
while (!authenticationSuccessful && saslException == null) {
|
|
|
|
final long now = System.currentTimeMillis();
|
2016-12-19 15:13:05 +01:00
|
|
|
if (now >= deadline) break;
|
2015-09-13 18:12:33 +02:00
|
|
|
// Wait until SASL negotiation finishes
|
|
|
|
wait(deadline - now);
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
2017-05-23 16:45:04 +02:00
|
|
|
if (saslException != null) {
|
2019-02-10 19:50:46 +01:00
|
|
|
if (saslException instanceof SmackSaslException) {
|
|
|
|
throw (SmackSaslException) saslException;
|
2014-08-01 10:34:47 +02:00
|
|
|
} else if (saslException instanceof SASLErrorException) {
|
|
|
|
throw (SASLErrorException) saslException;
|
2019-02-10 19:50:46 +01:00
|
|
|
} else if (saslException instanceof NotConnectedException) {
|
|
|
|
throw (NotConnectedException) saslException;
|
2014-08-01 10:34:47 +02:00
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("Unexpected exception type" , saslException);
|
|
|
|
}
|
|
|
|
}
|
2015-05-03 22:00:41 +02:00
|
|
|
|
|
|
|
if (!authenticationSuccessful) {
|
2015-06-02 17:21:33 +02:00
|
|
|
throw NoResponseException.newWith(connection, "successful SASL authentication");
|
2015-05-03 22:00:41 +02:00
|
|
|
}
|
2019-02-04 08:59:39 +01:00
|
|
|
|
|
|
|
return currentMechanism;
|
2014-08-01 10:34:47 +02:00
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
|
|
|
|
/**
|
2014-08-01 10:34:47 +02:00
|
|
|
* Wrapper for {@link #challengeReceived(String, boolean)}, with <code>finalChallenge</code> set
|
|
|
|
* to <code>false</code>.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2014-08-01 10:34:47 +02:00
|
|
|
* @param challenge a base64 encoded string representing the challenge.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws SmackException if Smack detected an exceptional situation.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2015-02-14 09:43:44 +01:00
|
|
|
public void challengeReceived(String challenge) throws SmackException, InterruptedException {
|
2014-08-01 10:34:47 +02:00
|
|
|
challengeReceived(challenge, false);
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The server is challenging the SASL authentication we just sent. Forward the challenge
|
2014-08-01 10:34:47 +02:00
|
|
|
* to the current SASLMechanism we are using. The SASLMechanism will eventually send a response to
|
2014-02-17 23:58:40 +01:00
|
|
|
* the server. The length of the challenge-response sequence varies according to the
|
|
|
|
* SASLMechanism in use.
|
|
|
|
*
|
|
|
|
* @param challenge a base64 encoded string representing the challenge.
|
2014-08-01 10:34:47 +02:00
|
|
|
* @param finalChallenge true if this is the last challenge send by the server within the success stanza
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws SmackSaslException if a SASL specific error occured.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2019-02-10 19:50:46 +01:00
|
|
|
public void challengeReceived(String challenge, boolean finalChallenge) throws SmackSaslException, NotConnectedException, InterruptedException {
|
2014-08-01 10:34:47 +02:00
|
|
|
try {
|
|
|
|
currentMechanism.challengeReceived(challenge, finalChallenge);
|
2019-02-10 19:50:46 +01:00
|
|
|
} catch (InterruptedException | SmackSaslException | NotConnectedException e) {
|
2014-08-01 10:34:47 +02:00
|
|
|
authenticationFailed(e);
|
|
|
|
throw e;
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification message saying that SASL authentication was successful. The next step
|
|
|
|
* would be to bind the resource.
|
2017-12-23 20:21:19 +01:00
|
|
|
* @param success result of the authentication.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws SmackException if Smack detected an exceptional situation.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2015-02-14 09:43:44 +01:00
|
|
|
public void authenticated(Success success) throws SmackException, InterruptedException {
|
2014-08-01 10:34:47 +02:00
|
|
|
// RFC6120 6.3.10 "At the end of the authentication exchange, the SASL server (the XMPP
|
|
|
|
// "receiving entity") can include "additional data with success" if appropriate for the
|
|
|
|
// SASL mechanism in use. In XMPP, this is done by including the additional data as the XML
|
|
|
|
// character data of the <success/> element." The used SASL mechanism should be able to
|
|
|
|
// verify the data send by the server in the success stanza, if any.
|
|
|
|
if (success.getData() != null) {
|
|
|
|
challengeReceived(success.getData(), true);
|
|
|
|
}
|
2014-10-21 11:59:11 +02:00
|
|
|
currentMechanism.checkIfSuccessfulOrThrow();
|
2014-09-11 09:49:16 +02:00
|
|
|
authenticationSuccessful = true;
|
2014-03-24 19:30:34 +01:00
|
|
|
// Wake up the thread that is waiting in the #authenticate method
|
2014-04-27 12:27:12 +02:00
|
|
|
synchronized (this) {
|
|
|
|
notify();
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification message saying that SASL authentication has failed. The server may have
|
|
|
|
* closed the connection depending on the number of possible retries.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2014-03-12 11:50:05 +01:00
|
|
|
* @param saslFailure the SASL failure as reported by the server
|
|
|
|
* @see <a href="https://tools.ietf.org/html/rfc6120#section-6.5">RFC6120 6.5</a>
|
2014-02-17 23:58:40 +01:00
|
|
|
*/
|
2014-05-15 15:04:46 +02:00
|
|
|
public void authenticationFailed(SASLFailure saslFailure) {
|
2014-08-01 10:34:47 +02:00
|
|
|
authenticationFailed(new SASLErrorException(currentMechanism.getName(), saslFailure));
|
|
|
|
}
|
|
|
|
|
2019-02-10 21:51:01 +01:00
|
|
|
private void authenticationFailed(Exception exception) {
|
2014-08-01 10:34:47 +02:00
|
|
|
saslException = exception;
|
2014-03-24 19:30:34 +01:00
|
|
|
// Wake up the thread that is waiting in the #authenticate method
|
2014-04-27 12:27:12 +02:00
|
|
|
synchronized (this) {
|
|
|
|
notify();
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
|
|
|
|
2014-09-11 09:49:16 +02:00
|
|
|
public boolean authenticationSuccessful() {
|
|
|
|
return authenticationSuccessful;
|
|
|
|
}
|
|
|
|
|
2014-02-17 23:58:40 +01:00
|
|
|
/**
|
|
|
|
* Initializes the internal state in order to be able to be reused. The authentication
|
|
|
|
* is used by the connection at the first login and then reused after the connection
|
|
|
|
* is disconnected and then reconnected.
|
|
|
|
*/
|
2015-05-18 18:21:05 +02:00
|
|
|
void init() {
|
2014-09-11 09:49:16 +02:00
|
|
|
authenticationSuccessful = false;
|
2014-08-01 10:34:47 +02:00
|
|
|
saslException = null;
|
|
|
|
}
|
|
|
|
|
2015-05-18 18:21:05 +02:00
|
|
|
String getNameOfLastUsedSaslMechansism() {
|
|
|
|
SASLMechanism lastUsedMech = currentMechanism;
|
|
|
|
if (lastUsedMech == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return lastUsedMech.getName();
|
|
|
|
}
|
|
|
|
|
2019-02-10 19:50:46 +01:00
|
|
|
private SASLMechanism selectMechanism(EntityBareJid authzid) throws SmackException.SmackSaslException {
|
2014-08-01 10:34:47 +02:00
|
|
|
Iterator<SASLMechanism> it = REGISTERED_MECHANISMS.iterator();
|
2015-05-03 22:00:41 +02:00
|
|
|
final List<String> serverMechanisms = getServerMechanisms();
|
|
|
|
if (serverMechanisms.isEmpty()) {
|
|
|
|
LOGGER.warning("Server did not report any SASL mechanisms");
|
|
|
|
}
|
2014-08-01 10:34:47 +02:00
|
|
|
// Iterate in SASL Priority order over registered mechanisms
|
|
|
|
while (it.hasNext()) {
|
|
|
|
SASLMechanism mechanism = it.next();
|
|
|
|
String mechanismName = mechanism.getName();
|
|
|
|
synchronized (BLACKLISTED_MECHANISMS) {
|
|
|
|
if (BLACKLISTED_MECHANISMS.contains(mechanismName)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2015-05-03 22:00:41 +02:00
|
|
|
if (!configuration.isEnabledSaslMechanism(mechanismName)) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-06-16 18:50:30 +02:00
|
|
|
if (authzid != null) {
|
|
|
|
if (!mechanism.authzidSupported()) {
|
|
|
|
LOGGER.fine("Skipping " + mechanism + " because authzid is required by not supported by this SASL mechanism");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2015-05-03 22:00:41 +02:00
|
|
|
if (serverMechanisms.contains(mechanismName)) {
|
2014-08-01 10:34:47 +02:00
|
|
|
// Create a new instance of the SASLMechanism for every authentication attempt.
|
2016-11-20 19:32:26 +01:00
|
|
|
return mechanism.instanceForAuthentication(connection, configuration);
|
2014-08-01 10:34:47 +02:00
|
|
|
}
|
|
|
|
}
|
2015-05-03 22:00:41 +02:00
|
|
|
|
|
|
|
synchronized (BLACKLISTED_MECHANISMS) {
|
|
|
|
// @formatter:off
|
2019-02-10 19:50:46 +01:00
|
|
|
throw new SmackException.SmackSaslException(
|
2015-05-03 22:00:41 +02:00
|
|
|
"No supported and enabled SASL Mechanism provided by server. " +
|
|
|
|
"Server announced mechanisms: " + serverMechanisms + ". " +
|
2017-12-13 23:10:11 +01:00
|
|
|
"Registered SASL mechanisms with Smack: " + REGISTERED_MECHANISMS + ". " +
|
|
|
|
"Enabled SASL mechanisms for this connection: " + configuration.getEnabledSaslMechanisms() + ". " +
|
2015-05-03 22:00:41 +02:00
|
|
|
"Blacklisted SASL mechanisms: " + BLACKLISTED_MECHANISMS + '.'
|
|
|
|
);
|
|
|
|
// @formatter;on
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|
2014-09-11 09:49:16 +02:00
|
|
|
|
2015-05-03 22:00:41 +02:00
|
|
|
private List<String> getServerMechanisms() {
|
2014-09-11 09:49:16 +02:00
|
|
|
Mechanisms mechanisms = connection.getFeature(Mechanisms.ELEMENT, Mechanisms.NAMESPACE);
|
2014-11-16 19:03:03 +01:00
|
|
|
if (mechanisms == null) {
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
2014-09-11 09:49:16 +02:00
|
|
|
return mechanisms.getMechanisms();
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|