Copyright © 2010 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

(as stable API)

A channel interface for SASL authentication, as defined by RFC 4422. When this interface appears on a ServerAuthentication channel, it represents authentication with the server. In future, it could also be used to authenticate with secondary services, or even to authenticate end-to-end connections with contacts. As a result, this interface does not REQUIRE ServerAuthentication to allow for a potential future Channel.Type.PeerAuthentication interface.

In any protocol that requires a password, the connection manager can use this channel to let a user interface carry out a simple SASL-like handshake with it, as a way to get the user's credentials interactively. This can be used to connect to protocols that may require a password, without requiring that the password is saved in the Account.Parameters.

In some protocols, such as XMPP, authentication with the server is also carried out using SASL. In these protocols, a channel with this interface can provide a simple 1:1 mapping of the SASL negotiations taking place in the protocol, allowing more advanced clients to perform authentication via SASL mechanisms not known to the connection manager.

By providing SASL directly when the protocol supports it, we can use mechanisms like Kerberos or Google's X-GOOGLE-TOKEN without specific support in the connection manager.

For channels managed by a ChannelDispatcher, only the channel's Handler may call the methods on this interface. Other clients MAY observe the authentication process by watching its signals and properties.

There can only be one Handler, which is a good fit for SASL's 1-1 conversation between a client and a server.

A SASL mechanism, as defined by RFC 4422 and registered in the IANA registry of SASL mechanisms, or an unregistered SASL mechanism such as X-GOOGLE-TOKEN used in the same contexts.

As a special case, pseudo-mechanisms starting with X-TELEPATHY- are defined by this specification. Use of these pseudo-mechanisms indicates that the user's credentials are to be passed to the connection manager, which will then use them for authentication with the service, either by implementing the client side of some SASL mechanisms itself or by using a non-SASL protocol. The only such pseudo-mechanism currently defined is X-TELEPATHY-PASSWORD.

The X-TELEPATHY-PASSWORD mechanism is extremely simple:

  • The client MUST call StartMechanismWithData, with Initial_Data set to the password encoded in UTF-8. For simplicity, calling StartMechanism followed by calling Respond is not allowed in this mechanism.
  • The connection manager uses the password, together with authentication details from the Connection parameters, to authenticate itself to the server.
  • When the connection manager finishes its attempt to authenticate to the server, the channel's state changes to either SASL_Status_Server_Succeeded or SASL_Status_Server_Failed as appropriate.

The SASL mechanisms as offered by the server, plus any pseudo-SASL mechanisms supported by the connection manager for credentials transfer. For instance, in a protocol that natively uses SASL (like XMPP), this might be [ "X-TELEPATHY-PASSWORD", "PLAIN", "DIGEST-MD5", "SCRAM-SHA-1" ].

To make it possible to implement a very simple password-querying user interface without knowledge of any particular SASL mechanism, implementations of this interface MUST implement the pseudo-mechanism X-TELEPATHY-PASSWORD, unless none of the available mechanisms use a password at all.

If true, StartMechanismWithData can be expected to work for SASL mechanisms not starting with X-TELEPATHY- (this is the case in most, but not all, protocols). If false, StartMechanism must be used instead.

This property does not affect the X-TELEPATHY- pseudo-mechanisms such as X-TELEPATHY-PASSWORD, which can use StartMechanismWithData regardless of the value of this property.

If true, StartMechanism and (if supported) StartMechanismWithData can be expected to work when in one of the Failed states. If false, the only thing you can do after failure is to close the channel.

Retrying isn't required to work, although some protocols and implementations allow it.

The current status of this channel. Change notification is via the SASLStatusChanged signal.

The reason for the SASLStatus, or an empty string if the state is neither Server_Failed nor Client_Failed.

In particular, an ordinary authentication failure (as would be produced for an incorrect password) SHOULD be represented by AuthenticationFailed, cancellation by the user's request SHOULD be represented by Cancelled, and cancellation by a local process due to inconsistent or invalid challenges from the server SHOULD be represented by ServiceConfused.

If this interface appears on a ServerAuthentication channel, and connection to the server fails with an authentication failure, this error code SHOULD be copied into the Connection.ConnectionError signal.

If SASLError is non-empty, any additional information about the last disconnection; otherwise, the empty map. The keys and values are the same as for the second argument of Connection.ConnectionError.

If this interface appears on a ServerAuthentication channel, and connection to the server fails with an authentication failure, these details SHOULD be copied into the Connection.ConnectionError signal.

The identity for which authorization is being attempted, typically the 'account' from the RequestConnection parameters, normalized and formatted according to the conventions used for SASL in this protocol.

The normalization used for SASL might not be the same normalization used elsewhere: for instance, in a protocol with email-like identifiers such as XMPP or SIP, the user "juliet@example.com" might have to authenticate to the example.com server via SASL PLAIN as "juliet".

This is usually achieved by using the authorization identity for authentication, but an advanced Handler could offer the option to authenticate under a different identity.

The terminology used here is that the authorization identity is who you want to act as, and the authentication identity is used to prove that you may do so. For instance, if Juliet is authorized to access a role account, "sysadmin@example.com", and act on its behalf, it might be possible to authenticate as "juliet@example.com" with her own password, but request to be authorized as "sysadmin@example.com" instead of her own account. See RFC 4422 §3.4.1 for more details.

In SASL the authorization identity is normally guessed from the authentication identity, but the information available to the connection manager is the identity for which authorization is required, such as the desired JID in XMPP, so that's what we signal to UIs; it's up to the UI to choose whether to authenticate as the authorization identity or some other identity.

As a concrete example, the "sysadmin" XMPP account mentioned above would have { 'account': 'sysadmin@example.com' } in its Parameters, and this property would also be 'sysadmin@example.com'. A simple Handler would merely prompt for sysadmin@example.com's password, and use that JID as both the authorization and authentication identity, which might result in SASL PLAIN authentication with the initial response '\000sysadmin@example.com\000root'.

A more advanced Handler might also ask for an authentication identity, defaulting to 'sysadmin@example.com'; if Juliet provided authentication identity 'juliet@example.com' and password 'romeo', the Handler might perform SASL PLAIN authentication using the initial response 'sysadmin@example.com\000juliet@example.com\000romeo'.

The default username for use with SASL mechanisms that deal with a "simple username" (as defined in RFC 4422). If such a SASL mechanism is in use, clients SHOULD default to using the DefaultUsername; also, if the client uses the DefaultUsername, it SHOULD assume that the authorization identity AuthorizationIdentity will be derived from it by the server.

In XMPP, servers typically expect "user@example.com" to authenticate with username "user"; this was a SHOULD in RFC 3920.

3920bis weakens that SHOULD to "in the absence of local information provided by the server, an XMPP client SHOULD assume that the authentication identity for such a SASL mechanism is the combination of a user name and password, where the simple user name is the localpart of the user's JID".

For example, in the simple case, if the user connects with RequestConnection({ account: "user@example.com" }) and use PLAIN with password "password", he or she should authenticate like so: "\0user\0password" and the channel will look like this:

{ "...DefaultUsername": "user",
  "...AuthorizationIdentity": "user@example.com }

In the complex case, if the same user is using his or her sysadmin powers to log in as the "announcements" role address, he or she would connect with RequestConnection({ account: "announcements@example.com" }) and the SASL channel would look like this:

{ "...DefaultUsername": "announcements",
  "...AuthorizationIdentity": "announcements@example.com }

A sufficiently elaborate UI could give the opportunity to override the username from "announcements" to "user". The user's simple username is still "user", and the password is still "password", but this time he or she is trying to authorize to act as announcements@example.com, so the UI would have to perform SASL PLAIN with this string: "announcements@example.com\0user\0password", where "announcements@example.com" is the AuthorizationIdentity.

The default realm (as defined in RFC 2831) to use for authentication, if the server does not supply one.

The server is not required to provide a realm; if it doesn't, the client is expected to ask the user or provide a sensible default, typically the requested DNS name of the server. In some implementations of DIGEST-MD5, the server does not specify a realm, but expects that the client will choose a particular default, and authentication will fail if the client's default is different. Connection managers for protocols where this occurs are more easily able to work around these implementations than a generic client would be.

The chosen mechanism.

Start an authentication try using Mechanism, without sending initial data (an "initial response" as defined in RFC 4422).

This method is appropriate for mechanisms where the client cannot send anything until it receives a challenge from the server, such as DIGEST-MD5 in "initial authentication" mode.

The channel is not in a state where starting authentication makes sense (i.e. SASL_Status_Not_Started, or (if CanTryAgain is true) SASL_Status_Server_Failed or SASL_Status_Client_Failed). You should call AbortSASL and wait for SASL_Status_Client_Failed before starting another attempt. The server or connection manager doesn't implement the given SASL mechanism. Choose a SASL mechanism from AvailableMechanisms, or abort authentication if none of them are suitable.
The chosen mechanism. Initial data (an "initial response" in RFC 4422's terminology) to send with the mechanism.

Start an authentication try using Mechanism, and send Initial_Data as the "initial response" defined in RFC 4422 §3.3.

This method is appropriate for mechanisms where the client may send data first, such as PLAIN, or must send data first, such as DIGEST-MD5 in "subsequent authentication" mode.

Having two methods allows any mechanism where it makes a difference to distinguish between the absence of an initial response (StartMechanism) and a zero-byte initial response (StartMechanismWithData, with Initial_Data empty).

If the HasInitialData property is false, this indicates that the underlying protocol does not make it possible to send initial data. In such protocols, this method may only be used for the X-TELEPATHY- pseudo-mechanisms (such as X-TELEPATHY-PASSWORD), and will fail if used with an ordinary SASL mechanism.

For instance, the IRC SASL extension implemented in Charybdis and Atheme does not support initial data - the first message in the exchange only carries the mechanism. This is significant if using DIGEST-MD5, which cannot be used in the faster "subsequent authentication" mode on a protocol not supporting initial data.

The channel is not in a state where starting authentication makes sense (i.e. SASL_Status_Not_Started, or (if CanTryAgain is true) SASL_Status_Server_Failed or SASL_Status_Client_Failed). You should call AbortSASL and wait for SASL_Status_Client_Failed before starting another attempt. The server or connection manager doesn't implement the given SASL mechanism (choose one from AvailableMechanisms, or abort authentication if none of them are suitable), or doesn't allow initial data to be sent (as indicated by HasInitialData; call StartMechanism instead).
The response data.

Send a response to the the last challenge received via NewChallenge.

Either the state is not In_Progress, or no challenge has been received yet, or you have already responded to the last challenge.

If the channel's status is SASL_Status_Server_Succeeded, this method confirms successful authentication and advances the status of the channel to SASL_Status_Succeeded.

If the channel's status is SASL_Status_In_Progress, calling this method indicates that the last NewChallenge signal was in fact additional data sent after a successful SASL negotiation, and declares that from the client's point of view, authentication was successful. This advances the state of the channel to SASL_Status_Client_Accepted.

In mechanisms where the server authenticates itself to the client, calling this method indicates that the client considers this to have been successful. In the case of ServerAuthentication channels, this means that the connection manager MAY continue to connect, and MAY advance the Connection.Status to Connected.

Either the state is neither In_Progress nor Server_Succeeded, or no challenge has been received yet, or you have already responded to the last challenge.
Reason for abort. Debug message for abort.

Abort the current authentication try.

If the current status is SASL_Status_Server_Failed or SASL_Status_Client_Failed, this method returns successfully, but has no further effect. If the current status is SASL_Status_Succeeded or SASL_Status_Client_Accepted then NotAvailable is raised. Otherwise, it changes the channel's state to SASL_Status_Client_Failed, with an appropriate error name and reason code.

The current state is either Succeeded or Client_Accepted.
Emitted when the status of the channel changes. The new value of SASLStatus. The new value of SASLError. The new value of SASLErrorDetails.

Emitted when a new challenge is received from the server, or when a message indicating successful authentication and containing additional data is received from the server.

When the channel's handler is ready to proceed, it should respond to the challenge by calling Respond, or respond to the additional data by calling AcceptSASL. Alternatively, it may call AbortSASL to abort authentication.

The challenge data or additional data from the server.

A reason why SASL authentication was aborted by the client.

The server sent an invalid challenge or data. The user aborted the authentication.
The initial state. The Handler SHOULD either call AbortSASL, or connect to the NewChallenge signal then call StartMechanism or StartMechanismWithData. The challenge/response exchange is in progress. The Handler SHOULD call either Respond or AcceptSASL exactly once per emission of NewChallenge, or call AbortSASL at any time. The server has indicated successful authentication, and the connection manager is waiting for confirmation from the Handler. The Handler must call either AcceptSASL or AbortSASL to indicate whether it considers authentication to have been successful. The Handler has indicated successful authentication, and the connection manager is waiting for confirmation from the server. The state will progress to either Succeeded or Server_Failed when confirmation is received. Everyone is happy (the server sent success, and the client has called AcceptSASL). Connection to the server will proceed as soon as this state is reached. The Handler SHOULD call Close to close the channel. The server has indicated an authentication failure. If CanTryAgain is true, the client may try to authenticate again, by calling StartMechanism or StartMechanismWithData again. Otherwise, it should give up completely, by calling Close on the channel. The client has indicated an authentication failure. The possible actions are the same as for Server_Failed.