Class Sasl2TaskManager

java.lang.Object
org.jivesoftware.openfire.sasl.task.Sasl2TaskManager

public class Sasl2TaskManager extends Object
Registry for Sasl2TaskProvider implementations, and driver of the SASL2 <continue/> flow that is defined in XEP-0388 § 2.5.

Registration

Third-party code registers a provider once, typically from a plugin:

 public void initializePlugin(PluginManager manager, File pluginDirectory) {
     provider = new MyTaskProvider();
     Sasl2TaskManager.getInstance().register(provider);
 }

 public void destroyPlugin() {
     Sasl2TaskManager.getInstance().unregister(provider);
 }
 
Unregistering a provider does not disturb negotiations that are already in progress: they hold direct references to the provider and to its tasks.

Flow

  1. addStreamFeatures(LocalSession, Element) lets providers advertise opt-in features.
  2. onAuthenticateElement(LocalSession, Element, String) starts a negotiation and lets providers read the peer's <authenticate/> element.
  3. offerTasks(LocalSession, String, String, byte[]) is invoked once the SASL exchange has succeeded. If any task is eligible, it sends <continue/> and returns true, and the SASL2 negotiation is suspended.
  4. handleTaskElement(LocalSession, Element) processes the peer's <next/> and <task-data/> elements until every eligible task has completed.
  5. endNegotiation(LocalSession, boolean) tears the state down.
Tasks are offered only to LocalClientSessions: the flow has no meaning for server-to-server or component connections.
See Also:
  • Field Details

    • ENABLED

      public static final SystemProperty<Boolean> ENABLED
      Controls whether SASL2 tasks are processed at all. When disabled, no task is advertised or offered, and a peer that sends <next/> or <task-data/> has its negotiation failed. This is the kill switch for deployments that run into trouble with a third-party provider.
    • DISABLED_PROVIDERS

      public static final SystemProperty<List<String>> DISABLED_PROVIDERS
      Identifiers (see Sasl2TaskProvider.getIdentifier()) of providers that are registered but must not be consulted. Lets an administrator disable one provider without unloading the plugin that supplies it.
    • MAX_ROUNDS

      public static final SystemProperty<Integer> MAX_ROUNDS
      The maximum number of <continue/> elements that are sent during one negotiation. This bounds the effect of a provider that keeps offering a task that never becomes ineligible, which would otherwise let a peer loop indefinitely.
    • NEGOTIATION_KEY

      public static final String NEGOTIATION_KEY
      Session data key under which the Sasl2Negotiation of the session's current SASL2 negotiation is stored.
      See Also:
    • ADVERTISED_KEY

      public static final String ADVERTISED_KEY
      Session data key under which the stream feature elements that each provider advertised are stored, as a Map of provider identifier to a List of Elements.
      See Also:
  • Constructor Details

    • Sasl2TaskManager

      protected Sasl2TaskManager()
  • Method Details

    • getInstance

      @Nonnull public static Sasl2TaskManager getInstance()
    • register

      public void register(@Nonnull Sasl2TaskProvider provider)
      Registers a provider of SASL2 tasks.
      Parameters:
      provider - the provider to register (cannot be null).
      Throws:
      IllegalArgumentException - if the provider is invalid, or if its identifier or one of its task names is already taken by another registered provider.
    • unregister

      public boolean unregister(@Nonnull Sasl2TaskProvider provider)
      Removes a previously registered provider. Negotiations that are already in progress are unaffected.
      Parameters:
      provider - the provider to remove (cannot be null).
      Returns:
      true if the provider was registered.
    • unregister

      public boolean unregister(@Nonnull String identifier)
      Removes a previously registered provider. Negotiations that are already in progress are unaffected.
      Parameters:
      identifier - the identifier of the provider to remove (cannot be null).
      Returns:
      true if a provider was registered under this identifier.
    • getProviders

      @Nonnull public Collection<Sasl2TaskProvider> getProviders()
      All registered providers, including those that are disabled by configuration.
      Returns:
      an immutable collection of providers (never null).
    • getEnabledProviders

      @Nonnull protected List<Sasl2TaskProvider> getEnabledProviders()
      The providers that are eligible to be consulted, in the order in which they are to be consulted.
      Returns:
      an ordered list of providers (never null, possibly empty).
    • addStreamFeatures

      public void addStreamFeatures(@Nonnull LocalSession session, @Nonnull org.dom4j.Element authenticationFeature)
      Adds every registered provider's opt-in elements to the SASL2 <authentication/> stream feature, and records on the session what was advertised. Invoke this while assembling the <authentication xmlns='urn:xmpp:sasl:2'/> feature, after the <mechanism/> elements have been added.
      Parameters:
      session - the session that features are being advertised to (cannot be null).
      authenticationFeature - the <authentication/> element being assembled (cannot be null).
    • onAuthenticateElement

      public void onAuthenticateElement(@Nonnull LocalSession session, @Nonnull org.dom4j.Element authenticate, @Nonnull String mechanismName) throws SaslFailureException
      Starts a task negotiation for a SASL2 authentication attempt, and lets every provider inspect the peer's <authenticate/> element. Any state left over from an earlier attempt on the same session is discarded first.
      Parameters:
      session - the session that is authenticating (cannot be null).
      authenticate - the peer's <authenticate/> element (cannot be null).
      mechanismName - the name of the SASL mechanism that the peer selected (cannot be null).
      Throws:
      SaslFailureException - if a provider rejects the request.
    • offerTasks

      public boolean offerTasks(@Nonnull LocalSession session, @Nullable String authorizationIdentity, @Nonnull String saslMechanismName, @Nullable byte[] saslSuccessData) throws SaslFailureException
      Determines whether any task is to be performed before the SASL2 negotiation can be concluded, and if so, sends a <continue/> element to the peer. Invoke this once the SASL exchange has succeeded and before the session is authenticated. When this returns true, the caller must suspend the negotiation and wait for the peer's next element; when it returns false, nothing has been sent and the caller proceeds as it would without tasks.
      Parameters:
      session - the session that is authenticating (cannot be null).
      authorizationIdentity - the authenticated username, or null for an anonymous authentication.
      saslMechanismName - the mechanism name as reported by the SaslServer (cannot be null).
      saslSuccessData - the success data produced by the SASL mechanism, or null. When a <continue/> is sent, this data is delivered in that element (XEP-0388 § 2.5), which is why the caller must not also place it in a <success/> element.
      Returns:
      true if a <continue/> was sent, false if no task applies.
      Throws:
      SaslFailureException - if the maximum number of <continue/> rounds (MAX_ROUNDS) was exceeded, or if an unexpected internal error occurred while assembling the round. A provider's own failure to determine its eligible tasks is isolated and logged, and does not, by itself, cause this. The negotiation is torn down (as if by endNegotiation(LocalSession, boolean) with successful=false) before this exception propagates.
    • handleTaskElement

      @Nonnull public Sasl2TaskManager.Outcome handleTaskElement(@Nonnull LocalSession session, @Nonnull org.dom4j.Element element) throws SaslFailureException
      Processes a <next/> or <task-data/> element received from the peer.
      Parameters:
      session - the session that is authenticating (cannot be null).
      element - the received element (cannot be null).
      Returns:
      whether the negotiation can now be concluded, or more is expected from the peer.
      Throws:
      SaslFailureException - if the element is unexpected or malformed, or if a task failed.
    • endNegotiation

      @Nullable public Sasl2Negotiation endNegotiation(@Nonnull LocalSession session, boolean successful)
      Ends the negotiation, if one is in progress: aborts any task that is still running, notifies every provider that participated, and removes all state from the session.
      Parameters:
      session - the session (cannot be null).
      successful - true if the SASL2 negotiation completed successfully.
      Returns:
      the negotiation that was ended, or null if none was in progress.
    • reset

      public void reset(@Nonnull LocalSession session)
      Discards any task negotiation state on the session, without notifying providers of a completed negotiation. Invoked when a new authentication attempt starts.
      Parameters:
      session - the session (cannot be null).
    • getNegotiation

      @Nullable public Sasl2Negotiation getNegotiation(@Nonnull LocalSession session)
      The negotiation that is in progress for the given session, if any.
      Parameters:
      session - the session (cannot be null).
      Returns:
      a negotiation, or null.