diff --git a/README.md b/README.md
index 618617759..d5e3f973f 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ Instructions on how to use Smack in your Java or Android project are provided in
License
-------
-Most of Smack is governed by the Apache License 2.0 (SPDX License Identifier: Apache 2.0). This license requires that the contents of a NOICE text file are shown "…within a display generated by the Derivative Works, if and wherever such third-party notices normally appear.".
+Most of Smack is governed by the Apache License 2.0 (SPDX License Identifier: Apache 2.0). This license requires that the contents of a NOTICE text file are shown "…within a display generated by the Derivative Works, if and wherever such third-party notices normally appear.".
Smack comes which such a NOTICE file. Moreover, since `smack-core` is licensed under the Apache License 2.0, the conditions apply to every project using Smack. The content of Smack's NOTICE file can conveniently be retrieved using `Smack.getNoticeStream()`.
diff --git a/resources/javadoc-overview.html b/resources/javadoc-overview.html
index 1b92b1739..4f63c64a8 100644
--- a/resources/javadoc-overview.html
+++ b/resources/javadoc-overview.html
@@ -14,15 +14,35 @@
AbstractXMPPConnection connection = new XMPPTCPConnection("mtucker", "password", "jabber.org");
connection.connect().login();
-Message message = new Message("jsmith@igniterealtime.org", "Howdy! How are you?");
+Message message = connection.getStanzaFactory()
+ .buildMessageStanza()
+ .to("jsmith@igniterealtime.org")
+ .setBody("Howdy! How are you?")
+ .build();
+
connection.sendStanza(message);
+
+connection.disconnect();
Smack doesn't force you to code at the protcol level of XMPP. The library provides intelligent higher level constructs, often called {@link org.jivesoftware.smack.Manager}, which let you program more efficiently. Other examples of those constructs are the Chat and Roster classes.
Smack comes with APIs for easy machine-to-machine communication. You can set any number of properties on each message, including properties that are Java objects.
- Smack is open-source under the Apache License 2.0, which means you can incorporate Smack into your commercial or non-commercial applications.
+ License
+
+ Smack is open-source and most parts are under the Apache License
+ 2.0, which means you can incorporate Smack into your commercial or
+ non-commercial applications. Some parts of Smack may be under a
+ different open-source license. Please refer to the individual
+ subprojects for their license statement.
+
+ Note that the Apache License 2.0 requires that the contents of a
+ NOICE text file are shown "…within a display generated by the
+ Derivative Works, if and wherever such third-party notices normally
+ appear.". Smack comes with such a NOTICE file. The content of
+ Smack's NOTICE file can conveniently be retrieved using
+ {@link org.jivesoftware.smack.Smack#getNoticeStream}.
About XMPP
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java
index 4a930003f..f12ff85e0 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java
@@ -1407,6 +1407,13 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
return successNonza;
}
+ private void maybeNotifyDebuggerAboutIncoming(TopLevelStreamElement incomingTopLevelStreamElement) {
+ final SmackDebugger debugger = this.debugger;
+ if (debugger != null) {
+ debugger.onIncomingStreamElement(incomingTopLevelStreamElement);
+ }
+ }
+
protected final void parseAndProcessNonza(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
ParserUtils.assertAtStartTag(parser);
@@ -1435,6 +1442,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
Nonza nonza = nonzaProvider.parse(parser, incomingStreamXmlEnvironment);
+ maybeNotifyDebuggerAboutIncoming(nonza);
+
for (NonzaCallback nonzaCallback : nonzaCallbacks) {
nonzaCallback.onNonzaReceived(nonza);
}
@@ -1474,10 +1483,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
protected void processStanza(final Stanza stanza) throws InterruptedException {
assert stanza != null;
- final SmackDebugger debugger = this.debugger;
- if (debugger != null) {
- debugger.onIncomingStreamElement(stanza);
- }
+ maybeNotifyDebuggerAboutIncoming(stanza);
lastStanzaReceived = System.currentTimeMillis();
// Deliver the incoming packet to listeners.
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SASLAuthentication.java b/smack-core/src/main/java/org/jivesoftware/smack/SASLAuthentication.java
index 650212d09..4685bf4af 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/SASLAuthentication.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/SASLAuthentication.java
@@ -42,6 +42,7 @@ import org.jivesoftware.smack.sasl.core.ScramSha1PlusMechanism;
import org.jivesoftware.smack.sasl.packet.SaslNonza;
import org.jivesoftware.smack.sasl.packet.SaslNonza.SASLFailure;
import org.jivesoftware.smack.sasl.packet.SaslNonza.Success;
+import org.jivesoftware.smack.util.StringUtils;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.EntityBareJid;
@@ -184,7 +185,7 @@ public final class SASLAuthentication {
SASLMechanism authenticate(String username, String password, EntityBareJid authzid, SSLSession sslSession)
throws XMPPErrorException, SASLErrorException, IOException,
InterruptedException, SmackSaslException, NotConnectedException, NoResponseException {
- final SASLMechanism mechanism = selectMechanism(authzid);
+ final SASLMechanism mechanism = selectMechanism(authzid, password);
final CallbackHandler callbackHandler = configuration.getCallbackHandler();
final String host = connection.getHost();
final DomainBareJid xmppServiceDomain = connection.getXMPPServiceDomain();
@@ -311,34 +312,48 @@ public final class SASLAuthentication {
return lastUsedMech.getName();
}
- private SASLMechanism selectMechanism(EntityBareJid authzid) throws SmackException.SmackSaslException {
+ private SASLMechanism selectMechanism(EntityBareJid authzid, String password) throws SmackException.SmackSaslException {
+ final boolean passwordAvailable = StringUtils.isNotEmpty(password);
+
Iterator it = REGISTERED_MECHANISMS.iterator();
final List serverMechanisms = getServerMechanisms();
if (serverMechanisms.isEmpty()) {
LOGGER.warning("Server did not report any SASL mechanisms");
}
+
+ List skipReasons = new ArrayList<>();
+
// Iterate in SASL Priority order over registered mechanisms
while (it.hasNext()) {
SASLMechanism mechanism = it.next();
String mechanismName = mechanism.getName();
+
+ if (!serverMechanisms.contains(mechanismName)) {
+ continue;
+ }
+
synchronized (BLACKLISTED_MECHANISMS) {
if (BLACKLISTED_MECHANISMS.contains(mechanismName)) {
continue;
}
}
+
if (!configuration.isEnabledSaslMechanism(mechanismName)) {
continue;
}
- if (authzid != null) {
- if (!mechanism.authzidSupported()) {
- LOGGER.fine("Skipping " + mechanism + " because authzid is required by not supported by this SASL mechanism");
- continue;
- }
+
+ if (authzid != null && !mechanism.authzidSupported()) {
+ skipReasons.add("Skipping " + mechanism + " because authzid is required by not supported by this SASL mechanism");
+ continue;
}
- if (serverMechanisms.contains(mechanismName)) {
- // Create a new instance of the SASLMechanism for every authentication attempt.
- return mechanism.instanceForAuthentication(connection, configuration);
+
+ if (mechanism.requiresPassword() && !passwordAvailable) {
+ skipReasons.add("Skipping " + mechanism + " because a password is required for it, but none was provided to the connection configuration");
+ continue;
}
+
+ // Create a new instance of the SASLMechanism for every authentication attempt.
+ return mechanism.instanceForAuthentication(connection, configuration);
}
synchronized (BLACKLISTED_MECHANISMS) {
@@ -348,7 +363,8 @@ public final class SASLAuthentication {
"Server announced mechanisms: " + serverMechanisms + ". " +
"Registered SASL mechanisms with Smack: " + REGISTERED_MECHANISMS + ". " +
"Enabled SASL mechanisms for this connection: " + configuration.getEnabledSaslMechanisms() + ". " +
- "Blacklisted SASL mechanisms: " + BLACKLISTED_MECHANISMS + '.'
+ "Blacklisted SASL mechanisms: " + BLACKLISTED_MECHANISMS + ". " +
+ "Skip reasons: " + skipReasons
);
// @formatter;on
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/Smack.java b/smack-core/src/main/java/org/jivesoftware/smack/Smack.java
index 690b9bb2d..6608bba4b 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/Smack.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/Smack.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright 2020 Florian Schmaus
+ * Copyright 2020-2021 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@ package org.jivesoftware.smack;
import java.io.InputStream;
import java.util.logging.Logger;
+import org.jivesoftware.smack.util.FileUtils;
+
public class Smack {
private static final Logger LOGGER = Logger.getLogger(Smack.class.getName());
@@ -38,8 +40,20 @@ public class Smack {
private static final String NOTICE_RESOURCE = SMACK_PACKAGE + "/NOTICE";
+ /**
+ * Get the stream of the NOTICE file of Smack.
+ *
+ * This license of Smack requires that the contents of this NOTICE text file are shown "…within a display generated by
+ * the Derivative Works, if and wherever such third-party notices normally appear.".
+ *
+ *
+ * @return the stream of the NOTICE file of Smack.
+ * @since 4.4.0
+ */
public static InputStream getNoticeStream() {
- return ClassLoader.getSystemResourceAsStream(NOTICE_RESOURCE);
+ InputStream res = FileUtils.getInputStreamForClasspathFile(NOTICE_RESOURCE);
+ assert res != null;
+ return res;
}
public static void ensureInitialized() {
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/SASLMechanism.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/SASLMechanism.java
index e821e8e91..f1c00ef19 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/sasl/SASLMechanism.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/SASLMechanism.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright 2003-2007 Jive Software, 2014-2019 Florian Schmaus
+ * Copyright 2003-2007 Jive Software, 2014-2021 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -311,6 +311,10 @@ public abstract class SASLMechanism implements Comparable {
return false;
}
+ public boolean requiresPassword() {
+ return true;
+ }
+
public boolean isAuthenticationSuccessful() {
return authenticationSuccessful;
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/FileUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/FileUtils.java
index 2cdac90a4..7cb4bd0d9 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/util/FileUtils.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/util/FileUtils.java
@@ -41,6 +41,19 @@ public final class FileUtils {
private static final Logger LOGGER = Logger.getLogger(FileUtils.class.getName());
+ public static InputStream getInputStreamForClasspathFile(String path) {
+ return getInputStreamForClasspathFile(path, null);
+ }
+
+ public static InputStream getInputStreamForClasspathFile(String path, ClassLoader loader) {
+ try {
+ return getStreamForClasspathFile(path, loader);
+ } catch (IOException e) {
+ LOGGER.log(Level.FINE, "Suppressed IOException in getInputStreamForClasspathFile", e);
+ return null;
+ }
+ }
+
public static InputStream getStreamForClasspathFile(String path, ClassLoader loader) throws IOException {
// Get an array of class loaders to try loading the providers files from.
List classLoaders = getClassLoaders();
diff --git a/smack-sasl-javax/src/main/java/org/jivesoftware/smack/sasl/javax/SASLExternalMechanism.java b/smack-sasl-javax/src/main/java/org/jivesoftware/smack/sasl/javax/SASLExternalMechanism.java
index 83500d5c1..d0f24e537 100644
--- a/smack-sasl-javax/src/main/java/org/jivesoftware/smack/sasl/javax/SASLExternalMechanism.java
+++ b/smack-sasl-javax/src/main/java/org/jivesoftware/smack/sasl/javax/SASLExternalMechanism.java
@@ -65,4 +65,9 @@ public class SASLExternalMechanism extends SASLJavaXMechanism {
public SASLExternalMechanism newInstance() {
return new SASLExternalMechanism();
}
+
+ @Override
+ public boolean requiresPassword() {
+ return false;
+ }
}
diff --git a/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLExternalMechanism.java b/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLExternalMechanism.java
index cf5fea0af..f1cd947d4 100644
--- a/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLExternalMechanism.java
+++ b/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLExternalMechanism.java
@@ -76,4 +76,8 @@ public class SASLExternalMechanism extends SASLMechanism {
return true;
}
+ @Override
+ public boolean requiresPassword() {
+ return false;
+ }
}