Authenticate Via External Cookie
Contents
Requirements
The external cookie authentication alternative may be a good choice for your installation if your MoinMoin wiki topic is closely associated with some other application. You may be using MoinMoin for application documentation, popup help functions, or bug tracking. Several of your application pages may have hyperlinks to wiki pages. Wiki pages may contain custom macros that present data from your application database. Wiki users must login before they can update wiki pages (or you wish that were the case). Everyone with an application login ID also has a wiki login ID. Your users are annoyed that they frequently must login twice, first to the other application and then to MoinMoin. Your administrators are annoyed because they must maintain login IDs in two places.
To authenticate a MoinMoin user with an external cookie, your other application must be modified to create a cookie with each successful login. It must delete the cookie as part of the logout process.
In order to prevent hackers from easily creating their own cookie, MoinMoin transactions need to authenticate the cookie. One way to do this is to modify your other application to store a hash of the cookie value in a database, file, or other secure shared storage area that can be accessed by MoinMoin.
Strategy
The MoinMoin wiki code will be customized in two places. wikiconfig.py will be modified to create a new ExternalCookie class that will be used to authenticate a user. Logging in to your other application will effectively log you in to the wiki. Logging off of your other application will log you out of the wiki. Several variables will be added to wikiconfig.py to customize the Settings:Preferences page and to automatically create new user records when required.
Your wiki themes may be modified to override the username method of the Theme class. This method generates the login and logout hyperlinks within the wiki navigation area. These hyperlinks will be customized to point to the login and logout pages of your other application.
You must modify your other application as outlined above to create/delete a cookie and (optionally) add/delete entries to a shared storage area. If your wiki users can read the wiki without logging in, you may want to modify your other application login page so a wiki reader (logging in from a wiki page) will be returned to their referred-from page after login is complete (similar to the way MoinMoin login works).
Alternative Strategies Not Implemented
It is probably best to not synchronize inactivity timeouts between the other application and the wiki. If a logged in user on the other application times out after an hour of inactivity, he can continue to edit and save pages on the wiki provided the other application timeout process is not modified to delete the entry in the shared storage area. If the other application timed-out user logs in again, a new entry in the shared storage area will be created and a new MoinAuth cookie generated -- subsequent wiki transactions will use the new cookie. The example wikiconfig.py contains an example showing how inactive entries might be removed from a MySQL table soon after expiration by a MoinMoin transaction. However, most installations will probably choose to clear obsolete entries in the shared storage area with a process embedded in the other application.
One alternative to the use of a shared storage area is to encrypt the cookie in the other application and decrypt the cookie in the external_auth method. If this method were implemented, the addition of a timestamp to the cookie value could force cookies to timeout with the addition of an aging check. Without the aging check, any cookie generated would be valid forever (a minor issue) or until the encryption keys were changed. Brief tests with the ezPyCrypto example programs were discouraging because of the amount of compute time required. MySQL was faster -- the measured wall time to validate the cookie was usually 0 seconds and always less than 0.02 seconds.
Another possibility to thwart the use of stolen cookies is to add the authenticated user's IP address to the cookie value and then check it against the IP address of the incoming MoinMoin transaction. But this has marginal value because some ISPs (AOL) change the low order bits of the IP address with each transaction and in other cases several users could appear to be coming from the same IP address.
ExternalCookie Class
The first step is to override the external_auth method of the Config class by adding the code snippet below to your wikiconfig.py.
The code below is for Moin 1.9.
- edit your wikiconfig.py or farmconfig.py
find the line containing class Config(DefaultConfig): or class FarmConfig(DefaultConfig):
- replace the above line with all of the code below
if using farmconfig.py find and comment/uncomment the appropriate class statements
1 # +++++++++++++++ beginning of external_cookie example
2
3 # This is some sample code you might find useful when you want to use some
4 # external cookie (made by some other program, not moin) with moin.
5 # See the +++ places for customizing it to your needs. Copy this
6 # code into your farmconfig.py or wikiconfig.py by pasting it over the current:
7 #
8 # class Config(DefaultConfig):
9 # OR
10 # class FarmConfig(DefaultConfig):
11
12
13 from MoinMoin.config.multiconfig import DefaultConfig
14 from MoinMoin.auth import BaseAuth
15
16 # This is included in case you want to create a log file during testing
17 import time
18 def writeLog(*args):
19 '''Write an entry in a log file with a timestamp and all of the args.'''
20 s = time.strftime('%Y-%m-%d %H:%M:%S ',time.localtime())
21 for a in args:
22 s = '%s %s;' % (s,a)
23 log = open('/somelogfile', 'a') # +++ location for log file
24 log.write('\n' + s + '\n')
25 log.close()
26 return
27
28 # these 2 methods are examples of how to "authenticate" the other application cookie
29 import MySQLdb
30 def verifySession(sidHash): # +++ to use this, uncomment a procedure call below in ExternalCookie
31 """Return True if sidHash value exists (meaning user is currently logged on), false otherwise.
32
33 If you are not a MySQL user, find another way to store this information. ActiveSession is a two-column table
34 containing a hashed cookie value (sidHash) plus a date-time stamp (tStamp).
35 Your other application must add an entry to this table each time a user logs on and delete the entry when the user logs off.
36 """
37 db = MySQLdb.connect(db='mydb',user='myid',passwd='mypw') #+++ user ID needs read access
38 c = db.cursor()
39 q = 'select sidHash from ActiveSession where sidHash="%s"' % sidHash
40 