Ticket #70: database-cc.py

File database-cc.py, 3.4 kB (added by athomas, 3 years ago)

database.py by Charlie Clark (out of date)

Line 
1 # -*- coding: iso8859-1 -*-
2 #
3 # Copyright (C) 2005 yellowTAB GmbH http://www.yellowtab.com/
4 #
5 # Released under modified BSD licence
6 #
7 # Author: Charlie Clark <charlie.clark@yellowtab.com>
8
9 from __future__ import generators
10 import crypt
11 from trac.core import *
12 from api import IPasswordStore
13 from binascii import hexlify
14
15 try:
16     from os import urandom
17 except ImportError:
18     def urandom(n):
19         return open('/dev/urandom').read(n)
20
21 def salt():
22     s = ''
23     v = long(hexlify(urandom(4)), 16)
24     itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
25     for i in range(8):
26         s += itoa64[v & 0x3f]; v >>= 6
27     return s
28
29
30 class AbstractPasswordDatabaseStore(Component):
31     """Base class for managing passwords stored in databases such as imported from Bugzilla
32
33     Sub-classes must provide relation and relvars preferably through configs
34     """
35
36     sql_select_all_users = "SELECT %s FROM %s"
37     sql_select_user = "SELECT %s FROM %s WHERE %s = %%s"
38     sql_delete_user = "DELETE FROM %s WHERE %s = %%s"
39     sql_insert_user = "INSERT INTO %s (%s, %s) VALUES (%%s, %%s)"
40     sql_update_user = "UPDATE %s SET %s = %%s WHERE %s = %%s"
41
42     def __init__(self):
43         """get information from config file. Must be implemented in subclass"""
44         pass
45
46     def __init__(self):
47         self.relation = self.config.get("account-manager", "relation")
48         self.rel_user = self.config.get("account-manager", "username_variable")
49         self.rel_password = self.config.get("account-manager", "password_variable")
50         self.log.error("table %s, user %s, pw %s" %(self.relation, self.rel_user, self.rel_password))
51
52
53     def has_user(self, user):
54         db = self.env.get_db_cnx()
55         c = db.cursor()
56         sql = self.sql_select_user %(self.rel_user, self.relation, self.rel_user)
57         c.execute(sql, (user,))
58         users = c.fetchone()
59         if users:
60             return users[0]
61         return None
62
63     def get_users(self):
64         db = self.env.get_db_cnx()
65         c = db.cursor()
66         sql = self.sql_select_all_users %(self.relation)
67         c.execute(sql)
68         users = c.fetchall()
69         if users:
70             return [user[0] for user in users]
71         return []
72
73     def set_password(self, user, password):
74         db = self.env.get_db_cnx()
75         c = db.cursor()
76         if self.has_user(user):
77             sql = self.sql_update_user %(self.relation, self.rel_user, self.rel_password)
78         else:
79             sql = self.sql_insert_user %(self.relation, self.rel_user, self.rel_password)
80         password = self.crypt_password(password)
81         c.execute(sql, (user, password))
82         db.commit()
83
84     def delete_user(self, user):
85         db = self.env.get_db_cnx()
86         c = db.cursor()
87         sql = self.sql_delete_user %(self.relation, self.rel_user)
88         c.execute(sql, (user,))
89         db.commit()
90
91     def crypt_password(self, password):
92         return password
93
94 class CryptDatabasePasswdStore(AbstractPasswordDatabaseStore):
95     """Manages user accounts stored in the database
96        password encryption matches Bugzilla
97
98     To use this implementation add the following configuration section to trac.ini
99     {{{
100     [account-manager]
101     password_format = crypt_db
102     username_variable = username or whatever
103     password_variable = password or whatever
104         }}}
105     """
106     implements(IPasswordStore)
107
108
109     def config_key(self):
110         return 'crypt_db'
111
112     def crypt_password(self, password):
113          return crypt.crypt(password, salt())