1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 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   
 33      """Provides PLAIN SASL authentication for a client.""" 
 34   
 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   
 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   
 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   
108      """Provides PLAIN SASL authentication for a server.""" 
109   
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   
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   
164