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 __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
32 """Provides PLAIN SASL authentication for a client."""
33
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
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
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
107 """Provides PLAIN SASL authentication for a server."""
108
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
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
163