def auth(self, mechanism, authobject, *, initial_response_ok=True): """Authentication command - requires response processing. 'mechanism' specifies which authentication mechanism is to be used - the valid values are those listed in the 'auth' element of 'esmtp_features'. 'authobject' must be a callable object taking a single argument: data = authobject(challenge) It will be called to process the server's challenge response; the challenge argument it is passed will be a bytes. It should return bytes data that will be base64 encoded and sent to the server. Keyword arguments: - initial_response_ok: Allow sending the RFC 4954 initial-response to the AUTH command, if the authentication methods supports it. """ mechanism = mechanism.upper() initial_response = authobject() if initial_response_ok else None if initial_response is not None: response = encode_base64(initial_response.encode('ascii'), eol='') code, resp = self.docmd('AUTH', mechanism + ' ' + response) else: code, resp = self.docmd('AUTH', mechanism) if code == 334: challenge = base64.decodebytes(resp) response = encode_base64(authobject(challenge).encode('ascii'), eol='') code, resp = self.docmd(response) if code in (235, 503): return code, resp raise SMTPAuthenticationError(code, resp)
def auth(self, mechanism, authobject, *, initial_response_ok=True): """Authentication command - requires response processing. 'mechanism' specifies which authentication mechanism is to be used - the valid values are those listed in the 'auth' element of 'esmtp_features'. 'authobject' must be a callable object taking a single argument: data = authobject(challenge) It will be called to process the server's challenge response; the challenge argument it is passed will be a bytes. It should return an ASCII string that will be base64 encoded and sent to the server. Keyword arguments: - initial_response_ok: Allow sending the RFC 4954 initial-response to the AUTH command, if the authentication methods supports it. """ # RFC 4954 allows auth methods to provide an initial response. Not all # methods support it. By definition, if they return something other # than None when challenge is None, then they do. See issue #15014. mechanism = mechanism.upper() initial_response = (authobject() if initial_response_ok else None) if initial_response is not None: response = encode_base64(initial_response.encode('ascii'), eol='') (code, resp) = self.docmd("AUTH", mechanism + " " + response) else: (code, resp) = self.docmd("AUTH", mechanism) # If server responds with a challenge, send the response. if code == 334: challenge = base64.decodebytes(resp) response = encode_base64(authobject(challenge).encode('ascii'), eol='') (code, resp) = self.docmd(response) if code in (235, 503): return (code, resp) raise SMTPAuthenticationError(code, resp)
def sendMail( self, password ): with SMTP( common['mailserver'], 587 ) as smtp: smtp.set_debuglevel(1) smtp.ehlo() smtp.starttls() smtp.ehlo() if not (hex(sys.hexversion) == '0x30500f0'): smtp.login( self.getShortAddressList()[0], password ) else: # Application side workaround for http://bugs.python.org/issue25446 # smtp.login using AUTH LOGIN mechanism is broken in released Python 3.5.0 # # prefer AUTH LOGIN over other mechanism if available if not "LOGIN" in smtp.esmtp_features["auth"].split(): # best effort approach: allow any other mechanism smtp.login( self.getShortAddressList()[0], password ) else: (code, resp) = smtp.docmd("AUTH", "LOGIN " + encode_base64(self.getShortAddressList()[0].encode('ascii'), eol='')) if not code == 334: raise SMTPException("Authentication not possible with this login.") (code, resp) = smtp.docmd(encode_base64(password.encode('ascii'), eol='')) # 235 : 'Authentication successful' # 503 : 'Error: already authenticated' if not code in (235, 503): raise SMTPException("Authentication unsuccessful.") smtp.sendmail( self.message[self.FROM], self.header[self.TO] + self.header[self.CC], self.message.as_string() )
def login(self, user, password): def encode_cram_md5(challenge, user, password): challenge = base64.b64decode(challenge) response = user + " " + hmac.HMAC(password.encode('ascii'), challenge, 'md5').hexdigest() return encode_base64(response.encode('ascii'), eol='') def encode_plain(user, password): s = "\0%s\0%s" % (user, password) return encode_base64(s.encode('ascii'), eol='') AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" yield from self.ehlo_or_helo_if_needed() if not self.supports("auth"): raise SMTPException("SMTP AUTH extension not supported by server.") # Authentication methods the server claims to support advertised_authlist = self.esmtp_extensions["auth"] # 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] # We try the authentication methods the server advertises, but only the # ones *we* support. And in our preferred order. authlist = [auth for auth in preferred_auths if auth in advertised_authlist] if not authlist: raise SMTPException("No suitable authentication method found.") # Some servers advertise authentication methods they don't really # support, so if authentication fails, we continue until we've tried # all methods. for authmethod in authlist: if authmethod == AUTH_CRAM_MD5: (code, resp) = yield from self.execute_command("AUTH", AUTH_CRAM_MD5) if code == 334: (code, resp) = yield from self.execute_command(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = yield from self.execute_command("AUTH", AUTH_PLAIN + " " + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = yield from self.execute_command("AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol=''))) if code == 334: (code, resp) = yield from self.execute_command(encode_base64(password.encode('ascii'), eol='')) # 235 == 'Authentication successful' # 503 == 'Error: already authenticated' if code in (235, 503): return (code, resp) # We could not login sucessfully. Return result of last attempt. raise SMTPAuthenticationError(code, resp)
def login(self, user, password): def encode_cram_md5(challenge, user, password): challenge = base64.decodestring(challenge) response = user + " " + hmac.HMAC(password, challenge).hexdigest() return encode_base64(response) def encode_plain(user, password): s = "\0%s\0%s" % (user, password) return encode_base64(s.encode('ascii'), eol='') AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" self.ehlo_or_helo_if_needed() if not self.has_extn("auth"): raise SMTPException("SMTP AUTH extension not supported by server.") authlist = self.esmtp_features["auth"].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authmethod = None for method in preferred_auths: if method in authlist: authmethod = method break if authmethod == AUTH_LOGIN: (code, resp) = self.docmd("AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user))) if code != 334: raise SMTPAuthenticationError(code, resp) (code, resp) = self.docmd(encode_base64(password)) elif authmethod == AUTH_PLAIN: temp_encode_plain = str(encode_plain(user, password)) temp_encode_plain = temp_encode_plain.replace("\n","") (code, resp) = self.docmd("AUTH", AUTH_PLAIN + " " + temp_encode_plain) elif authmethod == AUTH_CRAM_MD5: (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5) if code == 503: return (code, resp) (code, resp) = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod is None: raise SMTPException("No suitable authentication method found.") if code not in (235, 503): raise SMTPAuthenticationError(code, resp) return (code, resp)
def login(self, user, password): def encode_cram_md5(challenge, user, password): challenge = encode_base64.decodestring(challenge) response = user + " " + smtplib.hmac.HMAC(password, challenge).hexdigest() return encode_base64(response) def encode_plain(user, password): s = "\0%s\0%s" % (user, password) return encode_base64(s.encode('ascii'), eol='') AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" self.ehlo_or_helo_if_needed() if not self.has_extn("auth"): raise smtplib.SMTPException( "SMTP AUTH extension not supported by server.") authlist = self.esmtp_features["auth"].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authmethod = None for method in preferred_auths: if method in authlist: authmethod = method break if authmethod == AUTH_LOGIN: (code, resp) = self.docmd("AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user))) if code != 334: raise smtplib.SMTPAuthenticationError(code, resp) (code, resp) = self.docmd(encode_base64(password)) elif authmethod == AUTH_PLAIN: temp_encode_plain = str(encode_plain(user, password)) temp_encode_plain = temp_encode_plain.replace("\n", "") (code, resp) = self.docmd("AUTH", AUTH_PLAIN + " " + temp_encode_plain) elif authmethod == AUTH_CRAM_MD5: (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5) if code == 503: return (code, resp) (code, resp) = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod is None: raise smtplib.SMTPException( "No suitable authentication method found.") if code not in (235, 503): raise smtplib.SMTPAuthenticationError(code, resp) return (code, resp)
def login(self, username, password): def encode_cram_md5(challenge, username, password): challenge = base64.decodebytes(challenge) response = username + " " + hmac.HMAC(password.encode("ascii"), challenge, "md5").hexdigest() return encode_base64(response.encode("ascii"), eol="") def encode_plain(user, password): return encode_base64(("\0%s\0%s" % (user, password)).encode("ascii"), eol="") AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" yield self.ehlo_or_helo_if_needed() if not self.has_extn("auth"): raise smtplib.SMTPException("SMTP Auth extension not supported by server ") advertised_authlist = self.esmtp_features["auth"].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authlist = [auth for auth in preferred_auths if auth in advertised_authlist] if not authlist: raise smtplib.SMTPException("No suitable authentication method found.") # Some servers advertise authentication methods they don't really # support, so if authentication fails, we continue until we've tried # all methods. for authmethod in authlist: if authmethod == AUTH_CRAM_MD5: (code, resp) = yield self.docmd(b"AUTH", AUTH_CRAM_MD5) if code == 334: (code, resp) = yield self.docmd(encode_cram_md5(resp, username, password).encode("ascii")) elif authmethod == AUTH_PLAIN: (code, resp) = yield self.docmd( b"AUTH", (AUTH_PLAIN + " " + encode_plain(username, password)).encode("ascii") ) elif authmethod == AUTH_LOGIN: (code, resp) = yield self.docmd( b"AUTH", ("%s %s" % (AUTH_LOGIN, encode_base64(username.encode("ascii"), eol=""))).encode("ascii") ) if code == 334: (code, resp) = yield self.docmd(encode_base64(password.encode("ascii"), eol="").encode("ascii")) # 235 == 'Authentication successful' # 503 == 'Error: already authenticated' if code in (235, 503): return (code, resp) # We could not login sucessfully. Return result of last attempt. raise smtplib.SMTPAuthenticationError(code, resp)
def login(self, user, password): 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 = "******" self.ehlo_or_helo_if_needed() if not self.has_extn("auth"): raise SMTPException("SMTP AUTH extension not supported by server.") authlist = self.esmtp_features["auth"].split() 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: (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5) if code == 503: # 503 == 'Error: already authenticated' return (code, resp) (code, resp) = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = self.docmd( "AUTH", AUTH_PLAIN + " " + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = self.docmd( "AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user, eol=""))) if code != 334: raise SMTPAuthenticationError(code, resp) (code, resp) = self.docmd(encode_base64(password, eol="")) 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) return (code, resp)
def login(self, username, password): def encode_cram_md5(challenge, username, password): challenge = base64.decodebytes(challenge) response = username + " " + hmac.HMAC(password.encode('ascii'), challenge, 'md5').hexdigest() return encode_base64(response.encode('ascii'), eol="") def encode_plain(user, password): return encode_base64(("\0%s\0%s" % (user, password)).encode('ascii'), eol="") AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" yield self.ehlo_or_helo_if_needed() if not self.has_extn('auth'): raise smtplib.SMTPException("SMTP Auth extension not supported by server ") advertised_authlist = self.esmtp_features["auth"].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authlist = [auth for auth in preferred_auths if auth in advertised_authlist] if not authlist: raise smtplib.SMTPException("No suitable authentication method found.") # Some servers advertise authentication methods they don't really # support, so if authentication fails, we continue until we've tried # all methods. for authmethod in authlist: if authmethod == AUTH_CRAM_MD5: (code, resp) = yield self.docmd(b'AUTH', AUTH_CRAM_MD5) if code == 334: (code, resp) =yield self.docmd(encode_cram_md5(resp, username, password).encode('ascii')) elif authmethod == AUTH_PLAIN: (code, resp) =yield self.docmd(b'AUTH', (AUTH_PLAIN + " " + encode_plain(username, password)).encode('ascii')) elif authmethod == AUTH_LOGIN: (code, resp) = yield self.docmd(b'AUTH', ("%s %s" % (AUTH_LOGIN, encode_base64(username.encode('ascii'), eol=''))).encode('ascii')) if code == 334: (code, resp) = yield self.docmd(encode_base64(password.encode('ascii'), eol='').encode('ascii')) # 235 == 'Authentication successful' # 503 == 'Error: already authenticated' if code in (235, 503): raise gen.Return((code, resp)) # We could not login sucessfully. Return result of last attempt. raise smtplib.SMTPAuthenticationError(code, resp)
def login (self, phase = 1, resp = None): def encode_cram_md5(challenge, user, password): challenge = base64.decodebytes(challenge) response = user + " " + hmac.HMAC(password.encode('ascii'), challenge, 'md5').hexdigest() return encode_base64(response.encode('ascii'), eol='') def encode_plain(user, password): s = "\0%s\0%s" % (user, password) return encode_base64(s.encode('ascii'), eol='') try: advertised_authlist = self.esmtp_features["auth"].split() except KeyError: advertised_authlist = [] user, password = self.composer.get_LOGIN () AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authlist = [auth for auth in preferred_auths if auth in advertised_authlist] if not authlist: self.__code, self.__resp = 900, "No Suitable Authentication Method" self.__stat = 9 self.push ("rset") return if AUTH_PLAIN in authlist: self.push ("AUTH %s %s" % (AUTH_PLAIN, encode_plain (user, password))) self.__stat = 3 elif AUTH_LOGIN in authlist: if phase == 1: self.push ("AUTH %s %s" % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol=''))) self.__stat = 2.5 else: self.push (encode_base64(password.encode('ascii'), eol='')) self.__stat = 3 else: if phase == 1: self.push ("AUTH %s" % (AUTH_CRAM_MD5,)) self.__stat = 2.5 else: self.push (encode_cram_md5 (resp, user, password)) self.__stat = 3
def encode_digest_md5(challenge, user, password): challenge = base64.decodestring(challenge) c = digest_md5_decode_challenge(challenge) realm = c["realm"] nonce = c["nonce"] qop = c["qop"] cnonce = generate_cnonce() if "realm" in c: digest_uri = "smtp/%s" % realm realmPair = ',realm="%s"' % realm else: digest_uri = "smtp/localhost" realmPair = "" credential = md5("%s:%s:%s" % (user, realm, password)) # XXX: not support authorization ID a1 = "%s:%s:%s" % (credential, nonce, cnonce) if qop == "auth": a2 = "AUTHENTICATE:%s" % digest_uri else: # XXX: most servers and clients don't implement auth-int/auth-conf, # they use dummy MD5 digest for body. a2 = "AUTHENTICATE:%s:00000000000000000000000000000000" % digest_uri a1 = hexlify(md5(a1)) a2 = hexlify(md5(a2)) response = hexlify( md5("%s:%s:00000001:%s:%s:%s" % (a1, nonce, cnonce, qop, a2))) response = ( 'username="******"%s,nonce="%s",cnonce="%s",' 'nc=00000001,qop=%s,digest-uri="%s",response=%s' % (user, realmPair, nonce, cnonce, qop, digest_uri, response)) return encode_base64(response, eol="")
def encode_digest_md5(challenge, user, password): challenge = base64.decodestring(challenge) c = digest_md5_decode_challenge(challenge) realm = c["realm"] nonce = c["nonce"] qop = c["qop"] cnonce = generate_cnonce() if "realm" in c: digest_uri = "smtp/%s" % realm realmPair = ',realm="%s"' % realm else: digest_uri = "smtp/localhost" realmPair = "" credential = md5("%s:%s:%s" % (user, realm, password)) # XXX: not support authorization ID a1 = "%s:%s:%s" % (credential, nonce, cnonce) if qop == "auth": a2 = "AUTHENTICATE:%s" % digest_uri else: # XXX: most servers and clients don't implement auth-int/auth-conf, # they use dummy MD5 digest for body. a2 = "AUTHENTICATE:%s:00000000000000000000000000000000" % digest_uri a1 = hexlify(md5(a1)) a2 = hexlify(md5(a2)) response = hexlify(md5("%s:%s:00000001:%s:%s:%s" % (a1, nonce, cnonce, qop, a2))) response = ( 'username="******"%s,nonce="%s",cnonce="%s",' 'nc=00000001,qop=%s,digest-uri="%s",response=%s' % (user, realmPair, nonce, cnonce, qop, digest_uri, response)) return encode_base64(response, eol="")
def auth_login(self, challenge): """ Authobject to use with LOGIN authentication. Requires self.user and self.password to be set.""" (code, resp) = self.docmd(encode_base64(self.user.encode("ascii"), eol="")) if code == 334: return self.password raise SMTPAuthenticationError(code, resp)
def auth(self, mechanism, authobject): """Authentication command - requires response processing. 'mechanism' specifies which authentication mechanism is to be used - the valid values are those listed in the 'auth' element of 'esmtp_features'. 'authobject' must be a callable object taking a single argument: data = authobject(challenge) It will be called to process the server's challenge response; the challenge argument it is passed will be a bytes. It should return bytes data that will be base64 encoded and sent to the server. """ mechanism = mechanism.upper() (code, resp) = self.docmd("AUTH", mechanism) # Server replies with 334 (challenge) or 535 (not supported) if code == 334: challenge = base64.decodebytes(resp) response = encode_base64( authobject(challenge).encode('ascii'), eol='') (code, resp) = self.docmd(response) if code in (235, 503): return (code, resp) raise SMTPAuthenticationError(code, resp)
def login(self, user, password): 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('\x00%s\x00%s' % (user, password), eol='') AUTH_PLAIN = 'PLAIN' AUTH_CRAM_MD5 = 'CRAM-MD5' AUTH_LOGIN = '******' self.ehlo_or_helo_if_needed() if not self.has_extn('auth'): raise SMTPException('SMTP AUTH extension not supported by server.') authlist = self.esmtp_features['auth'].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authmethod = None for method in preferred_auths: if method in authlist: authmethod = method break if authmethod == AUTH_CRAM_MD5: code, resp = self.docmd('AUTH', AUTH_CRAM_MD5) if code == 503: return (code, resp) code, resp = self.docmd(encode_cram_md5(resp, user, password)) else: if authmethod == AUTH_PLAIN: code, resp = self.docmd( 'AUTH', AUTH_PLAIN + ' ' + encode_plain(user, password)) else: if authmethod == AUTH_LOGIN: code, resp = self.docmd( 'AUTH', '%s %s' % (AUTH_LOGIN, encode_base64(user, eol=''))) if code != 334: raise SMTPAuthenticationError(code, resp) code, resp = self.docmd(encode_base64(password, eol='')) else: if authmethod is None: raise SMTPException( 'No suitable authentication method found.') if code not in (235, 503): raise SMTPAuthenticationError(code, resp) return (code, resp)
def auth_login(self, challenge): """ Authobject to use with LOGIN authentication. Requires self.user and self.password to be set.""" (code, resp) = self.docmd( encode_base64(self.user.encode('ascii'), eol='')) if code == 334: return self.password raise SMTPAuthenticationError(code, resp)
def encode_cram_md5(challenge, user, password): challenge = base64.decodestring(challenge) if isinstance( password, unicode_type ): # Added by Kovid, see http://bugs.python.org/issue5285 password = password.encode('utf-8') response = user + " " + hmac.HMAC(password, challenge).hexdigest() return encode_base64(response, eol="")
def auth_cram_md5(user, password): res = send("AUTH CRAM-MD5") if res[0] != "5": challenge = res[4:] challenge = base64.decodestring(challenge) response = user + " " + hmac.HMAC(password, challenge).hexdigest() if send(encode_base64(response, eol=""))[0] == '2': return True return False
def login(self): #log in on the SMTP server self.putcmd('auth login') (code, msg) = self.getreply() if code != 334: raise SMTPResponseException(code, msg) self.putcmd(encode_base64(self.username, eol='')) (code, msg) = self.getreply() if code != 334: raise SMTPResponseException(code, msg) self.putcmd(encode_base64(self.password, eol='')) (code, msg) = self.getreply() if code not in (235, 503): # 235 == 'Authentication successful' # 503 == 'Error: already authenticated' raise SMTPResponseException(code, msg) return (code, msg)
def auth(self, mechanism, authobject, *, initial_response_ok=True): """Authentication command - requires response processing.""" mechanism = mechanism.upper() initial_response = (authobject() if initial_response_ok else None) if initial_response is not None: response = encode_base64(initial_response.encode('ascii'), eol='') (code, resp) = self.docmd('AUTH', mechanism + ' ' + response) else: (code, resp) = self.docmd('AUTH', mechanism) # If server responds with a challenge, send the response. if code == 334: challenge = base64.decodebytes(resp) response = encode_base64( authobject(challenge).encode('ascii'), eol='') (code, resp) = self.docmd(response) if code in (235, 503): return code, resp raise SMTPAuthenticationError(code, resp)
def login(self, user, password): def encode_cram_md5(challenge, user, password): challenge = base64.decodebytes(challenge) response = user + ' ' + hmac.HMAC(password.encode('ascii'), challenge).hexdigest() return encode_base64(response.encode('ascii'), eol='') def encode_plain(user, password): s = '\x00%s\x00%s' % (user, password) return encode_base64(s.encode('ascii'), eol='') AUTH_PLAIN = 'PLAIN' AUTH_CRAM_MD5 = 'CRAM-MD5' AUTH_LOGIN = '******' self.ehlo_or_helo_if_needed() if not self.has_extn('auth'): raise SMTPException('SMTP AUTH extension not supported by server.') advertised_authlist = self.esmtp_features['auth'].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authlist = [ auth for auth in preferred_auths if auth in advertised_authlist ] if not authlist: raise SMTPException('No suitable authentication method found.') for authmethod in authlist: if authmethod == AUTH_CRAM_MD5: (code, resp) = self.docmd('AUTH', AUTH_CRAM_MD5) if code == 334: (code, resp) = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = self.docmd( 'AUTH', AUTH_PLAIN + ' ' + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = self.docmd( 'AUTH', '%s %s' % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol=''))) if code == 334: (code, resp) = self.docmd( encode_base64(password.encode('ascii'), eol='')) while code in (235, 503): return (code, resp) raise SMTPAuthenticationError(code, resp)
def smtp_AUTH(self, arg): user = self.__server.auth.get('user') password = self.__server.auth.get('password') s = encode_base64("\0%s\0%s" % (user, password), eol="") if arg == 'PLAIN {}'.format(s): self.push('235 Authentication successful') else: self.push( '535 SMTP Authentication unsuccessful/' 'Bad username or password')
def login(self, user, password): 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('\x00%s\x00%s' % (user, password), eol='') AUTH_PLAIN = 'PLAIN' AUTH_CRAM_MD5 = 'CRAM-MD5' AUTH_LOGIN = '******' self.ehlo_or_helo_if_needed() if not self.has_extn('auth'): raise SMTPException('SMTP AUTH extension not supported by server.') authlist = self.esmtp_features['auth'].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authmethod = None for method in preferred_auths: if method in authlist: authmethod = method break if authmethod == AUTH_CRAM_MD5: code, resp = self.docmd('AUTH', AUTH_CRAM_MD5) if code == 503: return (code, resp) code, resp = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: code, resp = self.docmd('AUTH', AUTH_PLAIN + ' ' + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: code, resp = self.docmd('AUTH', '%s %s' % (AUTH_LOGIN, encode_base64(user, eol=''))) if code != 334: raise SMTPAuthenticationError(code, resp) code, resp = self.docmd(encode_base64(password, eol='')) elif authmethod is None: raise SMTPException('No suitable authentication method found.') if code not in (235, 503): raise SMTPAuthenticationError(code, resp) return (code, resp)
def smtp_login(): global file_smtp, sock_smtp_ssl, username, password #userstr = username_verify.get() # userstr = "*****@*****.**" #username = userstr print("username") print(username) user64 = encode_base64(username.encode('ascii'), eol='') #passstr = password_verify.get() # passstr = "<your-password>" #password = passstr print(password) pass64 = encode_base64(password.encode('ascii'), eol='') auths = '%s %s%s' % ("AUTH", "LOGIN" + " " + user64, CRLF) rcode, rstatus = send_command_smtp(sock_smtp_ssl, auths) passs = '%s%s' % (pass64, CRLF) rcode, rstatus = send_command_smtp(sock_smtp_ssl, passs) print(rcode) return int(rcode)
def auth(self, mechanism, authobject, *, initial_response_ok=True): """Authentication command - requires response processing. 'mechanism' specifies which authentication mechanism is to be used - the valid values are those listed in the 'auth' element of 'esmtp_features'. 'authobject' must be a callable object taking a single argument: data = authobject(challenge) It will be called to process the server's challenge response; the challenge argument it is passed will be a bytes. It should return an ASCII string that will be base64 encoded and sent to the server. Keyword arguments: - initial_response_ok: Allow sending the RFC 4954 initial-response to the AUTH command, if the authentication methods supports it. """ # RFC 4954 allows auth methods to provide an initial response. Not all # methods support it. By definition, if they return something other # than None when challenge is None, then they do. See issue #15014. mechanism = mechanism.upper() initial_response = (authobject() if initial_response_ok else None) if initial_response is not None: response = encode_base64(initial_response.encode('ascii'), eol='') (code, resp) = self.docmd("AUTH", mechanism + " " + response) else: (code, resp) = self.docmd("AUTH", mechanism) # If server responds with a challenge, send the response. if code == 334: challenge = base64.decodebytes(resp) response = encode_base64( authobject(challenge).encode('ascii'), eol='') (code, resp) = self.docmd(response) if code in (235, 503): return (code, resp) raise SMTPAuthenticationError(code, resp)
def login(self, user, password): def encode_cram_md5(challenge, user, password): challenge = base64.decodebytes(challenge) response = user + ' ' + hmac.HMAC(password.encode('ascii'), challenge).hexdigest() return encode_base64(response.encode('ascii'), eol='') def encode_plain(user, password): s = '\x00%s\x00%s' % (user, password) return encode_base64(s.encode('ascii'), eol='') AUTH_PLAIN = 'PLAIN' AUTH_CRAM_MD5 = 'CRAM-MD5' AUTH_LOGIN = '******' self.ehlo_or_helo_if_needed() if not self.has_extn('auth'): raise SMTPException('SMTP AUTH extension not supported by server.') advertised_authlist = self.esmtp_features['auth'].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authlist = [auth for auth in preferred_auths if auth in advertised_authlist] if not authlist: raise SMTPException('No suitable authentication method found.') for authmethod in authlist: if authmethod == AUTH_CRAM_MD5: (code, resp) = self.docmd('AUTH', AUTH_CRAM_MD5) if code == 334: (code, resp) = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = self.docmd('AUTH', AUTH_PLAIN + ' ' + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = self.docmd('AUTH', '%s %s' % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol=''))) if code == 334: (code, resp) = self.docmd(encode_base64(password.encode('ascii'), eol='')) while code in (235, 503): return (code, resp) raise SMTPAuthenticationError(code, resp)
def send_mail(self, eml_path): self.__smtp_connection() smtp_hdr = [] smtp_hdr.append("ehlo %s\r\n" % (self.ehlo)) if self.uid != None and self.pwd != None and get_param( ("--auth", "-a")) == "True": auth_key = b"" auth_key += '\x00' auth_key += self.uid.encode('ascii') auth_key += '\x00' auth_key += self.pwd.encode('ascii') smtp_hdr.append("AUTH PLAIN %s\r\n" % (encode_base64(auth_key, eol=''))) for hdr_it in smtp_hdr: sys.stdout.write("%sC%s > %s" % (C_GREEN, C_END, hdr_it)) self.sock.send(hdr_it.encode()) sleep(0.05) smtp_hdr = [] smtp_hdr.append("quit\r\n") if type(eml_path) != list: eml_path = [ eml_path, ] for item in eml_path: if os.path.exists(item) == False: continue self.__send_mail_from_log(item) for hdr_it in smtp_hdr: sys.stdout.write("%sC%s > %s" % (C_GREEN, C_END, hdr_it)) sleep(0.05) self.sock.send(hdr_it.encode()) for i in range(2500): if self.asw_command[-1] == "221": break sleep(0.001) self.__smtp_disconnection()
def login_auth(user, password): login = encode_base64(user, eol="") #aXNzYWhhckBpbmJveC5ydQ== password = encode_base64(password, eol="") #Mjh6UjVRMXRK if request("AUTH LOGIN")[0] == '3' and request(login)[0] == '3' and request(password)[0] == '2': return True return False
self.assertEqual(self.serv.last_message.decode(), expected) self.assertIn("BODY=8BITMIME", self.serv.last_mail_options) self.assertIn("SMTPUTF8", self.serv.last_mail_options) self.assertEqual(self.serv.last_rcpt_options, []) def test_send_message_error_on_non_ascii_addrs_if_no_smtputf8(self): msg = EmailMessage() msg["From"] = "Páolo <fő[email protected]>" msg["To"] = "Dinsdale" msg["Subject"] = "Nudge nudge, wink, wink \u1F609" smtp = smtplib.SMTP(HOST, self.port, local_hostname="localhost", timeout=3) self.addCleanup(smtp.close) self.assertRaises(smtplib.SMTPNotSupportedError, smtp.send_message(msg)) EXPECTED_RESPONSE = encode_base64(b"\0psu\0doesnotexist", eol="") class SimSMTPAUTHInitialResponseChannel(SimSMTPChannel): def smtp_AUTH(self, arg): # RFC 4954's AUTH command allows for an optional initial-response. # Not all AUTH methods support this; some require a challenge. AUTH # PLAIN does those, so test that here. See issue #15014. args = arg.split() if args[0].lower() == "plain": if len(args) == 2: # AUTH PLAIN <initial-response> with the response base 64 # encoded. Hard code the expected response for the test. if args[1] == EXPECTED_RESPONSE: self.push("235 Ok") return
def login(self, user, password): def encode_cram_md5(challenge, user, password): challenge = base64.b64decode(challenge) response = user + " " + hmac.HMAC(password.encode('ascii'), challenge, 'md5').hexdigest() return encode_base64(response.encode('ascii'), eol='') def encode_plain(user, password): s = "\0%s\0%s" % (user, password) return encode_base64(s.encode('ascii'), eol='') AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" yield from self.ehlo_or_helo_if_needed() if not self.supports("auth"): raise SMTPException("SMTP AUTH extension not supported by server.") # Authentication methods the server claims to support advertised_authlist = self.esmtp_extensions["auth"] # 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] # We try the authentication methods the server advertises, but only the # ones *we* support. And in our preferred order. authlist = [ auth for auth in preferred_auths if auth in advertised_authlist ] if not authlist: raise SMTPException("No suitable authentication method found.") # Some servers advertise authentication methods they don't really # support, so if authentication fails, we continue until we've tried # all methods. for authmethod in authlist: if authmethod == AUTH_CRAM_MD5: (code, resp) = yield from self.execute_command( "AUTH", AUTH_CRAM_MD5) if code == 334: (code, resp) = yield from self.execute_command( encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = yield from self.execute_command( "AUTH", AUTH_PLAIN + " " + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = yield from self.execute_command( "AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol=''))) if code == 334: (code, resp) = yield from self.execute_command( encode_base64(password.encode('ascii'), eol='')) # 235 == 'Authentication successful' # 503 == 'Error: already authenticated' if code in (235, 503): return (code, resp) # We could not login sucessfully. Return result of last attempt. raise SMTPAuthenticationError(code, resp)
def encode_cram_md5(challenge, user, password): challenge = base64.decodestring(challenge) response = user + " " + hmac.HMAC(password, challenge).hexdigest() return encode_base64(response, eol="")
self.assertIn('SMTPUTF8', self.serv.last_mail_options) self.assertEqual(self.serv.last_rcpt_options, []) def test_send_message_error_on_non_ascii_addrs_if_no_smtputf8(self): msg = EmailMessage() msg['From'] = "Páolo <fő[email protected]>" msg['To'] = 'Dinsdale' msg['Subject'] = 'Nudge nudge, wink, wink \u1F609' smtp = smtplib.SMTP( HOST, self.port, local_hostname='localhost', timeout=3) self.addCleanup(smtp.close) self.assertRaises(smtplib.SMTPNotSupportedError, smtp.send_message(msg)) EXPECTED_RESPONSE = encode_base64(b'\0psu\0doesnotexist', eol='') class SimSMTPAUTHInitialResponseChannel(SimSMTPChannel): def smtp_AUTH(self, arg): # RFC 4954's AUTH command allows for an optional initial-response. # Not all AUTH methods support this; some require a challenge. AUTH # PLAIN does those, so test that here. See issue #15014. args = arg.split() if args[0].lower() == 'plain': if len(args) == 2: # AUTH PLAIN <initial-response> with the response base 64 # encoded. Hard code the expected response for the test. if args[1] == EXPECTED_RESPONSE: self.push('235 Ok') return self.push('571 Bad authentication')
def encode_plain(user, password): s = "\0%s\0%s" % (user, password) return encode_base64(s.encode('ascii'), eol='')
def encode_plain(user, password): s = "\0%s\0%s" % (user, password) return encode_base64(s.encode("ascii"), eol="")
def generate_cnonce(): s = "" for i in range(16): s = s + chr(random.randint(0, 0xff)) return encode_base64(s, eol="")
def encode_cram_md5(challenge, username, password): challenge = base64.decodebytes(challenge) response = username + " " + hmac.HMAC(password.encode("ascii"), challenge, "md5").hexdigest() return encode_base64(response.encode("ascii"), eol="")
def auth_plain(login, password): if send("AUTH PLAIN " + encode_base64("\0%s\0%s" % (login, password), eol=""))[0] == "2": return True return False
def login(self, user, password): """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('\x00%s\x00%s' % (user, password), eol='') AUTH_PLAIN = 'PLAIN' AUTH_CRAM_MD5 = 'CRAM-MD5' AUTH_LOGIN = '******' self.ehlo_or_helo_if_needed() if not self.has_extn('auth'): raise SMTPException('SMTP AUTH extension not supported by server.') authlist = self.esmtp_features['auth'].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authmethod = None for method in preferred_auths: if method in authlist: authmethod = method break if authmethod == AUTH_CRAM_MD5: code, resp = self.docmd('AUTH', AUTH_CRAM_MD5) if code == 503: return (code, resp) code, resp = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: code, resp = self.docmd('AUTH', AUTH_PLAIN + ' ' + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: code, resp = self.docmd('AUTH', '%s %s' % (AUTH_LOGIN, encode_base64(user, eol=''))) if code != 334: raise SMTPAuthenticationError(code, resp) code, resp = self.docmd(encode_base64(password, eol='')) elif authmethod is None: raise SMTPException('No suitable authentication method found.') if code not in (235, 503): raise SMTPAuthenticationError(code, resp) return (code, resp)
def encode_cram_md5(challenge, user, password): challenge = base64.decodebytes(challenge) response = user + " " + hmac.HMAC(password.encode('ascii'), challenge).hexdigest() return encode_base64(response.encode('ascii'), eol='')
def login(self, user, password): """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.decodebytes(challenge) response = user + " " + hmac.HMAC(password.encode('ascii'), challenge, 'md5').hexdigest() return encode_base64(response.encode('ascii'), eol='') def encode_plain(user, password): s = "\0%s\0%s" % (user, password) return encode_base64(s.encode('ascii'), eol='') AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" 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 claims to support advertised_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] # We try the authentication methods the server advertises, but only the # ones *we* support. And in our preferred order. authlist = [auth for auth in preferred_auths if auth in advertised_authlist] if not authlist: raise SMTPException("No suitable authentication method found.") # Some servers advertise authentication methods they don't really # support, so if authentication fails, we continue until we've tried # all methods. for authmethod in authlist: if authmethod == AUTH_CRAM_MD5: (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5) if code == 334: (code, resp) = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = self.docmd("AUTH", AUTH_PLAIN + " " + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = self.docmd("AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol=''))) if code == 334: (code, resp) = self.docmd(encode_base64(password.encode('ascii'), eol='')) # 235 == 'Authentication successful' # 503 == 'Error: already authenticated' if code in (235, 503): return (code, resp) # We could not login sucessfully. Return result of last attempt. raise SMTPAuthenticationError(code, resp)
def encode_cram_md5(challenge, user, password): challenge = base64.decodebytes(challenge) response = user + " " + hmac.HMAC(password.encode('ascii'), challenge, 'md5').hexdigest() return encode_base64(response.encode('ascii'), eol='')
def login(self, user, password): """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 digest_md5_decode_challenge(challenge): # Challenge is formed with these pairs separated by comma. # realm="hostname" (multiple allowed) # nonce="randomized data, at least 64bit" # qop="auth,auth-int,auth-conf" # maxbuf=number (with auth-int, auth-conf, defaults to 64k) # charset="utf-8" (iso-8859-1 if it doesn't exist) # algorithm="md5-sess" # cipher="3des,des,rc4-40,rc4,rc4-56" (with auth-conf) # # XXX: multiple realms are not supported c = {} for e in challenge.split(','): off = e.index('=') v = e[off + 1:].strip() if v[0] == '"': v = v[1:-1] c[e[:off].strip()] = v return c def generate_cnonce(): s = "" for i in range(16): s = s + chr(random.randint(0, 0xff)) return encode_base64(s, eol="") def md5(indata): try: import hashlib md5 = hashlib.md5(indata) except ImportError: import md5 md5 = md5.new(indata) return md5.digest() def encode_digest_md5(challenge, user, password): challenge = base64.decodestring(challenge) c = digest_md5_decode_challenge(challenge) realm = c["realm"] nonce = c["nonce"] qop = c["qop"] cnonce = generate_cnonce() if "realm" in c: digest_uri = "smtp/%s" % realm realmPair = ',realm="%s"' % realm else: digest_uri = "smtp/localhost" realmPair = "" credential = md5("%s:%s:%s" % (user, realm, password)) # XXX: not support authorization ID a1 = "%s:%s:%s" % (credential, nonce, cnonce) if qop == "auth": a2 = "AUTHENTICATE:%s" % digest_uri else: # XXX: most servers and clients don't implement auth-int/auth-conf, # they use dummy MD5 digest for body. a2 = "AUTHENTICATE:%s:00000000000000000000000000000000" % digest_uri a1 = hexlify(md5(a1)) a2 = hexlify(md5(a2)) response = hexlify( md5("%s:%s:00000001:%s:%s:%s" % (a1, nonce, cnonce, qop, a2))) response = ( 'username="******"%s,nonce="%s",cnonce="%s",' 'nc=00000001,qop=%s,digest-uri="%s",response=%s' % (user, realmPair, nonce, cnonce, qop, digest_uri, response)) 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_DIGEST_MD5 = "DIGEST-MD5" AUTH_LOGIN = "******" 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_DIGEST_MD5, 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_DIGEST_MD5: (code, resp) = self.docmd("AUTH", AUTH_DIGEST_MD5) if code == 503: # 503 == 'Error: already authenticated' return (code, resp) (code, resp) = self.docmd(encode_digest_md5(resp, user, password)) if code == 334: # XXX: need validate "resp"? (code, resp) = self.docmd("") elif authmethod == AUTH_CRAM_MD5: (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5) if code == 503: # 503 == 'Error: already authenticated' return (code, resp) (code, resp) = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = self.docmd( "AUTH", AUTH_PLAIN + " " + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = self.docmd( "AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user, eol=""))) if code != 334: raise SMTPAuthenticationError(code, resp) (code, resp) = self.docmd(encode_base64(password, eol="")) 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) return (code, resp)
def login(self, user, password): """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 = "******" 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: (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5) if code == 503: # 503 == 'Error: already authenticated' return (code, resp) (code, resp) = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = self.docmd("AUTH", AUTH_PLAIN + " " + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = self.docmd("AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user, eol=""))) if code != 334: raise SMTPAuthenticationError(code, resp) (code, resp) = self.docmd(encode_base64(password, eol="")) 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) return (code, resp)
def encode_plain(user, password): return encode_base64("\0%s\0%s" % (user, password), eol="")
def encode_plain(user, password): return encode_base64(("\0%s\0%s" % (user, password)).encode('ascii'), eol="")
def login(self, user, password): """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.decodebytes(challenge) response = user + " " + hmac.HMAC(password.encode('ascii'), challenge).hexdigest() return encode_base64(response.encode('ascii'), eol='') def encode_plain(user, password): s = "\0%s\0%s" % (user, password) return encode_base64(s.encode('ascii'), eol='') AUTH_PLAIN = "PLAIN" AUTH_CRAM_MD5 = "CRAM-MD5" AUTH_LOGIN = "******" 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 claims to support advertised_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] # We try the authentication methods the server advertises, but only the # ones *we* support. And in our preferred order. authlist = [ auth for auth in preferred_auths if auth in advertised_authlist ] if not authlist: raise SMTPException("No suitable authentication method found.") # Some servers advertise authentication methods they don't really # support, so if authentication fails, we continue until we've tried # all methods. for authmethod in authlist: if authmethod == AUTH_CRAM_MD5: (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5) if code == 334: (code, resp) = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = self.docmd( "AUTH", AUTH_PLAIN + " " + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = self.docmd( "AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol=''))) if code == 334: (code, resp) = self.docmd( encode_base64(password.encode('ascii'), eol='')) # 235 == 'Authentication successful' # 503 == 'Error: already authenticated' if code in (235, 503): return (code, resp) # We could not login sucessfully. Return result of last attempt. raise SMTPAuthenticationError(code, resp)
def auth_login(user, password): login_base64 = encode_base64(user, eol="") password_base64 = encode_base64(password, eol="") if send("AUTH LOGIN")[0] == '3' and send(login_base64)[0] == '3' and send(password_base64)[0] == '2': return True return False
def login(self, user, password): """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('\x00%s\x00%s' % (user, password), eol='') AUTH_PLAIN = 'PLAIN' AUTH_CRAM_MD5 = 'CRAM-MD5' AUTH_LOGIN = '******' self.ehlo_or_helo_if_needed() if not self.has_extn('auth'): raise SMTPException('SMTP AUTH extension not supported by server.') authlist = self.esmtp_features['auth'].split() preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN] authmethod = None for method in preferred_auths: if method in authlist: authmethod = method break if authmethod == AUTH_CRAM_MD5: code, resp = self.docmd('AUTH', AUTH_CRAM_MD5) if code == 503: return (code, resp) code, resp = self.docmd(encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: code, resp = self.docmd( 'AUTH', AUTH_PLAIN + ' ' + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: code, resp = self.docmd( 'AUTH', '%s %s' % (AUTH_LOGIN, encode_base64(user, eol=''))) if code != 334: raise SMTPAuthenticationError(code, resp) code, resp = self.docmd(encode_base64(password, eol='')) elif authmethod is None: raise SMTPException('No suitable authentication method found.') if code not in (235, 503): raise SMTPAuthenticationError(code, resp) return (code, resp)
def encode_plain(user, password): return encode_base64('\x00%s\x00%s' % (user, password), 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: (code, resp) = yield gen.Task(self.docmd, "AUTH", AUTH_CRAM_MD5) if code == 503: # 503 == 'Error: already authenticated' if callback: callback((code, resp)) return (code, resp) = yield gen.Task(self.docmd, encode_cram_md5(resp, user, password)) elif authmethod == AUTH_PLAIN: (code, resp) = yield gen.Task(self.docmd, "AUTH", AUTH_PLAIN + " " + encode_plain(user, password)) elif authmethod == AUTH_LOGIN: (code, resp) = yield gen.Task(self.docmd, "AUTH", "%s %s" % (AUTH_LOGIN, encode_base64(user, eol=""))) if code != 334: raise SMTPAuthenticationError(code, resp) (code, resp) = yield gen.Task(self.docmd, encode_base64(password, eol="")) 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 plain_auth(user, password): if request("AUTH PLAIN " + encode_base64("\0%s\0%s" % (user, password), eol=""))[0] == "2": return True return False
def encode_cram_md5(challenge, user, password): challenge = base64.decodestring(challenge) if isinstance(password, unicode): # Added by Kovid, see http://bugs.python.org/issue5285 password = password.encode('utf-8') response = user + " " + hmac.HMAC(password, challenge).hexdigest() return encode_base64(response, eol="")