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

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

Added OpenSAML credits

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