~ubuntu-branches/ubuntu/hardy/gnue-common/hardy

« back to all changes in this revision

Viewing changes to doc/technotes/00005.txt

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Mitchell
  • Date: 2005-03-09 11:06:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050309110631-8gvvn39q7tjz1kj6
Tags: upstream-0.5.14
ImportĀ upstreamĀ versionĀ 0.5.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Title: Writing a Custom Login/Authentication Handler
 
2
Status: Current
 
3
Revised: 18-SEP-2002
 
4
 
 
5
 
 
6
Introduction
 
7
------------
 
8
 
 
9
By default, GNUe clients look at a database connection, determine what
 
10
fields it needs in order to login (e.g., username and password), and then
 
11
asks its platform/interface dependent login handler to prompt the user for
 
12
this information. Once returned, the client connects to the database using
 
13
this information.
 
14
 
 
15
If needed, you can intercept a client's normal login handler to add your
 
16
own behavior.
 
17
 
 
18
 
 
19
Why?
 
20
----
 
21
Sometimes it is not enough to prompt for the "database" login.  Perhaps
 
22
you want finer control over logins, or simply need to authenticate against
 
23
something besides the database.
 
24
 
 
25
You might want to authenticate against an NIS source, LDAP, or some custom
 
26
source.  Maybe you have many users and want to authenticate against rows in
 
27
a database table and have the actual database login name/password be a
 
28
common one that no one knows; i.e., while users Jason and James might log
 
29
in using "jason" and "james", they might both connect to the database as
 
30
"commonuser".  Since you may not trust James, you only want him to know
 
31
that he is logging in as "james" and never know that he is being connected
 
32
as "commonuser".
 
33
 
 
34
 
 
35
 
 
36
What do I do?
 
37
-------------
 
38
 
 
39
First, a little explanation of how logins work:
 
40
 
 
41
1. A client needs to initialize a connection to a database, so it passes
 
42
   GNUe-Common a description of the database and asks for it to connect.
 
43
 
 
44
2. GNUe-Common looks at the database description, determines what values
 
45
   are needed to connect (usually, username and password).
 
46
 
 
47
3. GNUe-Common creates an instance of (or uses an existing instance of)
 
48
   gnue.common.GLoginHander.LoginHandler, or if the client provides a
 
49
   more advanced login handler (e.g., GNUe Form's graphical handler), an
 
50
   instance of this.
 
51
 
 
52
4. GNUe-Common calls LoginHandler.getLogin(), passing it basic information
 
53
   about the needed connection and a list of values that login handler
 
54
   should provide (i.e., '_username' & '_password').
 
55
 
 
56
5. GNUe-Common uses the results of the call to LoginHandler.getLogin() to
 
57
   create a connection to the database.
 
58
 
 
59
 
 
60
Now, if needed, you can create an Authenticator class that basically
 
61
intervenes in between steps #3-4 above and provide your own functionality.
 
62
 
 
63
If all goes well, your login handler will be used the next time you log in.
 
64
 
 
65
Some notes:
 
66
 
 
67
  1) Almost the only restriction placed on getLogin's functionality is
 
68
     that it must return a hash containing at least the values requested
 
69
     when getLogin was called, using the value id's supplied. Your code,
 
70
     in theory, can do whatever it needs in order to return these values.
 
71
 
 
72
     HOWEVER: Even though it is possible, it is NOT recommended that you
 
73
     try to write your code to prompt for the values.  It is HIGHLY
 
74
     recommended that you return values in the getLoginFields method so
 
75
     LoginHandler.getLogin can prompt for input.  The LoginHandler will
 
76
     know how to handle the current user's environment (i.e., should it
 
77
     display a GTK login box, generate HTML for a login box, not display
 
78
     a box at all, but prompt using good ol' fashioned text prompts?)
 
79
     It is quite extensible.  If you need to prompt for more fields than
 
80
     simply Username and Password, then simply add a definition to your
 
81
     requiredFields tuple and let the LoginHandler's getLogin prompt for 
 
82
     you.
 
83
 
 
84
 
 
85
There are three steps to adding a custom authenticator:
 
86
 
 
87
1. Create (or copy) a Python file that implements an Authenticator.
 
88
   An Authenticator contains a class called Authenticator, which has
 
89
   two methods, getRequiredFields() and login().  See the example below
 
90
   for details on what's expected from these two methods.
 
91
 
 
92
2. Place this file in either your Python search path, or in a
 
93
   path specified by ImportPath (in the [common] section of gnue.conf)
 
94
 
 
95
3. In your connections.conf file, add a custom_auth parameter that
 
96
   is the name of the file (without the path or .py extension):
 
97
 
 
98
     [myconn]
 
99
     adapter = psycopg
 
100
     host = localhost
 
101
     dbname = mydb
 
102
     custom_auth = MyPostgresAuthenticator
 
103
 
 
104
 
 
105
Creating a custom authenticator
 
106
===============================
 
107
A slightly more complicated example.  You have a table in one of your databases
 
108
called "users", that has a user and password field.
 
109
 
 
110
Your users will connect to the database using the username and password:
 
111
dbUser  and dbPassword.
 
112
 
 
113
You, however, want them to use their own username and password to be
 
114
authenticated, but after getting authenticated, the database only cares
 
115
about the real "dbUser" and "dbPassword".
 
116
 
 
117
File: MyPostgresAuthenticator.py
 
118
===============================================================================
 
119
import psycopg
 
120
from gnue.common.GConnections import LoginError
 
121
 
 
122
class Authenticator:
 
123
  #
 
124
  # getLoginFields is passed an list consisting of:
 
125
  #   Fields to Input:
 
126
  #      Attribute Name, Label/Description, Is Password?
 
127
  #
 
128
  #   This list is a list of the values the dbdriver
 
129
  #   expects to get back in order to login.
 
130
  #
 
131
  #   It should return a similarly formatted list that
 
132
  #   tells the LoginHandler what values need to be
 
133
  #   prompted for. (Typically, _username and _password)
 
134
  #   If nothing should be prompted (e.g., you have a
 
135
  #   certificate) then return () (an empty list).
 
136
  #
 
137
  def getLoginFields(self, dbRequiredFields):
 
138
    return dbRequiredFields
 
139
 
 
140
  #
 
141
  # Authenticate the user givem the values prompted for.
 
142
  # If the information is incorrect, then raise
 
143
  # gnue.common.GConnections.LoginError
 
144
  #
 
145
  # It should return a dictionary of {Attribute Name: Value}
 
146
  #
 
147
  def login(self, loginData):
 
148
    conn = psycopg.connect(user="theValidator",
 
149
                 password="hotmomma",
 
150
                 dbname="logins",
 
151
                 host="localhost"')
 
152
    cursor = conn.cursor()
 
153
    results = cursor.execute (
 
154
        'select 1 from users where username=%s and password=%s',
 
155
        (loginData['_username'],
 
156
         loginData['_password']) )
 
157
    if not cursor.fetchone():
 
158
      raise LoginError
 
159
    else:
 
160
      loginData['_username'] = 'dbLogin'
 
161
      loginData['_password'] = 'dbPassword'
 
162
      
 
163
    return loginData  
 
164
===============================================================================
 
165
 
 
166
Note: there are no hard and fast rules about what can go into the
 
167
connections.conf file.  If your authenticator needs more information
 
168
stored in connections.conf, it is fine to do so.
 
169
 
 
170
However, to avoid namespace collisions, you should probably prefix
 
171
any custom connection.conf entries with common prefix. For example,
 
172
if you are writing an NIS adapter, you should prefix entries in
 
173
connections.conf like:
 
174
 
 
175
  auth_nis_domain = MYDOMAIN
 
176
 
 
177
instead of something like:
 
178
 
 
179
  domain = MYDOMAIN
 
180
 
 
181
More examples:
 
182
 
 
183
  auth_ldap_*
 
184
  auth_pg_*
 
185
  auth_mysql_*
 
186
  auth_kerberos_*
 
187
  auth_custom_*
 
188
 
 
189
 
 
190
If you have written a customized login handler using backends not currently
 
191
in our samples file (i.e., against NIS, Kerberos, LDAP, etc) and would like
 
192
to donate your example for others to learn from, please email it to:
 
193
 
 
194
       info@gnue.org
 
195