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
asynciocoroutines 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, \*[, after_scram_plus]) |
The password-based SCRAM (non-PLUS) SASL mechanism (see RFC 5802). |
SCRAMPLUS(credential_provider, cb_provider, ...) |
The password-based SCRAM-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:
(SASLState.SUCCESS, payload)– After successful authentication, success is returned. Depending on the mechanism, a payload (asbytesobject) may be attached to the result, otherwise,payloadisNone.(SASLState.CHALLENGE, payload)– A challenge was sent by the server in reply to the previous command.(SASLState.FAILURE, None)– This is only ever returned byabort(). All other methods must raise errors asSASLFailure.
Changed in version 0.4: The first element of the returned tuples are now elements of
SASLState. For compatibility with previous versions ofaiosaslthe first elements of the string may be one of the strings"success","failure"or “challenge”. For more information seeSASLState.from_reply().-
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
bytesobject 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
bytesobject 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 (
(SASLState.FAILURE, None)) or aSASLFailureexception if the response from the peer did not indicate abortion (e.g. another error was returned by the peer or the peer indicated success).
-
class
aiosasl.SASLState[source]¶ The states of the SASL state machine.
-
CHALLENGE¶ the server sent a SASL challenge
-
SUCCESS¶ the authentication was successful
-
FAILURE¶ the authentication failed
Internal states used by the state machine:
-
INITIAL¶ the state of the state machine before the authentication is started
-
SUCCESS_SIMULATE_CHALLENGE¶ used to unwrap success replies that carry final data
These internal states must not be returned by the
SASLInterfacemethods as first component of the result tuple.The following method is used to process replies returned by the
SASLInterfacemethods:-
SASL mechansims¶
-
class
aiosasl.PLAIN(credential_provider)[source]¶ The password-based
PLAINSASL mechanism (see RFC 4616).Warning
This is generally unsafe over unencrypted connections and should not be used there. Exclusion of the
PLAINmechanism over unsafe connections is out of scope foraiosasland needs to be handled by the protocol implementation!credential_provider must be coroutine which returns a
(user, password)tuple.
-
class
aiosasl.SCRAM(credential_provider, *[, after_scram_plus=False][, enforce_minimum_iteration_count=True])[source]¶ The password-based SCRAM (non-PLUS) SASL mechanism (see RFC 5802).
Parameters: Note
As “non-PLUS” suggests, this does not support channel binding. Use
SCRAMPLUSif you want channel binding.credential_provider must be coroutine function which returns a
(user, password)tuple.If this is used after
SCRAMPLUSin a method list, the keyword argument after_scram_plus should be set toTrue. Then we will use the gs2 headery,,to prevent down-grade attacks by a man-in-the-middle attacker.enforce_minimum_iteration_count controls the enforcement of the specified minimum iteration count for the key derivation function used in SCRAM. By default, this enforcement is enabled, and you are strongly advised to not disable it: it can be used to make the exchange weaker.
Disabling enforce_minimum_iteration_count only makes sense if the authentication exchange would otherwise fall back to using
PLAINor a similarly weak authentication mechanism.Changed in version 0.4: The enforce_minimum_iteration_count argument and the behaviour to enforce the minimum iteration count by default was added.
-
class
aiosasl.SCRAMPLUS(credential_provider, cb_provider, *[, enforce_minimum_iteration_count=True])[source]¶ The password-based SCRAM-PLUS SASL mechanism (see RFC 5802).
Parameters: - credential_provider – A coroutine function which returns credentials.
- cb_provider (
ChannelBindingProvider) – Object which provides channel binding data and information. - after_scram_plus (
bool) – Flag to indicate that SCRAM-PLUS is supported by your implementation. - enforce_minimum_iteration_count (
bool) – Enforce the minimum iteration count specified by the SCRAM specifications.
credential_provider must be coroutine which returns a
(user, password)tuple.cb_provider must be an instance of
ChannelBindingProvider, which specifies and implements the channel binding type to use.enforce_minimum_iteration_count controls the enforcement of the specified minimum iteration count for the key derivation function used in SCRAM. By default, this enforcement is enabled, and you are strongly advised to not disable it: it can be used to make the exchange weaker.
See also
SCRAMfor more information on enforce_minimum_iteration_count.Changed in version 0.4: The enforce_minimum_iteration_count argument and the behaviour to enforce the minimum iteration count by default was added.
-
class
aiosasl.ANONYMOUS(token)[source]¶ The ANONYMOUS SASL mechanism (see RFC 4505).
New in version 0.3.
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 returnNone.Otherwise, it must return a non-
Nonevalue. Applications must not assign any meaning to any value (except thatNoneis 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 evenFalseindicates success!The return value must be passed as second argument to
authenticate().authenticate()must not be called with aNonevalue.
-
authenticate(sm, token)[source]¶ Execute the mechanism identified by token (the non-
Nonevalue which has been returned byany_supported()before) using the givenSASLStateMachinesm.If authentication fails, an appropriate exception is raised (
AuthenticationFailure). If the authentication fails for a reason unrelated to credentials,SASLFailureis raised.
Note
Administrative note
Patches for new SASL mechanisms are welcome!
-
classmethod
A note for implementers¶
The SASLStateMachine unwraps (SASLState.SUCCESS, payload) messages
passed in from a SASLInterface to the equivalent sequence
(SASLState.CHALLENGE, payload) (requiring the empty string as response) and
(SASLState.SUCCESS, None). The two forms are equivalent as per the SASL
specification and this unwrapping allows uniform treatment of both
forms by the SASLMechanism implementations.
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(),failurestates are never returned but thrown asSASLFailureinstead.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
Nonewhich 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 ofSASLFailureandAuthenticationFailure, 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
NonebySASLMechanismimplementations 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
SASLInterfacemethods.
-
class
aiosasl.AuthenticationFailure(opaque_error, text=None)[source]¶ A SASL error which indicates that the provided credentials are invalid. This may be raised by
SASLInterfacemethods.
Version information¶
Channel binding methods¶
The module aiosasl.channel_binding_methods provides
implementations of the ChannelBindingProvider
interface for use with ssl respective OpenSSL.
-
class
aiosasl.channel_binding_methods.StdlibTLS(connection, type_)[source]¶ Provider for channel binding for
ssl.Parameters: - connection (
ssl.SSLSocket) – the SSL connection - type (
str) – the channel binding type
- connection (
-
class
aiosasl.channel_binding_methods.TLSUnique(connection)[source]¶ Provider for the channel binding
tls-uniqueas specified by RFC 5929 forOpenSSL.Warning
This only supports connections that were not created by session resumption.
Parameters: connection ( OpenSSL.SSL.Connection) – the SSL connection
-
class
aiosasl.channel_binding_methods.TLSServerEndPoint(connection)[source]¶ Provider for the channel binding
tls-server-end-pointas specified by RFC 5929 forOpenSSL.Parameters: connection ( OpenSSL.SSL.Connection) – the SSL connection