Welcome to aiosasl’s documentation!

aiosasl is a generic SASL implementation for use with asyncio protocols. It makes very few assumptions about the protocol which uses SASL, making it usable in different contexts. The assumptions are:

  • It uses SASL, i.e. you can perform SASL initiation, responses and abortions.
  • Those actions can be encapsulated in asyncio coroutines which return the server response.

API Reference

Using SASL in a protocol

To make use of SASL over an existing protocol, you first need to subclass and implement SASLInterface.

The usable mechanisms need to be detected by your application using the protocol over which to implement SASL. This is generally protocol-specific. For example, XMPP uses stream features to announce which SASL mechanisms are supported by the server.

When a set of SASL mechanism strings has been obtained by the server (let us call a set with the mechanism strings sasl_mechanisms), the mechanisms supported by your application (a list of SASLMechanism subclass instances, let us call it mechanism_impls) can be queried for support:

# intf = <instance of your subclass of SASLInterface>
for impl in mechanism_impl:
    token = impl.any_supported(sasl_mechanisms)
    if token is not None:
        sm = aiosasl.SASLStateMachine(intf)
        try:
            yield from impl.authenticate(sm, token)
        except aiosasl.AuthenticationFailure:
            # handle authentication failure
            # it is generally not sensible to re-try with other mechanisms
        except aiosasl.SASLFailure:
            # this is a protocol problem, it is sensible to re-try other
            # mechanisms
        else:
            # authentication was successful!

The instances for the mechanisms can be re-used; they do not save any state, the state is held by SASLStateMachine instead. The different mechanisms require different arguments (the password-based mechanisms generally require a callback which provides credentials).

The mechanisms which are currently supported by aiosasl are summarised below:

PLAIN(credential_provider) The password-based PLAIN SASL mechanism (see RFC 4616).
SCRAM(credential_provider) The password-based SCRAM (non-PLUS) SASL mechanism (see RFC 5802).

Interface for protocols using SASL

To implement SASL on an existing protocol, you need to subclass SASLInterface and implement the abstract methods:

class aiosasl.SASLInterface[source]

This class serves as an abstract base class for interfaces for use with SASLStateMachine. Specific protocols using SASL (such as XMPP, IMAP or SMTP) can subclass this interface to implement SASL on top of the existing protocol.

The interface class does not need to implement any state checking. State checking is done by the SASLStateMachine. The following interface must be implemented by subclasses.

The return values of the methods below are tuples of the following form:

  • ("success", payload) – After successful authentication, success is returned. Depending on the mechanism, a payload (as bytes object) may be attached to the result, otherwise, payload is None.
  • ("challenge", payload) – A challenge was sent by the server in reply to the previous command.
  • ("failure", None) – This is only ever returned by abort(). All other methods must raise errors as SASLFailure.
initiate(mechanism, payload=None)[source]

Send a SASL initiation request for the given mechanism. Depending on the mechanism, an initial payload may be given. The payload is then a bytes object which needs to be passed as initial payload during the initiation request.

Wait for a reply by the peer and return the reply as a next-state tuple in the format documented at SASLInterface.

respond(payload)[source]

Send a response to a challenge. The payload is a bytes object which is to be sent as response.

Wait for a reply by the peer and return the reply as a next-state tuple in the format documented at SASLInterface.

abort()[source]

Abort the authentication. The result is either the failure tuple (("failure", None)) or a SASLFailure exception if the response from the peer did not indicate abortion (e.g. another error was returned by the peer or the peer indicated success).

SASL mechansims

class aiosasl.PLAIN(credential_provider)[source]

The password-based PLAIN SASL mechanism (see RFC 4616).

Warning

This is generally unsafe over unencrypted connections and should not be used there. Exclusion of the PLAIN mechanism over unsafe connections is out of scope for aiosasl and needs to be handled by the protocol implementation!

credential_provider must be coroutine which returns a (user, password) tuple.

class aiosasl.SCRAM(credential_provider)[source]

The password-based SCRAM (non-PLUS) SASL mechanism (see RFC 5802).

Note

As “non-PLUS” suggests, this does not support channel binding. Patches welcome.

It may make sense to implement the -PLUS mechanisms as separate SASLMechanism subclass or at least allow disabling them via an optional argument (defaulting to disabled). Channel binding may not be reliably available in all cases.

credential_provider must be coroutine which returns a (user, password) tuple.

Base class

class aiosasl.SASLMechanism[source]

Implementation of a SASL mechanism. Two methods must be implemented by subclasses:

classmethod any_supported(mechanisms)[source]

Determine whether this class can perform any SASL mechanism in the set of strings mechanisms.

If the class cannot perform any of the SASL mechanisms in mechanisms, it must return None.

Otherwise, it must return a non-None value. Applications must not assign any meaning to any value (except that None is a sure indicator that the class cannot perform any of the listed mechanisms) and must not alter any value returned by this function. Note that even False indicates success!

The return value must be passed as second argument to authenticate(). authenticate() must not be called with a None value.

authenticate(sm, token)[source]

Execute the mechanism identified by token (the non-None value which has been returned by any_supported() before) using the given SASLStateMachine sm.

If authentication fails, an appropriate exception is raised (AuthenticationFailure). If the authentication fails for a reason unrelated to credentials, SASLFailure is raised.

Note

Administrative note

Patches for new SASL mechanisms are welcome!

SASL state machine

class aiosasl.SASLStateMachine(interface)[source]

A state machine to reduce code duplication during SASL handshake.

The state methods change the state and return the next client state of the SASL handshake, optionally with server-supplied payload.

Note that, with the notable exception of abort(), failure states are never returned but thrown as SASLFailure instead.

The initial state is never returned.

Exception classes

class aiosasl.SASLError(opaque_error, kind, text=None)[source]

Base class for a SASL related error. opaque_error may be anything but None which helps your application re-identify the error at the outer layers. kind is a string which helps identifying the class of the error; this is set implicitly by the constructors of SASLFailure and AuthenticationFailure, which you are encouraged to use.

text may be a human-readable string describing the error condition in more detail.

opaque_error is set to None by SASLMechanism implementations to indicate errors which originate from the local mechanism implementation.

opaque_error

The value passed to the respective constructor argument.

text

The value passed to the respective constructor argument.

class aiosasl.SASLFailure(opaque_error, text=None)[source]

A SASL protocol failure which is unrelated to the credentials passed. This may be raised by SASLInterface methods.

class aiosasl.AuthenticationFailure(opaque_error, text=None)[source]

A SASL error which indicates that the provided credentials are invalid. This may be raised by SASLInterface methods.

Version information

aiosasl.__version__ = '0.1.0'

The imported aiosasl version as a string.

The version number is dot-separated; in pre-release or development versions, the version number is followed by a hypen-separated pre-release identifier.

aiosasl.version_info = (0, 1, 0, None)

The imported aiosasl version as a tuple.

The components of the tuple are, in order: major version, minor version, patch level, and pre-release identifier.

Indices and tables