source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/saml/__init__.py @ 5510

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/saml/__init__.py@5510
Revision 5510, 17.9 KB checked in by pjkersha, 10 years ago (diff)

Working SAML Assertion code with ESG specific Group/Role? attributes

Line 
1"""Implementation of SAML 2.0 for NDG Security
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "22/07/08"
7__copyright__ = "(C) 2009 Science and Technology Facilities Council"
8__contact__ = "Philip.Kershaw@stfc.ac.uk"
9__license__ = "BSD - see LICENSE file in top-level directory"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = "$Id$"
12
13import logging
14log = logging.getLogger(__name__)
15
16# Time module for use with validity times
17from time import strftime, strptime
18from datetime import datetime, timedelta
19   
20from ndg.security.common.utils import QName
21from ndg.security.common.saml.xml import SAMLConstants, XMLConstants
22
23     
24class SAMLObject(object):
25    """Base class for all SAML types"""
26
27
28class SAMLVersion(object):
29    """Version helper class"""
30    VERSION_10 = (1, 0)
31    VERSION_11 = (1, 1)
32    VERSION_20 = (2, 0)
33   
34    def __init__(self, version):
35        self.__version = version
36   
37    def __str__(self):
38        return ".".join([str(i) for i in self.__version])
39   
40    @staticmethod
41    def valueOf(version):
42        return tuple(version.split("."))
43   
44
45class Assertion(SAMLObject):
46    """SAML 2.0 Attribute Assertion for use with NERC DataGrid   
47    """   
48    ns = "urn:oasis:names:tc:SAML:1.0:assertion"
49    nsPfx = "saml"
50    issuer = 'http:#badc.nerc.ac.uk'
51    attributeName = "urn:mace:dir:attribute-def:eduPersonAffiliation"
52    attributeNS = "urn:mace:shibboleth:1.0:attributeNamespace:uri"
53
54    # Element local name.
55    DEFAULT_ELEMENT_LOCAL_NAME = "Assertion"
56
57    # Default element name.
58    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
59                                 DEFAULT_ELEMENT_LOCAL_NAME,
60                                 SAMLConstants.SAML20_PREFIX)
61
62    # Local name of the XSI type.
63    TYPE_LOCAL_NAME = "AssertionType"
64
65    # QName of the XSI type.
66    TYPE_NAME = QName(SAMLConstants.SAML20_NS, TYPE_LOCAL_NAME,
67                      SAMLConstants.SAML20_PREFIX)
68
69    # Version attribute name.
70    VERSION_ATTRIB_NAME = "Version"
71
72    # IssueInstant attribute name.
73    ISSUE_INSTANT_ATTRIB_NAME = "IssueInstant"
74
75    # ID attribute name.
76    ID_ATTRIB_NAME = "ID"
77
78    def __init__(self, **xmlSecDocKw):
79        """@type **xmlSecDocKw: dict
80        @param **xmlSecDocKw: see XMLSec.XMLSec class for an explanation.
81        Keywords include, filePath for the cert. for reading/writing and
82        cert./private key settings for digital signature and verification."""
83
84        # Base class initialisation
85        super(Assertion, self).__init__()
86       
87        self._version = None
88        self._issueInstant = None
89        self._id = None
90        self._issuer = None
91        self._subject = None
92        self._conditions = []
93        self._advice = None
94        self._statements = []
95        self._authnStatements = []
96        self._authzDecisionStatements = []
97        self._attributeStatements = []
98       
99    def _get_version(self):
100        '''@return the SAML Version of this assertion.
101        '''
102        return self._version
103   
104    def _set_version(self, version):
105        '''@param version the SAML Version of this assertion
106        '''
107        if not isinstance(version, SAMLVersion):
108            raise TypeError("Expecting SAMLVersion type got: %r" % 
109                            version.__class__)
110       
111        self._version = version
112       
113    version = property(fget=_get_version,
114                       fset=_set_version,
115                       doc="SAML Version of the assertion")
116
117    def _get_issueInstant(self):
118        '''Gets the issue instance of this assertion.
119       
120        @return the issue instance of this assertion'''
121        return self._issueInstant
122   
123    def _set_issueInstant(self, issueInstant):
124        '''Sets the issue instance of this assertion.
125       
126        @param newIssueInstance the issue instance of this assertion
127        '''
128        if not isinstance(issueInstant, datetime):
129            raise TypeError('Expecting "datetime" type for "issueInstant", '
130                            'got %r' % issueInstant.__class__)
131           
132        self._issueInstant = issueInstant
133       
134    issueInstant = property(fget=_get_issueInstant, 
135                            fset=_set_issueInstant,
136                            doc="Issue instant of the assertion")
137
138    def _get_id(self):
139        '''Sets the ID of this assertion.
140       
141        @return the ID of this assertion
142        '''
143        return self._id
144   
145    def _set_id(self, _id):
146        '''Sets the ID of this assertion.
147       
148        @param newID the ID of this assertion
149        '''
150        if not isinstance(_id, basestring):
151            raise TypeError('Expecting basestring derived type for "id", got '
152                            '%r' % _id.__class__)
153        self._id = _id
154       
155    id = property(fget=_get_id, fset=_set_id, doc="ID of assertion")
156
157   
158    def _set_issuer(self, issuer):
159        """Set issuer"""
160        if not isinstance(issuer, basestring):
161            raise TypeError("issuer must be a string, got %r" % 
162                            issuer.__class__)
163       
164        self._issuer = issuer
165   
166    def _get_issuer(self):
167        """Get the issuer name """
168        return self._issuer
169
170    issuer = property(fget=_get_issuer, 
171                      fset=_set_issuer,
172                      doc="Issuer of assertion")
173   
174
175    def _set_subject(self, subject):
176        """Set subject string."""
177        if not isinstance(subject, basestring):
178            raise TypeError("subject must be a string, got %r" % 
179                            subject.__class__)
180
181        self._subject = subject
182   
183    def _get_subject(self):
184        """Get subject string."""
185        return self._subject
186
187    subject = property(fget=_get_subject,
188                       fset=_set_subject, 
189                       doc="Attribute Assertion subject")
190   
191    def _set_conditions(self, conditions):
192        """Set assertion conditions."""
193        if not isinstance(conditions, (list, tuple)):
194            raise TypeError("conditions must be a string")
195
196        self._conditions = list(conditions)
197   
198    def _get_conditions(self):
199        """Get conditions string."""
200        return self._conditions
201
202    conditions = property(fget=_get_conditions,
203                          fset=_set_conditions, 
204                          doc="Attribute Assertion conditions")
205   
206    def _set_advice(self, advice):
207        """Set advice string."""
208        if not isinstance(advice, basestring):
209            raise TypeError("advice must be a string")
210
211        self._advice = advice
212   
213    def _get_advice(self):
214        """Get advice string."""
215        return self._advice
216
217    advice = property(fget=_get_advice,
218                      fset=_set_advice, 
219                      doc="Attribute Assertion advice")
220   
221    def _set_statements(self, statements):
222        """Set statements list."""
223        if not isinstance(statements, (list, tuple)):
224            raise TypeError("statements must be a list/tuple.")
225
226        self._statements = list(statements)
227   
228    def _get_statements(self):
229        """Get statements string."""
230        return self._statements
231
232    statements = property(fget=_get_statements,
233                          fset=_set_statements, 
234                          doc="Attribute Assertion statements")
235
236    def _set_authnStatements(self, authnStatements):
237        """Set authentication statements string."""
238        if not isinstance(authnStatements, (list, tuple)):
239            raise TypeError("authnStatements must be a list/tuple")
240
241        self._authnStatements = list(authnStatements)
242   
243    def _get_authnStatements(self):
244        """Get authnStatements string."""
245        return self._authnStatements
246
247    authnStatements = property(fget=_get_authnStatements,
248                               fset=_set_authnStatements, 
249                               doc="Attribute Assertion authentication "
250                                   "statements")
251   
252    def _set_authzDecisionStatements(self, authzDecisionStatements):
253        """Set authorisation decision statements."""
254        if not isinstance(authzDecisionStatements, (list, tuple)):
255            raise TypeError("authorisation decision statements must be a "
256                            "list/tuple")
257
258        self._authzDecisionStatements = list(authzDecisionStatements)
259   
260    def _get_authzDecisionStatements(self):
261        """Get authorisation decision statements."""
262        return self._authzDecisionStatements
263
264    authzDecisionStatements = property(fget=_get_authzDecisionStatements,
265                                       fset=_set_authzDecisionStatements, 
266                                       doc="Attribute Assertion authorisation "
267                                           "decision statements")
268   
269
270    def _set_attributeStatements(self, attributeStatements):
271        """Set attribute statements for the asssertion."""
272        if not isinstance(attributeStatements, (list, tuple)):
273            raise TypeError("attributeStatements must be a list/tuple")
274
275        self._attributeStatements = list(attributeStatements)
276   
277    def _get_attributeStatements(self):
278        """Get attributeStatements string."""
279        return self._attributeStatements
280
281    attributeStatements = property(fget=_get_attributeStatements,
282                               fset=_set_attributeStatements, 
283                               doc="Attribute Assertion attribute statements")
284
285
286class Attribute(SAMLObject):
287    '''SAML 2.0 Core Attribute.'''
288   
289    # Local name of the Attribute element.
290    DEFAULT_ELEMENT_LOCAL_NAME = "Attribute"
291
292    # Default element name.
293    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
294                                 DEFAULT_ELEMENT_LOCAL_NAME,
295                                 SAMLConstants.SAML20_PREFIX)
296
297    # Local name of the XSI type.
298    TYPE_LOCAL_NAME = "AttributeType"
299
300    # QName of the XSI type.
301    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
302                      TYPE_LOCAL_NAME,
303                      SAMLConstants.SAML20_PREFIX)
304
305    # Name of the Name attribute.
306    NAME_ATTRIB_NAME = "Name"
307
308    # Name for the NameFormat attribute.
309    NAME_FORMAT_ATTRIB_NAME = "NameFormat"
310
311    # Name of the FriendlyName attribute.
312    FRIENDLY_NAME_ATTRIB_NAME = "FriendlyName"
313
314    # Unspecified attribute format ID.
315    UNSPECIFIED = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
316
317    # URI reference attribute format ID.
318    URI_REFERENCE = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
319
320    # Basic attribute format ID.
321    BASIC = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
322
323    def __init__(self):
324        self._name = None
325        self._nameFormat = None
326        self._friendlyName = None
327        self._attributeValues = []
328
329    def _get_name(self):
330        return self._name
331   
332    def _set_name(self, name):
333        if not isinstance(name, basestring):
334            raise TypeError("Expecting basestring type for name, got %r"% name)
335       
336        self._name = name
337       
338    name = property(fget=_get_name,
339                    fset=_set_name,
340                    doc="name of this attribute")
341   
342    def _get_nameFormat(self):
343        return self._nameFormat
344   
345    def _set_nameFormat(self, nameFormat):
346        if not isinstance(nameFormat, basestring):
347            raise TypeError("Expecting basestring type for nameFormat, got %r"
348                            % nameFormat)
349           
350        self._nameFormat = nameFormat
351       
352    nameFormat = property(fget=_get_nameFormat,
353                          fset=_set_nameFormat,
354                          doc="Get the name format of this attribute.")
355   
356    def _get_friendlyName(self):
357        return self._friendlyName
358   
359    def _set_friendlyName(self, friendlyName):
360        if not isinstance(friendlyName, basestring):
361            raise TypeError("Expecting basestring type for friendlyName, got "
362                            "%r" % friendlyName)
363           
364        self._friendlyName = friendlyName
365       
366    friendlyName = property(fget=_get_friendlyName,
367                            fset=_set_friendlyName,
368                            doc="the friendly name of this attribute.")
369   
370    def _get_attributeValues(self):
371        return self._attributeValues
372   
373    def _set_attributeValues(self, attributeValues):
374        if not isinstance(attributeValues, (list, tuple)):
375            raise TypeError("Expecting basestring type for attributeValues, "
376                            "got %r" % attributeValues)
377           
378        self._attributeValues = attributeValues
379       
380    attributeValues = property(fget=_get_attributeValues,
381                               fset=_set_attributeValues,
382                               doc="the list of attribute values for this "
383                               "attribute.")
384
385class AttributeValue(SAMLObject):
386
387    # Element name, no namespace
388    DEFAULT_ELEMENT_LOCAL_NAME = "AttributeValue"
389
390    # Default element name
391    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
392                                 DEFAULT_ELEMENT_LOCAL_NAME,
393                                 SAMLConstants.SAML20_PREFIX)
394   
395   
396class XSStringAttributeValue(AttributeValue):
397
398    # Local name of the XSI type
399    TYPE_LOCAL_NAME = "string"
400       
401    # QName of the XSI type
402    TYPE_NAME = QName(XMLConstants.XSD_NS, 
403                      TYPE_LOCAL_NAME, 
404                      XMLConstants.XSD_PREFIX)
405 
406    def __init__(self):
407        self.__value = None
408       
409    def _getValue(self):
410        return self.__value
411       
412    def _setValue(self, value):
413        if not isinstance(value, basestring):
414            raise TypeError("Input must be a basestring derived type, got %r" %
415                            value.__class__)
416           
417        self.__value = value
418
419    value = property(fget=_getValue, fset=_setValue, doc="string value") 
420   
421class Statement(SAMLObject):
422    pass
423
424class AttributeStatement(Statement):
425    '''SAML 2.0 Core AttributeStatement'''
426
427    def __init__(self):
428        self._attributes = []
429        self._encryptedAttributes = []
430
431    # Element local name
432    DEFAULT_ELEMENT_LOCAL_NAME = "AttributeStatement"
433   
434    # Default element name.
435    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
436                                 DEFAULT_ELEMENT_LOCAL_NAME, 
437                                 SAMLConstants.SAML20_PREFIX)
438   
439    # Local name of the XSI type.
440    TYPE_LOCAL_NAME = "AttributeStatementType" 
441       
442    # QName of the XSI type.
443    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
444                      TYPE_LOCAL_NAME, 
445                      SAMLConstants.SAML20_PREFIX)
446
447    def _get_attributes(self):
448        '''@return the attributes expressed in this statement
449        '''
450        return self._attributes
451
452    attributes = property(fget=_get_attributes)
453   
454    def _get_encryptedAttributes(self):
455       '''@return the encrypted attribtues expressed in this statement
456       '''
457       return self._encryptedAttributes
458   
459    encryptedAttributes = property(fget=_get_encryptedAttributes)
460   
461
462class XSGroupRoleAttributeValue(AttributeValue): 
463    '''ESG Specific Group/Role attribute value.  ESG attribute permissions are
464    organised into group/role pairs
465    '''
466    DEFAULT_NS = "http://www.esg.org"
467    DEFAULT_PREFIX = "esg"
468    TYPE_LOCAL_NAME = "groupRole"
469   
470    GROUP_ATTRIB_NAME = "group"
471    ROLE_ATTRIB_NAME = "role"
472   
473    # QName of the XSI type
474    TYPE_NAME = QName(DEFAULT_NS, 
475                      TYPE_LOCAL_NAME, 
476                      DEFAULT_PREFIX)
477     
478    def __init__(self, 
479                 namespaceURI=DEFAULT_NS, 
480                 elementLocalName=TYPE_LOCAL_NAME, 
481                 namespacePrefix=DEFAULT_PREFIX):
482        '''@param namespaceURI: the namespace the element is in
483        @param elementLocalName: the local name of the XML element this Object
484        represents
485        @param namespacePrefix: the prefix for the given namespace'''
486        self.__namespaceURI = namespaceURI
487        self.__elementLocalName = elementLocalName
488        self.__namespacePrefix = namespacePrefix
489        self.__group = None
490        self.__role = None       
491
492    def _getNamespaceURI(self):
493        return self.__namespaceURI
494
495    def _setNamespaceURI(self, value):
496        if not isinstance(value, basestring):
497            raise TypeError("Expecting %r type for namespaceURI got %r" %
498                            (basestring, value.__class__))
499        self.__namespaceURI = value
500
501    def _getElementLocalName(self):
502        return self.__elementLocalName
503
504    def _setElementLocalName(self, value):
505        if not isinstance(value, basestring):
506            raise TypeError("Expecting %r type for elementLocalName got %r" %
507                            (basestring, value.__class__))
508        self.__elementLocalName = value
509
510    def _getNamespacePrefix(self):
511        return self.__namespacePrefix
512
513    def _setNamespacePrefix(self, value):
514        if not isinstance(value, basestring):
515            raise TypeError("Expecting %r type for namespacePrefix got %r" %
516                            (basestring, value.__class__))
517        self.__namespacePrefix = value
518
519    namespaceURI = property(fget=_getNamespaceURI, 
520                            fset=_setNamespaceURI, 
521                            doc="the namespace the element is in")
522
523    elementLocalName = property(fget=_getElementLocalName, 
524                                fset=_setElementLocalName, 
525                                doc="the local name of the XML element this "
526                                    "Object represents")
527
528    namespacePrefix = property(fget=_getNamespacePrefix, 
529                               fset=_setNamespacePrefix, 
530                               doc="the prefix for the given namespace")
531
532    def _getGroup(self):
533        return self.__group
534     
535    def _setGroup(self, group): 
536        self.__group = group
537     
538    group = property(fget=_getGroup, fset=_setGroup)
539     
540    def _getRole(self):
541        return self.__role
542     
543    def _setRole(self, role):
544        self.__role = role
545     
546    role = property(fget=_getRole, fset=_setRole)
547
548    def getOrderedChildren(self):
549        # no children
550        return None
Note: See TracBrowser for help on using the repository browser.