Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions i18n/src/main/resources/openfire_i18n.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,11 @@ session.details.hide-extended=Show Less Details
session.details.show-extended=Show More Details
session.details.security=Security
session.details.features=Features & Functionality
session.details.bind-method=Bind Method
session.details.bind-method-bind2=Bind 2 (inline, XEP-0386)
session.details.bind-method-legacy=Resource Binding (legacy IQ)
session.details.bind2-inline-features=Bind 2 Inline Features
session.details.negotiated-via-bind2=negotiated via Bind 2

# Session row Page

Expand Down
5 changes: 5 additions & 0 deletions i18n/src/main/resources/openfire_i18n_nl.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1756,6 +1756,11 @@ session.details.hide-extended=Toon Minder Details
session.details.show-extended=Toon Meer Details
session.details.security=Beveiliging
session.details.features=Functies & Functionaliteit
session.details.bind-method=Bindmethode
session.details.bind-method-bind2=Bind 2 (inline, XEP-0386)
session.details.bind-method-legacy=Resource-binding (verouderde IQ)
session.details.bind2-inline-features=Bind 2 inline-functies
session.details.negotiated-via-bind2=onderhandeld via Bind 2

# Session row Page

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.jivesoftware.openfire.net.Bind2InlineHandler;
import org.jivesoftware.openfire.net.Bind2Request;
import org.jivesoftware.openfire.session.LocalClientSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
Expand Down Expand Up @@ -67,17 +69,28 @@ public synchronized void stop() {
*/
static class Bind2CSIHandler implements Bind2InlineHandler
{
private static final Logger Log = LoggerFactory.getLogger(Bind2CSIHandler.class);

@Override
public String getNamespace() {
return CsiManager.NAMESPACE;
}

@Override
public boolean handleElement(LocalClientSession session, Element bound, Element element) {
public String getDisplayName() {
return "Client State Indication";
}

@Override
public boolean handleElement(LocalClientSession session, Element bound, Element element)
{
if (element.getName().equals("active")) {
session.getCsiManager().activate();
} else if (element.getName().equals("inactive")) {
session.getCsiManager().deactivate();
} else {
Log.debug("Received unexpected element '{}'; ignoring.", element.getName());
return false;
}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,35 @@
import org.dom4j.Element;
import org.jivesoftware.openfire.net.Bind2InlineHandler;
import org.jivesoftware.openfire.session.LocalClientSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Handles inline elements related to Message Carbons during Bind2 requests.
*/
public class Bind2CarbonsHandler implements Bind2InlineHandler
{
private static final Logger Log = LoggerFactory.getLogger(Bind2CarbonsHandler.class);

public class Bind2CarbonsHandler implements Bind2InlineHandler {
@Override
public String getNamespace() {
return "urn:xmpp:carbons:2";
}

@Override
public boolean handleElement(LocalClientSession session, Element bound, Element element) {
session.setMessageCarbonsEnabled(element.getName().equals("enable"));
public String getDisplayName() {
return "Message Carbons";
}

@Override
public boolean handleElement(LocalClientSession session, Element bound, Element element)
{
final String name = element.getName();
if (!"enable".equals(name) && !"disable".equals(name)) {
Log.debug("Received unexpected element '{}'; ignoring.", element.getName());
return false;
}
session.setMessageCarbonsEnabled("enable".equals(name));
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ public String getNamespace() {
return StreamManager.NAMESPACE_V3;
}

@Override
public String getDisplayName() {
return "Stream Management";
}

@Override
public boolean isEnabled() {
return StreamManager.isStreamManagementActive();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ public interface Bind2InlineHandler {
*/
String getNamespace();

/**
* Gets a human-friendly name for this handler.
*
* @return a human-friendly name for this handler.
*/
default String getDisplayName() {
return getNamespace();
}

/**
* Process an inline element from a bind2 request.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ public class Bind2Request {
// Add a map to store registered handlers by namespace
private static final Map<String, Bind2InlineHandler> elementHandlers = new ConcurrentHashMap<>();

/**
* The namespaces of inline feature requests that were successfully processed
* during {@link #processFeatureRequests}, for observability purposes. Empty until that
* method has run.
*/
private Set<String> negotiatedFeatureNamespaces = Collections.emptySet();

/**
* Registers a handler for processing inline elements with a specific namespace.
*
Expand Down Expand Up @@ -103,27 +110,32 @@ public static boolean unregisterElementHandler(@Nonnull final Bind2InlineHandler
*/
public Element processFeatureRequests(LocalClientSession clientSession, Element successElement) {
Element bound = successElement.addElement(new QName("bound", new Namespace("", NAMESPACE)));
final Set<String> succeeded = new LinkedHashSet<>();

for (Element element : featureRequests) {
String namespace = element.getNamespaceURI();
Bind2InlineHandler handler = elementHandlers.get(namespace);

if (handler != null && handler.isEnabled()) {
try {
if (!handler.handleElement(clientSession, bound, element)) {
Log.info("Handler for namespace {} failed to process element", namespace);
if (handler.handleElement(clientSession, bound, element)) {
Log.trace("Handler for namespace {} successfully processed element for session: {}", namespace, clientSession);
succeeded.add(namespace);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} else {
Log.info("Handler for namespace {} failed to process element for session: {}", namespace, clientSession);
invokeFailureHandler(clientSession, bound, element, null, handler, namespace);
}
} catch (Exception e) {
Log.warn("Error processing element with namespace: {}", namespace, e);
Log.warn("Error processing element with namespace: {} for session: {}", namespace, clientSession, e);
invokeFailureHandler(clientSession, bound, element, e, handler, namespace);
}
} else {
Log.debug("No handler registered/enabled for namespace: {}", namespace);
Log.debug("No handler registered/enabled for namespace: {} for session: {}", namespace, clientSession);
// We don't fail here because there's no obvious way we could fail.
}
}

negotiatedFeatureNamespaces = Collections.unmodifiableSet(succeeded);
return bound;
}

Expand All @@ -147,6 +159,25 @@ private static void invokeFailureHandler(final LocalClientSession clientSession,
}
}

/**
* Returns the namespaces of inline feature requests that were successfully processed
* during {@link #processFeatureRequests}, for observability purposes. Empty until that
* method has run.
*/
public Set<String> getNegotiatedFeatureNamespaces() {
return negotiatedFeatureNamespaces;
}

/**
* Looks up the registered inline handler for a given namespace, if any.
*
* @param namespace The namespace to look up.
* @return An Optional containing the handler, or an empty Optional if no handler is registered for the namespace.
*/
public static Optional<Bind2InlineHandler> getHandler(@Nonnull final String namespace) {
return Optional.ofNullable(elementHandlers.get(namespace));
}

public static Element featureElement() {
Element bind2 = DocumentHelper.createElement(new QName("bind", new Namespace("", "urn:xmpp:bind:0")));
Element bind2inline = bind2.addElement("inline");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,20 @@ public class SASLAuthentication {
*/
private static final String SASL2_RESUME_REQUEST = "Sasl2.resume-request";

/**
* Session Data property name used to record that a session's resource was bound via an inline XEP-0386 Bind 2
* request during SASL2 authentication, as opposed to legacy IQ-based binding. Set only once binding has actually
* completed successfully; never set for sessions that bind via legacy IQ, and never set when an inline XEP-0198
* resume made the inlined bind2 request moot.
*/
public static final String BIND2_USED = "Bind2.used";

/**
* Session Data property name holding the set of XML namespaces of inline feature requests that
* were successfully negotiated via a XEP-0386 Bind 2 request, if any.
*/
public static final String BIND2_INLINE_FEATURES = "Bind2.inline-features";

/**
* Controls whether the SCRAM mechanisms that are advertised to a client are tailored to the user that is expected
* to authenticate.
Expand Down Expand Up @@ -1047,6 +1061,11 @@ private static void completeSasl2Bind2(@Nonnull final LocalClientSession clientS
clientSession.deliverRawText(success.asXML());
successDelivered = true;

clientSession.setSessionData(BIND2_USED, Boolean.TRUE);
if (!bind2Request.getNegotiatedFeatureNamespaces().isEmpty()) {
clientSession.setSessionData(BIND2_INLINE_FEATURES, bind2Request.getNegotiatedFeatureNamespaces());
}

SessionEventDispatcher.dispatchEvent(clientSession, SessionEventDispatcher.EventType.resource_bound);

// Deliver stream features now that <success/> has been sent.
Expand Down
Loading
Loading