def compose(authinfo): username = authinfo['username'] password = authinfo['password'] username = username.encode('ISO8859-1') password = password.encode('ISO8859-1') return encode_base64(b'%s:%s' % (username, password)).strip()
def encode_plain(user, password): return encode_base64("\0%s\0%s" % (user, password), eol="")
def encode_cram_md5(challenge, user, password): challenge = base64.decodestring(challenge) response = user + " " + hmac.HMAC(password, challenge).hexdigest() return encode_base64(response, eol="")
def login(self, user, password, callback=None): """Log in on an SMTP server that requires authentication. The arguments are: - user: The user name to authenticate with. - password: The password for the authentication. If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first. This method will return normally if the authentication was successful. This method may raise the following exceptions: SMTPHeloError The server didn't reply properly to the helo greeting. SMTPAuthenticationError The server didn't accept the username/ password combination. SMTPException No suitable authentication method was found. """ def encode_cram_md5(challenge, user, password): challenge = base64.decodestring(challenge) response = user + " " + hmac.HMAC(password, challenge).hexdigest() return encode_base64(response, eol="") def encode_plain(user, password): return encode_base64("\0%s\0%s" % (user, password), eol="") AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" yield gen.Task(self.ehlo_or_helo_if_needed) if not self.has_extn("auth"): raise SMTPException("SMTP AUTH extension not supported by server.") # Authentication methods the server supports: authlist = self.esmtp_features["auth"].split() # List of authentication methods we support: from preferred to # less preferred methods. Except for the purpose of testing the weaker # ones, we prefer stronger methods like CRAM-MD5: preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] # Determine the authentication method we'll use authmethod = None for method in preferred_auths: if method in authlist: authmethod = method break if authmethod == AUTH_CRAM_MD5: result = yield gen.Task(self.docmd, "AUTH", AUTH_CRAM_MD5) (code, resp) = result.args if code == 503: # 503 == 'Error: already authenticated' if callback: callback(code, resp) result = yield gen.Task(self.docmd, encode_cram_md5(resp, user, password)) (code, resp) = result.args elif authmethod == AUTH_PLAIN: result = yield gen.Task(self.docmd, "AUTH", AUTH_PLAIN + " " + encode_plain(user, password) ) (code, resp) = result.args elif authmethod == AUTH_LOGIN: result = yield gen.Task(self.docmd, "AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user, eol=""))) (code, resp) = result.args if code != 334: raise SMTPAuthenticationError(code, resp) result = yield gen.Task(self.docmd, encode_base64(password, eol="")) (code, resp) = result.args elif authmethod is None: raise SMTPException("No suitable authentication method found.") if code not in (235, 503): # 235 == 'Authentication successful' # 503 == 'Error: already authenticated' raise SMTPAuthenticationError(code, resp) if callback: callback(code, resp)
def read(self, fh, off, size): f = self.openfiles[fh].file f.seek(off) return str(encode_base64(f.read(size)).strip(), 'ascii')