Package pyxmpp :: Package sasl :: Module plain

[hide private]

# Source Code for Module pyxmpp.sasl.plain

      1  #
      2  # (C) Copyright 2003-2010 Jacek Konieczny <jajcus@jajcus.net>
      3  #
      4  # This program is free software; you can redistribute it and/or modify
      5  # it under the terms of the GNU Lesser General Public License Version
      6  # 2.1 as published by the Free Software Foundation.
      7  #
      8  # This program is distributed in the hope that it will be useful,
      9  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  # GNU Lesser General Public License for more details.
     12  #
     13  # You should have received a copy of the GNU Lesser General Public
     14  # License along with this program; if not, write to the Free Software
     15  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     16  #
     17  """PLAIN authentication mechanism for PyXMPP SASL implementation.
     18
     19  Normative reference:
     20    - `RFC 2595 <http://www.ietf.org/rfc/rfc2595.txt>`__
     21  """
     22
     23  __docformat__="restructuredtext en"
     24
     25  import logging
     26
     27  from pyxmpp.utils import to_utf8,from_utf8
     28  from pyxmpp.sasl.core import ClientAuthenticator,ServerAuthenticator
     29  from pyxmpp.sasl.core import Success,Failure,Challenge,Response
     30
     31 -class PlainClientAuthenticator(ClientAuthenticator):
     32      """Provides PLAIN SASL authentication for a client."""
     33
     34 -    def __init__(self,password_manager):
     35          """Initialize a `PlainClientAuthenticator` object.
     36
     37          :Parameters:
     38              - `password_manager`: name of the password manager object providing
     39                authentication credentials.
     40          :Types:
     41              - `password_manager`: `PasswordManager`"""
     42          ClientAuthenticator.__init__(self,password_manager)
     43          self.username=None
     44          self.finished=None
     45          self.password=None
     46          self.authzid=None
     47          self.__logger=logging.getLogger("pyxmpp.sasl.PlainClientAuthenticator")
     48
     49 -    def start(self,username,authzid):
     50          """Start the authentication process and return the initial response.
     51
     52          :Parameters:
     53              - `username`: username (authentication id).
     54              - `authzid`: authorization id.
     55          :Types:
     56              - `username`: `unicode`
     57              - `authzid`: `unicode`
     58
     59          :return: the initial response or a failure indicator.
     60          :returntype: `sasl.Response` or `sasl.Failure`"""
     61          self.username=username
     62          if authzid:
     63              self.authzid=authzid
     64          else:
     65              self.authzid=""
     66          self.finished=0
     67          return self.challenge("")
     68
     69 -    def challenge(self, challenge):
     70          """Process the challenge and return the response.
     71
     72          :Parameters:
     73              - `challenge`: the challenge.
     74          :Types:
     75              - `challenge`: `str`
     76
     77          :return: the response or a failure indicator.
     78          :returntype: `sasl.Response` or `sasl.Failure`"""
     79          _unused = challenge
     80          if self.finished:
     81              self.__logger.debug("Already authenticated")
     82              return Failure("extra-challenge")
     83          self.finished=1
     84          if self.password is None:
     85              self.password,pformat=self.password_manager.get_password(self.username)
     86          if not self.password or pformat!="plain":
     87              self.__logger.debug("Couldn't retrieve plain password")
     88              return Failure("password-unavailable")
     89          return Response("%s\000%s\000%s" % (    to_utf8(self.authzid),
     90                              to_utf8(self.username),
     91                              to_utf8(self.password)))
     92
     93 -    def finish(self,data):
     94          """Handle authentication succes information from the server.
     95
     96          :Parameters:
     97              - `data`: the optional additional data returned with the success.
     98          :Types:
     99              - `data`: `str`
    100
    101          :return: a success indicator.
    102          :returntype: `Success`"""
    103          _unused = data
    104          return Success(self.username,None,self.authzid)
    105
    106 -class PlainServerAuthenticator(ServerAuthenticator):
    107      """Provides PLAIN SASL authentication for a server."""
    108
    109 -    def __init__(self,password_manager):
    110          """Initialize a `PlainServerAuthenticator` object.
    111
    112          :Parameters:
    113              - `password_manager`: name of the password manager object providing
    114                authentication credential verification.
    115          :Types:
    116              - `password_manager`: `PasswordManager`"""
    117          ServerAuthenticator.__init__(self,password_manager)
    118          self.__logger=logging.getLogger("pyxmpp.sasl.PlainServerAuthenticator")
    119
    120 -    def start(self,response):
    121          """Start the authentication process.
    122
    123          :Parameters:
    124              - `response`: the initial response from the client.
    125          :Types:
    126              - `response`: `str`
    127
    128          :return: a challenge, a success indicator or a failure indicator.
    129          :returntype: `sasl.Challenge`, `sasl.Success` or `sasl.Failure`"""
    130          if not response:
    131              return Challenge("")
    132          return self.response(response)
    133
    134 -    def response(self,response):
    135          """Process a client reponse.
    136
    137          :Parameters:
    138              - `response`: the response from the client.
    139          :Types:
    140              - `response`: `str`
    141
    142          :return: a challenge, a success indicator or a failure indicator.
    143          :returntype: `sasl.Challenge`, `sasl.Success` or `sasl.Failure`"""
    144          s=response.split("\000")
    145          if len(s)!=3:
    146              self.__logger.debug("Bad response: %r" % (response,))
    147              return Failure("not-authorized")
    148          authzid,username,password=s
    149          authzid=from_utf8(authzid)
    150          username=from_utf8(username)
    151          password=from_utf8(password)
    152          if not self.password_manager.check_password(username,password):
    153              self.__logger.debug("Bad password. Response was: %r" % (response,))
    154              return Failure("not-authorized")
    155          info={"mechanism":"PLAIN","username":username}
    156          if self.password_manager.check_authzid(authzid,info):
    157              return Success(username,None,authzid)
    158          else:
    159              self.__logger.debug("Authzid verification failed.")
    160              return Failure("invalid-authzid")
    161
    162  # vi: sts=4 et sw=4
    163