Bug#359213: Kerberos
* John Goerzen (jgoerzen@complete.org) wrote: > tages 359213 help > thanks > > Hi folks, > > Unfortunately, I lack both the expertise to add Kerberos > authentication and a way to test this. A patch would be very welcome > :-) Well it was a bit unclear but there's a patch for offlineimap attached to Guido's message: http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=10;filename=support-GSSAPI-via-pykerberos.diff;att=1;bug=359213 I've tried it out and it works great! Except that if the Kerberos layer throws an exception it wouldn't fail over to plain authentication properly. Attached is a slightly reworked patch that I tested it in the following situations: 1. python-kerberos uninstalled, with kerberos credentials. Prompted for password authentication as expected. 2. python-kerberos installed, with kerberos credentials. Keberos authentication was successful and my mail was fetched without password prompting. Yeehaw! 3. python-kerberos installed, with no kerberos credentials. Prompted for password authentication as expected. I think those are all the interesting situations. So I think this is ready to go in, with a Suggest on python-kerberos (>= 1.0+mk080218-1). -- Eric Dorland <eric@kuroneko.ca> ICQ: #61138586, Jabber: hooty@jabber.com
This commit is contained in:
parent
cf1a1b31e2
commit
f7b5aa4ba3
@ -21,7 +21,16 @@ from offlineimap import imaplibutil, imaputil, threadutil
|
|||||||
from offlineimap.ui import UIBase
|
from offlineimap.ui import UIBase
|
||||||
from threading import *
|
from threading import *
|
||||||
import thread, hmac, os
|
import thread, hmac, os
|
||||||
|
import base64
|
||||||
|
|
||||||
|
try:
|
||||||
|
# do we have a recent pykerberos?
|
||||||
|
have_gss = False
|
||||||
|
import kerberos
|
||||||
|
if 'authGSSClientWrap' in dir(kerberos):
|
||||||
|
have_gss = True
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
class UsefulIMAPMixIn:
|
class UsefulIMAPMixIn:
|
||||||
def getstate(self):
|
def getstate(self):
|
||||||
@ -58,6 +67,8 @@ class UsefulIMAP4_SSL(UsefulIMAPMixIn, imaplibutil.WrappedIMAP4_SSL):
|
|||||||
class UsefulIMAP4_Tunnel(UsefulIMAPMixIn, imaplibutil.IMAP4_Tunnel): pass
|
class UsefulIMAP4_Tunnel(UsefulIMAPMixIn, imaplibutil.IMAP4_Tunnel): pass
|
||||||
|
|
||||||
class IMAPServer:
|
class IMAPServer:
|
||||||
|
GSS_STATE_STEP = 0
|
||||||
|
GSS_STATE_WRAP = 1
|
||||||
def __init__(self, config, reposname,
|
def __init__(self, config, reposname,
|
||||||
username = None, password = None, hostname = None,
|
username = None, password = None, hostname = None,
|
||||||
port = None, ssl = 1, maxconnections = 1, tunnel = None,
|
port = None, ssl = 1, maxconnections = 1, tunnel = None,
|
||||||
@ -86,6 +97,9 @@ class IMAPServer:
|
|||||||
self.semaphore = BoundedSemaphore(self.maxconnections)
|
self.semaphore = BoundedSemaphore(self.maxconnections)
|
||||||
self.connectionlock = Lock()
|
self.connectionlock = Lock()
|
||||||
self.reference = reference
|
self.reference = reference
|
||||||
|
self.gss_step = self.GSS_STATE_STEP
|
||||||
|
self.gss_vc = None
|
||||||
|
self.gssapi = False
|
||||||
|
|
||||||
def getpassword(self):
|
def getpassword(self):
|
||||||
if self.goodpassword != None:
|
if self.goodpassword != None:
|
||||||
@ -135,6 +149,33 @@ class IMAPServer:
|
|||||||
'Attempting plain authentication')
|
'Attempting plain authentication')
|
||||||
imapobj.login(self.username, self.getpassword())
|
imapobj.login(self.username, self.getpassword())
|
||||||
|
|
||||||
|
def gssauth(self, response):
|
||||||
|
data = base64.b64encode(response)
|
||||||
|
try:
|
||||||
|
if self.gss_step == self.GSS_STATE_STEP:
|
||||||
|
if not self.gss_vc:
|
||||||
|
rc, self.gss_vc = kerberos.authGSSClientInit('imap@' +
|
||||||
|
self.hostname)
|
||||||
|
response = kerberos.authGSSClientResponse(self.gss_vc)
|
||||||
|
rc = kerberos.authGSSClientStep(self.gss_vc, data)
|
||||||
|
if rc != kerberos.AUTH_GSS_CONTINUE:
|
||||||
|
self.gss_step = self.GSS_STATE_WRAP
|
||||||
|
elif self.gss_step == self.GSS_STATE_WRAP:
|
||||||
|
rc = kerberos.authGSSClientUnwrap(self.gss_vc, data)
|
||||||
|
response = kerberos.authGSSClientResponse(self.gss_vc)
|
||||||
|
rc = kerberos.authGSSClientWrap(self.gss_vc, response,
|
||||||
|
self.username)
|
||||||
|
response = kerberos.authGSSClientResponse(self.gss_vc)
|
||||||
|
except kerberos.GSSError, err:
|
||||||
|
# Kerberos errored out on us, respond with None to cancel the
|
||||||
|
# authentication
|
||||||
|
UIBase.getglobalui().debug('imap',
|
||||||
|
'%s: %s' % (err[0][0], err[1][0]))
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not response:
|
||||||
|
response = ''
|
||||||
|
return base64.b64decode(response)
|
||||||
|
|
||||||
def acquireconnection(self):
|
def acquireconnection(self):
|
||||||
"""Fetches a connection from the pool, making sure to create a new one
|
"""Fetches a connection from the pool, making sure to create a new one
|
||||||
@ -186,6 +227,20 @@ class IMAPServer:
|
|||||||
|
|
||||||
if not self.tunnel:
|
if not self.tunnel:
|
||||||
try:
|
try:
|
||||||
|
# Try GSSAPI and continue if it fails
|
||||||
|
if 'AUTH=GSSAPI' in imapobj.capabilities and have_gss:
|
||||||
|
UIBase.getglobalui().debug('imap',
|
||||||
|
'Attempting GSSAPI authentication')
|
||||||
|
try:
|
||||||
|
imapobj.authenticate('GSSAPI', self.gssauth)
|
||||||
|
except imapobj.error, val:
|
||||||
|
UIBase.getglobalui().debug('imap',
|
||||||
|
'GSSAPI Authentication failed')
|
||||||
|
else:
|
||||||
|
self.gssapi = True
|
||||||
|
self.password = None
|
||||||
|
|
||||||
|
if not self.gssapi:
|
||||||
if 'AUTH=CRAM-MD5' in imapobj.capabilities:
|
if 'AUTH=CRAM-MD5' in imapobj.capabilities:
|
||||||
UIBase.getglobalui().debug('imap',
|
UIBase.getglobalui().debug('imap',
|
||||||
'Attempting CRAM-MD5 authentication')
|
'Attempting CRAM-MD5 authentication')
|
||||||
|
Loading…
Reference in New Issue
Block a user