source: TI12-security/trunk/python/NDG/AttAuthority.py @ 1018

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/NDG/AttAuthority.py@1018
Revision 1018, 29.6 KB checked in by pjkersha, 13 years ago (diff)

Tests/SecurityClientTest?.py: mods to run on gabriel.

Tests/security.py: added functionality to get trusted host info.

dist/NDG-Security-0.66.tar.gz: new distro for testing on gabriel.

conf/mapConfig.xml: added loginURI tag for each trusted host - indicate URI for user login useful for forwarding of
login page from remote site.

NDG/AttAuthorityIO.py: include loginURI tag in trusted host info response message.

NDG/SecurityCGI.py: include functionality to get trusted host info from an AttAuthority?

NDG/AttAuthority.py: added loginURI tag for getTrustedHostInfo call.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1"""NDG Attribute Authority handles security authentication and authorization
2
3NERC Data Grid Project
4
5P J Kershaw 15/04/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
13reposID = '$Id$'
14
15import types
16
17
18# Create unique names for attribute certificates
19import tempfile
20import os
21
22# Alter system path for dynamic import of user roles class
23import sys
24
25# For parsing of properties file
26import cElementTree as ElementTree
27
28# X509 Certificate handling
29from X509 import *
30
31# NDG Attribute Certificate
32from AttCert import *
33
34# Format for XML messages passed over WS
35from AttAuthorityIO import *
36
37
38#_____________________________________________________________________________
39class AttAuthorityError(Exception):
40    """Exception handling for NDG Attribute Authority class."""
41   
42    def __init__(self, msg):
43        self.__msg = msg
44         
45    def __str__(self):
46        return self.__msg
47
48
49
50
51#_____________________________________________________________________________
52class AttAuthorityAccessDenied(AttAuthorityError):
53    """NDG Attribute Authority - access denied exception.
54
55    Raise from authorise method where no roles are available for the user
56    but that the request is otherwise valid.  In all other error cases raise
57    AttAuthorityError"""   
58    pass
59
60
61
62#_____________________________________________________________________________
63class AttAuthority(dict):
64
65    """NDG Attribute Authority - server for user authentication/authorization.
66    """
67
68    # Code designed from NERC Data Grid Enterprise and Information Viewpoint
69    # documents.
70    #
71    # Also, draws from Neil Bennett's ACServer class used in the Java
72    # implementation of NDG Security
73
74    # valid configuration property keywords
75    __validKeys = [ 'name',
76                    'keyFile',
77                    'keyPwd',
78                    'certFile',
79                    'caCertFile',
80                    'attCertLifeTime',
81                    'attCertNotBeforeOff',
82                    'attCertFilePfx',
83                    'attCertFileSfx',
84                    'mapConfigFile',
85                    'attCertDir',
86                    'dnSeparator',
87                    'usrRolesModFilePath',
88                    'usrRolesModName',
89                    'usrRolesClassName',
90                    'usrRolesPropFile']
91   
92    def __init__(self, propFilePath, bReadMapConfig=True):
93        """Create new NDG Attribute Authority instance
94
95        propFilePath:   path to file containing Attribute Authority
96                        configuration parameters.
97        bReadMapConfig: by default the Map Configuration file is read.  Set
98                        this flag to False to override.
99        """
100
101        # Base class initialisation
102        dict.__init__(self)
103       
104        if not isinstance(propFilePath, basestring):
105            raise AttAuthorityError("Input Properties file path " + \
106                                    "must be a valid string.")
107
108
109        # Initialise role mapping look-ups - These are set in readMapConfig()
110        self.__mapConfig = None
111        self.__localRole2RemoteRole = None
112        self.__remoteRole2LocalRole = None
113
114
115        # Configuration file properties are held together in a dictionary
116        self.__prop = {}
117
118        # Read Attribute Authority Properties file
119        self.readProperties(propFilePath)
120
121        # Read the Map Configuration file
122        if bReadMapConfig:
123            self.readMapConfig()
124
125        # Instantiate Certificate object
126        self.__cert = X509Cert(self.__prop['certFile'])
127        self.__cert.read()
128
129        # Check it's valid
130        try:
131            self.__cert.isValidTime(raiseExcep=True)
132           
133        except Exception, e:
134            raise AttAuthorityError(\
135                    "Attribute Authority's certificate is invalid: " + str(e))
136       
137        # Check CA certificate
138        caCert = X509Cert(self.__prop['caCertFile'])
139        caCert.read()
140       
141        try:
142            caCert.isValidTime(raiseExcep=True)
143           
144        except Exception, e:
145            raise AttAuthorityError("CA certificate is invalid: " + str(e))
146       
147        # Issuer details - serialise using the separator string set in the
148        # properties file
149        self.__issuer = \
150            self.__cert.dn.serialise(separator=self.__prop['dnSeparator'])
151
152        self.__issuerSerialNumber = self.__cert.serialNumber
153
154       
155        # Set-up user roles interface
156        try:
157            try:
158                # Temporarily extend system path ready for import
159                sysPathBak = sys.path[:]
160                sys.path.append(self.__prop['usrRolesModFilePath'])
161               
162                # Import module name specified in properties file
163                usrRolesMod = __import__(self.__prop['usrRolesModName'],
164                                         globals(),
165                                         locals(),
166                                         [self.__prop['usrRolesClassName']])
167   
168                usrRolesClass = eval('usrRolesMod.' + \
169                                     self.__prop['usrRolesClassName'])
170            finally:
171                sys.path[:] = sysPathBak
172                               
173        except Exception, e:
174            raise AttAuthorityError('Importing User Roles module: %s' % e)
175
176        # Check class inherits from AAUserRoles abstract base class
177        if not issubclass(usrRolesClass, AAUserRoles):
178            raise AttAuthorityError(\
179                "User Roles class %s must be derived from AAUserRoles" % \
180                self.__prop['usrRolesClassName'])
181
182
183        # Instantiate custom class
184        try:
185            self.__usrRoles = usrRolesClass(self.__prop['usrRolesPropFile'])
186           
187        except Exception, e:
188            raise AttAuthorityError(\
189                "Error instantiating User Roles interface: " + str(e))
190     
191       
192    #_________________________________________________________________________
193    # Methods for Attribute Authority dictionary like behaviour       
194    def __delitem__(self, key):
195        self.__class__.__name__ + " keys cannot be removed"       
196        raise KeyError('Keys cannot be deleted from '+self.__class__.__name__)
197
198
199    def __getitem__(self, key):
200        self.__class__.__name__ + """ behaves as data dictionary of Attribute
201        Authority properties
202        """
203        if key not in self.__prop:
204            raise KeyError("Invalid key " + key)
205       
206        return self.__prop[key]
207       
208
209    def clear(self):
210        raise KeyError("Data cannot be cleared from "+self.__class__.__name__)
211   
212    def keys(self):
213        return self.__prop.keys()
214
215    def items(self):
216        return self.__prop.items()
217
218    def values(self):
219        return self.__prop.values()
220
221    def has_key(self, key):
222        return self.__prop.has_key(key)
223
224    # 'in' operator
225    def __contains__(self, key):
226        return key in self.__prop
227
228       
229    #_________________________________________________________________________
230    def authorise(self,
231                  reqXMLtxt=None, 
232                  proxyCertFilePath=None,
233                  userAttCertFilePath=None,
234                  **reqKeys):
235
236        """Request a new Attribute Certificate for authorisation
237
238        reqXMLtxt:              input keywords as tags in formatted XML string
239                                String must follow format for
240                                AttAuthorityIO.AuthorisationReq class to
241                                parse.
242                               
243        proxyCertFilePath|proxyCert:
244
245                                user's proxy certificate use appropriate
246                                keyword for input as a file path or as the
247                                text content respectively.
248                               
249                                Nb. proxyCert is set via reqKeys
250                               
251        userAttCertFilePath|userAttCert:
252       
253                                externally provided attribute certificate
254                                from another data centre.  This is only
255                                necessary if the user is not registered with
256                                this attribute authority.
257
258                                Pass in either the file path or a string
259                                containing the certificate XML content.
260                               
261                                Nb. userAttCert is set via reqKeys
262                                """
263
264        if reqXMLtxt is not None:
265            # Parse XML text into keywords corresponding to the input
266            # parameters
267            if not isinstance(reqXMLtxt, basestring):
268                raise AttAuthorityError(\
269                            "XML Authorisation request must be a string")
270                                       
271            # Parse and decrypt as necessary
272            try:
273                # 1st assume that the request was encrypted
274                reqKeys = AuthorisationReq(encrXMLtxt=reqXMLtxt,
275                                    encrPriKeyFilePath=self.__prop['keyFile'],
276                                    encrPriKeyPwd=self.__prop['keyPwd'])
277            except Exception, e:
278               
279                # Error occured decrypting - Trying parsing again, but this
280                # time assuming non-encrypted
281                try:
282                    reqKeys = AuthorisationReq(xmlTxt=reqXMLtxt)
283                   
284                except Exception, e:
285                    raise AttAuthorityError(\
286                        "Error parsing authorisation request: %s" % e)
287
288
289        # Read proxy certificate
290        try:
291            usrProxyCert = X509Cert()
292           
293            if proxyCertFilePath is not None and \
294               isinstance(proxyCertFilePath, basestring):
295
296                # Proxy Certificate input as a file
297                usrProxyCert.read(proxyCertFilePath)
298               
299            elif reqKeys['proxyCert'] is not None:
300
301                # Proxy Certificate input as string text
302                usrProxyCert.parse(reqKeys['proxyCert'])
303
304            else:
305                raise AttAuthorityError(\
306                    "no input proxy certificate file path or file text")
307           
308        except Exception, e:
309            raise AttAuthorityError("User Proxy Certificate: %s" % e)
310
311
312        # Check proxy certificate hasn't expired
313        try:
314            usrProxyCert.isValidTime(raiseExcep=True)
315           
316        except Exception, e:
317            raise AttAuthorityError("User Proxy Certificate is invalid: " + \
318                                    str(e))
319
320           
321        # Get Distinguished name from certificate as an X500DN type
322        usrDN = usrProxyCert.dn
323       
324       
325        # Make a new Attribute Certificate instance passing in certificate
326        # details for later signing
327        #
328        # Nb. new attribute certificate file path is created from the
329        # Credentials Repository
330        certFilePathList = [self.__prop['certFile'],self.__prop['caCertFile']]
331        attCert = AttCert(self.__newAttCertFilePath(),
332                          signingKeyFilePath=self.__prop['keyFile'],
333                          certFilePathList=certFilePathList)
334
335
336        # Set holder's (user's) Distinguished Name
337        try:
338            attCert['holder'] = \
339                        usrDN.serialise(separator=self.__prop['dnSeparator'])
340           
341        except Exception, e:
342            raise AttAuthorityError("User DN: %s" % e)
343
344       
345        # Set Issuer details from Attribute Authority
346        issuerDN = self.__cert.dn
347        try:
348            attCert['issuer'] = \
349                    issuerDN.serialise(separator=self.__prop['dnSeparator'])
350           
351        except Exception, e:
352            raise AttAuthorityError("Issuer DN: %s" % e)
353       
354        attCert['issuerName'] = self.__prop['name']
355        attCert['issuerSerialNumber'] = self.__issuerSerialNumber
356
357
358        # Set validity time
359        try:
360            attCert.setValidityTime(\
361                        lifeTime=self.__prop['attCertLifeTime'],
362                        notBeforeOffset=self.__prop['attCertNotBeforeOff'])
363
364            # Check against the proxy certificate's expiry
365            dtUsrProxyNotAfter = usrProxyCert.notAfter
366           
367            if attCert.getValidityNotAfter(asDatetime=True) > \
368               dtUsrProxyNotAfter:
369
370                # Adjust the attribute certificate's expiry date time
371                # so that it agrees with that of the proxy certificate
372                attCert.setValidityTime(dtNotAfter=dtUsrProxyNotAfter)
373           
374        except Exception, e:
375            raise AttAuthorityError("Error setting validity time: %s" % e)
376       
377
378        # Check name is registered with this Attribute Authority - if no
379        # user roles are found, the user is not registered
380        usrRoles = self.getRoles(str(usrDN))
381        if usrRoles:           
382            # Set as an Original Certificate
383            #
384            # User roles found - user is registered with this data centre
385            # Add roles for this user for this data centre
386            attCert.addRoles(usrRoles)
387
388            # Mark new Attribute Certificate as an original
389            attCert['provenance'] = 'original'
390
391        else:           
392            # Set as a Mapped Certificate
393            #
394            # No roles found - user is not registered with this data centre
395            # Check for an externally provided certificate from another
396            # trusted data centre
397            if userAttCertFilePath:
398               
399                # Read externally provided certificate
400                try:
401                    extAttCert = AttCertRead(userAttCertFilePath)
402                   
403                except Exception, e:
404                    raise AttAuthorityError(\
405                            "Reading external Attribute Certificate: %s" + e)
406                               
407            elif 'userAttCert' in reqKeys and reqKeys['userAttCert']:
408                extAttCert = reqKeys['userAttCert']
409               
410            else:
411                raise AttAuthorityAccessDenied(\
412                    "User \"%s\" is not registered " % attCert['holder'] + \
413                    "and no external attribute certificate is available " + \
414                    "to make a mapping.")
415
416
417            # Check it's an original certificate - mapped certificates can't
418            # be used to make further mappings
419            if extAttCert.isMapped():
420                raise AttAuthorityError(\
421                    "External Attribute Certificate must have an " + \
422                    "original provenance in order to make further mappings.")
423
424
425            # Check it's valid and signed
426            try:
427                # Give path to CA cert to allow check
428                extAttCert.isValid(raiseExcep=True,
429                                   certFilePathList=self.__prop['caCertFile'])
430               
431            except Exception, e:
432                raise AttAuthorityError(\
433                            "Invalid Remote Attribute Certificate: " + str(e))       
434
435
436            # Check that's it's holder matches the user certificate DN
437            try:
438                holderDN = X500DN(dn=extAttCert['holder'])
439               
440            except Exception, e:
441                raise AttAuthorityError(\
442                    "Error creating X500DN for holder: %s" + e)
443           
444            if holderDN != usrDN:
445                raise AttAuthorityError(\
446                    "User certificate and Attribute Certificate DNs " + \
447                    "don't match: " + str(usrDN) + " and " + str(holderDN))
448           
449 
450            # Get roles from external Attribute Certificate
451            trustedHostRoles = extAttCert.getRoles()
452
453
454            # Map external roles to local ones
455            localRoles = self.mapRemoteRoles2LocalRoles(\
456                                                    extAttCert['issuerName'],
457                                                    trustedHostRoles)
458            if not localRoles:
459                raise AttAuthorityAccessDenied(\
460                    "No local roles mapped to the %s roles: %s" % \
461                    (extAttCert['issuerName'], str(trustedHostRoles)))
462
463            attCert.addRoles(localRoles)
464           
465           
466            # Mark new Attribute Certificate as mapped
467            attCert['provenance'] = 'mapped'
468
469            # End set mapped certificate block
470           
471
472        try:
473            # Digitally sign certificate using Attribute Authority's
474            # certificate and private key
475            attCert.sign(signingKeyPwd=self.__prop['keyPwd'])
476           
477            # Check the certificate is valid
478            attCert.isValid(raiseExcep=True)
479           
480            # Write out certificate to keep a record of it for auditing
481            attCert.write()
482
483            # Return the cert to caller
484            return attCert
485       
486        except Exception, e:
487            raise AttAuthorityError("New Attribute Certificate \"%s\": %s" % \
488                                    (attCert.filePath, e))
489
490   
491
492
493    def readProperties(self, propFilePath=None):
494
495        """Read the configuration properties for the Attribute Authority
496
497        propFilePath: file path to properties file
498        """
499       
500        if propFilePath is not None:
501            if not isinstance(propFilePath, basestring):
502                raise AttAuthorityError("Input Properties file path " + \
503                                        "must be a valid string.")
504           
505            self.__propFilePath = propFilePath
506
507
508        try:
509            tree = ElementTree.parse(self.__propFilePath)
510           
511        except IOError, ioErr:
512            raise AttAuthorityError(\
513                                "Error parsing properties file \"%s\": %s" % \
514                                (ioErr.filename, ioErr.strerror))
515
516       
517        aaProp = tree.getroot()
518
519        # Copy properties from file as member variables
520        prop = dict([(elem.tag, elem.text) for elem in aaProp])
521
522
523        # Check for missing properties
524        propKeys = prop.keys()
525        missingKeys = [key for key in AttAuthority.__validKeys \
526                       if key not in propKeys]
527        if missingKeys != []:
528            raise AttAuthorityError("The following properties are " + \
529                                    "missing from the properties file: " + \
530                                    ', '.join(missingKeys))
531
532        # Strip white space - apart from fields where may be required
533        for key in prop:
534            if key != 'keyPwd' and prop[key]: 
535                prop[key] = prop[key].strip()
536               
537            # Check for environment variables in file paths
538            tagCaps = key.upper()
539            if 'FILE' in tagCaps or 'PATH' in tagCaps or 'DIR' in tagCaps:
540                prop[key] = os.path.expandvars(prop[key])
541 
542 
543        # Ensure Certificate time parameters are converted to numeric type
544        prop['attCertLifeTime'] = float(prop['attCertLifeTime'])
545        prop['attCertNotBeforeOff'] = float(prop['attCertNotBeforeOff'])
546         
547        self.__prop = prop
548
549       
550        # Check directory path
551        try:
552            dirList = os.listdir(self.__prop['attCertDir'])
553
554        except OSError, osError:
555            raise AttAuthorityError(\
556                "Invalid directory path Attribute Certificates store: " + \
557                osError.strerror)
558
559       
560       
561       
562    def readMapConfig(self, mapConfigFilePath=None):
563        """Parse Map Configuration file.
564
565        mapConfigFilePath:  file path for map configuration file.  If omitted,
566                            use member variable __mapConfigFilePath.
567        """
568       
569        if mapConfigFilePath is not None:
570            if not isinstance(mapConfigFilePath, basestring):
571                raise AttAuthorityError("Input Map Configuration file path "+\
572                                        "must be a valid string.")
573           
574            self.__prop['mapConfigFile'] = mapConfigFilePath
575
576       
577        tree = ElementTree.parse(self.__prop['mapConfigFile'])
578        rootElem = tree.getroot()
579
580        trustedElem = rootElem.findall('trusted')
581
582        # Dictionaries:
583        # 1) to hold all the data
584        self.__mapConfig = {}
585
586        # ... look-up
587        # 2) hosts corresponding to a given role and
588        # 3) roles of external data centre to this data centre
589        self.__localRole2TrustedHost = {}
590        self.__localRole2RemoteRole = {}
591        self.__remoteRole2LocalRole = {}
592       
593        for elem in trustedElem:
594
595            roleElem = elem.findall('role')
596            if not roleElem:
597                raise AttAuthorityError("\"role\" tag not found in \"%s\"" % \
598                                        self.__prop['mapConfigFile'])
599
600            try:
601                trustedHost = elem.attrib.values()[0]
602               
603            except Exception, e:
604                raise AttAuthorityError(\
605                                    "Error setting trusted host name: %s" % e)
606
607           
608            # Add signatureFile and list of roles
609            #
610            # (Currently Optional) additional tag allows query of the URI
611            # where a user would normally login at the trusted host.  Added
612            # this feature to allow users to be forwarded to their home site
613            # if they are accessing a secure resource and are not
614            # authenticated
615            #
616            # P J Kershaw 25/05/06
617            self.__mapConfig[trustedHost] = \
618            {
619                'loginURI':     elem.findtext('loginURI'),
620                'wsdl':         elem.findtext('wsdl'),
621                'role':         [dict(i.items()) for i in roleElem]
622            }
623
624                   
625            self.__localRole2RemoteRole[trustedHost] = {}
626            self.__remoteRole2LocalRole[trustedHost] = {}
627           
628            for role in self.__mapConfig[trustedHost]['role']:
629
630                localRole = role['local']
631                remoteRole = role['remote']
632               
633                # Role to host look-up
634                if localRole in self.__localRole2TrustedHost:
635                   
636                    if trustedHost not in \
637                       self.__localRole2TrustedHost[localRole]:
638                        self.__localRole2TrustedHost[localRole].\
639                                                        append(trustedHost)                       
640                else:
641                    self.__localRole2TrustedHost[localRole] = [trustedHost]
642
643
644                # Trusted Host to local role and trusted host to trusted role
645                # map look-ups
646                try:
647                    self.__remoteRole2LocalRole[trustedHost][remoteRole].\
648                                                            append(localRole)                 
649                except KeyError:
650                    self.__remoteRole2LocalRole[trustedHost][remoteRole] = \
651                                                                [localRole]
652                   
653                try:
654                    self.__localRole2RemoteRole[trustedHost][localRole].\
655                                                            append(remoteRole)                 
656                except KeyError:
657                    self.__localRole2RemoteRole[trustedHost][localRole] = \
658                                                                [remoteRole]                 
659 
660
661           
662    def usrIsRegistered(self, usrDN):
663        """Check a particular user is registered with the Data Centre that the
664        Attribute Authority represents"""
665        return self.__usrRoles.usrIsRegistered(usrDN)
666       
667
668
669
670
671    def getRoles(self, dn):
672        """Get the roles available to the registered user identified usrDN.
673        """
674
675        # Call to AAUserRoles derived class.  Each Attribute Authority
676        # should define it's own roles class derived from AAUserRoles to
677        # define how roles are accessed
678        try:
679            return self.__usrRoles.getRoles(dn)
680
681        except Exception, e:
682            raise AttAuthorityError("Getting user roles: %s" % e)
683
684
685
686   
687    def getTrustedHostInfo(self, role=None):
688        """Return a dictionary of the hosts that have trust relationships
689        with this AA.  The dictionary is indexed by the trusted host name
690        and contains WSDL URIs and the roles that map to the
691        given input local role.
692
693        If no role is input, return all the AA's trusted hosts with all
694        their possible roles
695
696        Returns emoty dictionary if role isn't recognised"""
697                                         
698        if not self.__localRole2RemoteRole:
699            raise AttAuthorityError("Roles to host look-up is not set - " + \
700                                    "ensure readMapConfig() has been called.")
701
702
703        if role is None:
704            # No role input - return all trusted hosts with their WSDL URIs
705            # and the remote roles they map to
706            #
707            # Nb. {}.fromkeys([...]).keys() is a fudge to get unique elements
708            # from a list i.e. convert the list elements to a dict eliminating
709            # duplicated elements and convert the keys bacl into a list.
710            trustedHostInfo = dict(\
711            [\
712                (\
713                    k, \
714                    {
715                        'wsdl':        v['wsdl'], \
716                        'loginURI':    v['loginURI'], \
717                        'role':        {}.fromkeys(\
718                            [\
719                                role['remote'] for role in v['role']
720                            ]\
721                        ).keys()
722                    }
723                ) for k, v in self.__mapConfig.items()
724            ])
725
726        else:           
727            # Get trusted hosts for given input local role       
728            try:
729                trustedHosts = self.__localRole2TrustedHost[role]
730            except:
731                return {}
732   
733   
734            # Get associated WSDL URI and roles for the trusted hosts
735            # identified and return as a dictionary indexed by host name
736            trustedHostInfo = dict(\
737            [\
738                (\
739                    host, \
740                    {
741                        'wsdl':     self.__mapConfig[host]['wsdl'],
742                        'loginURI': self.__mapConfig[host]['loginURI'],
743                        'role':     self.__localRole2RemoteRole[host][role]
744                    }\
745                 ) for host in trustedHosts
746            ])
747                         
748        return trustedHostInfo
749
750
751
752
753    def mapRemoteRoles2LocalRoles(self, trustedHost, trustedHostRoles):
754        """Map roles of trusted hosts to roles for this data centre
755
756        trustedHost:        name of external trusted data centre
757        trustedHostRoles:   list of external roles to map"""
758
759        if not self.__remoteRole2LocalRole:
760            raise AttAuthorityError("Roles map is not set - ensure " + \
761                                    "readMapConfig() has been called.")
762
763
764        # Check the host name is a trusted one recorded in the map
765        # configuration
766        if not self.__remoteRole2LocalRole.has_key(trustedHost):
767            return []
768
769        # Add local roles, skipping if no mapping is found
770        localRoles = []
771        for trustedRole in trustedHostRoles:
772            if trustedRole in self.__remoteRole2LocalRole[trustedHost]:
773                localRoles.extend(\
774                        self.__remoteRole2LocalRole[trustedHost][trustedRole])
775               
776        return localRoles
777
778
779
780
781    def __newAttCertFilePath(self):
782        """Create a new unique attribute certificate file path"""
783       
784        attCertFd, attCertFilePath = \
785                   tempfile.mkstemp(suffix=self.__prop['attCertFileSfx'],
786                                    prefix=self.__prop['attCertFilePfx'],
787                                    dir=self.__prop['attCertDir'],
788                                    text=True)
789
790        # The file is opened - close using the file descriptor returned in the
791        # first element of the tuple
792        os.close(attCertFd)
793
794        # The file path is the 2nd element
795        return attCertFilePath
796
797
798
799
800#_____________________________________________________________________________
801class AAUserRolesError(Exception):
802
803    """Exception handling for NDG Attribute Authority User Roles interface
804    class."""
805   
806    def __init__(self, msg):
807        self.__msg = msg
808         
809    def __str__(self):
810        return self.__msg
811
812
813
814#_____________________________________________________________________________
815class AAUserRoles:
816
817    """An abstract base class to define the user roles interface to an
818    Attribute Authority.
819
820    Each NDG data centre should implement a derived class which implements
821    the way user roles are provided to its representative Attribute Authority.
822   
823    Roles are expected to indexed by user Distinguished Name (DN).  They
824    could be stored in a database or file."""
825
826    # User defined class may wish to specify a URI for a database interface or
827    # path for a user roles configuration file
828    def __init__(self, dbURI=None, filePath=None):
829        """User Roles abstract base class - derive from this class to define
830        roles interface to Attribute Authority"""
831        raise NotImplementedError(\
832            self.__init__.__doc__.replace('\n       ',''))
833
834
835    def usrIsRegistered(self, dn):
836        """Derived method should return True if user is known otherwise
837        False"""
838        raise NotImplementedError(
839            self.UserIsRegistered.__doc__.replace('\n       ',''))
840
841
842    def getRoles(self, dn):
843        """Derived method should return the roles for the given user's
844        DN or else raise an exception"""
845        raise NotImplementedError(
846            self.getRoles.__doc__.replace('\n       ',''))
847                         
Note: See TracBrowser for help on using the repository browser.