source: TI12-security/trunk/python/ndg_security_myproxy_attribute_extapp/ndg/security/server/myproxy/certificate_extapp/saml_attribute_assertion.py @ 5898

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg_security_myproxy_attribute_extapp/ndg/security/server/myproxy/certificate_extapp/saml_attribute_assertion.py@5898
Revision 5898, 6.4 KB checked in by pjkersha, 10 years ago (diff)

New egg for MyProxy? certificate callout application. For ESG, MyProxy? will be configured to add in a SAML attribute assertion into certificates issued. This application creates the assertion for use by MyProxy?.

Line 
1"""X.509 certificate extension application for adding SAML assertions into
2certificates issued by MyProxy
3
4NERC DataGrid Project
5"""
6__author__ = "P J Kershaw"
7__date__ = "29/10/09"
8__copyright__ = "(C) 2009 Science and Technology Facilities Council"
9__license__ = "BSD - see LICENSE file in top-level directory"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = '$Id: $'
12import logging
13log = logging.getLogger(__name__)
14
15from datetime import datetime
16from uuid import uuid4
17
18from saml.common.xml import SAMLConstants
19from saml.saml2.core import (
20    Assertion, Attribute, 
21    SAMLVersion, Subject, NameID, Issuer, AttributeQuery, 
22    XSStringAttributeValue, 
23    StatusCode)
24from saml.xml.etree import ResponseElementTree
25   
26from ndg.security.common.saml.bindings import SOAPBinding as SamlSoapBinding
27
28
29class SamlAssertionMyProxyCertExtApp(object):
30    """Application to create a X.509 certificate extension containing a SAML
31    assertion for inclusion by MyProxy into an issued certificate"""
32    XSSTRING_NS = "%s#%s" % (
33        SAMLConstants.XSD_NS,
34        XSStringAttributeValue.TYPE_LOCAL_NAME
35    )
36    N_ATTR_DESCR_ELEM_ITEMS = 3
37    DEFAULT_ATTR_DESCR = (
38        ("urn:esg:first:name", "FirstName", XSSTRING_NS),
39        ("urn:esg:last:name", "LastName", XSSTRING_NS),
40        ("urn:esg:email:address", "emailAddress", XSSTRING_NS),
41    )
42   
43    def __init__(self):
44        self.__attributeAuthorityURI = None
45        self.__userOpenID = None
46        self.__issuerName = None
47       
48        # Use property here in case DEFAULT_ATTR_DESCR has been altered
49        self.attributeDescr = SamlAssertionMyProxyCertExtApp.DEFAULT_ATTR_DESCR
50
51    def _getAttributeDescr(self):
52        return self.__attributeDescr
53
54    def _setAttributeDescr(self, value):
55        if not isinstance(value, tuple):
56            raise TypeError('Expecting tuple type for "attributeDescr";'
57                            ' got %r instead' % type(value))
58           
59        for i in value:
60            if not isinstance(value, tuple):
61                raise TypeError('Expecting tuple type for "attributeDescr" '
62                                'tuple sub-elements; got %r instead' % 
63                                type(value))
64            if len(i) != SamlAssertionMyProxyCertExtApp.N_ATTR_DESCR_ELEM_ITEMS:
65                raise TypeError('Expecting %d element tuple for '
66                    '"attributeDescr" sub-elements; got %d elements instead' % 
67                    (SamlAssertionMyProxyCertExtApp.N_ATTR_DESCR_ELEM_ITEMS,
68                    len(i)))
69               
70        self.__attributeDescr = value
71
72    def _getAttributeAuthorityURI(self):
73        return self.__attributeAuthorityURI
74
75    def _setAttributeAuthorityURI(self, value):
76        if not isinstance(value, basestring):
77            raise TypeError('Expecting string type for "attributeAuthorityURI";'
78                            ' got %r instead' % type(value))
79        self.__attributeAuthorityURI = value
80
81    def _getUserOpenID(self):
82        return self.__userOpenID
83
84    def _setUserOpenID(self, value):
85        if not isinstance(value, basestring):
86            raise TypeError('Expecting string type for "userOpenID";'
87                            ' got %r instead' % type(value))
88        self.__userOpenID = value
89
90    def _getIssuerName(self):
91        return self.__issuerName
92
93    def _setIssuerName(self, value):
94        if not isinstance(value, basestring):
95            raise TypeError('Expecting string type for "issuerName";'
96                            ' got %r instead' % type(value))
97        self.__issuerName = value
98
99    attributeAuthorityURI = property(_getAttributeAuthorityURI,
100                                     _setAttributeAuthorityURI, 
101                                     doc="AttributeAuthorityURI's Docstring")
102
103    userOpenID = property(_getUserOpenID, _setUserOpenID, 
104                          doc="OpenID corresponding to user certificate to "
105                              "be issued")
106
107    issuerName = property(_getIssuerName, _setIssuerName, 
108                          doc="Name of issuer of SAML Attribute Query to "
109                              "Attribute Authority")
110   
111    attributeDescr = property(_getAttributeDescr, 
112                              _setAttributeDescr, 
113                              doc="List of name, friendly name, format tuples "
114                                  "determining attributes to query from the "
115                                  "Attribute Authority")
116       
117    def _attributeQuery(self, attributeDescr=DEFAULT_ATTR_DESCR):
118        """Query an Attribute Authority to retrieve an assertion for the
119        given user"""
120               
121        # Create a SAML attribute query
122        attributeQuery = AttributeQuery()
123        attributeQuery.version = SAMLVersion(SAMLVersion.VERSION_20)
124        attributeQuery.id = str(uuid4())
125        attributeQuery.issueInstant = datetime.utcnow()
126       
127        attributeQuery.issuer = Issuer()
128        attributeQuery.issuer.format = "urn:esg:issuer"
129        attributeQuery.issuer.value = self.issuerName 
130                       
131        attributeQuery.subject = Subject() 
132        attributeQuery.subject.nameID = NameID()
133        attributeQuery.subject.nameID.format = "urn:esg:openid"
134        attributeQuery.subject.nameID.value = self.userOpenID
135                 
136        # Add list of attributes to query                     
137        for name, friendlyName, format in attributeDescr:
138            attribute = Attribute()
139            attribute.name = name
140            attribute.nameFormat = format
141            attribute.friendlyName = friendlyName
142   
143            attributeQuery.attributes.append(attribute)
144
145        # Make query over SOAP interface to remote service
146        binding = SamlSoapBinding()
147        response = binding.attributeQuery(attributeQuery, 
148                                          self.attributeAuthorityURI)
149       
150        assert(response.status.statusCode.value==StatusCode.SUCCESS_URI)
151       
152        # Check Query ID matches the query ID the service received
153        assert(response.inResponseTo == attributeQuery.id)
154       
155        now = datetime.utcnow()
156        assert(response.issueInstant < now)
157        assert(response.assertions[-1].issueInstant < now)       
158        assert(response.assertions[-1].conditions.notBefore < now) 
159        assert(response.assertions[-1].conditions.notOnOrAfter > now)
160         
161        samlResponseElem = ResponseElementTree.toXML(response)
162       
163        return
Note: See TracBrowser for help on using the repository browser.