diff --git a/smack-core/build.gradle b/smack-core/build.gradle index 9a8bd757d5..30633d5c29 100644 --- a/smack-core/build.gradle +++ b/smack-core/build.gradle @@ -10,6 +10,7 @@ dependencies { compile "org.jxmpp:jxmpp-core:$jxmppVersion" compile "org.jxmpp:jxmpp-jid:$jxmppVersion" compile "org.minidns:minidns-core:$miniDnsVersion" + compile "org.bouncycastle:bcprov-jdk15on:$bouncyCastleVersion" testFixturesImplementation project(':smack-xmlparser-stax') testFixturesImplementation project(':smack-xmlparser-xpp3') diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiContext.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiContext.java new file mode 100644 index 0000000000..fdd418b6f7 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiContext.java @@ -0,0 +1,5 @@ +package org.jivesoftware.smack.sasl.gssApi; + +public class GssApiContext extends GssContext { + +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiManager.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiManager.java new file mode 100644 index 0000000000..c8c2d5e52c --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiManager.java @@ -0,0 +1,72 @@ +package org.jivesoftware.smack.sasl.gssApi; + +import org.ietf.jgss.*; +import org.jivesoftware.smack.XMPPConnection; + +import java.security.Provider; + +public class GssApiManager { + + GSSManager gssManager; + GSSName userName = null; + GSSName serverName = null; + GSSCredential userCredential = null; + GSSContext clientContext = null; + + Oid objectIdentifiers; + byte[] clientToken; + + private static GssApiManager gssApiManager = null; + + public static synchronized GssApiManager getInstanceFor(XMPPConnection connection) { + if (gssApiManager == null) { + return new GssApiManager(connection); + } + return gssApiManager; + } + + private GssApiManager(XMPPConnection connection){ + gssManager = GSSManager.getInstance(); + + try { + userName = gssManager.createName(connection.getUser().asEntityBareJid().asEntityBareJidString(),GSSName.NT_USER_NAME); + serverName = gssManager.createName(connection.getHost(),objectIdentifiers); + userCredential = gssManager.createCredential(userName,GSSCredential.DEFAULT_LIFETIME,objectIdentifiers,GSSCredential.INITIATE_ONLY); + clientContext = gssManager.createContext(serverName,objectIdentifiers,userCredential,GSSContext.DEFAULT_LIFETIME); + clientContext.requestMutualAuth(true); + clientContext.requestConf(true); + clientContext.requestInteg(true); + } catch (GSSException e) { + e.printStackTrace(); + } + } + + public byte[] authenticate() throws GSSException { + clientToken = clientContext.initSecContext(new byte[0], 0, 0); + + // Send client token over the network + return clientToken; + } + + public byte[] acceptServerToken(byte[] serverToken) { + try { + return clientContext.initSecContext(serverToken,0,serverToken.length); + } catch (GSSException e) { + e.printStackTrace(); + return null; + } + } + + public boolean isContextEstablished() { + return clientContext.isEstablished(); + } + + public byte[] sendData(byte[] messageBytes) throws GSSException { + MessageProp clientProp = new MessageProp(0,true); + clientToken = clientContext.wrap(messageBytes,0,messageBytes.length,clientProp); + + // Send client token over the network + return clientToken; + } + +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanism.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanism.java new file mode 100644 index 0000000000..5501d92826 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanism.java @@ -0,0 +1,168 @@ +/** + * + * Copyright 2020 Aditya Borikar + * + * 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.gssApi; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; + +import javax.security.auth.callback.CallbackHandler; + +import org.ietf.jgss.*; +import org.jivesoftware.smack.SmackException.SmackSaslException; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.sasl.SASLMechanism; + +import org.jivesoftware.smack.util.SHA1; +import org.jivesoftware.smack.util.stringencoder.Base32; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * Use of GSS-API mechanism in SASL by defining a new SASL mechanism family called GS2. + * This mechanism offers a number of improvements over the previous "SASL/GSSAPI" mechanism. + * In general, it uses fewer messages for authentication phase in some cases, and supports negotiable use of channel binding. + * Only GSS-API mechanisms that support channel binding and mutual authentication are supported. + *
+ * The absence of `PLUS` suffix in the name `GSS-API` suggests that the server doesn't support channel binding. + *
+ * SASL implementations can use the GSS_Inquire_SASLname_for_mech call + * to query for the SASL mechanism name of a GSS-API mechanism. + *
+ * If the GSS_Inquire_SASLname_for_mech interface is not used, the GS2 + * implementation needs some other mechanism to map mechanism Object + * Identifiers (OIDs) to SASL names internally. + *
+ * In this case, the implementation can only support the mechanisms for which it knows the + * SASL name. + * + * @author adiaholic + */ +public class GssApiMechanism extends SASLMechanism{ + + public static final String NAME = "GSS-API"; + + public static final String GS2_PREFIX = "GS2-"; + + private Oid objectIdentifiers = null; + + private GssApiManager gssApiManager = null; + + GssApiMechanism(Oid oid, XMPPConnection connection) { + super(); + this.connection = connection; + gssApiManager = GssApiManager.getInstanceFor(connection); + setObjectIdentifier(oid); + } + + @Override + protected byte[] getAuthenticationText() throws SmackSaslException { + try { + return gssApiManager.authenticate(); + } catch (GSSException e) { + e.printStackTrace(); + return null; + } + } + + @Override + protected byte[] evaluateChallenge(byte[] challenge) throws SmackSaslException { + return gssApiManager.acceptServerToken(challenge); + } + + /* + * The SASL Mechanism name is concatenation of the string "GS2-" and the + * Base32 encoding of the first 55 bits of the binary SHA-1 hash string + * computed over the ASN.1 DER encoding + *
+ * Note : Some older GSS-API mechanisms were not specified with a SASL GS2 mechanism name. + */ + public String generateSASLMechanismNameFromGSSApiOIDs (String objectIdentifier) throws NoSuchAlgorithmException, IOException { + + // To generate a SHA-1 hash string over ASN1.DER. + byte[] ASN1_DER = getASN1DERencoding(objectIdentifier); + String sha1_hash = SHA1.hex(ASN1_DER); + + // Obtain first 55 bits of the SHA-1 hash. + String binary55Bits = getbinary55Bits(sha1_hash); + + // Make groups of 5 bits each + String[] binaryGroups = new String[11]; + for (int i = 0 ; i < binary55Bits.length() / 5 ; i++) { + String binaryGroup = ""; + for (int j = 0 ; j < 5 ; j++) { + binaryGroup += binary55Bits.charAt(5 * i + j); + } + // int decimalForGroup = Integer.parseInt(binaryGroup,2); + + binaryGroups[i] = binaryGroup; + } + + // Base32 encoding for the above binaryGroups + String base32Encoding = ""; + for (int i = 0 ; i < 11 ; i++) { + int decimalValue = Integer.parseInt(binaryGroups[i], 2); + base32Encoding += Base32.encodeIntValue(decimalValue); + } + return GS2_PREFIX + base32Encoding; + } + + private static String getbinary55Bits(String sha1_hash) { + // Get first 7 octets. + String first7Octets = sha1_hash.substring(0, 14); + + // Convert first 7 octets of the sha1 hash into binary. + String binaryOctets = new BigInteger(first7Octets, 16).toString(2); + + // Return first 55 bits of the binary hash. + return binaryOctets.substring(0, 55); + } + + public byte[] getASN1DERencoding(String objectIdentifier) throws IOException { + ASN1ObjectIdentifier asn1ObjectIdentifier = new ASN1ObjectIdentifier(objectIdentifier).intern(); + byte[] encoded = asn1ObjectIdentifier.getEncoded(); + return encoded; + } + + @Override + protected void authenticateInternal(CallbackHandler cbh) throws SmackSaslException { + } + + @Override + public String getName() { + return NAME; + } + + @Override + public int getPriority() { + return 0; + } + + @Override + protected void checkIfSuccessfulOrThrow() throws SmackSaslException { + } + + @Override + protected GssApiMechanism newInstance() { + return new GssApiMechanism(null,null); + } + + public void setObjectIdentifier(Oid oid) { + this.objectIdentifiers = oid; + } + +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiPlusMechanism.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiPlusMechanism.java new file mode 100644 index 0000000000..fc35dbfb6a --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiPlusMechanism.java @@ -0,0 +1,58 @@ +/** + * + * Copyright 2020 Aditya Borikar + * + * 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.gssApi; + +import javax.security.auth.callback.CallbackHandler; + +import org.jivesoftware.smack.SmackException.SmackSaslException; +import org.jivesoftware.smack.sasl.SASLMechanism; + +/** + * The plus inside the GSS-API-plus mechanism name suggests that the server supports channel binding. + * + * @author adiaholic + */ +public class GssApiPlusMechanism extends SASLMechanism{ + + @Override + protected void authenticateInternal(CallbackHandler cbh) throws SmackSaslException { + } + + @Override + protected byte[] getAuthenticationText() throws SmackSaslException { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public int getPriority() { + return 0; + } + + @Override + protected void checkIfSuccessfulOrThrow() throws SmackSaslException { + } + + @Override + protected SASLMechanism newInstance() { + return null; + } +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssContext.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssContext.java new file mode 100644 index 0000000000..3730072efb --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssContext.java @@ -0,0 +1,208 @@ +package org.jivesoftware.smack.sasl.gssApi; + +import org.ietf.jgss.*; + +import java.io.InputStream; +import java.io.OutputStream; + +public class GssContext implements GSSContext { + @Override + public byte[] initSecContext(byte[] bytes, int i, int i1) throws GSSException { + return new byte[0]; + } + + @Override + public int initSecContext(InputStream inputStream, OutputStream outputStream) throws GSSException { + return 0; + } + + @Override + public byte[] acceptSecContext(byte[] bytes, int i, int i1) throws GSSException { + return new byte[0]; + } + + @Override + public void acceptSecContext(InputStream inputStream, OutputStream outputStream) throws GSSException { + + } + + @Override + public boolean isEstablished() { + return false; + } + + @Override + public void dispose() throws GSSException { + + } + + @Override + public int getWrapSizeLimit(int i, boolean b, int i1) throws GSSException { + return 0; + } + + @Override + public byte[] wrap(byte[] bytes, int i, int i1, MessageProp messageProp) throws GSSException { + return new byte[0]; + } + + @Override + public void wrap(InputStream inputStream, OutputStream outputStream, MessageProp messageProp) throws GSSException { + + } + + @Override + public byte[] unwrap(byte[] bytes, int i, int i1, MessageProp messageProp) throws GSSException { + return new byte[0]; + } + + @Override + public void unwrap(InputStream inputStream, OutputStream outputStream, MessageProp messageProp) throws GSSException { + + } + + @Override + public byte[] getMIC(byte[] bytes, int i, int i1, MessageProp messageProp) throws GSSException { + return new byte[0]; + } + + @Override + public void getMIC(InputStream inputStream, OutputStream outputStream, MessageProp messageProp) throws GSSException { + + } + + @Override + public void verifyMIC(byte[] bytes, int i, int i1, byte[] bytes1, int i2, int i3, MessageProp messageProp) throws GSSException { + + } + + @Override + public void verifyMIC(InputStream inputStream, InputStream inputStream1, MessageProp messageProp) throws GSSException { + + } + + @Override + public byte[] export() throws GSSException { + return new byte[0]; + } + + @Override + public void requestMutualAuth(boolean b) throws GSSException { + + } + + @Override + public void requestReplayDet(boolean b) throws GSSException { + + } + + @Override + public void requestSequenceDet(boolean b) throws GSSException { + + } + + @Override + public void requestCredDeleg(boolean b) throws GSSException { + + } + + @Override + public void requestAnonymity(boolean b) throws GSSException { + + } + + @Override + public void requestConf(boolean b) throws GSSException { + + } + + @Override + public void requestInteg(boolean b) throws GSSException { + + } + + @Override + public void requestLifetime(int i) throws GSSException { + + } + + @Override + public void setChannelBinding(ChannelBinding channelBinding) throws GSSException { + + } + + @Override + public boolean getCredDelegState() { + return false; + } + + @Override + public boolean getMutualAuthState() { + return false; + } + + @Override + public boolean getReplayDetState() { + return false; + } + + @Override + public boolean getSequenceDetState() { + return false; + } + + @Override + public boolean getAnonymityState() { + return false; + } + + @Override + public boolean isTransferable() throws GSSException { + return false; + } + + @Override + public boolean isProtReady() { + return false; + } + + @Override + public boolean getConfState() { + return false; + } + + @Override + public boolean getIntegState() { + return false; + } + + @Override + public int getLifetime() { + return 0; + } + + @Override + public GSSName getSrcName() throws GSSException { + return null; + } + + @Override + public GSSName getTargName() throws GSSException { + return null; + } + + @Override + public Oid getMech() throws GSSException { + return null; + } + + @Override + public GSSCredential getDelegCred() throws GSSException { + return null; + } + + @Override + public boolean isInitiator() throws GSSException { + return false; + } +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssStatusCodes.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssStatusCodes.java new file mode 100644 index 0000000000..84783343ff --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssStatusCodes.java @@ -0,0 +1,55 @@ +/** + * + * Copyright 2020 Aditya Borikar + * + * 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.gssApi; + +public class GssStatusCodes { + + public enum FatalErrorCodes { + GSS_S_BAD_BINDINGS, // channel binding mismatch + GSS_S_BAD_MECH, // unsupported mechanism requested + GSS_S_BAD_NAME, // invalid name provided + GSS_S_BAD_NAMETYPE, // name of unsupported type provided + GSS_S_BAD_STATUS, // invalid input status selector + GSS_S_BAD_SIG, // token had invalid integrity check + GSS_S_BAD_MIC, // preferred alias for GSS_S_BAD_SIG + GSS_S_CONTEXT_EXPIRED, // specified security context expired + GSS_S_CREDENTIALS_EXPIRED, // expired credentials detected + GSS_S_DEFECTIVE_CREDENTIAL, // defective credential detected + GSS_S_DEFECTIVE_TOKEN, // defective token detected + GSS_S_FAILURE, // failure, unspecified at GSS-API level + GSS_S_NO_CONTEXT, // no valid security context specified + GSS_S_NO_CRED, // no valid credentials provided + GSS_S_BAD_QOP, // unsupported QOP value + GSS_S_UNAUTHORIZED, // operation unauthorized + GSS_S_UNAVAILABLE, // operation unavailable + GSS_S_DUPLICATE_ELEMENT, // duplicate credential element requested + GSS_S_NAME_NOT_MN // name contains multi-mechanism elements + } + + public enum InformatoryStatusCodes { + GSS_S_COMPLETE, // normal completion + GSS_S_CONTINUE_NEEDED, // continuation call to routine required + GSS_S_DUPLICATE_TOKEN, // duplicate per-message token detected + GSS_S_OLD_TOKEN, // timed-out per-message token detected + GSS_S_UNSEQ_TOKEN, // reordered (early) per-message token detected + GSS_S_GAP_TOKEN // skipped predecessor token(s) detected + } + + public static String OID_SimplePublicKeyGssApi = "1.3.6.1.5.5.1.1"; + public static String OID_Kerberos_V5_GssAPI = " 1.2.840.113554.1.2.2"; + +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/package-info.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/package-info.java new file mode 100644 index 0000000000..e80c0f143e --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/package-info.java @@ -0,0 +1,20 @@ +/** + * + * Copyright 2020 Aditya Borikar + * + * 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.gssApi; +/* + * Implementation for RFC 5801 : GSSAPI for SASL - The GS2 Mechanism Family. + */ diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/stringencoder/Base32.java b/smack-core/src/main/java/org/jivesoftware/smack/util/stringencoder/Base32.java index 9711ab8a50..87febc441f 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/stringencoder/Base32.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/stringencoder/Base32.java @@ -159,6 +159,10 @@ public static String encode(String str) { return res; } + public static char encodeIntValue(int i) { + return ALPHABET.charAt(i); + } + private static int lenToPadding(int blocklen) { switch (blocklen) { case 1: @@ -193,4 +197,4 @@ private static int paddingToLen(int padlen) { } } -} +} \ No newline at end of file diff --git a/smack-core/src/test/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanismTest.java b/smack-core/src/test/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanismTest.java new file mode 100644 index 0000000000..0c2f3f738a --- /dev/null +++ b/smack-core/src/test/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanismTest.java @@ -0,0 +1,95 @@ +/** + * + * Copyright 2020 Aditya Borikar + * + * 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.gssApi; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; + +import org.ietf.jgss.GSSException; +import org.ietf.jgss.Oid; +import org.jivesoftware.smack.DummyConnection; +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.test.util.SmackTestSuite; + +import org.junit.Test; +import org.jxmpp.jid.JidTestUtil; + +public class GssApiMechanismTest extends SmackTestSuite { + + public static final String OID = "1.2.840.113554.1.2.2"; + public static final String ASN_1_DER_of_OID_in_HEX = "06092A864886F712010202"; + + public static final String SHA1_of_ASN_1_DER_in_HEX = "82d27325766bd6c845aa9325516afcff04b04360"; + + public static final String first_7_octets_to_binary_drop_last_bit = "1000001011010010011100110010010101110110011010111101011"; + public static final String binary_in_group_of_5 = "10000 01011 01001 00111 00110 01001 01011 10110 01101 01111 01011"; + public static final String decimal_of_each_group = "16 11 9 7 6 9 11 22 13 15 11"; + public static final String base32Encoding = "QLJHGJLWNPL"; + public static final String MECHANISM_NAME = "GS2-" + base32Encoding; + + @Test + public void generateASN1DERTest() throws IOException { + GssApiMechanism gssApiMechanism = new GssApiMechanism(null,null); + byte[] asn1DERencoding = gssApiMechanism.getASN1DERencoding(OID); + + String asn1_der_of_oid_in_hex = ""; + + for (byte b : asn1DERencoding) { + asn1_der_of_oid_in_hex += String.format("%02X", b); + } + assertEquals(ASN_1_DER_of_OID_in_HEX, asn1_der_of_oid_in_hex); + } + + @Test + public void getSubsequentOctetsTest() throws GSSException { + GssApiMechanism gssApiMechanism = new GssApiMechanism(new Oid(OID),null); + // System.out.println("First 2 octets : " + gssApiMechanism.generateFirstOctet()); + } + + @Test + public void generateMechanismName() throws IOException, NoSuchAlgorithmException, GSSException { + GssApiMechanism gssApiMechanism = new GssApiMechanism(new Oid(OID),null); + String mechanismName = gssApiMechanism.generateSASLMechanismNameFromGSSApiOIDs(OID); + assertEquals(MECHANISM_NAME, mechanismName); + } + + @Test + public void getLevelObjectIdentiferCompoentTest() throws GSSException { + GssApiMechanism gssApiMechanism = new GssApiMechanism(new Oid(OID),null); + // String component = gssApiMechanism.getLevelObjectIdentiferComponent(3); + // assertEquals("840",component); + } + + @Test + public void getSubsequentObjectIdentifierComponentTest() throws GSSException { + GssApiMechanism gssApiMechanism = new GssApiMechanism(new Oid(OID),null); + // String subsequentCompoents = gssApiMechanism.getSubsequentOctets(); + // System.out.println(subsequentCompoents + " : are the subsequent octets"); + } + + public static final String USERNAME = "user"; + public static final String PASSWORD = "pencil"; + + @Test + public void GssApiManagerTest() throws GSSException, SmackException.NotConnectedException, InterruptedException, SmackException.SmackSaslException { + + + + } +} diff --git a/smack-core/src/testFixtures/java/org/jivesoftware/smack/DummyConnection.java b/smack-core/src/testFixtures/java/org/jivesoftware/smack/DummyConnection.java index 135fd79d03..d3fc316eef 100644 --- a/smack-core/src/testFixtures/java/org/jivesoftware/smack/DummyConnection.java +++ b/smack-core/src/testFixtures/java/org/jivesoftware/smack/DummyConnection.java @@ -56,7 +56,7 @@ public class DummyConnection extends AbstractXMPPConnection { public static DummyConnectionConfiguration.Builder getDummyConfigurationBuilder() { return DummyConnectionConfiguration.builder().setXmppDomain(JidTestUtil.EXAMPLE_ORG).setUsernameAndPassword("dummy", - "dummypass"); + "dummypass").setHost("dummyHost"); } public DummyConnection() {