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