Ticket #70: database.py

File database.py, 4.4 kB (added by luks, 3 years ago)

Component to store user accounts in the database.

Line 
1 # -*- coding: utf-8 -*-
2 #
3 # AccountManagerPlugin component to store user accounts in the database.
4 # Copyright (C) 2005 Lukáš LalinskÜ <lalinsky@gmail.com>
5 #
6
7 from __future__ import generators
8
9 from sha import sha
10
11 from trac.core import *
12 from trac.db_default import Table, Column, Index
13 from trac.env import IEnvironmentSetupParticipant
14 from api import IPasswordStore
15
16 class SHADatabasePasswordStore(Component):
17     """Manages user accounts stored in the database using SHA to encode passwords.
18
19     To use this implementation add the following configuration section to trac.ini
20     {{{
21     [account-manager]
22     password_format = sha_db
23     }}}
24     """
25    
26     implements(IPasswordStore, IEnvironmentSetupParticipant)
27
28     # IPasswordStore methods
29
30     def config_key(self):
31         """Returns a string used to identify this implementation in the config.
32         This password storage implementation will be used if the value of
33         the config property "account-manager.password_format" matches.
34         """
35         return 'sha_db'
36        
37     def get_users(self):
38         """Returns an iterable of the known usernames
39         """
40         db = self.env.get_db_cnx()
41         cursor = db.cursor()
42         cursor.execute("SELECT name FROM user ORDER BY name")
43         return [row[0] for row in cursor]
44
45     def has_user(self, user):
46         """Returns whether the user account exists.
47         """
48         db = self.env.get_db_cnx()
49         cursor = db.cursor()
50         cursor.execute("SELECT COUNT(*) FROM user WHERE name=%s", (user,))
51         return int(cursor.fetchone()[0]) > 0
52    
53     def set_password(self, user, password):
54         """Sets the password for the user.  This should create the user account
55         if it doesn't already exist.
56         Returns True if a new account was created, False if an existing account
57         was updated.
58         """     
59         db = self.env.get_db_cnx()
60         cursor = db.cursor()
61         password = sha(password).hexdigest()
62         if self.has_user(user):
63             cursor.execute("UPDATE user SET password=%s WHERE name=%s", (password, user))
64             created = False
65         else:
66             cursor.execute("INSERT INTO user (name, password) VALUES (%s, %s)", (user, password))
67             created = True
68         db.commit()
69         return created
70  
71     def check_password(self, user, password):
72         """Checks if the password is valid for the user.
73         """
74         db = self.env.get_db_cnx()
75         cursor = db.cursor()
76         password = sha(password).hexdigest()
77         cursor.execute("SELECT COUNT(*) FROM user WHERE name=%s AND password=%s", (user, password))
78         return int(cursor.fetchone()[0]) > 0
79          
80     def delete_user(self, user):
81         """Deletes the user account.
82         Returns True if the account existed and was deleted, False otherwise.
83         """
84         db = self.env.get_db_cnx()
85         cursor = db.cursor()
86         if self.has_user(user):
87             cursor.execute("DELETE FROM user WHERE name=%s", (user,))
88             db.commit()
89             return True
90         else:   
91             return False
92        
93      # IEnvironmentSetupParticipant methods
94
95     version = 1
96    
97     schema = [
98         Table('user', key=('name'))[
99             Column('name'),
100             Column('password')],
101         ]
102
103     def environment_created(self):
104         """Called when a new Trac environment is created."""
105         pass
106    
107     def environment_needs_upgrade(self, db):
108         """Called when Trac checks whether the environment needs to be upgraded.
109         
110         Should return `True` if this participant needs an upgrade to be
111         performed, `False` otherwise.
112         """
113         cursor = db.cursor()
114         try:
115             cursor.execute("SELECT value FROM system WHERE name='shauserdb_version'")
116             return int(cursor.fetchone()[0]) != self.version
117         except:
118             return True
119         return False
120    
121     def upgrade_environment(self, db):
122         """Actually perform an environment upgrade.
123         
124         Implementations of this method should not commit any database
125         transactions. This is done implicitly after all participants have
126         performed the upgrades they need without an error being raised.
127         """
128         cursor = db.cursor()
129         for table in self.schema:
130             for stmt in db.to_sql(table):
131                 cursor.execute(stmt)
132         cursor.execute("INSERT INTO system VALUES ('shauserdb_version', %s)", (self.version,))