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:
await 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:
ANONYMOUS (token) |
The ANONYMOUS SASL mechanism (see RFC 4505). |
PLAIN (credential_provider, Coroutine[Any, …) |
The password-based PLAIN SASL mechanism (see RFC 4616). |
SCRAM (credential_provider, Coroutine[Any, …) |
The password-based SCRAM (non-PLUS) SASL mechanism (see RFC 5802). |
SCRAMPLUS (credential_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 (asbytes
object) may be attached to the result, otherwise,payload
isNone
.(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 ofaiosasl
the first elements of the string may be one of the strings"success"
,"failure"
or “challenge
”. For more information seeSASLState.from_reply()
.-
initiate
(mechanism: str, payload: Optional[bytes] = None) → Tuple[aiosasl.common.SASLState, Optional[bytes]][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: bytes) → Tuple[aiosasl.common.SASLState, Optional[bytes]][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
() → None[source]¶ Abort the authentication. The result is either the failure tuple (
(SASLState.FAILURE, None)
) or aSASLFailure
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).
-
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
SASLInterface
methods as first component of the result tuple.The following method is used to process replies returned by the
SASLInterface
methods:-
SASL mechansims¶
-
class
aiosasl.
PLAIN
(credential_provider: Callable[[], Coroutine[Any, Any, Tuple[str, str]]])[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 foraiosasl
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, *[, 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
SCRAMPLUS
if you want channel binding.credential_provider must be coroutine function which returns a
(user, password)
tuple.If this is used after
SCRAMPLUS
in 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
PLAIN
or 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
SCRAM
for 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: str)[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: Iterable[str]) → Any[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-
None
value. Applications must not assign any meaning to any value (except thatNone
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 evenFalse
indicates success!The return value must be passed as second argument to
authenticate()
.authenticate()
must not be called with aNone
value.
-
authenticate
(sm: aiosasl.statemachine.SASLStateMachine, token: Any) → None[source]¶ Execute the mechanism identified by token (the non-
None
value which has been returned byany_supported()
before) using the givenSASLStateMachine
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!
-
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: aiosasl.statemachine.SASLInterface)[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 asSASLFailure
instead.The initial state is never returned.
Exception classes¶
-
class
aiosasl.
SASLError
(opaque_error: Any, kind: str, text: Optional[str] = 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 ofSASLFailure
andAuthenticationFailure
, 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
bySASLMechanism
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: Any, text: Optional[str] = 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: Any, text: Optional[str] = None)[source]¶ A SASL error which indicates that the provided credentials are invalid. This may be raised by
SASLInterface
methods.
Version information¶
Channel binding methods¶
The module aiosasl.channel_binding
provides
implementations of the ChannelBindingProvider
interface for use with ssl
respective OpenSSL
.
-
class
aiosasl.channel_binding.
ChannelBindingProvider
[source]¶ Interface for a channel binding method.
The needed external information is supplied to the constructors of the specific instances.
-
class
aiosasl.channel_binding.
StdlibTLS
(connection: ssl.SSLSocket, type_: str)[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.
TLSUnique
(connection: OpenSSL.SSL.Connection)[source]¶ Provider for the channel binding
tls-unique
as 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.
TLSServerEndPoint
(connection: OpenSSL.SSL.Connection)[source]¶ Provider for the channel binding
tls-server-end-point
as specified by RFC 5929 forOpenSSL
.Parameters: connection ( OpenSSL.SSL.Connection
) – the SSL connection