source: TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/axinterface/csv.py @ 6064

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/openid/provider/axinterface/csv.py@6064
Revision 6064, 7.7 KB checked in by pjkersha, 11 years ago (diff)
  • Fixed slots definitions from global search
  • reran nosetests
Line 
1"""NDG Security OpenID Provider AX Interface for CSV file based attribute store
2
3For test purposes only
4
5NERC DataGrid Project
6"""
7__author__ = "P J Kershaw"
8__date__ = "30/09/09"
9__copyright__ = "(C) 2009 Science and Technology Facilities Council"
10__license__ = "BSD - see LICENSE file in top-level directory"
11__contact__ = "Philip.Kershaw@stfc.ac.uk"
12__revision__ = "$Id$"
13import logging
14log = logging.getLogger(__name__)
15
16import re
17
18from ndg.security.server.wsgi.openid.provider.axinterface import AXInterface, \
19    AXInterfaceConfigError, MissingRequiredAttrs
20from ndg.security.server.wsgi.openid.provider import AbstractAuthNInterface, \
21    OpenIDProviderMiddleware
22
23class CSVFileAXInterface(AXInterface):
24    """OpenID Provider Attribute Exchange Interface based on a Comma Separated
25    Variable file containing user identities and associated attributes. 
26    For test/development purposes
27    only.
28   
29    The expected file format is:
30   
31    <OpenID>, <attr 1>, <attr 2>, ... <attr N>
32    """
33    ATTR_NAMES = (
34        "csvFilePath",
35        "attributeNames",
36        "attributeMap",
37    )
38    __slots__ += tuple(["__%s" % n for n in ATTR_NAMES])
39    del n
40   
41    IDENTITY_URI_SESSION_KEYNAME = \
42                        OpenIDProviderMiddleware.IDENTITY_URI_SESSION_KEYNAME
43   
44    def __init__(self, **properties):
45        """
46        @param properties: file path to Comma Separated file
47        containing user ids and roles
48        @type properties: dict
49        """
50        self.__csvFilePath = None
51        self.__attributeNames = []
52        self.__attributeMap = {}
53       
54        self.setProperties(**properties)
55        if self.csvFilePath is not None:
56            self.read()
57
58    def _getAttributeNames(self):
59        return self.__attributeNames
60
61    def _setAttributeNames(self, value):
62        """@param value: if a string, it will be parsed into a list delimiting
63        elements by whitespace
64        @type value: basestring/tuple or list
65        """
66        if isinstance(value, (list, tuple)):
67            self.__attributeNames = list(value)
68           
69        elif isinstance(value, basestring):
70            self.__attributeNames = value.split() 
71        else:
72            raise TypeError('Expecting string, list or tuple type for '
73                            '"attributeNames"; got %r' % type(value))
74       
75    attributeNames = property(fget=_getAttributeNames, 
76                              fset=_setAttributeNames, 
77                              doc="list of attribute names supported.  The "
78                                  "order of the names is important and "
79                                  "determines the order in which they will be "
80                                  "assigned from the columns in the CSV file")
81
82    def setProperties(self, **properties):
83        for name, val in properties.items():
84            setattr(self, name, val)
85   
86    def read(self):
87        csvFile = open(self.csvFilePath)
88        lines = csvFile.readlines()
89       
90        nAttributes = len(self.attributeNames)
91        for line in lines:
92            fields = re.split(',\W*', line.strip())
93           
94            # Dictionary keyed by user ID with each val itself a dict keyed
95            # by attribute name
96            self.attributeMap[fields[0]] = dict(zip(self.attributeNames,
97                                                    fields[1:nAttributes+1]))
98               
99    def _getCsvFilePath(self):
100        return self.__csvFilePath
101
102    def _setCsvFilePath(self, value):
103        if not isinstance(value, basestring):
104            raise TypeError('Expecting string type for "csvFilePath"; got %r'
105                            % type(value))
106        self.__csvFilePath = value
107
108    csvFilePath = property(fget=_getCsvFilePath, 
109                           fset=_setCsvFilePath, 
110                           doc="file path to Comma Separated Variable format "
111                               "file containing user IDs and attributes")
112   
113    def _getAttributeMap(self):
114        return self.__attributeMap
115
116    def _setAttributeMap(self, value):
117        self.__attributeMap = value
118
119    attributeMap = property(fget=_getAttributeMap, 
120                            fset=_setAttributeMap, 
121                            doc="Dictionary of attributes keyed by user ID")
122   
123    def __call__(self, ax_req, ax_resp, authnInterface, authnCtx):
124        """Add the attributes to the ax_resp object requested in the ax_req
125        object.  If it is not possible to return them, raise
126        MissingRequiredAttrs error
127       
128        @type ax_req: openid.extensions.ax.FetchRequest
129        @param ax_req: attribute exchange request object.  To find out what
130        attributes the Relying Party has requested for example, call
131        ax_req.getRequiredAttrs()
132        @type ax_resp: openid.extensions.ax.FetchResponse
133        @param ax_resp: attribute exchange response object.  This method should
134        update the settings in this object.  Use addValue and setValues methods
135        @type authnInterface: AbstractAuthNInterface
136        @param authnInterface: custom authentication interface set at login. 
137        See ndg.security.server.openid.provider.AbstractAuthNInterface for more
138        information
139        @type authnCtx: dict like
140        @param authnCtx: session containing authentication context information
141        such as username and OpenID user identifier URI snippet
142        """
143        log.debug('CSVFileAXInterface.__call__  ...')
144       
145        identityURI = authnCtx.get(
146                                CSVFileAXInterface.IDENTITY_URI_SESSION_KEYNAME)
147        if identityURI is None:
148            raise AXInterfaceConfigError("No OpenID user identifier set in "
149                                         "session context")
150       
151        requiredAttributeURIs = ax_req.getRequiredAttrs()
152           
153        userAttributeMap = self.attributeMap.get(identityURI)
154        if userAttributeMap is None:
155            raise AXInterfaceConfigError("No attribute entry for user [%s] " %
156                                         identityURI)
157                                     
158        missingAttributeURIs = [
159            requiredAttributeURI
160            for requiredAttributeURI in requiredAttributeURIs
161            if requiredAttributeURI not in self.attributeNames
162        ]
163        if len(missingAttributeURIs) > 0:
164            raise MissingRequiredAttrs("OpenID Provider does not support "
165                                       "release of these attributes required "
166                                       "by the Relying Party: %s" %
167                                       ', '.join(missingAttributeURIs))
168       
169        # Add the required attributes
170        for requiredAttributeURI in requiredAttributeURIs:
171            log.info("Adding required AX parameter %s=%s ...", 
172                     requiredAttributeURI,
173                     userAttributeMap[requiredAttributeURI])
174           
175            ax_resp.addValue(requiredAttributeURI,
176                             userAttributeMap[requiredAttributeURI])
177           
178        # Append requested attribute if available
179        for requestedAttributeURI in ax_req.requested_attributes.keys():
180            if requestedAttributeURI in self.attributeNames:
181                log.info("Adding requested AX parameter %s=%s ...", 
182                         requestedAttributeURI,
183                         userAttributeMap[requestedAttributeURI])
184               
185                ax_resp.addValue(requestedAttributeURI,
186                                 userAttributeMap[requestedAttributeURI])
187            else:
188                log.info("Skipping Relying Party requested AX parameter %s: "
189                         "this parameter is not available", 
190                         requestedAttributeURI)
191               
Note: See TracBrowser for help on using the repository browser.