mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-10-31 22:15:59 +01:00
Merge branch '4.4'
This commit is contained in:
commit
e04a3877fb
9 changed files with 103 additions and 21 deletions
|
@ -23,7 +23,7 @@ Instructions on how to use Smack in your Java or Android project are provided in
|
||||||
License
|
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()`.
|
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()`.
|
||||||
|
|
||||||
|
|
|
@ -14,15 +14,35 @@
|
||||||
AbstractXMPPConnection connection = new XMPPTCPConnection("mtucker", "password", "jabber.org");
|
AbstractXMPPConnection connection = new XMPPTCPConnection("mtucker", "password", "jabber.org");
|
||||||
connection.connect().login();
|
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.sendStanza(message);
|
||||||
|
|
||||||
|
connection.disconnect();
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>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.</p>
|
<p>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.</p>
|
||||||
|
|
||||||
<p>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.</p>
|
<p>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.</p>
|
||||||
|
|
||||||
<p>Smack is open-source under the Apache License 2.0, which means you can incorporate Smack into your commercial or non-commercial applications.</p>
|
<h2>License</h2>
|
||||||
|
|
||||||
|
<p>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.</p>
|
||||||
|
|
||||||
|
<p>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}.</p>
|
||||||
|
|
||||||
<h2>About XMPP</h2>
|
<h2>About XMPP</h2>
|
||||||
|
|
||||||
|
|
|
@ -1407,6 +1407,13 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
return successNonza;
|
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 {
|
protected final void parseAndProcessNonza(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
|
||||||
ParserUtils.assertAtStartTag(parser);
|
ParserUtils.assertAtStartTag(parser);
|
||||||
|
|
||||||
|
@ -1435,6 +1442,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
|
|
||||||
Nonza nonza = nonzaProvider.parse(parser, incomingStreamXmlEnvironment);
|
Nonza nonza = nonzaProvider.parse(parser, incomingStreamXmlEnvironment);
|
||||||
|
|
||||||
|
maybeNotifyDebuggerAboutIncoming(nonza);
|
||||||
|
|
||||||
for (NonzaCallback nonzaCallback : nonzaCallbacks) {
|
for (NonzaCallback nonzaCallback : nonzaCallbacks) {
|
||||||
nonzaCallback.onNonzaReceived(nonza);
|
nonzaCallback.onNonzaReceived(nonza);
|
||||||
}
|
}
|
||||||
|
@ -1474,10 +1483,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
protected void processStanza(final Stanza stanza) throws InterruptedException {
|
protected void processStanza(final Stanza stanza) throws InterruptedException {
|
||||||
assert stanza != null;
|
assert stanza != null;
|
||||||
|
|
||||||
final SmackDebugger debugger = this.debugger;
|
maybeNotifyDebuggerAboutIncoming(stanza);
|
||||||
if (debugger != null) {
|
|
||||||
debugger.onIncomingStreamElement(stanza);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastStanzaReceived = System.currentTimeMillis();
|
lastStanzaReceived = System.currentTimeMillis();
|
||||||
// Deliver the incoming packet to listeners.
|
// Deliver the incoming packet to listeners.
|
||||||
|
|
|
@ -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;
|
||||||
import org.jivesoftware.smack.sasl.packet.SaslNonza.SASLFailure;
|
import org.jivesoftware.smack.sasl.packet.SaslNonza.SASLFailure;
|
||||||
import org.jivesoftware.smack.sasl.packet.SaslNonza.Success;
|
import org.jivesoftware.smack.sasl.packet.SaslNonza.Success;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
import org.jxmpp.jid.DomainBareJid;
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
|
@ -184,7 +185,7 @@ public final class SASLAuthentication {
|
||||||
SASLMechanism authenticate(String username, String password, EntityBareJid authzid, SSLSession sslSession)
|
SASLMechanism authenticate(String username, String password, EntityBareJid authzid, SSLSession sslSession)
|
||||||
throws XMPPErrorException, SASLErrorException, IOException,
|
throws XMPPErrorException, SASLErrorException, IOException,
|
||||||
InterruptedException, SmackSaslException, NotConnectedException, NoResponseException {
|
InterruptedException, SmackSaslException, NotConnectedException, NoResponseException {
|
||||||
final SASLMechanism mechanism = selectMechanism(authzid);
|
final SASLMechanism mechanism = selectMechanism(authzid, password);
|
||||||
final CallbackHandler callbackHandler = configuration.getCallbackHandler();
|
final CallbackHandler callbackHandler = configuration.getCallbackHandler();
|
||||||
final String host = connection.getHost();
|
final String host = connection.getHost();
|
||||||
final DomainBareJid xmppServiceDomain = connection.getXMPPServiceDomain();
|
final DomainBareJid xmppServiceDomain = connection.getXMPPServiceDomain();
|
||||||
|
@ -311,34 +312,48 @@ public final class SASLAuthentication {
|
||||||
return lastUsedMech.getName();
|
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<SASLMechanism> it = REGISTERED_MECHANISMS.iterator();
|
Iterator<SASLMechanism> it = REGISTERED_MECHANISMS.iterator();
|
||||||
final List<String> serverMechanisms = getServerMechanisms();
|
final List<String> serverMechanisms = getServerMechanisms();
|
||||||
if (serverMechanisms.isEmpty()) {
|
if (serverMechanisms.isEmpty()) {
|
||||||
LOGGER.warning("Server did not report any SASL mechanisms");
|
LOGGER.warning("Server did not report any SASL mechanisms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> skipReasons = new ArrayList<>();
|
||||||
|
|
||||||
// Iterate in SASL Priority order over registered mechanisms
|
// Iterate in SASL Priority order over registered mechanisms
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
SASLMechanism mechanism = it.next();
|
SASLMechanism mechanism = it.next();
|
||||||
String mechanismName = mechanism.getName();
|
String mechanismName = mechanism.getName();
|
||||||
|
|
||||||
|
if (!serverMechanisms.contains(mechanismName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (BLACKLISTED_MECHANISMS) {
|
synchronized (BLACKLISTED_MECHANISMS) {
|
||||||
if (BLACKLISTED_MECHANISMS.contains(mechanismName)) {
|
if (BLACKLISTED_MECHANISMS.contains(mechanismName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!configuration.isEnabledSaslMechanism(mechanismName)) {
|
if (!configuration.isEnabledSaslMechanism(mechanismName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (authzid != null) {
|
|
||||||
if (!mechanism.authzidSupported()) {
|
if (authzid != null && !mechanism.authzidSupported()) {
|
||||||
LOGGER.fine("Skipping " + mechanism + " because authzid is required by not supported by this SASL mechanism");
|
skipReasons.add("Skipping " + mechanism + " because authzid is required by not supported by this SASL mechanism");
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (serverMechanisms.contains(mechanismName)) {
|
|
||||||
// Create a new instance of the SASLMechanism for every authentication attempt.
|
if (mechanism.requiresPassword() && !passwordAvailable) {
|
||||||
return mechanism.instanceForAuthentication(connection, configuration);
|
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) {
|
synchronized (BLACKLISTED_MECHANISMS) {
|
||||||
|
@ -348,7 +363,8 @@ public final class SASLAuthentication {
|
||||||
"Server announced mechanisms: " + serverMechanisms + ". " +
|
"Server announced mechanisms: " + serverMechanisms + ". " +
|
||||||
"Registered SASL mechanisms with Smack: " + REGISTERED_MECHANISMS + ". " +
|
"Registered SASL mechanisms with Smack: " + REGISTERED_MECHANISMS + ". " +
|
||||||
"Enabled SASL mechanisms for this connection: " + configuration.getEnabledSaslMechanisms() + ". " +
|
"Enabled SASL mechanisms for this connection: " + configuration.getEnabledSaslMechanisms() + ". " +
|
||||||
"Blacklisted SASL mechanisms: " + BLACKLISTED_MECHANISMS + '.'
|
"Blacklisted SASL mechanisms: " + BLACKLISTED_MECHANISMS + ". " +
|
||||||
|
"Skip reasons: " + skipReasons
|
||||||
);
|
);
|
||||||
// @formatter;on
|
// @formatter;on
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2020 Florian Schmaus
|
* Copyright 2020-2021 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.io.InputStream;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.FileUtils;
|
||||||
|
|
||||||
public class Smack {
|
public class Smack {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(Smack.class.getName());
|
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";
|
private static final String NOTICE_RESOURCE = SMACK_PACKAGE + "/NOTICE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the stream of the NOTICE file of Smack.
|
||||||
|
* <p>
|
||||||
|
* 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.".
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return the stream of the NOTICE file of Smack.
|
||||||
|
* @since 4.4.0
|
||||||
|
*/
|
||||||
public static InputStream getNoticeStream() {
|
public static InputStream getNoticeStream() {
|
||||||
return ClassLoader.getSystemResourceAsStream(NOTICE_RESOURCE);
|
InputStream res = FileUtils.getInputStreamForClasspathFile(NOTICE_RESOURCE);
|
||||||
|
assert res != null;
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureInitialized() {
|
public static void ensureInitialized() {
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -311,6 +311,10 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean requiresPassword() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAuthenticationSuccessful() {
|
public boolean isAuthenticationSuccessful() {
|
||||||
return authenticationSuccessful;
|
return authenticationSuccessful;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,19 @@ public final class FileUtils {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(FileUtils.class.getName());
|
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 {
|
public static InputStream getStreamForClasspathFile(String path, ClassLoader loader) throws IOException {
|
||||||
// Get an array of class loaders to try loading the providers files from.
|
// Get an array of class loaders to try loading the providers files from.
|
||||||
List<ClassLoader> classLoaders = getClassLoaders();
|
List<ClassLoader> classLoaders = getClassLoaders();
|
||||||
|
|
|
@ -65,4 +65,9 @@ public class SASLExternalMechanism extends SASLJavaXMechanism {
|
||||||
public SASLExternalMechanism newInstance() {
|
public SASLExternalMechanism newInstance() {
|
||||||
return new SASLExternalMechanism();
|
return new SASLExternalMechanism();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresPassword() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,4 +76,8 @@ public class SASLExternalMechanism extends SASLMechanism {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresPassword() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue