mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-22 03:52:06 +01:00
Ads support for SCRAM-SHA-1-PLUS
Related to SMACK-398.
This commit is contained in:
parent
44744de003
commit
1f1bc236fd
14 changed files with 252 additions and 63 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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(",");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue