Package pyxmpp :: Package sasl :: Module plain

[hide private]

# Source Code for Module pyxmpp.sasl.plain

      1  #
      2  # (C) Copyright 2003-2006 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  __revision__="$Id: plain.py 647 2006-08-26 18:27:39Z jajcus $"
     24  __docformat__="restructuredtext en"
     25
     26  import logging
     27
     28  from pyxmpp.utils import to_utf8,from_utf8
     29  from pyxmpp.sasl.core import ClientAuthenticator,ServerAuthenticator
     30  from pyxmpp.sasl.core import Success,Failure,Challenge,Response
     31
     32 -class PlainClientAuthenticator(ClientAuthenticator):
     33      """Provides PLAIN SASL authentication for a client."""
     34
     35 -    def __init__(self,password_manager):
     36          """Initialize a `PlainClientAuthenticator` object.
     37
     38          :Parameters:
     39              - `password_manager`: name of the password manager object providing
     40                authentication credentials.
     41          :Types:
     42              - `password_manager`: `PasswordManager`"""
     43          ClientAuthenticator.__init__(self,password_manager)
     44          self.username=None
     45          self.finished=None
     46          self.password=None
     47          self.authzid=None
     48          self.__logger=logging.getLogger("pyxmpp.sasl.PlainClientAuthenticator")
     49
     50 -    def start(self,username,authzid):
     51          """Start the authentication process and return the initial response.
     52
     53          :Parameters:
     54              - `username`: username (authentication id).
     55              - `authzid`: authorization id.
     56          :Types:
     57              - `username`: `unicode`
     58              - `authzid`: `unicode`
     59
     60          :return: the initial response or a failure indicator.
     61          :returntype: `sasl.Response` or `sasl.Failure`"""
     62          self.username=username
     63          if authzid:
     64              self.authzid=authzid
     65          else:
     66              self.authzid=""
     67          self.finished=0
     68          return self.challenge("")
     69
     70 -    def challenge(self, challenge):
     71          """Process the challenge and return the response.
     72
     73          :Parameters:
     74              - `challenge`: the challenge.
     75          :Types:
     76              - `challenge`: `str`
     77
     78          :return: the response or a failure indicator.
     79          :returntype: `sasl.Response` or `sasl.Failure`"""
     80          _unused = challenge
     81          if self.finished:
     82              self.__logger.debug("Already authenticated")
     83              return Failure("extra-challenge")
     84          self.finished=1
     85          if self.password is None:
     86              self.password,pformat=self.password_manager.get_password(self.username)
     87          if not self.password or pformat!="plain":
     88              self.__logger.debug("Couldn't retrieve plain password")
     89              return Failure("password-unavailable")
     90          return Response("%s\000%s\000%s" % (    to_utf8(self.authzid),
     91                              to_utf8(self.username),
     92                              to_utf8(self.password)))
     93
     94 -    def finish(self,data):
     95          """Handle authentication succes information from the server.
     96
     97          :Parameters:
     98              - `data`: the optional additional data returned with the success.
     99          :Types:
    100              - `data`: `str`
    101
    102          :return: a success indicator.
    103          :returntype: `Success`"""
    104          _unused = data
    105          return Success(self.username,None,self.authzid)
    106
    107 -class PlainServerAuthenticator(ServerAuthenticator):
    108      """Provides PLAIN SASL authentication for a server."""
    109
    110 -    def __init__(self,password_manager):
    111          """Initialize a `PlainServerAuthenticator` object.
    112
    113          :Parameters:
    114              - `password_manager`: name of the password manager object providing
    115                authentication credential verification.
    116          :Types:
    117              - `password_manager`: `PasswordManager`"""
    118          ServerAuthenticator.__init__(self,password_manager)
    119          self.__logger=logging.getLogger("pyxmpp.sasl.PlainServerAuthenticator")
    120
    121 -    def start(self,response):
    122          """Start the authentication process.
    123
    124          :Parameters:
    125              - `response`: the initial response from the client.
    126          :Types:
    127              - `response`: `str`
    128
    129          :return: a challenge, a success indicator or a failure indicator.
    130          :returntype: `sasl.Challenge`, `sasl.Success` or `sasl.Failure`"""
    131          if not response:
    132              return Challenge("")
    133          return self.response(response)
    134
    135 -    def response(self,response):
    136          """Process a client reponse.
    137
    138          :Parameters:
    139              - `response`: the response from the client.
    140          :Types:
    141              - `response`: `str`
    142
    143          :return: a challenge, a success indicator or a failure indicator.
    144          :returntype: `sasl.Challenge`, `sasl.Success` or `sasl.Failure`"""
    145          s=response.split("\000")
    146          if len(s)!=3:
    147              self.__logger.debug("Bad response: %r" % (response,))
    148              return Failure("not-authorized")
    149          authzid,username,password=s
    150          authzid=from_utf8(authzid)
    151          username=from_utf8(username)
    152          password=from_utf8(password)
    153          if not self.password_manager.check_password(username,password):
    154              self.__logger.debug("Bad password. Response was: %r" % (response,))
    155              return Failure("not-authorized")
    156          info={"mechanism":"PLAIN","username":username}
    157          if self.password_manager.check_authzid(authzid,info):
    158              return Success(username,None,authzid)
    159          else:
    160              self.__logger.debug("Authzid verification failed.")
    161              return Failure("invalid-authzid")
    162
    163  # vi: sts=4 et sw=4
    164