source: TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/subjectquery.py @ 6566

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/subjectquery.py@6566
Revision 6566, 8.0 KB checked in by pjkersha, 11 years ago (diff)

Refactoring SAML SOAP bindings module to include AuthzDecisionQuery?

Line 
1   
2   
3class SubjectQuerySOAPBinding(SOAPBinding): 
4    """SAML Subject Query SOAP Binding
5   
6    Nb. Assumes X.509 subject type for query issuer
7    """
8    SUBJECT_ID_OPTNAME = 'subjectID'
9    ISSUER_NAME_OPTNAME = 'issuerName'
10    CLOCK_SKEW_OPTNAME = 'clockSkewTolerance'
11    VERIFY_TIME_CONDITIONS_OPTNAME = 'verifyTimeConditions'
12   
13    CONFIG_FILE_OPTNAMES = (
14        SUBJECT_ID_OPTNAME,
15        ISSUER_NAME_OPTNAME,                 
16        CLOCK_SKEW_OPTNAME,
17        VERIFY_TIME_CONDITIONS_OPTNAME           
18    )
19   
20    __PRIVATE_ATTR_PREFIX = "__"
21    __slots__ = tuple([__PRIVATE_ATTR_PREFIX + i
22                       for i in CONFIG_FILE_OPTNAMES])
23    del i
24   
25    def __init__(self, **kw):
26        '''Create SOAP Client for SAML Attribute Query'''
27        self.__issuerName = None
28        self.__clockSkewTolerance = timedelta(seconds=0.)
29        self.__verifyTimeConditions = True
30       
31        super(SubjectQuerySOAPBinding, self).__init__(**kw)
32
33    def _getVerifyTimeConditions(self):
34        return self.__verifyTimeConditions
35
36    def _setVerifyTimeConditions(self, value):
37        if isinstance(value, bool):
38            self.__verifyTimeConditions = value
39           
40        if isinstance(value, basestring):
41            self.__verifyTimeConditions = str2Bool(value)
42        else:
43            raise TypeError('Expecting bool or string type for '
44                            '"verifyTimeConditions"; got %r instead' % 
45                            type(value))
46
47    verifyTimeConditions = property(_getVerifyTimeConditions, 
48                                    _setVerifyTimeConditions, 
49                                    doc='Set to True to verify any time '
50                                        'Conditions set in the returned '
51                                        'response assertions')
52       
53    def _getSubjectID(self):
54        return self.__subjectID
55
56    def _setSubjectID(self, value):
57        if not isinstance(value, basestring):
58            raise TypeError('Expecting string type for "subjectID"; got %r '
59                            'instead' % type(value))
60        self.__subjectID = value
61
62    subjectID = property(_getSubjectID, _setSubjectID, 
63                         doc="ID to be sent as query subject") 
64
65    def _getIssuerName(self):
66        return self.__issuerName
67
68    def _setIssuerName(self, value):
69        if not isinstance(value, basestring):
70            raise TypeError('Expecting string type for "issuerName"; '
71                            'got %r instead' % type(value))
72           
73        self.__issuerName = value
74
75    issuerName = property(_getIssuerName, _setIssuerName, 
76                        doc="Distinguished Name of issuer of SAML Attribute "
77                            "Query to Attribute Authority")
78
79    def _getClockSkewTolerance(self):
80        return self.__clockSkewTolerance
81
82    def _setClockSkewTolerance(self, value):
83        if isinstance(value, (float, int, long)):
84            self.__clockSkewTolerance = timedelta(seconds=value)
85           
86        elif isinstance(value, basestring):
87            self.__clockSkewTolerance = timedelta(seconds=float(value))
88        else:
89            raise TypeError('Expecting float, int, long or string type for '
90                            '"clockSkewTolerance"; got %r' % type(value))
91
92    clockSkewTolerance = property(fget=_getClockSkewTolerance, 
93                                  fset=_setClockSkewTolerance, 
94                                  doc="Allow a tolerance in seconds for SAML "
95                                      "Query issueInstant parameter check and "
96                                      "assertion condition notBefore and "
97                                      "notOnOrAfter times to allow for clock "
98                                      "skew") 
99
100    def _createQuery(self, queryClass=SubjectQuery):
101        """ Create a SAML SubjectQuery derived type instance
102        @param queryClass: query type to create - must be
103        saml.saml2.core.SubjectQuery type
104        @type queryClass: type
105        @return: query instance
106        @rtype: saml.saml2.core.SubjectQuery
107        """
108        if not isinstance(queryClass, SubjectQuery):
109            raise TypeError('Query class %r is not a SubjectQuery derived type'
110                            % queryClass)
111           
112        query = queryClass()
113        query.version = SAMLVersion(SAMLVersion.VERSION_20)
114        query.id = str(uuid4())
115        query.issueInstant = datetime.utcnow()
116       
117        if self.issuerName is None:
118            raise AttributeError('No issuer DN has been set for SAML Query')
119       
120        query.issuer = Issuer()
121        query.issuer.format = Issuer.X509_SUBJECT
122        query.issuer.value = self.issuerName
123                       
124        query.subject = Subject() 
125        query.subject.nameID = NameID()
126        query.subject.nameID.format = EsgSamlNamespaces.NAMEID_FORMAT
127        query.subject.nameID.value = self.subjectID
128           
129        return query
130
131    def send(self, **kw):
132        '''Make an attribute query to a remote SAML service
133       
134        @type uri: basestring
135        @param uri: uri of service.  May be omitted if set from request.url
136        @type request: ndg.security.common.soap.UrlLib2SOAPRequest
137        @param request: SOAP request object to which query will be attached
138        defaults to ndg.security.common.soap.client.UrlLib2SOAPRequest
139        '''
140        query = self._createQuery()
141           
142        response = super(SubjectQuerySOAPBinding, self).send(query, **kw)
143
144        # Perform validation
145        if response.status.statusCode.value != StatusCode.SUCCESS_URI:
146            msg = ('Return status code flagged an error.  The message is: %r' %
147                   response.status.statusMessage.value)
148            samlRespError = SubjectQueryResponseError(msg)
149            samlRespError.response = response
150            raise samlRespError
151       
152        # Check Query ID matches the query ID the service received
153        if response.inResponseTo != query.id:
154            msg = ('Response in-response-to ID %r, doesn\'t match the original '
155                   'query ID, %r' % (response.inResponseTo, query.id))
156           
157            samlRespError = SubjectQueryResponseError(msg)
158            samlRespError.response = response
159            raise samlRespError
160       
161        utcNow = datetime.utcnow() + self.clockSkewTolerance
162        if response.issueInstant > utcNow:
163            msg = ('SAML Attribute Response issueInstant [%s] is after '
164                   'the current clock time [%s]' % 
165                   (query.issueInstant, SAMLDateTime.toString(utcNow)))
166           
167            samlRespError = SubjectQueryResponseError(msg)                 
168            samlRespError.response = response
169            raise samlRespError
170       
171        for assertion in response.assertions:
172            if self.verifyTimeConditions and assertion.conditions is not None:
173                if utcNow < assertion.conditions.notBefore:           
174                    msg = ('The current clock time [%s] is before the SAML '
175                           'Attribute Response assertion conditions not before '
176                           'time [%s]' % 
177                           (SAMLDateTime.toString(utcNow),
178                            assertion.conditions.notBefore))
179                             
180                    samlRespError = SubjectQueryResponseError(msg)
181                    samlRespError.response = response
182                    raise samlRespError
183                 
184                if utcNow >= assertion.conditions.notOnOrAfter:           
185                    msg = ('The current clock time [%s] is on or after the '
186                           'SAML Attribute Response assertion conditions not '
187                           'on or after time [%s]' % 
188                           (SAMLDateTime.toString(utcNow),
189                            response.assertion.conditions.notOnOrAfter))
190                   
191                    samlRespError = SubjectQueryResponseError(msg) 
192                    samlRespError.response = response
193                    raise samlRespError   
194           
195        return response
Note: See TracBrowser for help on using the repository browser.