The following example is used to login to Roundup via a Windows NT authentication process. This extension uses Windows SSPI services to enable the authentication process. To validate a user in a Windows Domain Controller use this service along with the NTLM protocol.
You will need the pywin32 extension. Try to install a current one as the SSPI services weren't added until recently (sometime in 2005). I know that version 205 already has it.
This example is just a mix of LDAPLogin published in this wiki and the code in validate.py
that's included in pywin32 library.
User profiles are also stored in Roundup database, to minimize code modifications. Also:
- user can also be stored and authenticated only internally into Roundup database.
- user's profile are not automatically created (I took it off just to simplify this code).
In your extensions directory, create a file sspilogin.py with:
import win32security
from sspi import ClientAuth, ServerAuth
from roundup.cgi.actions import LoginAction
from roundup.i18n import _
class SSPIloginAction(LoginAction):
# parameters for NTLM authentication.
domain = ""
pkg_name = "NTLM"
def verifyLocalPassword(self, password):
''' Verify the password that the user has supplied '''
stored = self.db.user.get(self.client.userid, 'password')
if password == stored:
return 1
if not password and not stored:
return 1
return 0
def local_login (self, password):
''' Local authentication '''
# make sure the user exists
try:
self.client.userid = self.db.user.lookup(self.client.user)
except KeyError:
self.client.error_message.append(_('Unknown user "%s"')%self.client.user)
return 0
# verify the password
if not self.verifyLocalPassword(password):
self.client.error_message.append(_('Invalid password'))
return 0
return 1
def sspi_login (self, password):
''' Authentication via Windows SSPI '''
try:
auth_info = self.client.user, self.domain, password
ca = ClientAuth(self.pkg_name, auth_info = auth_info)
sa = ServerAuth(self.pkg_name)
data = err = None
while err != 0:
err, data = ca.authorize(data)
err, data = sa.authorize(data)
# If we get here without exception, we worked!
except win32security.error, details:
hr, func, msg = details
self.client.error_message.append (_('Unknown SSPI account "%s"')% self.client.user)
self.client.error_message.append (_('SSPIError = %s (%d)"') % (msg, hr))
return 0
return 1
def verifyLogin(self, username, password):
# try to login throught SSPI or with local account
sspi_ok = None
if not self.local_login(password):
sspi_ok = self.sspi_login(password)
if not sspi_ok:
self.client.make_user_anonymous ()
return
self.client.error_message = []
# reload user profile
try:
self.client.userid = self.db.user.lookup(self.client.user)
except:
self.client.make_user_anonymous()
self.client.error_message.append(_("No account created without SSPI account"))
return
def init(instance):
instance.registerAction('login', SSPIloginAction)
You only need to specify the Windows Domain of your users in case Roundup is not running in a server that belongs to this same domain. Otherwise leave it blank.
Regards,
-Hernan. (hfoffani@gmail.com)