
Writing a Customized Login Handler
==================================


Introduction
------------

By default, GNUe clients look at a database connection, determine what 
fields it needs in order to login (e.g., username and password), and then 
asks its platform/interface dependent login handler to prompt the user for 
this information. Once returned, the client connects to the database using 
this information. 

If needed, you can intercept a client's normal login handler to add your 
own behavior.


Why?
----
Sometimes it is not enough to prompt for the "database" login.  Perhaps 
you want finer control over logins, or simply need to authenticate against 
something besides the database.

You might want to authenticate against an NIS source, LDAP, or some custom 
source.  Maybe you have many users and want to authenticate against rows in 
a database table and have the actual database login name/password be a 
common one that no one knows; i.e., while users Jason and James might log 
in using "jason" and "james", they might both connect to the database as 
"commonuser".  Since you may not trust James, you only want him to know 
that he is logging in as "james" and never know that he is being connected 
as "commonuser".



What do I do?
-------------

First, a little explanation of how logins work: 
  
1. A client needs to initialize a connection to a database, so it passes 
   GNUe-Common a description of the database and asks for it to connect.

2. GNUe-Common looks at the database description, determines what values 
   are needed to connect (usually, username and password).

3. GNUe-Common creates an instance of (or uses an existing instance of) 
   gnue.common.GLoginHander.LoginHandler, or if the client provides a
   more advanced login handler (e.g., GNUe Form's graphical handler), an
   instance of this.

4. GNUe-Common calls LoginHandler.getLogin(), passing it basic information 
   about the needed connection and a list of values that login handler 
   should provide (i.e., '_username' & '_password'). 

5. GNUe-Common uses the results of the call to LoginHandler.getLogin() to 
   create a connection to the database. 


Now, if needed, you can subclass LoginHandler (basically intercepting 
steps #3-4 above) and provide your own functionality.  All that is needed 
is for you to provide class with a method called getLogin that takes as 
input a tuple of:

    (database id, description, (requiredValues) ) 

and return a hash containing a dictionary/hash: 
    
    { 'field': 'value' }. 

RequiredValues is a tuple of tuples containing:

    (value id, value description, isPassword)

Example of a getLogin call as used by GNUe Common

    loginHandler.getLogin ('gnue',                  # Connection ID
                           'GNUe Test Database',    # Connection Name
                           ( ('_username','User Name', 0),    # Required
                             ('_password','Password', 1) ) )  # Fields

You would want to write your own handler as such: 


    #####################################################
    #
    # Template for a custom login handler
    #
    
    # Import the base login handler; 
    # Note: it is important that this line not change.
    from gnue.common.GLoginHander import LoginHandler
    
    # Do not rename this class. 
    # GNUe clients expect to see a MyLoginHander class
    class MyLoginHandler(LoginHandler): 
    
      #
      # getLogin is passed an list consisting of: 
      #   Connection Name
      #   Connection Comments/Description 
      #   List of Fields to Input: 
      #      Attribute Name, Label/Description, Is Password?
      #
      # It should return a dictionary of {Attribute Name: Inputted Value}
      #
      def getLogin(self, loginData): 
    
        connName = loginData[0]
        connDescription = loginData[1]
        requiredFields = loginData[2]
    
        # Perform any tasks prior to prompting for username/password. 
        # At this point, you might want to add your needed fields to
        # requiredFields or set default values.  Note: to set default
        # values, set  'self._defaults['fieldname'] = 'default' 
        # (e.g., 'self._defaults['_username'] = os.env['LOGNAME'] )
    
        loginFields = LoginHandler.getLogin (self, (connName, 
                                                    connDescription, 
                                                    requiredFields) )
    
        # Perform any tasks prior to returning username/password 
        # The entered username/password is stored in loginFields['_username']
        # and loginFields['_password']. At this point
       
        return loginFields
    
    #
    #####################################################

    
Save this file as a .py file and put it's location in your gnue.conf (change 
"loginHandler =" to "loginHandler = /path/to/myhandler.py" )

If all goes well, your login handler will be used the next time you log in.

Some notes: 

  1) GNUe-Common will expect to see to two objects in your handler's 
     namespace:   LoginHandler   (from the import statement) and 
                  MyLoginHandler (your customized login class)

     For this reason, do NOT change the import statement to read: 
       from gnue.common import GLoginHandler
     and then change the class' parent to be GLoginHandler.LoginHandler.
     If you do, your customized handler will probably not work the way
     you expect. 

  2) Almost the only restriction placed on getLogin's functionality is
     that it must return a hash containing at least the values requested 
     when getLogin was called, using the value id's supplied. Your code, 
     in theory, can do whatever it needs in order to return these values.

     HOWEVER: Even though it is possible, it is NOT recommended that you 
     try to write your code to prompt for the values.  It is HIGHLY 
     recommended that you call LoginHandler.getLogin (your superclass's
     getLogin) to prompt for input.  The superclass' LoginHandler will  
     know how to handle the current user's environment (i.e., should it 
     display a GTK login box, generate HTML for a login box, not display 
     a box at all, but prompt using good ol' fashioned text prompts?)
     It is quite extensible.  If you need to prompt for more fields than 
     simply Username and Password, then simply add a definition to your 
     requiredFields tuple and let the superclass' getLogin prompt for you.


If you have written a customized login handler using backends not currently
in our samples file (i.e., against NIS, Kerberos, LDAP, etc) and would like 
to donate your example for others to learn from, please email it to: 

       info@gnue.org
    

