source: security/trunk/python/NDG/BADCUserRoles.py @ 494

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/security/trunk/python/NDG/BADCUserRoles.py@494
Revision 494, 7.5 KB checked in by pjkersha, 14 years ago (diff)

* empty log message *

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1"""NDG User Roles interface to BADC Attribute Authority
2
3NERC Data Grid Project
4
5P J Kershaw 01/07/05
6
7Copyright (C) 2005 CCLRC & NERC
8
9This software may be distributed under the terms of the Q Public License,
10version 1.0 or later.
11"""
12
13cvsID = '$Id$'
14
15# BADC Ingres database
16import ingresdbi
17
18# For parsing of properties file
19import cElementTree as ElementTree
20
21from AttAuthority import AAUserRoles, AAUserRolesError
22from X509 import X500DN
23
24
25
26class BADCUserRoles(AAUserRoles):
27    """User Roles interface to BADC Attribute Authority"""
28
29    def __init__(self,
30                 propertiesFilePath=None,
31                 CreateRoles=True,
32                 **connectKeys):
33       
34        """Connect to BADC User database
35
36        Omit connectKeys or explicitly set CreateRoles to False if wish to
37        avoid querying the database on object creation"""
38
39        self.__con = None
40        self.__rolesLUT = {}
41
42        if propertiesFilePath is not None:
43            connectKeys = self.readPropertiesFile(propertiesFilePath)
44
45        # keywords for connection to database either from input arguments or
46        # read from properties file
47        if connectKeys.items() is not None:
48            self.connect(**connectKeys)
49            if CreateRoles: self.createRoles()
50         
51       
52    def __del__(self):
53        """Call close() - Commit any changes and close database connection"""
54        try:
55            self.close()
56        except:
57            pass
58       
59
60    def readPropertiesFile(self, propertiesFilePath):
61
62        """Read the configuration properties for the database connection
63
64        propertiesFilePath: file path to properties file
65        """
66       
67        if not isinstance(propertiesFilePath, basestring):
68            raise AAUserRolesError("Input Properties file path " + \
69                  "must be a valid string.")
70
71        try:
72            tree = ElementTree.parse(propertiesFilePath)
73           
74        except IOError, ioErr:
75            raise AAUserRolesError(\
76                                "Error parsing properties file \"%s\": %s" % \
77                                (ioErr.filename, ioErr.strerror))
78
79       
80        prop = tree.getroot()
81
82        # Return properties as dictionary
83        return dict([(elem.tag, elem.text) for elem in prop])
84
85
86    def connect(self, enableTrace=False, **ingresDBIConnectKeys):
87        """Make a connection to the database"""
88       
89        if enableTrace is True:
90            trace = (7, None)
91        else:
92            trace = (0, None)
93       
94        self.__con = ingresdbi.connect(**ingresDBIConnectKeys)
95
96       
97    def close(self):   
98        """Commit any changes and close database connection"""
99        self.__con.commit()
100        self.__con.close()
101
102
103    def createRoles(self):
104        """Query the BADC user database in order to create a list of user
105        roles.
106
107        This is called on object creation but can be called again to update
108        an existing object following changes to the database content"""
109
110        # Roles based on the institute type a user belongs to
111        instSqlStmt = "select accountid, type from " + \
112                      "tbusers, addresses, tbinstitutes " + \
113                      "where tbusers.addresskey = addresses.addresskey and " +\
114                      "addresses.institutekey = tbinstitutes.institutekey"
115
116        cursor = self.__con.cursor()
117        try:
118            cursor.execute(instSqlStmt)
119            instQueryRes = cursor.fetchall()
120           
121        except Exception, e:
122            raise AAUserRolesError("Querying for institutes: %s" % str(e))
123
124        # Make a dictionary of username vs. roles list
125        self.__rolesLUT = dict([(k, [v.lower()]) for k,v in instQueryRes])
126   
127
128        # Get groups and NERC funded info to add as roles
129        grpSqlStmt = "select accountid, nercfunded, grp from " + \
130                     "tbusers, tbdatasetjoin, tbdatasets " + \
131                     "where tbusers.userkey = tbdatasetjoin.userkey and " + \
132                     "tbdatasetjoin.datasetid = tbdatasets.datasetid and " + \
133                     "tbdatasetjoin.removed = 0"
134
135        try:
136            cursor.execute(grpSqlStmt)
137            grpQueryRes = cursor.fetchall()
138           
139        except Exception, e:
140            raise AAUserRolesError(\
141                        "Querying for groups and NERC funded: %s" % str(e))
142
143        for i in grpQueryRes:
144            # Check - some users may have been missed out in first query
145            if not self.__rolesLUT.has_key(i[0]):
146                self.__rolesLUT[i[0]] = []
147               
148            # Add new groups as roles
149            if i[2] and i[2] not in self.__rolesLUT[i[0]]:
150                self.__rolesLUT[i[0]].append(i[2])
151
152            # Check for NERC funded
153            if i[1] != 0 and 'nercFunded' not in self.__rolesLUT[i[0]]:
154                self.__rolesLUT[i[0]].append('nercFunded')
155
156
157        # Catch remaining users left out from join queries above
158        cursor.execute("select accountid from tbusers")
159        allQueryRes = cursor.fetchall()
160        for i in allQueryRes:
161            if i[0] and not self.__rolesLUT.has_key(i[0]):
162                self.__rolesLUT[i[0]] = []
163
164
165
166       
167    def usrIsRegistered(self, dn=None, x500DN=None):
168        """Return boolean to indicate whether user with given DN is
169        registered
170
171        Interface method to AttAuthority - Overrides AAUserRoles base
172        class"""
173
174        # Parse username from DN string
175        try:
176            if dn:
177                userName = X500DN(dn)['CN']
178            else:
179                userName = x500DN['CN']
180               
181        except Exception, e:
182            raise AAUserRolesError("Parsing userName from DN %s: %s" % (dn,e))
183
184
185        sqlStmt = "select distinct accountid from tbusers " + \
186                  "where accountid = '%s'" % userName
187
188        try:
189            self.__con.cursor().execute(sqlStmt)
190            match = cursor.fetchall()
191           
192        except Exception, e:
193            raise AAUserRolesError("Searching for user %s: %s" % (userName,e))
194        if len(match) == 1:
195            return True
196        else:
197            return False
198
199
200    def getRoles(self, dn=None, x500DN=None):
201        """Return valid roles for the BADC database
202       
203        Interface method to AttAuthority - Overrides AAUserRoles base
204        class
205
206        dn:     distinguished name as a string
207        x500DN: distinguished name as an X500DN instance"""
208
209        # Parse username from DN string
210        try:
211            if dn:
212                userName = X500DN(dn)['CN']
213            else:
214                userName = x500DN['CN']
215               
216        except Exception, e:
217            raise AAUserRolesError("Parsing userName from DN %s: %s" % (dn,e))
218
219        try:
220            return self.__rolesLUT[userName]
221        except:
222            return []
223
224
225    def cursor(self):
226        """Return a database cursor instance"""
227        return self.__con.cursor()
228
229   
230    def printSurnames(self):
231        """Test method - print all user surnames held in database"""
232       
233        c = self.__con.cursor()
234
235        c.execute("select surname from tbusers order by surname")
236
237        description = c.description
238        pprint.pprint(description)
239
240        rows = c.fetchall()
241
242        for row in rows:           
243            count = 0
244            for column in row:
245                  print description[count][0] , ': ', column
246                  count += 1
247                 
248            print "-----------------------------"
249
250
251def badcUserRolesTest(**keys):
252
253    userRoles = BADCUserRoles(**keys)
254    userRoles.printSurnames()
255   
256   
257if __name__ == "__main__":
258    badcUserRolesTest()
Note: See TracBrowser for help on using the repository browser.