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

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@5782
Revision 5782, 7.4 KB checked in by pjkersha, 11 years ago (diff)

Re-testing OpenID Attribute Exchange interface - added CSV file based test AX Response class.

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    <userID>, <role1>, <role2>, ... <roleN>
32    """
33    __slots__ = (
34        "csvFilePath",
35        "attributeNames",
36        "attributeMap",
37    )
38    USERIDENTIFIER_SESSIONKEY = \
39        OpenIDProviderMiddleware.USERIDENTIFIER_SESSIONKEY
40   
41    def __init__(self, **properties):
42        """
43        @param properties: file path to Comma Separated file
44        containing user ids and roles
45        @type properties: dict
46        """
47        self.__csvFilePath = None
48        self.__attributeNames = []
49        self.__attributeMap = {}
50       
51        self.setProperties(**properties)
52        if self.csvFilePath is not None:
53            self.read()
54
55    def _getAttributeNames(self):
56        return self.__attributeNames
57
58    def _setAttributeNames(self, value):
59        """@param value: if a string, it will be parsed into a list delimiting
60        elements by whitespace
61        @type value: basestring/tuple or list
62        """
63        if isinstance(value, (list, tuple)):
64            self.__attributeNames = list(value)
65           
66        elif isinstance(value, basestring):
67            self.__attributeNames = value.split() 
68        else:
69            raise TypeError('Expecting string, list or tuple type for '
70                            '"attributeNames"; got %r' % type(value))
71       
72    attributeNames = property(fget=_getAttributeNames, 
73                              fset=_setAttributeNames, 
74                              doc="list of attribute names supported.  The "
75                                  "order of the names is important and "
76                                  "determines the order in which they will be "
77                                  "assigned from the columns in the CSV file")
78
79    def setProperties(self, **properties):
80        for name, val in properties.items():
81            setattr(self, name, val)
82   
83    def read(self):
84        csvFile = open(self.csvFilePath)
85        lines = csvFile.readlines()
86       
87        nAttributes = len(self.attributeNames)
88        for line in lines:
89            fields = re.split(',\W*', line.strip())
90           
91            # Dictionary keyed by user ID with each val itself a dict keyed
92            # by attribute name
93            self.attributeMap[fields[0]] = dict(zip(self.attributeNames,
94                                                    fields[1:nAttributes+1]))
95               
96    def _getCsvFilePath(self):
97        return self.__csvFilePath
98
99    def _setCsvFilePath(self, value):
100        if not isinstance(value, basestring):
101            raise TypeError('Expecting string type for "csvFilePath"; got %r'
102                            % type(value))
103        self.__csvFilePath = value
104
105    csvFilePath = property(fget=_getCsvFilePath, 
106                           fset=_setCsvFilePath, 
107                           doc="file path to Comma Separated Variable format "
108                               "file containing user IDs and attributes")
109   
110    def _getAttributeMap(self):
111        return self.__attributeMap
112
113    def _setAttributeMap(self, value):
114        self.__attributeMap = value
115
116    attributeMap = property(fget=_getAttributeMap, 
117                            fset=_setAttributeMap, 
118                            doc="Dictionary of attributes keyed by user ID")
119   
120    def __call__(self, ax_req, ax_resp, authnInterface, authnCtx):
121        """Add the attributes to the ax_resp object requested in the ax_req
122        object.  If it is not possible to return them, raise
123        MissingRequiredAttrs error
124       
125        @type ax_req: openid.extensions.ax.FetchRequest
126        @param ax_req: attribute exchange request object.  To find out what
127        attributes the Relying Party has requested for example, call
128        ax_req.getRequiredAttrs()
129        @type ax_resp: openid.extensions.ax.FetchResponse
130        @param ax_resp: attribute exchange response object.  This method should
131        update the settings in this object.  Use addValue and setValues methods
132        @type authnInterface: AbstractAuthNInterface
133        @param authnInterface: custom authentication interface set at login. 
134        See ndg.security.server.openid.provider.AbstractAuthNInterface for more
135        information
136        @type authnCtx: dict like
137        @param authnCtx: session containing authentication context information
138        such as username and OpenID user identifier URI snippet
139        """
140        log.debug('CSVFileAXInterface.__call__  ...')
141       
142        userIdentifier = authnCtx.get(
143                                CSVFileAXInterface.USERIDENTIFIER_SESSIONKEY)
144        if userIdentifier is None:
145            raise AXInterfaceConfigError("No OpenID user identifier set in "
146                                         "session context")
147       
148        requiredAttributeURIs = ax_req.getRequiredAttrs()
149        missingAttributeURIs = [
150            requiredAttributeURI
151            for requiredAttributeURI in requiredAttributeURIs
152            if requiredAttributeURI not in self.attributeNames
153        ]
154        if len(missingAttributeURIs) > 0:
155            raise MissingRequiredAttrs("OpenID Provider does not support "
156                                       "release of these attributes required "
157                                       "by the Relying Party: %s" %
158                                       ', '.join(missingAttributeURIs))
159       
160        userAttributeMap = self.attributeMap.get
161        # Add the required attributes
162        for requiredAttributeURI in requiredAttributeURIs:
163            log.info("Adding required AX parameter %s=%s ...", 
164                     requiredAttributeURI,
165                     self.attributeMap[authnCtx][requiredAttributeURI])
166           
167            ax_resp.addValue(requiredAttributeURI,
168                             self.attributeMap[authnCtx][requiredAttributeURI])
169           
170        # Append requested attribute if available
171        for requestedAttributeURI in ax_req.requested_attributes.keys():
172            if requestedAttributeURI in self.attributeNames:
173                log.info("Adding requested AX parameter %s=%s ...", 
174                          requiredAttributeURI,
175                          self.attributeMap[authnCtx][requiredAttributeURI])
176               
177                ax_resp.addValue(requiredAttributeURI,
178                             self.attributeMap[authnCtx][requiredAttributeURI])
179            else:
180                log.info("Skipping Relying Party requested AX parameter %s: "
181                         "this parameter is not available", 
182                         requestedAttributeURI)
183               
Note: See TracBrowser for help on using the repository browser.