Log note : add my name in case anyone wants to blame Richard for this.
changed:
-
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 <a href="http://sourceforge.net/projects/pywin32/">pywin32</a> 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)