Add SASL PLAIN authentication method
- this method isn't as deprecated as IMAP LOGIN; - it allows to keep hashed passwords on the server side; - it has the ability to specify that the remote identity is different from authenticating username, so it even can be useful in some cases (e.g., migrated mailboxes); configuration variable "remote_identity" was introduced to leverage this functionality. From: Andreas Mack <andreas.mack@konsec.com> Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
This commit is contained in:
		 Andreas Mack
					Andreas Mack
				
			
				
					committed by
					
						 Eygene Ryabinkin
						Eygene Ryabinkin
					
				
			
			
				
	
			
			
			 Eygene Ryabinkin
						Eygene Ryabinkin
					
				
			
						parent
						
							7d313f49dc
						
					
				
				
					commit
					acaa96291d
				
			| @@ -16,6 +16,7 @@ WIP (add new stuff for the next release) | ||||
| * Honor the timezone of emails (Tobias Thierer) | ||||
| * Allow mbnames output to be sorted by a custom sort key by specifying | ||||
|   a 'sort_keyfunc' function in the [mbnames] section of the config. | ||||
| * Support SASL PLAIN authentication method.  (Andreas Mack) | ||||
|  | ||||
| OfflineIMAP v6.5.5-rc1 (2012-09-05) | ||||
| =================================== | ||||
|   | ||||
| @@ -353,6 +353,18 @@ ssl = yes | ||||
| # Specify the remote user name. | ||||
| remoteuser = username | ||||
|  | ||||
| # Specify the user to be authorized as.  Sometimes we want to | ||||
| # authenticate with our login/password, but tell the server that we | ||||
| # really want to be treated as some other user; perhaps server will | ||||
| # allow us to do that (or, may be, not).  Some IMAP servers migrate | ||||
| # account names using this functionality: your credentials remain | ||||
| # intact, but remote identity changes. | ||||
| # | ||||
| # Currently this variable is used only for SASL PLAIN authentication | ||||
| # mechanism. | ||||
| # | ||||
| # remote_identity = authzuser | ||||
|  | ||||
| # There are six ways to specify the password for the IMAP server: | ||||
| # | ||||
| # 1. No password at all specified in the config file. | ||||
|   | ||||
| @@ -55,6 +55,7 @@ class IMAPServer: | ||||
|         self.tunnel = repos.getpreauthtunnel() | ||||
|         self.usessl = repos.getssl() | ||||
|         self.username = None if self.tunnel else repos.getuser() | ||||
|         self.user_identity = repos.get_remote_identity() | ||||
|         self.password = None | ||||
|         self.passworderror = None | ||||
|         self.goodpassword = None | ||||
| @@ -133,6 +134,24 @@ class IMAPServer: | ||||
|         self.ui.debug('imap', 'Attempting IMAP LOGIN authentication') | ||||
|         imapobj.login(self.username, self.getpassword()) | ||||
|  | ||||
|  | ||||
|     def plainhandler(self, response): | ||||
|         """ | ||||
|         Implements SASL PLAIN authentication, RFC 4616, | ||||
|           http://tools.ietf.org/html/rfc4616 | ||||
|  | ||||
|         """ | ||||
|         authc = self.username | ||||
|         passwd = self.getpassword() | ||||
|         authz = '' | ||||
|         if self.user_identity != None: | ||||
|             authz = self.user_identity | ||||
|         NULL = u'\x00' | ||||
|         retval = NULL.join((authz, authc, passwd)).encode('utf-8') | ||||
|         self.ui.debug('imap', 'plainhandler: returning %s' % retval) | ||||
|         return retval | ||||
|  | ||||
|  | ||||
|     def gssauth(self, response): | ||||
|         data = base64.b64encode(response) | ||||
|         try: | ||||
| @@ -213,6 +232,8 @@ class IMAPServer: | ||||
|                   "TLS connection: %s" % str(e), | ||||
|                   OfflineImapError.ERROR.REPO) | ||||
|  | ||||
| 	# Hashed authenticators come first: they don't reveal | ||||
| 	# passwords. | ||||
|         if 'AUTH=CRAM-MD5' in imapobj.capabilities: | ||||
|             tried_to_authn = True | ||||
|             self.ui.debug('imap', 'Attempting ' | ||||
| @@ -224,6 +245,18 @@ class IMAPServer: | ||||
|                 self.ui.warn('CRAM-MD5 authentication failed: %s' % e) | ||||
|                 exc_stack.append(('CRAM-MD5', e)) | ||||
|  | ||||
|         # Try plaintext authenticators. | ||||
|         if 'AUTH=PLAIN' in imapobj.capabilities: | ||||
|             tried_to_authn = True | ||||
|             self.ui.debug('imap', 'Attempting ' | ||||
|               'PLAIN authentication') | ||||
|             try: | ||||
|                 imapobj.authenticate('PLAIN', self.plainhandler) | ||||
|                 return | ||||
|             except imapobj.error as e: | ||||
|                 self.ui.warn('PLAIN authentication failed: %s' % e) | ||||
|                 exc_stack.append(('PLAIN', e)) | ||||
|  | ||||
|         # Last resort: use LOGIN command, | ||||
|         # unless LOGINDISABLED is advertized (RFC 2595) | ||||
|         if 'LOGINDISABLED' in imapobj.capabilities: | ||||
|   | ||||
| @@ -115,6 +115,18 @@ class IMAPRepository(BaseRepository): | ||||
|                                    "'%s' specified." % self, | ||||
|                                OfflineImapError.ERROR.REPO) | ||||
|  | ||||
|  | ||||
|     def get_remote_identity(self): | ||||
|         """ | ||||
|         Remote identity is used for certain SASL mechanisms | ||||
|         (currently -- PLAIN) to inform server about the ID | ||||
|         we want to authorize as instead of our login name. | ||||
|  | ||||
|         """ | ||||
|  | ||||
|         return self.getconf('remote_identity', default=None) | ||||
|  | ||||
|  | ||||
|     def getuser(self): | ||||
|         user = None | ||||
|         localeval = self.localeval | ||||
|   | ||||
		Reference in New Issue
	
	Block a user