1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-11-25 05:22:06 +01:00

Ads support for SCRAM-SHA-1-PLUS

Related to SMACK-398.
This commit is contained in:
Florian Schmaus 2016-11-20 19:32:26 +01:00
parent 44744de003
commit 1f1bc236fd
14 changed files with 252 additions and 63 deletions

View file

@ -214,7 +214,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
protected void loginInternal(String username, String password, Resourcepart resource) throws XMPPException,
SmackException, IOException, InterruptedException {
// Authenticate using SASL
saslAuthentication.authenticate(username, password, config.getAuthzid());
saslAuthentication.authenticate(username, password, config.getAuthzid(), null);
bindResourceAndEstablishSession(resource);

View file

@ -462,9 +462,9 @@ public abstract class ConnectionConfiguration {
* @return true if the given SASL mechanism is enabled, false otherwise.
*/
public boolean isEnabledSaslMechanism(String saslMechanism) {
// If enabledSaslMechanisms is not set, then all mechanisms are enabled per default
// If enabledSaslMechanisms is not set, then all mechanisms which are not blacklisted are enabled per default.
if (enabledSaslMechanisms == null) {
return true;
return !SASLAuthentication.getBlacklistedSASLMechanisms().contains(saslMechanism);
}
return enabledSaslMechanisms.contains(saslMechanism);
}

View file

@ -22,11 +22,13 @@ 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;
import javax.net.ssl.SSLSession;
import javax.security.auth.callback.CallbackHandler;
import java.io.IOException;
@ -65,6 +67,11 @@ public final class SASLAuthentication {
private static final Set<String> BLACKLISTED_MECHANISMS = new HashSet<String>();
static {
// Blacklist SCRAM-SHA-1-PLUS for now.
blacklistSASLMechanism(ScramSha1PlusMechanism.NAME);
}
/**
* Registers a new SASL mechanism.
*
@ -137,9 +144,7 @@ public final class SASLAuthentication {
}
public static Set<String> getBlacklistedSASLMechanisms() {
synchronized(BLACKLISTED_MECHANISMS) {
return new HashSet<String>(BLACKLISTED_MECHANISMS);
}
return Collections.unmodifiableSet(BLACKLISTED_MECHANISMS);
}
private final AbstractXMPPConnection connection;
@ -173,13 +178,14 @@ public final class SASLAuthentication {
* @param username the username that is authenticating with the server.
* @param password the password to send to the server.
* @param authzid the authorization identifier (typically null).
* @param sslSession the optional SSL/TLS session (if one was established)
* @throws XMPPErrorException
* @throws SASLErrorException
* @throws IOException
* @throws SmackException
* @throws InterruptedException
*/
public void authenticate(String username, String password, EntityBareJid authzid)
public void authenticate(String username, String password, EntityBareJid authzid, SSLSession sslSession)
throws XMPPErrorException, SASLErrorException, IOException,
SmackException, InterruptedException {
currentMechanism = selectMechanism(authzid);
@ -189,10 +195,10 @@ public final class SASLAuthentication {
synchronized (this) {
if (callbackHandler != null) {
currentMechanism.authenticate(host, xmppServiceDomain, callbackHandler, authzid);
currentMechanism.authenticate(host, xmppServiceDomain, callbackHandler, authzid, sslSession);
}
else {
currentMechanism.authenticate(username, host, xmppServiceDomain, password, authzid);
currentMechanism.authenticate(username, host, xmppServiceDomain, password, authzid, sslSession);
}
final long deadline = System.currentTimeMillis() + connection.getPacketReplyTimeout();
while (!authenticationSuccessful && saslException == null) {
@ -340,7 +346,7 @@ public final class SASLAuthentication {
}
if (serverMechanisms.contains(mechanismName)) {
// Create a new instance of the SASLMechanism for every authentication attempt.
return mechanism.instanceForAuthentication(connection);
return mechanism.instanceForAuthentication(connection, configuration);
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2003-2007 Jive Software, 2014 Florian Schmaus
* Copyright 2003-2007 Jive Software, 2014-2016 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -35,6 +35,7 @@ import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.sasl.core.SASLAnonymous;
import org.jivesoftware.smack.sasl.core.SASLXOauth2Mechanism;
import org.jivesoftware.smack.sasl.core.SCRAMSHA1Mechanism;
import org.jivesoftware.smack.sasl.core.ScramSha1PlusMechanism;
import org.jivesoftware.smack.util.FileUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@ -137,6 +138,7 @@ public final class SmackInitialization {
}
SASLAuthentication.registerSASLMechanism(new SCRAMSHA1Mechanism());
SASLAuthentication.registerSASLMechanism(new ScramSha1PlusMechanism());
SASLAuthentication.registerSASLMechanism(new SASLXOauth2Mechanism());
SASLAuthentication.registerSASLMechanism(new SASLAnonymous());

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2003-2007 Jive Software, 2014 Florian Schmaus
* Copyright 2003-2007 Jive Software, 2014-2016 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
*/
package org.jivesoftware.smack.sasl;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
@ -27,44 +28,21 @@ import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.EntityBareJid;
import javax.net.ssl.SSLSession;
import javax.security.auth.callback.CallbackHandler;
/**
* Base class for SASL mechanisms. Subclasses must implement these methods:
* <ul>
* <li>{@link #getName()} -- returns the common name of the SASL mechanism.</li>
* </ul>
* Base class for SASL mechanisms.
* Subclasses will likely want to implement their own versions of these methods:
* <li>{@link #authenticate(String, String, DomainBareJid, String, EntityBareJid)} -- Initiate authentication stanza using the
* <li>{@link #authenticate(String, String, DomainBareJid, String, EntityBareJid, SSLSession)} -- Initiate authentication stanza using the
* deprecated method.</li>
* <li>{@link #authenticate(String, DomainBareJid, CallbackHandler, EntityBareJid)} -- Initiate authentication stanza
* <li>{@link #authenticate(String, DomainBareJid, CallbackHandler, EntityBareJid, SSLSession)} -- Initiate authentication stanza
* using the CallbackHandler method.</li>
* <li>{@link #challengeReceived(String, boolean)} -- Handle a challenge from the server.</li>
* </ul>
*
* Basic XMPP SASL authentication steps:
* 1. Client authentication initialization, stanza sent to the server (Base64 encoded):
* <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>
* 2. Server sends back to the client the challenge response (Base64 encoded)
* sample:
* realm=<sasl server realm>,nonce="OA6MG9tEQGm2hh",qop="auth",charset=utf-8,algorithm=md5-sess
* 3. The client responds back to the server (Base 64 encoded):
* sample:
* username=<userid>,realm=<sasl server realm from above>,nonce="OA6MG9tEQGm2hh",
* cnonce="OA6MHXh6VqTrRk",nc=00000001,qop=auth,
* digest-uri=<digesturi>,
* response=d388dad90d4bbd760a152321f2143af7,
* charset=utf-8,
* authzid=<id>
* 4. The server evaluates if the user is present and contained in the REALM
* if successful it sends: <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/> (Base64 encoded)
* if not successful it sends:
* sample:
* <challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
* cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZA==
* </challenge>
*
* @author Jay Kline
* @author Florian Schmaus
*/
public abstract class SASLMechanism implements Comparable<SASLMechanism> {
@ -92,6 +70,8 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
protected XMPPConnection connection;
protected ConnectionConfiguration connectionConfiguration;
/**
* Then authentication identity (authcid). RFC 6120 § 6.3.7 informs us that some SASL mechanisms use this as a
* "simple user name". But the exact form is a matter of the mechanism and that it does not necessarily map to an
@ -120,10 +100,15 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
protected String password;
protected String host;
/**
* The used SSL/TLS session (if any).
*/
protected SSLSession sslSession;
/**
* Builds and sends the <tt>auth</tt> stanza to the server. Note that this method of
* authentication is not recommended, since it is very inflexible. Use
* {@link #authenticate(String, DomainBareJid, CallbackHandler, EntityBareJid)} whenever possible.
* {@link #authenticate(String, DomainBareJid, CallbackHandler, EntityBareJid, SSLSession)} whenever possible.
*
* Explanation of auth stanza:
*
@ -165,17 +150,20 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
* serviceName format is: host [ "/" serv-name ] as per RFC-2831
* @param password the password for this account.
* @param authzid the optional authorization identity.
* @param sslSession the optional SSL/TLS session (if one was established)
* @throws SmackException If a network error occurs while authenticating.
* @throws NotConnectedException
* @throws InterruptedException
*/
public final void authenticate(String username, String host, DomainBareJid serviceName, String password, EntityBareJid authzid)
public final void authenticate(String username, String host, DomainBareJid serviceName, String password,
EntityBareJid authzid, SSLSession sslSession)
throws SmackException, NotConnectedException, InterruptedException {
this.authenticationId = username;
this.host = host;
this.serviceName = serviceName;
this.password = password;
this.authorizationId = authzid;
this.sslSession = sslSession;
assert(authorizationId == null || authzidSupported());
authenticateInternal();
authenticate();
@ -195,15 +183,17 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
* @param serviceName the xmpp service location
* @param cbh the CallbackHandler to obtain user information.
* @param authzid the optional authorization identity.
* @param sslSession the optional SSL/TLS session (if one was established)
* @throws SmackException
* @throws NotConnectedException
* @throws InterruptedException
*/
public void authenticate(String host, DomainBareJid serviceName, CallbackHandler cbh, EntityBareJid authzid)
public void authenticate(String host, DomainBareJid serviceName, CallbackHandler cbh, EntityBareJid authzid, SSLSession sslSession)
throws SmackException, NotConnectedException, InterruptedException {
this.host = host;
this.serviceName = serviceName;
this.authorizationId = authzid;
this.sslSession = sslSession;
assert(authorizationId == null || authzidSupported());
authenticateInternal(cbh);
authenticate();
@ -290,9 +280,10 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
public abstract void checkIfSuccessfulOrThrow() throws SmackException;
public SASLMechanism instanceForAuthentication(XMPPConnection connection) {
public SASLMechanism instanceForAuthentication(XMPPConnection connection, ConnectionConfiguration connectionConfiguration) {
SASLMechanism saslMechansim = newInstance();
saslMechansim.connection = connection;
saslMechansim.connectionConfiguration = connectionConfiguration;
return saslMechansim;
}

View file

@ -23,8 +23,8 @@ import org.jivesoftware.smack.util.MAC;
public class SCRAMSHA1Mechanism extends ScramMechanism {
public SCRAMSHA1Mechanism() {
super(new ScramHmac() {
static {
SHA_1_SCRAM_HMAC = new ScramHmac() {
@Override
public String getHmacName() {
return "SHA-1";
@ -33,7 +33,16 @@ public class SCRAMSHA1Mechanism extends ScramMechanism {
public byte[] hmac(byte[] key, byte[] str) throws InvalidKeyException {
return MAC.hmacsha1(key, str);
}
});
};
NAME = (new SCRAMSHA1Mechanism()).getName();
}
public static final String NAME;
static final ScramHmac SHA_1_SCRAM_HMAC;
public SCRAMSHA1Mechanism() {
super(SHA_1_SCRAM_HMAC);
}
@Override

View file

@ -28,6 +28,7 @@ import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.ByteUtils;
import org.jivesoftware.smack.util.SHA1;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jxmpp.util.cache.Cache;
import org.jxmpp.util.cache.LruCache;
@ -145,7 +146,8 @@ public abstract class ScramMechanism extends SASLMechanism {
// Parsing and error checking is done, we can now begin to calculate the values
// First the client-final-message-without-proof
String clientFinalMessageWithoutProof = "c=" + Base64.encode(getGS2Header()) + ",r=" + rvalue;
String channelBinding = "c=" + Base64.encodeToString(getCBindInput());
String clientFinalMessageWithoutProof = channelBinding + ",r=" + rvalue;
// AuthMessage := client-first-message-bare + "," + server-first-message + "," +
// client-final-message-without-proof
@ -154,7 +156,9 @@ public abstract class ScramMechanism extends SASLMechanism {
// RFC 5802 § 5.1 "Note that a client implementation MAY cache ClientKey&ServerKey … for later reauthentication …
// as it is likely that the server is going to advertise the same salt value upon reauthentication."
final String cacheKey = password + ',' + salt;
// Note that we also mangle the mechanism's name into the cache key, since the cache is used by multiple
// mechanisms.
final String cacheKey = password + ',' + salt + ',' + getName();
byte[] serverKey, clientKey;
Keys keys = CACHE.get(cacheKey);
if (keys == null) {
@ -211,7 +215,40 @@ public abstract class ScramMechanism extends SASLMechanism {
if (authorizationId != null) {
authzidPortion = "a=" + authorizationId;
}
return "n," + authzidPortion + ",";
String cbName = getChannelBindingName();
assert(StringUtils.isNotEmpty(cbName));
return cbName + ',' + authzidPortion + ",";
}
private final byte[] getCBindInput() throws SmackException {
byte[] cbindData = getChannelBindingData();
byte[] gs2Header = toBytes(getGS2Header());
if (cbindData == null) {
return gs2Header;
}
return ByteUtils.concact(gs2Header, cbindData);
}
protected String getChannelBindingName() {
if (sslSession != null && connectionConfiguration.isEnabledSaslMechanism(getName() + "-PLUS")) {
// Announce that we support Channel Binding, i.e., the '-PLUS' flavor of this SASL mechanism, but that we
// believe the server does not.
return "y";
}
return "n";
}
/**
*
* @return the Channel Binding data.
* @throws SmackException
*/
protected byte[] getChannelBindingData() throws SmackException {
return null;
}
private static Map<Character, String> parseAttributes(String string) throws SmackException {

View file

@ -0,0 +1,61 @@
/**
*
* Copyright 2016 Florian Schmaus
*
* 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.sasl.core;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import javax.net.ssl.SSLPeerUnverifiedException;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.util.TLSUtils;
/**
* SCRAM-X-PLUS implementation. Due limitations of the Java API, this mechanism only supports the 'tls-server-end-point'
* channel binding type. But on the other hand, the other relevant channel binding type 'tls-unique' has some flaws (see
* 3SHAKE, RFC 7627).
*
* @author Florian Schmaus
*/
public abstract class ScramPlusMechanism extends ScramMechanism {
protected ScramPlusMechanism(ScramHmac scramHmac) {
super(scramHmac);
}
@Override
public String getName() {
return super.getName() + "-PLUS";
}
@Override
protected String getChannelBindingName() {
return "p=tls-server-end-point";
}
@Override
protected byte[] getChannelBindingData() throws SmackException {
byte[] cbData;
try {
cbData = TLSUtils.getChannelBindingTlsServerEndPoint(sslSession);
}
catch (SSLPeerUnverifiedException | CertificateEncodingException | NoSuchAlgorithmException e) {
throw new SmackException(e);
}
return cbData;
}
}

View file

@ -0,0 +1,43 @@
/**
*
* Copyright 2016 Florian Schmaus
*
* 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.sasl.core;
import org.jivesoftware.smack.sasl.SASLMechanism;
public class ScramSha1PlusMechanism extends ScramPlusMechanism {
static {
NAME = (new ScramSha1PlusMechanism()).getName();
}
public static final String NAME;
public ScramSha1PlusMechanism() {
super(SCRAMSHA1Mechanism.SHA_1_SCRAM_HMAC);
}
@Override
public int getPriority() {
return 110;
}
@Override
protected SASLMechanism newInstance() {
return new ScramSha1PlusMechanism();
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2014 Florian Schmaus
* Copyright 2014-2016 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package org.jivesoftware.smack.util;
import java.security.KeyManagementException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
@ -27,10 +28,13 @@ import java.util.Set;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SmackException.SecurityNotPossibleException;
@ -166,6 +170,41 @@ public class TLSUtils {
}
}
/**
* Get the channel binding data for the 'tls-server-end-point' channel binding type. This channel binding type is
* defined in RFC 5929 § 4.
*
* @param sslSession the SSL/TLS session from which the data should be retrieved.
* @return the channel binding data.
* @throws SSLPeerUnverifiedException
* @throws CertificateEncodingException
* @throws NoSuchAlgorithmException
* @see <a href="https://tools.ietf.org/html/rfc5929#section-4">RFC 5929 § 4.</a>
*/
public static byte[] getChannelBindingTlsServerEndPoint(final SSLSession sslSession)
throws SSLPeerUnverifiedException, CertificateEncodingException, NoSuchAlgorithmException {
final Certificate[] peerCertificates = sslSession.getPeerCertificates();
final Certificate certificate = peerCertificates[0];
final String certificateAlgorithm = certificate.getPublicKey().getAlgorithm();
// RFC 5929 § 4.1 hash function selection.
String algorithm;
switch (certificateAlgorithm) {
case "MD5":
case "SHA-1":
algorithm = "SHA-256";
break;
default:
algorithm = certificateAlgorithm;
break;
}
final MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
final byte[] certificateDerEncoded = certificate.getEncoded();
messageDigest.update(certificateDerEncoded);
return messageDigest.digest();
}
/**
* A {@link X509TrustManager} that <b>doesn't validate</b> X.509 certificates.
* <p>

View file

@ -1,6 +1,6 @@
/**
*
* Copyright © 2014 Florian Schmaus
* Copyright © 2014-2016 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,15 +17,14 @@
package org.jivesoftware.smack.sasl;
import org.jivesoftware.smack.DummyConnection;
import org.jivesoftware.smack.XMPPConnection;
public class AbstractSaslTest {
protected final XMPPConnection xmppConnection = new DummyConnection();
protected final DummyConnection xmppConnection = new DummyConnection();
protected final SASLMechanism saslMechanism;
protected AbstractSaslTest(SASLMechanism saslMechanism) {
this.saslMechanism = saslMechanism.instanceForAuthentication(xmppConnection);
this.saslMechanism = saslMechanism.instanceForAuthentication(xmppConnection, xmppConnection.getConfiguration());
}
}

View file

@ -43,7 +43,7 @@ public class DigestMd5SaslTest extends AbstractSaslTest {
if (useAuthzid) {
authzid = JidCreate.entityBareFrom("shazbat@xmpp.org");
}
saslMechanism.authenticate("florian", "irrelevant", JidCreate.domainBareFrom("xmpp.org"), "secret", authzid);
saslMechanism.authenticate("florian", "irrelevant", JidCreate.domainBareFrom("xmpp.org"), "secret", authzid, null);
byte[] response = saslMechanism.evaluateChallenge(challengeBytes);
String responseString = new String(response);
String[] responseParts = responseString.split(",");

View file

@ -48,9 +48,9 @@ public class SCRAMSHA1MechanismTest extends SmackTestSuite {
}
};
mech.authenticate(USERNAME, "unusedFoo", JidTestUtil.DOMAIN_BARE_JID_1, PASSWORD, null);
mech.authenticate(USERNAME, "unusedFoo", JidTestUtil.DOMAIN_BARE_JID_1, PASSWORD, null, null);
AuthMechanism authMechanism = con.getSentPacket();
assertEquals((new SCRAMSHA1Mechanism().getName()), authMechanism.getMechanism());
assertEquals(SCRAMSHA1Mechanism.NAME, authMechanism.getMechanism());
assertEquals(CLIENT_FIRST_MESSAGE, saslLayerString(authMechanism.getAuthenticationText()));
mech.challengeReceived(Base64.encode(SERVER_FIRST_MESSAGE), false);

View file

@ -91,6 +91,7 @@ import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
@ -160,7 +161,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
*/
private boolean disconnectedButResumeable = false;
private boolean usingTLS = false;
private SSLSocket secureSocket;
/**
* Protected access level because of unit test purposes
@ -380,7 +381,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
protected synchronized void loginInternal(String username, String password, Resourcepart resource) throws XMPPException,
SmackException, IOException, InterruptedException {
// Authenticate using SASL
saslAuthentication.authenticate(username, password, config.getAuthzid());
SSLSession sslSession = secureSocket != null ? secureSocket.getSession() : null;
saslAuthentication.authenticate(username, password, config.getAuthzid(), sslSession);
// If compression is enabled then request the server to use stream compression. XEP-170
// recommends to perform stream compression before resource binding.
@ -442,7 +444,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
@Override
public boolean isSecureConnection() {
return usingTLS;
return secureSocket != null;
}
/**
@ -519,7 +521,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
}
authenticated = false;
connected = false;
usingTLS = false;
secureSocket = null;
reader = null;
writer = null;
@ -801,7 +803,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
}
// Set that TLS was successful
usingTLS = true;
secureSocket = sslSocket;
}
/**