source: TI12-security/trunk/ndg_saml/ndg/saml/saml2/core.py @ 6901

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/ndg_saml/ndg/saml/saml2/core.py@6901
Revision 6901, 110.6 KB checked in by pjkersha, 9 years ago (diff)

Incomplete - task 6: Put NDG SAML package on PyPI

  • updating epydoc for 'core' module
Line 
1"""SAML 2.0 core module
2
3Implementation of SAML 2.0 for NDG Security
4
5NERC DataGrid Project
6
7This implementation is adapted from the Java OpenSAML implementation.  The
8copyright and licence information are included here:
9
10Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
11
12Licensed under the Apache License, Version 2.0 (the "License");
13you may not use this file except in compliance with the License.
14You may obtain a copy of the License at
15
16http://www.apache.org/licenses/LICENSE-2.0
17
18Unless required by applicable law or agreed to in writing, software
19distributed under the License is distributed on an "AS IS" BASIS,
20WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21See the License for the specific language governing permissions and
22limitations under the License.
23"""
24__author__ = "P J Kershaw"
25__date__ = "11/08/09"
26__copyright__ = "(C) 2009 Science and Technology Facilities Council"
27__contact__ = "Philip.Kershaw@stfc.ac.uk"
28__license__ = "http://www.apache.org/licenses/LICENSE-2.0"
29__contact__ = "Philip.Kershaw@stfc.ac.uk"
30__revision__ = "$Id$"
31from datetime import datetime
32from urlparse import urlsplit, urlunsplit
33import urllib
34
35from ndg.saml.common import SAMLObject, SAMLVersion
36from ndg.saml.common.xml import SAMLConstants, QName
37from ndg.saml.utils import TypedList
38
39
40class Attribute(SAMLObject):
41    '''SAML 2.0 Core Attribute.
42    @cvar DEFAULT_ELEMENT_LOCAL_NAME:  Local name of the Attribute element.
43    @type DEFAULT_ELEMENT_LOCAL_NAME: string
44    @cvar DEFAULT_ELEMENT_NAME:  Default element name.
45    @type DEFAULT_ELEMENT_NAME: ndg.saml.common.xml.QName
46    @cvar TYPE_LOCAL_NAME:  Local name of the XSI type.
47    @type TYPE_LOCAL_NAME: string
48    @cvar TYPE_NAME:  QName of the XSI type.
49    @type TYPE_NAME: ndg.saml.common.xml.QName
50    @cvar NAME_ATTRIB_NAME:  Name of the Name attribute.
51    @type NAME_ATTRIB_NAME: string
52    @cvar NAME_FORMAT_ATTRIB_NAME:  Name for the NameFormat attribute.
53    @type NAME_FORMAT_ATTRIB_NAME: string
54    @cvar FRIENDLY_NAME_ATTRIB_NAME:  Name of the FriendlyName attribute.
55    @type FRIENDLY_NAME_ATTRIB_NAME: string
56    @cvar UNSPECIFIED:  Unspecified attribute format ID.
57    @type UNSPECIFIED: string
58    @cvar URI_REFERENCE:  URI reference attribute format ID.
59    @type URI_REFERENCE: string
60    @cvar BASIC:  Basic attribute format ID.
61    @type BASIC: string
62   
63    @ivar __name: attribute name
64    @type __name: NoneType / basestring
65    @ivar __nameFormat: name format
66    @type __nameFormat: NoneType / basestring
67    @ivar __friendlyName: friendly name for attribute
68    @type __friendlyName: NoneType / basestring
69    @ivar __attributeValues: list of values
70    @type __attributeValues: list / tuple
71    '''
72   
73    # Local name of the Attribute element.
74    DEFAULT_ELEMENT_LOCAL_NAME = "Attribute"
75
76    # Default element name.
77    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
78                                 DEFAULT_ELEMENT_LOCAL_NAME,
79                                 SAMLConstants.SAML20_PREFIX)
80
81    # Local name of the XSI type.
82    TYPE_LOCAL_NAME = "AttributeType"
83
84    # QName of the XSI type.
85    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
86                      TYPE_LOCAL_NAME,
87                      SAMLConstants.SAML20_PREFIX)
88
89    # Name of the Name attribute.
90    NAME_ATTRIB_NAME = "Name"
91
92    # Name for the NameFormat attribute.
93    NAME_FORMAT_ATTRIB_NAME = "NameFormat"
94
95    # Name of the FriendlyName attribute.
96    FRIENDLY_NAME_ATTRIB_NAME = "FriendlyName"
97
98    # Unspecified attribute format ID.
99    UNSPECIFIED = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
100
101    # URI reference attribute format ID.
102    URI_REFERENCE = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
103
104    # Basic attribute format ID.
105    BASIC = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
106
107    __slots__ = (
108        '__name',
109        '__nameFormat',
110        '__friendlyName',
111        '__attributeValues'
112    )
113   
114    def __init__(self, **kw):
115        """Initialise Attribute Class attributes
116        @param **kw: keywords SAMLObject parent instantiation
117        @type **kw: dict
118        """
119        super(Attribute, self).__init__(**kw)
120       
121        self.__name = None
122        self.__nameFormat = None
123        self.__friendlyName = None
124        self.__attributeValues = []
125
126    def __getstate__(self):
127        '''Enable pickling
128       
129        @return: object's attribute dictionary
130        @rtype: dict
131        '''
132        _dict = super(Attribute, self).__getstate__()
133        for attrName in Attribute.__slots__:
134            # Ugly hack to allow for derived classes setting private member
135            # variables
136            if attrName.startswith('__'):
137                attrName = "_Attribute" + attrName
138               
139            _dict[attrName] = getattr(self, attrName)
140           
141        return _dict
142   
143    def _get_name(self):
144        """Get name
145        @return: name
146        @rtype: string
147        """
148        return self.__name
149   
150    def _set_name(self, name):
151        """Set name
152        @param: name
153        @type: name
154        @raise TypeError: invalid input value type
155        """
156        if not isinstance(name, basestring):
157            raise TypeError("Expecting basestring type for name, got %r"% 
158                            type(name))
159       
160        self.__name = name
161       
162    name = property(fget=_get_name,
163                    fset=_set_name,
164                    doc="name of this attribute")
165   
166    def _get_nameFormat(self):
167        """Get name format
168        @return: name format
169        @rtype: string
170        """
171        return self.__nameFormat
172   
173    def _set_nameFormat(self, nameFormat):
174        """Set name format
175        @param: name format
176        @type: string
177        @raise TypeError: invalid input value type
178        """
179        if not isinstance(nameFormat, basestring):
180            raise TypeError("Expecting basestring type for nameFormat, got %r"
181                            % type(nameFormat))
182           
183        self.__nameFormat = nameFormat
184       
185    nameFormat = property(fget=_get_nameFormat,
186                          fset=_set_nameFormat,
187                          doc="Get the name format of this attribute.")
188   
189    def _get_friendlyName(self):
190        """Get friendly name
191        @return: friendly name
192        @rtype: string
193        """
194        return self.__friendlyName
195   
196    def _set_friendlyName(self, friendlyName):
197        """Set friendly name
198        @param: friendly name
199        @type: string
200        @raise TypeError: invalid input value type
201        """
202        if not isinstance(friendlyName, basestring):
203            raise TypeError("Expecting basestring type for friendlyName, got "
204                            "%r" % type(friendlyName))
205           
206        self.__friendlyName = friendlyName
207       
208    friendlyName = property(fget=_get_friendlyName,
209                            fset=_set_friendlyName,
210                            doc="the friendly name of this attribute.")
211   
212    def _get_attributeValues(self):
213        """Get attribute values
214        @return: attribute values
215        @rtype: string
216        """
217        return self.__attributeValues
218   
219    def _set_attributeValues(self, attributeValues):
220        """Set attribute values
221        @param: attribute values
222        @type: string
223        @raise TypeError: invalid input value type
224        """
225        if not isinstance(attributeValues, (list, tuple)):
226            raise TypeError("Expecting list/tuple type for attributeValues, "
227                            "got %r" % type(attributeValues))
228           
229        self.__attributeValues = attributeValues
230       
231    attributeValues = property(fget=_get_attributeValues,
232                               fset=_set_attributeValues,
233                               doc="the list of attribute values for this "
234                               "attribute.")
235
236
237class Statement(SAMLObject):
238    '''SAML 2.0 Core Statement.  Abstract base class which all statement
239    types must implement.
240   
241    @cvar DEFAULT_ELEMENT_LOCAL_NAME: Element local name
242    @type DEFAULT_ELEMENT_LOCAL_NAME: string
243    @cvar DEFAULT_ELEMENT_NAME: Default element name
244    @type DEFAULT_ELEMENT_NAME: ndg.saml.common.xml.QName
245    @cvar TYPE_LOCAL_NAME: Local name of the XSI type
246    @type TYPE_LOCAL_NAME: string
247    @cvar TYPE_NAME: QName of the XSI type
248    @type TYPE_NAME: ndg.saml.common.xml.QName
249    '''
250    __slots__ = ()
251   
252    # Element local name
253    DEFAULT_ELEMENT_LOCAL_NAME = "Statement"
254
255    # Default element name
256    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
257                                 DEFAULT_ELEMENT_LOCAL_NAME,
258                                 SAMLConstants.SAML20_PREFIX)
259
260    # Local name of the XSI type
261    TYPE_LOCAL_NAME = "StatementAbstractType"
262
263    # QName of the XSI type
264    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
265                      TYPE_LOCAL_NAME,
266                      SAMLConstants.SAML20_PREFIX)
267   
268           
269class AttributeStatement(Statement):
270    '''SAML 2.0 Core AttributeStatement
271   
272    @cvar DEFAULT_ELEMENT_LOCAL_NAME: Element local name
273    @type DEFAULT_ELEMENT_LOCAL_NAME: string
274    @cvar DEFAULT_ELEMENT_NAME: Default element name.
275    @type DEFAULT_ELEMENT_NAME: ndg.saml.common.xml.QName
276    @cvar TYPE_LOCAL_NAME: Local name of the XSI type.
277    @type TYPE_LOCAL_NAME: string
278    @cvar TYPE_NAME: QName of the XSI type.
279    @type TYPE_NAME: ndg.saml.common.xml.QName
280   
281    @ivar __attributes: list of ndg.saml.saml2.core.Attribute type attributes
282    @type __attributes: ndg.saml.utils.TypedList
283    @ivar __encryptedAttributes: list of encrypted attributes of type
284    ndg.saml.saml2.core.Attribute
285    @type __encryptedAttributes: ndg.saml.utils.TypedList
286    '''
287   
288    # Element local name
289    DEFAULT_ELEMENT_LOCAL_NAME = "AttributeStatement"
290   
291    # Default element name.
292    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
293                                 DEFAULT_ELEMENT_LOCAL_NAME, 
294                                 SAMLConstants.SAML20_PREFIX)
295   
296    # Local name of the XSI type.
297    TYPE_LOCAL_NAME = "AttributeStatementType" 
298       
299    # QName of the XSI type.
300    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
301                      TYPE_LOCAL_NAME, 
302                      SAMLConstants.SAML20_PREFIX)
303   
304    __slots__ = ('__attributes', '__encryptedAttributes')
305   
306    def __init__(self, **kw):
307        """
308        @param **kw: keywords Statement parent class instantiation
309        @type **kw: dict
310        """
311        super(AttributeStatement, self).__init__(**kw)
312       
313        self.__attributes = TypedList(Attribute)
314        self.__encryptedAttributes = TypedList(Attribute)
315
316    def __getstate__(self):
317        '''Enable pickling
318       
319        @return: object's attribute dictionary
320        @rtype: dict
321        '''
322
323        _dict = super(AttributeStatement, self).__getstate__()
324        for attrName in AttributeStatement.__slots__:
325            # Ugly hack to allow for derived classes setting private member
326            # variables
327            if attrName.startswith('__'):
328                attrName = "_AttributeStatement" + attrName
329               
330            _dict[attrName] = getattr(self, attrName)
331           
332        return _dict
333
334    def _get_attributes(self):
335        '''@return: the attributes expressed in this statement
336        @rtype: ndg.saml.utils.TypedList
337        '''
338        return self.__attributes
339
340    attributes = property(fget=_get_attributes)
341   
342    def _get_encryptedAttributes(self):
343       '''@return: the encrypted attribtues expressed in this statement
344       @rtype: ndg.saml.utils.TypedList
345       '''
346       return self.__encryptedAttributes
347   
348    encryptedAttributes = property(fget=_get_encryptedAttributes)
349
350
351class AuthnStatement(Statement):
352    '''SAML 2.0 Core AuthnStatement.  Currently implemented in abstract form
353    only
354   
355    @cvar DEFAULT_ELEMENT_LOCAL_NAME: Element local name
356    @type DEFAULT_ELEMENT_LOCAL_NAME: string
357    @cvar DEFAULT_ELEMENT_NAME: Default element name
358    @type DEFAULT_ELEMENT_NAME: ndg.saml.common.xml.QName
359    @cvar TYPE_LOCAL_NAME: Local name of the XSI type
360    @type TYPE_LOCAL_NAME: string
361    @cvar TYPE_NAME: QName of the XSI type
362    @type TYPE_NAME: ndg.saml.common.xml.QName
363    @cvar AUTHN_INSTANT_ATTRIB_NAME: AuthnInstant attribute name
364    @type AUTHN_INSTANT_ATTRIB_NAME: string
365    @cvar SESSION_INDEX_ATTRIB_NAME: SessionIndex attribute name
366    @type SESSION_INDEX_ATTRIB_NAME: string
367    @cvar SESSION_NOT_ON_OR_AFTER_ATTRIB_NAME: SessionNoOnOrAfter attribute name
368    @type SESSION_NOT_ON_OR_AFTER_ATTRIB_NAME: string
369    '''
370
371    # Element local name
372    DEFAULT_ELEMENT_LOCAL_NAME = "AuthnStatement"
373
374    # Default element name
375    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
376                                 DEFAULT_ELEMENT_LOCAL_NAME,
377                                 SAMLConstants.SAML20_PREFIX)
378
379    # Local name of the XSI type
380    TYPE_LOCAL_NAME = "AuthnStatementType"
381
382    # QName of the XSI type
383    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
384                      TYPE_LOCAL_NAME,
385                      SAMLConstants.SAML20_PREFIX)
386
387    # AuthnInstant attribute name
388    AUTHN_INSTANT_ATTRIB_NAME = "AuthnInstant"
389
390    # SessionIndex attribute name
391    SESSION_INDEX_ATTRIB_NAME = "SessionIndex"
392
393    # SessionNoOnOrAfter attribute name
394    SESSION_NOT_ON_OR_AFTER_ATTRIB_NAME = "SessionNotOnOrAfter"
395   
396    __slots__ = ()
397   
398    def _getAuthnInstant(self):
399        '''Abstract method.  Gets the time when the authentication took place.
400       
401        @return: the time when the authentication took place
402        @rtype: datetime.datetime
403        @raise NotImplementedError: abstract method
404        '''
405        raise NotImplementedError()
406
407    def _setAuthnInstant(self, value):
408        '''Sets the time when the authentication took place.
409       
410        @param value: the time when the authentication took place
411        @type: datetime.datetime
412        @raise NotImplementedError: abstract method
413        '''
414        raise NotImplementedError()
415
416    def _getSessionIndex(self):
417        '''Get the session index between the principal and the authenticating
418        authority.
419       
420        @return: the session index between the principal and the authenticating
421        authority
422        @rtype: ?
423        @raise NotImplementedError: abstract method
424        '''
425        raise NotImplementedError()
426
427    def _setSessionIndex(self, value):
428        '''Sets the session index between the principal and the authenticating
429        authority.
430       
431        @param value: the session index between the principal and the
432        authenticating authority
433        @type: ?
434        @raise NotImplementedError: abstract method
435        '''
436        raise NotImplementedError()
437
438    def _getSessionNotOnOrAfter(self):
439        '''Get the time when the session between the principal and the SAML
440        authority ends.
441       
442        @return: the time when the session between the principal and the SAML
443        authority ends
444        @rtype: datetime.datetime
445        @raise NotImplementedError: abstract method
446        '''
447        raise NotImplementedError()
448
449    def _setSessionNotOnOrAfter(self, value):
450        '''Set the time when the session between the principal and the SAML
451        authority ends.
452       
453        @param value: the time when the session between the
454        principal and the SAML authority ends
455        @type: datetime.datetime
456        @raise NotImplementedError: abstract method
457        '''
458        raise NotImplementedError()
459
460    def _getSubjectLocality(self):
461        '''Get the DNS domain and IP address of the system where the principal
462        was authenticated.
463       
464        @return: the DNS domain and IP address of the system where the principal
465        was authenticated
466        @rtype: ?
467        @raise NotImplementedError: abstract method
468        '''
469        raise NotImplementedError()
470
471    def _setSubjectLocality(self, value):
472        '''Set the DNS domain and IP address of the system where the principal
473        was authenticated.
474       
475        @param value: the DNS domain and IP address of the system where
476        the principal was authenticated
477        @type: ?
478        @raise NotImplementedError: abstract method
479        '''
480        raise NotImplementedError()
481
482    def _getAuthnContext(self):
483        '''Gets the context used to authenticate the subject.
484       
485        @return: the context used to authenticate the subject
486        @type: ?
487        @raise NotImplementedError: abstract method
488        '''
489        raise NotImplementedError()
490
491    def _setAuthnContext(self, value):
492        '''Sets the context used to authenticate the subject.
493       
494        @param value: the context used to authenticate the subject
495        @type: ?
496        @raise NotImplementedError: abstract method
497        '''
498        raise NotImplementedError()
499
500
501class DecisionType(object):
502    """Define decision types for the authorisation decisions
503       
504    @cvar PERMIT_STR: "Permit" decision type
505    @type PERMIT_STR: string
506    @cvar DENY_STR: "Deny" decision type
507    @type DENY_STR: string
508    @cvar INDETERMINATE_STR: "Indeterminate" decision type
509    @type INDETERMINATE_STR: string
510    @cvar TYPES: Permissable type strings
511    @type TYPES: string
512
513    @cvar PERMIT: permit as a decision type subclass
514    @type PERMIT: ndg.saml.saml2.core.PermitDecisionType
515    @cvar DENY: deny as a decision type subclass
516    @type DENY: ndg.saml.saml2.core.DenyDecisionType
517    @cvar INDETERMINATE: indeterminate as a decision type subclass
518    @type INDETERMINATE: ndg.saml.saml2.core.IndeterminateDecisionType
519   
520    @ivar __value: decision value
521    @type __value: string
522    """
523   
524    # "Permit" decision type
525    PERMIT_STR = "Permit"
526   
527    # "Deny" decision type
528    DENY_STR = "Deny"
529   
530    # "Indeterminate" decision type
531    INDETERMINATE_STR = "Indeterminate"
532   
533    # Permissable type strings
534    TYPES = (PERMIT_STR, DENY_STR, INDETERMINATE_STR)
535   
536    __slots__ = ('__value',)
537   
538    def __init__(self, decisionType):
539        '''@param decisionType: decision value
540        @type decisionType: string/ndg.saml.saml2.core.DecisionType
541        '''
542        self.__value = None
543        self.value = decisionType
544
545    def __getstate__(self):
546        '''Enable pickling
547       
548        @return: object's attribute dictionary
549        @rtype: dict
550        '''
551
552        _dict = {}
553        for attrName in DecisionType.__slots__:
554            # Ugly hack to allow for derived classes setting private member
555            # variables
556            if attrName.startswith('__'):
557                attrName = "_DecisionType" + attrName
558               
559            _dict[attrName] = getattr(self, attrName)
560           
561        return _dict
562 
563    def __setstate__(self, attrDict):
564        '''Enable pickling
565       
566        @param attrDict: object's attribute dictionary
567        @type attrDict: dict
568        '''
569        for attrName, val in attrDict.items():
570            setattr(self, attrName, val)
571           
572    def _setValue(self, value):
573        '''Set decision type
574        @param value: decision value
575        @type value: string/ndg.saml.saml2.core.DecisionType
576        '''
577        if isinstance(value, DecisionType):
578            # Cast to string
579            value = str(value)
580           
581        elif not isinstance(value, basestring):
582            raise TypeError('Expecting string or DecisionType instance for '
583                            '"value" attribute; got %r instead' % type(value))
584           
585        if value not in self.__class__.TYPES:
586            raise AttributeError('Permissable decision types are %r; got '
587                                 '%r instead' % (DecisionType.TYPES, value))
588        self.__value = value
589       
590    def _getValue(self):
591        '''Get decision type
592        @return: decision value
593        @rtype: string/ndg.saml.saml2.core.DecisionType
594        '''
595        return self.__value
596   
597    value = property(fget=_getValue, fset=_setValue, doc="Decision value")
598   
599    def __str__(self):
600        '''Representation of decision type as a string
601        @return: decision value
602        @rtype: string
603        '''
604        return self.__value
605
606    def __eq__(self, decision):
607        """Test for equality against an input decision type
608       
609        @param version: decision type
610        @type version: ndg.saml.saml2.core.DecisionType or basestring
611        @return: True if input and this object match
612        @rtype: bool
613        @raise TypeError: unexpected type for decision type input
614        """
615        if isinstance(decision, DecisionType):
616            # Cast to string
617            value = decision.value
618           
619        elif isinstance(decision, basestring):
620            value = decision
621           
622        else:
623            raise TypeError('Expecting string or DecisionType instance for '
624                            'input decision value; got %r instead' % 
625                            type(value))
626           
627        if value not in self.__class__.TYPES:
628            raise AttributeError('Permissable decision types are %r; got '
629                                 '%r instead' % (DecisionType.TYPES, value))
630           
631        return self.__value == value
632
633
634class PermitDecisionType(DecisionType):
635    """Permit authorisation Decision"""
636    __slots__ = ()
637
638    def __init__(self):
639        """Initialise with permit decision setting"""
640        super(PermitDecisionType, self).__init__(DecisionType.PERMIT_STR)
641       
642    def _setValue(self):
643        """
644        @raise AttributeError: instances have read only decision type
645        """ 
646        raise AttributeError("can't set attribute")
647
648
649class DenyDecisionType(DecisionType):
650    """Deny authorisation Decision"""
651    __slots__ = ()
652   
653    def __init__(self):
654        """Initialise with deny decision setting"""
655        super(DenyDecisionType, self).__init__(DecisionType.DENY_STR)
656       
657    def _setValue(self, value): 
658        """
659        @raise AttributeError: instances have read only decision type
660        """ 
661        raise AttributeError("can't set attribute")
662
663
664class IndeterminateDecisionType(DecisionType):
665    """Indeterminate authorisation Decision"""
666    __slots__ = ()
667   
668    def __init__(self):
669        """Initialise with indeterminate decision setting"""
670        super(IndeterminateDecisionType, self).__init__(
671                                            DecisionType.INDETERMINATE_STR)
672       
673    def _setValue(self, value): 
674        """
675        @raise AttributeError: instances have read only decision type
676        """ 
677        raise AttributeError("can't set attribute")
678
679# Add instances of each for convenience
680DecisionType.PERMIT = PermitDecisionType()
681DecisionType.DENY = DenyDecisionType()
682DecisionType.INDETERMINATE = IndeterminateDecisionType()
683
684
685class AuthzDecisionStatement(Statement):
686    '''SAML 2.0 Core AuthzDecisionStatement.  Currently implemented in abstract
687    form only'''
688   
689    # Element local name
690    DEFAULT_ELEMENT_LOCAL_NAME = "AuthzDecisionStatement"
691
692    # Default element name
693    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
694                                 DEFAULT_ELEMENT_LOCAL_NAME,
695                                 SAMLConstants.SAML20_PREFIX)
696
697    # Local name of the XSI type
698    TYPE_LOCAL_NAME = "AuthzDecisionStatementType"
699
700    # QName of the XSI type
701    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
702                      TYPE_LOCAL_NAME,
703                      SAMLConstants.SAML20_PREFIX)
704
705    # Resource attribute name
706    RESOURCE_ATTRIB_NAME = "Resource"
707
708    # Decision attribute name
709    DECISION_ATTRIB_NAME = "Decision"
710   
711    __slots__ = (
712        '__resource', 
713        '__decision', 
714        '__actions', 
715        '__evidence',
716        '__normalizeResource',
717        '__safeNormalizationChars')
718   
719    def __init__(self, 
720                 normalizeResource=True, 
721                 safeNormalizationChars='/%',
722                 **kw):
723        '''Create new authorisation decision statement
724        '''
725        super(AuthzDecisionStatement, self).__init__(**kw)
726
727        # Resource attribute value.
728        self.__resource = None 
729       
730        self.__decision = DecisionType.INDETERMINATE   
731        self.__actions = TypedList(Action)
732        self.__evidence = None
733       
734        # Tuning for normalization of resource URIs in property set method
735        self.normalizeResource = normalizeResource
736        self.safeNormalizationChars = safeNormalizationChars
737
738    def __getstate__(self):
739        '''Enable pickling
740       
741        @return: object's attribute dictionary
742        @rtype: dict
743        '''
744
745        _dict = super(AuthzDecisionStatement, self).__getstate__()
746        for attrName in AuthzDecisionStatement.__slots__:
747            # Ugly hack to allow for derived classes setting private member
748            # variables
749            if attrName.startswith('__'):
750                attrName = "_AuthzDecisionStatement" + attrName
751               
752            _dict[attrName] = getattr(self, attrName)
753           
754        return _dict
755   
756    def _getNormalizeResource(self):
757        return self.__normalizeResource
758
759    def _setNormalizeResource(self, value):
760        if not isinstance(value, bool):
761            raise TypeError('Expecting bool type for "normalizeResource" '
762                            'attribute; got %r instead' % type(value))
763           
764        self.__normalizeResource = value
765
766    normalizeResource = property(_getNormalizeResource, 
767                                 _setNormalizeResource, 
768                                 doc="Flag to normalize new resource value "
769                                     "assigned to the \"resource\" property.  "
770                                     "The setting only applies for URIs "
771                                     'beginning with "http://" or "https://"')
772
773    def _getSafeNormalizationChars(self):
774        return self.__safeNormalizationChars
775
776    def _setSafeNormalizationChars(self, value):
777        if not isinstance(value, basestring):
778            raise TypeError('Expecting string type for "normalizeResource" '
779                            'attribute; got %r instead' % type(value))
780           
781        self.__safeNormalizationChars = value
782
783    safeNormalizationChars = property(_getSafeNormalizationChars, 
784                                      _setSafeNormalizationChars, 
785                                      doc="String containing a list of "
786                                          "characters that should not be "
787                                          "converted when Normalizing the "
788                                          "resource URI.  These are passed to "
789                                          "urllib.quote when the resource "
790                                          "property is set.  The default "
791                                          "characters are '/%'")
792
793    def _getResource(self):
794        '''Gets the Resource attrib value of this query.
795
796        @return: the Resource attrib value of this query'''
797        return self.__resource
798   
799    def _setResource(self, value):
800        '''Sets the Resource attrib value of this query normalizing the path
801        component, removing spurious port numbers (80 for HTTP and 443 for
802        HTTPS) and converting the host component to lower case.
803       
804        @param value: the new Resource attrib value of this query'''
805        if not isinstance(value, basestring):
806            raise TypeError('Expecting string type for "resource" attribute; '
807                            'got %r instead' % type(value))
808       
809        if (self.normalizeResource and 
810            value.startswith('http://') or value.startswith('https://')):
811            # Normalise the path, set the host name to lower case and remove
812            # port redundant numbers 80 and 443
813            splitResult = urlsplit(value)
814            uriComponents = list(splitResult)
815           
816            # hostname attribute is lowercase
817            uriComponents[1] = splitResult.hostname
818           
819            if splitResult.port is not None:
820                isHttpWithStdPort = (splitResult.port == 80 and 
821                                     splitResult.scheme == 'http')
822               
823                isHttpsWithStdPort = (splitResult.port == 443 and
824                                      splitResult.scheme == 'https')
825               
826                if not isHttpWithStdPort and not isHttpsWithStdPort:
827                    uriComponents[1] += ":%d" % splitResult.port
828           
829            uriComponents[2] = urllib.quote(splitResult.path, 
830                                            self.safeNormalizationChars)
831           
832            self.__resource = urlunsplit(uriComponents)
833        else:
834            self.__resource = value
835   
836    resource = property(fget=_getResource, fset=_setResource,
837                        doc="Resource for which authorisation was requested")
838
839    def _getDecision(self):
840        '''
841        Gets the decision of the authorization request.
842       
843        @return: the decision of the authorization request
844        '''
845        return self.__decision
846
847    def _setDecision(self, value):
848        '''
849        Sets the decision of the authorization request.
850       
851        @param value: the decision of the authorization request
852        '''
853        if not isinstance(value, DecisionType):
854            raise TypeError('Expecting %r type for "decision" attribute; '
855                            'got %r instead' % (DecisionType, type(value)))
856        self.__decision = value
857
858    decision = property(_getDecision, _setDecision, 
859                        doc="Authorization decision as a DecisionType instance")
860   
861    @property
862    def actions(self):
863        '''The actions for which authorisation is requested
864       
865        @return: the Actions of this statement'''
866        return self.__actions
867   
868    def _getEvidence(self):
869        '''Gets the Evidence of this statement.
870
871        @return: the Evidence of this statement'''
872        return self.__evidence
873
874    def _setEvidence(self, value):
875        '''Sets the Evidence of this query.
876        @param newEvidence: the new Evidence of this statement''' 
877        if not isinstance(value, Evidence):
878            raise TypeError('Expecting Evidence type for "evidence" '
879                            'attribute; got %r' % type(value))
880
881        self.__evidence = value 
882
883    evidence = property(fget=_getEvidence, fset=_setEvidence, 
884                        doc="A set of assertions which the Authority may use "
885                            "to base its authorisation decision on")
886   
887    def getOrderedChildren(self):
888        children = []
889
890        superChildren = super(AuthzDecisionStatement, self).getOrderedChildren()
891        if superChildren:
892            children.extend(superChildren)
893
894        children.extend(self.__actions)
895       
896        if self.__evidence is not None:
897            children.extend(self.__evidence)
898
899        if len(children) == 0:
900            return None
901
902        return tuple(children)
903       
904
905class Subject(SAMLObject):
906    '''Concrete implementation of @link org.opensaml.saml2.core.Subject.'''
907   
908    # Element local name.
909    DEFAULT_ELEMENT_LOCAL_NAME = "Subject"
910
911    # Default element name.
912    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
913                                 DEFAULT_ELEMENT_LOCAL_NAME,
914                                 SAMLConstants.SAML20_PREFIX)
915
916    # Local name of the XSI type.
917    TYPE_LOCAL_NAME = "SubjectType"
918
919    # QName of the XSI type.
920    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
921                      TYPE_LOCAL_NAME,
922                      SAMLConstants.SAML20_PREFIX)
923    __slots__ = (
924        '__baseID',
925        '__nameID',
926        '__encryptedID',
927        '__subjectConfirmations'
928    )
929   
930    def __init__(self, **kw):
931        super(Subject, self).__init__(**kw)
932       
933        # BaseID child element.
934        self.__baseID = None
935   
936        # NameID child element.
937        self.__nameID = None
938   
939        # EncryptedID child element.
940        self.__encryptedID = None
941   
942        # Subject Confirmations of the Subject.
943        self.__subjectConfirmations = []
944
945    def __getstate__(self):
946        '''Enable pickling
947       
948        @return: object's attribute dictionary
949        @rtype: dict
950        '''
951
952        _dict = super(Subject, self).__getstate__()
953        for attrName in Subject.__slots__:
954            # Ugly hack to allow for derived classes setting private member
955            # variables
956            if attrName.startswith('__'):
957                attrName = "_Subject" + attrName
958               
959            _dict[attrName] = getattr(self, attrName)
960           
961        return _dict
962   
963    def _getBaseID(self): 
964        return self.__baseID
965
966    def _setBaseID(self, value):
967        if not isinstance(value, basestring):
968            raise TypeError("Expecting %r type for \"baseID\" got %r" %
969                            (basestring, value.__class__))
970        self.__baseID = value
971
972    baseID = property(fget=_getBaseID, 
973                      fset=_setBaseID, 
974                      doc="Base identifier")
975     
976    def _getNameID(self):
977        return self.__nameID
978   
979    def _setNameID(self, value):
980        if not isinstance(value, NameID):
981            raise TypeError("Expecting %r type for \"nameID\" got %r" %
982                            (NameID, type(value)))
983        self.__nameID = value
984
985    nameID = property(fget=_getNameID, 
986                      fset=_setNameID, 
987                      doc="Name identifier")
988   
989    def _getEncryptedID(self):
990        return self.__encryptedID
991   
992    def _setEncryptedID(self, value): 
993        self.__encryptedID = value
994
995    encryptedID = property(fget=_getEncryptedID, 
996                           fset=_setEncryptedID, 
997                           doc="EncryptedID's Docstring")
998   
999    def _getSubjectConfirmations(self): 
1000        return self.__subjectConfirmations
1001
1002    subjectConfirmations = property(fget=_getSubjectConfirmations, 
1003                                    doc="Subject Confirmations")   
1004   
1005    def getOrderedChildren(self): 
1006        children = []
1007
1008        if self.baseID is not None:
1009            children.append(self.baseID)
1010       
1011        if self.nameID is not None: 
1012            children.append(self.nameID)
1013       
1014        if self.encryptedID is not None: 
1015            children.append(self.encryptedID)
1016       
1017        children += self.subjectConfirmations
1018
1019        return tuple(children)
1020
1021
1022class AbstractNameIDType(SAMLObject):
1023    '''Abstract implementation of NameIDType'''
1024
1025    # SPNameQualifier attribute name.
1026    SP_NAME_QUALIFIER_ATTRIB_NAME = "SPNameQualifier"
1027
1028    # Format attribute name.
1029    FORMAT_ATTRIB_NAME = "Format"
1030
1031    # SPProviderID attribute name.
1032    SPPROVIDED_ID_ATTRIB_NAME = "SPProvidedID"
1033
1034    # URI for unspecified name format.
1035    UNSPECIFIED = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
1036
1037    # URI for email name format.
1038    EMAIL = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
1039
1040    # URI for X509 subject name format.
1041    X509_SUBJECT = "urn:oasis:names:tc:SAML:1.1:nameid-format:x509SubjectName"
1042
1043    # URI for windows domain qualified name name format.
1044    WIN_DOMAIN_QUALIFIED = \
1045        "urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName"
1046
1047    # URI for kerberos name format.
1048    KERBEROS = "urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos"
1049
1050    # URI for SAML entity name format.
1051    ENTITY = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
1052
1053    # URI for persistent name format.
1054    PERSISTENT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
1055
1056    # URI for transient name format.
1057    TRANSIENT = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
1058
1059    # Special URI used by NameIDPolicy to indicate a NameID should be encrypted
1060    ENCRYPTED = "urn:oasis:names:tc:SAML:2.0:nameid-format:encrypted"
1061   
1062    __slots__ = (
1063        '__name',
1064        '__nameQualifier',
1065        '__spNameQualifier',
1066        '__format',
1067        '__spProvidedID',
1068        '__value'
1069    )
1070   
1071    def __init__(self, **kw): 
1072        '''@param namespaceURI: the namespace the element is in
1073        @param elementLocalName: the local name of the XML element this Object
1074        represents
1075        @param namespacePrefix: the prefix for the given namespace
1076        '''
1077        super(AbstractNameIDType, self).__init__(**kw)
1078   
1079        # Name of the Name ID.
1080        self.__name = None
1081       
1082        # Name Qualifier of the Name ID.
1083        self.__nameQualifier = None
1084   
1085        # SP Name Qualifier of the Name ID.
1086        self.__spNameQualifier = None
1087   
1088        # Format of the Name ID.
1089        self.__format = None
1090   
1091        # SP ProvidedID of the NameID.
1092        self.__spProvidedID = None
1093
1094        self.__value = None
1095
1096    def __getstate__(self):
1097        '''Enable pickling
1098       
1099        @return: object's attribute dictionary
1100        @rtype: dict
1101        '''
1102
1103        _dict = super(AbstractNameIDType, self).__getstate__()
1104        for attrName in AbstractNameIDType.__slots__:
1105            # Ugly hack to allow for derived classes setting private member
1106            # variables
1107            if attrName.startswith('__'):
1108                attrName = "_AbstractNameIDType" + attrName
1109               
1110            _dict[attrName] = getattr(self, attrName)
1111           
1112        return _dict
1113             
1114    def _getValue(self):
1115        return self.__value
1116       
1117    def _setValue(self, value):
1118        if not isinstance(value, basestring):
1119            raise TypeError("\"value\" must be a basestring derived type, "
1120                            "got %r" % value.__class__)
1121           
1122        self.__value = value
1123
1124    value = property(fget=_getValue, fset=_setValue, doc="string value") 
1125   
1126    def _getNameQualifier(self): 
1127        return self.__nameQualifier
1128   
1129    def _setNameQualifier(self, value): 
1130        self.__nameQualifier = value
1131
1132    nameQualifier = property(fget=_getNameQualifier, 
1133                             fset=_setNameQualifier, 
1134                             doc="Name qualifier")   
1135
1136    def _getSPNameQualifier(self): 
1137        return self.__spNameQualifier
1138   
1139    def _setSPNameQualifier(self, value): 
1140        self.__spNameQualifier = value
1141
1142    spNameQualifier = property(fget=_getSPNameQualifier, 
1143                               fset=_setSPNameQualifier, 
1144                               doc="SP Name qualifier")   
1145   
1146    def _getFormat(self):
1147        return self.__format
1148       
1149    def _setFormat(self, format):
1150        if not isinstance(format, basestring):
1151            raise TypeError("\"format\" must be a basestring derived type, "
1152                            "got %r" % format.__class__)
1153           
1154        self.__format = format
1155
1156    format = property(fget=_getFormat, fset=_setFormat, doc="Name format") 
1157   
1158    def _getSPProvidedID(self): 
1159        return self.__spProvidedID
1160   
1161    def _setSPProvidedID(self, value): 
1162        self.__spProvidedID = value
1163
1164    spProvidedID = property(fget=_getSPProvidedID, fset=_setSPProvidedID, 
1165                            doc="SP Provided Identifier") 
1166   
1167    def getOrderedChildren(self): 
1168        raise NotImplementedError()
1169
1170   
1171class Issuer(AbstractNameIDType):
1172    """SAML 2.0 Core Issuer type"""
1173   
1174    # Element local name.
1175    DEFAULT_ELEMENT_LOCAL_NAME = "Issuer"
1176
1177    # Default element name.
1178    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1179                                 DEFAULT_ELEMENT_LOCAL_NAME,
1180                                 SAMLConstants.SAML20_PREFIX)
1181
1182    # Local name of the XSI type.
1183    TYPE_LOCAL_NAME = "IssuerType"
1184
1185    # QName of the XSI type.
1186    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
1187                      TYPE_LOCAL_NAME,
1188                      SAMLConstants.SAML20_PREFIX) 
1189   
1190    __slots__ = ()
1191
1192     
1193class NameID(AbstractNameIDType):
1194    '''SAML 2.0 Core NameID'''
1195    # Element local name.
1196    DEFAULT_ELEMENT_LOCAL_NAME = "NameID"
1197
1198    # Default element name.
1199    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1200                                 DEFAULT_ELEMENT_LOCAL_NAME,
1201                                 SAMLConstants.SAML20_PREFIX)
1202
1203    # Local name of the XSI type.
1204    TYPE_LOCAL_NAME = "NameIDType"
1205
1206    # QName of the XSI type.
1207    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
1208                      TYPE_LOCAL_NAME,
1209                      SAMLConstants.SAML20_PREFIX)
1210   
1211    __slots__ = ()
1212   
1213
1214class Conditions(SAMLObject): 
1215    '''SAML 2.0 Core Conditions.'''
1216   
1217    # Element local name.
1218    DEFAULT_ELEMENT_LOCAL_NAME = "Conditions"
1219
1220    # Default element name.
1221    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1222                                 DEFAULT_ELEMENT_LOCAL_NAME,
1223                                 SAMLConstants.SAML20_PREFIX)
1224
1225    # Local name of the XSI type.
1226    TYPE_LOCAL_NAME = "ConditionsType"
1227
1228    # QName of the XSI type.
1229    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
1230                      TYPE_LOCAL_NAME,
1231                      SAMLConstants.SAML20_PREFIX)
1232
1233    # NotBefore attribute name.
1234    NOT_BEFORE_ATTRIB_NAME = "NotBefore"
1235
1236    # NotOnOrAfter attribute name.
1237    NOT_ON_OR_AFTER_ATTRIB_NAME = "NotOnOrAfter"
1238
1239    __slots__ = (
1240        '__conditions',
1241        '__notBefore',
1242        '__notOnOrAfter'
1243    )
1244   
1245    def __init__(self, **kw):
1246        super(Conditions, self).__init__(**kw)
1247       
1248        # A Condition.
1249        self.__conditions = []
1250   
1251        # Not Before conditions.
1252        self.__notBefore = None
1253   
1254        # Not On Or After conditions.
1255        self.__notOnOrAfter = None
1256
1257    def __getstate__(self):
1258        '''Enable pickling
1259       
1260        @return: object's attribute dictionary
1261        @rtype: dict
1262        '''
1263
1264        _dict = super(Conditions, self).__getstate__()
1265        for attrName in Conditions.__slots__:
1266            # Ugly hack to allow for derived classes setting private member
1267            # variables
1268            if attrName.startswith('__'):
1269                attrName = "_Conditions" + attrName
1270               
1271            _dict[attrName] = getattr(self, attrName)
1272           
1273        return _dict
1274   
1275    def _getNotBefore(self):
1276        '''Get the date/time before which the assertion is invalid.
1277       
1278        @return: the date/time before which the assertion is invalid'''
1279        return self.__notBefore
1280   
1281    def _setNotBefore(self, value):
1282        '''Sets the date/time before which the assertion is invalid.
1283       
1284        @param value: the date/time before which the assertion is invalid
1285        '''
1286        if not isinstance(value, datetime):
1287            raise TypeError('Expecting "datetime" type for "notBefore", '
1288                            'got %r' % type(value))
1289        self.__notBefore = value
1290
1291    def _getNotOnOrAfter(self):
1292        '''Gets the date/time on, or after, which the assertion is invalid.
1293       
1294        @return: the date/time on, or after, which the assertion is invalid'
1295        '''
1296        return self.__notOnOrAfter
1297   
1298    def _setNotOnOrAfter(self, value):
1299        '''Sets the date/time on, or after, which the assertion is invalid.
1300       
1301        @param value: the date/time on, or after, which the assertion
1302        is invalid
1303        '''
1304        if not isinstance(value, datetime):
1305            raise TypeError('Expecting "datetime" type for "notOnOrAfter", '
1306                            'got %r' % type(value))
1307        self.__notOnOrAfter = value 
1308
1309    notBefore = property(_getNotBefore, _setNotBefore, 
1310                         doc="Not before time restriction")
1311
1312    notOnOrAfter = property(_getNotOnOrAfter, _setNotOnOrAfter, 
1313                            doc="Not on or after time restriction")
1314
1315    @property
1316    def conditions(self):
1317        '''All the conditions on the assertion.
1318       
1319        @return: all the conditions on the assertion
1320        '''
1321        return self.__conditions
1322   
1323    def _getAudienceRestrictions(self):
1324        '''Gets the audience restriction conditions for the assertion.
1325       
1326        @return: the audience restriction conditions for the assertion
1327        '''
1328        raise NotImplementedError()
1329
1330    def _getOneTimeUse(self):
1331        '''Gets the OneTimeUse condition for the assertion.
1332       
1333        @return: the OneTimeUse condition for the assertion
1334        '''
1335        raise NotImplementedError()
1336
1337    def _getProxyRestriction(self):   
1338        '''Gets the ProxyRestriction condition for the assertion.
1339       
1340        @return: the ProxyRestriction condition for the assertion
1341        '''
1342        raise NotImplementedError()
1343   
1344   
1345class Advice(SAMLObject):
1346    '''SAML 2.0 Core Advice.
1347    '''
1348
1349    # Element local name
1350    DEFAULT_ELEMENT_LOCAL_NAME = "Advice"
1351
1352    # Default element name.
1353    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1354                                 DEFAULT_ELEMENT_LOCAL_NAME,
1355                                 SAMLConstants.SAML20_PREFIX)
1356
1357    # Local name of the XSI type
1358    TYPE_LOCAL_NAME = "AdviceType"
1359
1360    # QName of the XSI type
1361    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
1362                      TYPE_LOCAL_NAME,
1363                      SAMLConstants.SAML20_PREFIX)
1364
1365    __slots__ = ()
1366   
1367    def _getChildren(self, typeOrName=None):
1368        '''
1369        Gets the list of all child elements attached to this advice.
1370       
1371        @return: the list of all child elements attached to this advice
1372        '''
1373        raise NotImplementedError()
1374
1375    def _getAssertionIDReferences(self):
1376        '''Gets the list of AssertionID references used as advice.
1377       
1378        @return: the list of AssertionID references used as advice
1379        '''
1380        raise NotImplementedError()
1381
1382    def _getAssertionURIReferences(self):
1383        '''Gets the list of AssertionURI references used as advice.
1384       
1385        @return: the list of AssertionURI references used as advice
1386        '''
1387        raise NotImplementedError()
1388   
1389    def _getAssertions(self):
1390        '''Gets the list of Assertions used as advice.
1391       
1392        @return: the list of Assertions used as advice
1393        '''
1394        raise NotImplementedError()
1395   
1396    def _getEncryptedAssertions(self):
1397        '''Gets the list of EncryptedAssertions used as advice.
1398       
1399        @return: the list of EncryptedAssertions used as advice
1400        '''
1401        raise NotImplementedError()
1402       
1403
1404class Assertion(SAMLObject):
1405    """SAML 2.0 Attribute Assertion for use with NERC DataGrid   
1406    """   
1407    # Element local name.
1408    DEFAULT_ELEMENT_LOCAL_NAME = "Assertion"
1409
1410    # Default element name.
1411    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1412                                 DEFAULT_ELEMENT_LOCAL_NAME,
1413                                 SAMLConstants.SAML20_PREFIX)
1414
1415    # Local name of the XSI type.
1416    TYPE_LOCAL_NAME = "AssertionType"
1417
1418    # QName of the XSI type.
1419    TYPE_NAME = QName(SAMLConstants.SAML20_NS, TYPE_LOCAL_NAME,
1420                      SAMLConstants.SAML20_PREFIX)
1421
1422    # Version attribute name.
1423    VERSION_ATTRIB_NAME = "Version"
1424
1425    # IssueInstant attribute name.
1426    ISSUE_INSTANT_ATTRIB_NAME = "IssueInstant"
1427
1428    # ID attribute name.
1429    ID_ATTRIB_NAME = "ID"
1430
1431    __slots__ = (
1432        '__version',
1433        '__issueInstant',
1434        '__id',
1435        '__issuer',
1436        '__subject',
1437        '__conditions',
1438        '__advice',
1439        '__statements',
1440        '__authnStatements',
1441        '__authzDecisionStatements',
1442        '__attributeStatements'
1443    )
1444   
1445    def __init__(self):
1446        # Base class initialisation
1447        super(Assertion, self).__init__()
1448       
1449        self.__version = None
1450        self.__issueInstant = None
1451        self.__id = None
1452        self.__issuer = None
1453        self.__subject = None
1454       
1455        self.__conditions = None
1456        self.__advice = None
1457        self.__statements = TypedList(Statement)
1458       
1459        # TODO: Implement AuthnStatement and AuthzDecisionStatement classes
1460        self.__authnStatements = []
1461        self.__authzDecisionStatements = TypedList(AuthzDecisionStatement)
1462        self.__attributeStatements = TypedList(AttributeStatement)
1463
1464    def __getstate__(self):
1465        '''Enable pickling
1466       
1467        @return: object's attribute dictionary
1468        @rtype: dict
1469        '''
1470
1471        _dict = super(Assertion, self).__getstate__()
1472        for attrName in Assertion.__slots__:
1473            # Ugly hack to allow for derived classes setting private member
1474            # variables
1475            if attrName.startswith('__'):
1476                attrName = "_Assertion" + attrName
1477               
1478            _dict[attrName] = getattr(self, attrName)
1479           
1480        return _dict   
1481                 
1482    def _get_version(self):
1483        '''@return: the SAML Version of this assertion.
1484        '''
1485        return self.__version
1486   
1487    def _set_version(self, version):
1488        '''@param version: the SAML Version of this assertion
1489        '''
1490        if not isinstance(version, SAMLVersion):
1491            raise TypeError("Expecting SAMLVersion type got: %r" % 
1492                            version.__class__)
1493       
1494        self.__version = version
1495       
1496    version = property(fget=_get_version,
1497                       fset=_set_version,
1498                       doc="SAML Version of the assertion")
1499
1500    def _get_issueInstant(self):
1501        '''Gets the issue instance of this assertion.
1502       
1503        @return: the issue instance of this assertion'''
1504        return self.__issueInstant
1505   
1506    def _set_issueInstant(self, issueInstant):
1507        '''Sets the issue instance of this assertion.
1508       
1509        @param issueInstant: the issue instance of this assertion
1510        '''
1511        if not isinstance(issueInstant, datetime):
1512            raise TypeError('Expecting "datetime" type for "issueInstant", '
1513                            'got %r' % issueInstant.__class__)
1514           
1515        self.__issueInstant = issueInstant
1516       
1517    issueInstant = property(fget=_get_issueInstant, 
1518                            fset=_set_issueInstant,
1519                            doc="Issue instant of the assertion")
1520
1521    def _get_id(self):
1522        '''Sets the ID of this assertion.
1523       
1524        @return: the ID of this assertion
1525        '''
1526        return self.__id
1527   
1528    def _set_id(self, _id):
1529        '''Sets the ID of this assertion.
1530       
1531        @param _id: the ID of this assertion
1532        '''
1533        if not isinstance(_id, basestring):
1534            raise TypeError('Expecting basestring derived type for "id", got '
1535                            '%r' % _id.__class__)
1536        self.__id = _id
1537       
1538    id = property(fget=_get_id, fset=_set_id, doc="ID of assertion")
1539   
1540    def _set_issuer(self, issuer):
1541        """Set issuer"""
1542        if not isinstance(issuer, Issuer):
1543            raise TypeError("issuer must be %r, got %r" % (Issuer, 
1544                                                           type(issuer)))
1545        self.__issuer = issuer
1546   
1547    def _get_issuer(self):
1548        """Get the issuer name """
1549        return self.__issuer
1550
1551    issuer = property(fget=_get_issuer, 
1552                      fset=_set_issuer,
1553                      doc="Issuer of assertion")
1554   
1555    def _set_subject(self, subject):
1556        """Set subject string."""
1557        if not isinstance(subject, Subject):
1558            raise TypeError("subject must be %r, got %r" % (Subject, 
1559                                                            type(subject)))
1560
1561        self.__subject = subject
1562   
1563    def _get_subject(self):
1564        """Get subject string."""
1565        return self.__subject
1566
1567    subject = property(fget=_get_subject,
1568                       fset=_set_subject, 
1569                       doc="Attribute Assertion subject")
1570   
1571    def _get_conditions(self):
1572        """Get conditions string."""
1573        return self.__conditions
1574   
1575    def _set_conditions(self, value):
1576        """Get conditions string."""
1577        if not isinstance(value, Conditions):
1578            raise TypeError("Conditions must be %r, got %r" % (Conditions, 
1579                                                               type(value)))
1580
1581        self.__conditions = value
1582
1583    conditions = property(fget=_get_conditions,
1584                          fset=_set_conditions,
1585                          doc="Attribute Assertion conditions")
1586   
1587    def _set_advice(self, advice):
1588        """Set advice string."""
1589        if not isinstance(advice, basestring):
1590            raise TypeError("advice must be a string")
1591
1592        self.__advice = advice
1593   
1594    def _get_advice(self):
1595        """Get advice string."""
1596        return self.__advice
1597
1598    advice = property(fget=_get_advice,
1599                      fset=_set_advice, 
1600                      doc="Attribute Assertion advice")
1601   
1602    @property
1603    def statements(self):
1604        """Attribute Assertion statements"""
1605        return self.__statements
1606   
1607    @property
1608    def authnStatements(self):
1609        """Attribute Assertion authentication"""
1610        return self.__authnStatements
1611   
1612    @property
1613    def authzDecisionStatements(self):
1614        """Attribute Assertion authorisation decision statements"""
1615        return self.__authzDecisionStatements
1616   
1617    @property
1618    def attributeStatements(self):
1619        """Attribute Assertion attribute statements"""
1620        return self.__attributeStatements
1621   
1622
1623class AttributeValue(SAMLObject):
1624    """Base class for Attribute Value type"""
1625   
1626    # Element name, no namespace
1627    DEFAULT_ELEMENT_LOCAL_NAME = "AttributeValue"
1628
1629    # Default element name
1630    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1631                                 DEFAULT_ELEMENT_LOCAL_NAME,
1632                                 SAMLConstants.SAML20_PREFIX)
1633    __slots__ = ()
1634
1635
1636class XSStringAttributeValue(AttributeValue):
1637    """XML XS:String Attribute Value type"""
1638   
1639    # Local name of the XSI type
1640    TYPE_LOCAL_NAME = "string"
1641       
1642    # QName of the XSI type
1643    TYPE_NAME = QName(SAMLConstants.XSD_NS, 
1644                      TYPE_LOCAL_NAME, 
1645                      SAMLConstants.XSD_PREFIX)
1646   
1647    DEFAULT_FORMAT = "%s#%s" % (SAMLConstants.XSD_NS, TYPE_LOCAL_NAME)
1648 
1649    __slots__ = ('__value',)
1650   
1651    def __init__(self, **kw):
1652        super(XSStringAttributeValue, self).__init__(**kw)
1653        self.__value = None
1654
1655    def __getstate__(self):
1656        '''Enable pickling
1657       
1658        @return: object's attribute dictionary
1659        @rtype: dict
1660        '''
1661
1662        _dict = super(XSStringAttributeValue, self).__getstate__()
1663        for attrName in XSStringAttributeValue.__slots__:
1664            # Ugly hack to allow for derived classes setting private member
1665            # variables
1666            if attrName.startswith('__'):
1667                attrName = "_XSStringAttributeValue" + attrName
1668               
1669            _dict[attrName] = getattr(self, attrName)
1670           
1671        return _dict
1672           
1673    def _getValue(self):
1674        return self.__value
1675       
1676    def _setValue(self, value):
1677        if not isinstance(value, basestring):
1678            raise TypeError("Input must be a basestring derived type, got %r" %
1679                            value.__class__)
1680           
1681        self.__value = value
1682
1683    value = property(fget=_getValue, fset=_setValue, doc="string value") 
1684
1685
1686class StatusDetail(SAMLObject):
1687    '''Implementation of SAML 2.0 StatusDetail'''
1688   
1689    # Local Name of StatusDetail.
1690    DEFAULT_ELEMENT_LOCAL_NAME = "StatusDetail"
1691
1692    # Default element name.
1693    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
1694                                 DEFAULT_ELEMENT_LOCAL_NAME,
1695                                 SAMLConstants.SAML20P_PREFIX)
1696
1697    # Local name of the XSI type.
1698    TYPE_LOCAL_NAME = "StatusDetailType"
1699
1700    # QName of the XSI type.
1701    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
1702                      TYPE_LOCAL_NAME,
1703                      SAMLConstants.SAML20P_PREFIX)
1704   
1705    __slots__ = ('__unknownChildren', )
1706   
1707    def __init__(self, **kw):
1708        super(StatusDetail, self).__init__(**kw)
1709       
1710        # child "any" elements.
1711        self.__unknownChildren = TypedList(SAMLObject)         
1712
1713    def __getstate__(self):
1714        '''Enable pickling
1715       
1716        @return: object's attribute dictionary
1717        @rtype: dict
1718        '''
1719
1720        _dict = super(StatusDetail, self).__getstate__()
1721        for attrName in StatusDetail.__slots__:
1722            # Ugly hack to allow for derived classes setting private member
1723            # variables
1724            if attrName.startswith('__'):
1725                attrName = "_StatusDetail" + attrName
1726               
1727            _dict[attrName] = getattr(self, attrName)
1728           
1729        return _dict
1730   
1731    def getUnknownXMLTypes(self, qname=None): 
1732        if qname is not None:
1733            if not isinstance(qname, QName):
1734                raise TypeError("\"qname\" must be a %r derived type, "
1735                                "got %r" % (QName, type(qname)))
1736               
1737            children = []
1738            for child in self.__unknownChildren:
1739                childQName = getattr(child, "qname", None)
1740                if childQName is not None:
1741                    if childQName.namespaceURI == qname.namespaceURI or \
1742                       childQName.localPart == qname.localPart:
1743                        children.append(child)
1744                       
1745            return children
1746        else:
1747            return self.__unknownChildren
1748   
1749    unknownChildren = property(fget=getUnknownXMLTypes,
1750                               doc="Child objects of Status Detail - may be "
1751                                   "any type")
1752   
1753
1754class StatusMessage(SAMLObject):
1755    '''Implementation of SAML 2.0 Status Message'''
1756
1757    DEFAULT_ELEMENT_LOCAL_NAME = "StatusMessage"
1758    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
1759                                 DEFAULT_ELEMENT_LOCAL_NAME,
1760                                 SAMLConstants.SAML20P_PREFIX)
1761   
1762    __slots__ = ('__value', )
1763   
1764    def __init__(self, **kw):
1765        super(StatusMessage, self).__init__(**kw)
1766       
1767        # Value attribute URI.
1768        self.__value = None       
1769
1770    def __getstate__(self):
1771        '''Enable pickling
1772       
1773        @return: object's attribute dictionary
1774        @rtype: dict
1775        '''
1776
1777        _dict = super(StatusMessage, self).__getstate__()
1778        for attrName in StatusMessage.__slots__:
1779            # Ugly hack to allow for derived classes setting private member
1780            # variables
1781            if attrName.startswith('__'):
1782                attrName = "_StatusMessage" + attrName
1783               
1784            _dict[attrName] = getattr(self, attrName)
1785           
1786        return _dict
1787   
1788    def _getValue(self):
1789        return self.__value
1790       
1791    def _setValue(self, value):
1792        if not isinstance(value, basestring):
1793            raise TypeError("\"value\" must be a basestring derived type, "
1794                            "got %r" % type(value))
1795           
1796        self.__value = value
1797
1798    value = property(fget=_getValue, fset=_setValue, doc="Status message value")
1799
1800
1801class StatusCode(SAMLObject):
1802    '''Implementation of SAML 2.0 StatusCode.'''
1803   
1804    # Local Name of StatusCode.
1805    DEFAULT_ELEMENT_LOCAL_NAME = "StatusCode"
1806
1807    # Default element name.
1808    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
1809                                 DEFAULT_ELEMENT_LOCAL_NAME,
1810                                 SAMLConstants.SAML20P_PREFIX)
1811
1812    # Local name of the XSI type.
1813    TYPE_LOCAL_NAME = "StatusCodeType"
1814
1815    # QName of the XSI type.
1816    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
1817                      TYPE_LOCAL_NAME,
1818                      SAMLConstants.SAML20P_PREFIX)
1819
1820    # Local Name of the Value attribute.
1821    VALUE_ATTRIB_NAME = "Value"
1822
1823    # URI for Success status code.
1824    SUCCESS_URI = "urn:oasis:names:tc:SAML:2.0:status:Success"
1825
1826    # URI for Requester status code.
1827    REQUESTER_URI = "urn:oasis:names:tc:SAML:2.0:status:Requester"
1828
1829    # URI for Responder status code.
1830    RESPONDER_URI = "urn:oasis:names:tc:SAML:2.0:status:Responder"
1831
1832    # URI for VersionMismatch status code.
1833    VERSION_MISMATCH_URI = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch"
1834
1835    # URI for AuthnFailed status code.
1836    AUTHN_FAILED_URI = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"
1837
1838    # URI for InvalidAttrNameOrValue status code.
1839    INVALID_ATTR_NAME_VALUE_URI = \
1840                "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue"
1841
1842    # URI for InvalidNameIDPolicy status code.
1843    INVALID_NAMEID_POLICY_URI = \
1844                "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"
1845
1846    # URI for NoAuthnContext status code.
1847    NO_AUTHN_CONTEXT_URI = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext"
1848
1849    # URI for NoAvailableIDP status code.
1850    NO_AVAILABLE_IDP_URI = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP"
1851
1852    # URI for NoPassive status code.
1853    NO_PASSIVE_URI = "urn:oasis:names:tc:SAML:2.0:status:NoPassive"
1854
1855    # URI for NoSupportedIDP status code.
1856    NO_SUPPORTED_IDP_URI = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP"
1857
1858    # URI for PartialLogout status code.
1859    PARTIAL_LOGOUT_URI = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout"
1860
1861    # URI for ProxyCountExceeded status code.
1862    PROXY_COUNT_EXCEEDED_URI = \
1863                "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded"
1864
1865    # URI for RequestDenied status code.
1866    REQUEST_DENIED_URI = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied"
1867
1868    # URI for RequestUnsupported status code.
1869    REQUEST_UNSUPPORTED_URI = \
1870                "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported"
1871
1872    # URI for RequestVersionDeprecated status code.
1873    REQUEST_VERSION_DEPRECATED_URI = \
1874                "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated"
1875
1876    # URI for RequestVersionTooHigh status code.
1877    REQUEST_VERSION_TOO_HIGH_URI = \
1878                "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh"
1879   
1880    # URI for RequestVersionTooLow status code.
1881    REQUEST_VERSION_TOO_LOW_URI = \
1882                "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow"
1883
1884    # URI for ResourceNotRecognized status code.
1885    RESOURCE_NOT_RECOGNIZED_URI = \
1886                "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized"
1887
1888    # URI for TooManyResponses status code.
1889    TOO_MANY_RESPONSES = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses"
1890
1891    # URI for UnknownAttrProfile status code.
1892    UNKNOWN_ATTR_PROFILE_URI = \
1893                "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile"
1894
1895    # URI for UnknownPrincipal status code.
1896    UNKNOWN_PRINCIPAL_URI = \
1897                "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal"
1898
1899    # URI for UnsupportedBinding status code.
1900    UNSUPPORTED_BINDING_URI = \
1901                "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding"
1902
1903    __slots__ = ('__value', '__childStatusCode',)
1904   
1905    def __init__(self, **kw):
1906        super(StatusCode, self).__init__(**kw)
1907       
1908        # Value attribute URI.
1909        self.__value = None
1910   
1911        # Nested secondary StatusCode child element.
1912        self.__childStatusCode = None
1913
1914    def __getstate__(self):
1915        '''Enable pickling
1916       
1917        @return: object's attribute dictionary
1918        @rtype: dict
1919        '''
1920
1921        _dict = super(StatusCode, self).__getstate__()
1922        for attrName in StatusCode.__slots__:
1923            # Ugly hack to allow for derived classes setting private member
1924            # variables
1925            if attrName.startswith('__'):
1926                attrName = "_StatusCode" + attrName
1927               
1928            _dict[attrName] = getattr(self, attrName)
1929           
1930        return _dict
1931   
1932    def _getStatusCode(self): 
1933        return self.__childStatusCode
1934   
1935    def _setStatusCode(self, value):
1936        if not isinstance(value, StatusCode):
1937            raise TypeError('Child "statusCode" must be a %r derived type, '
1938                            "got %r" % (StatusCode, type(value)))
1939           
1940        self.__childStatusCode = value
1941
1942    value = property(fget=_getStatusCode, 
1943                     fset=_setStatusCode, 
1944                     doc="Child Status code")
1945             
1946    def _getValue(self):
1947        return self.__value
1948       
1949    def _setValue(self, value):
1950        if not isinstance(value, basestring):
1951            raise TypeError("\"value\" must be a basestring derived type, "
1952                            "got %r" % value.__class__)
1953           
1954        self.__value = value
1955
1956    value = property(fget=_getValue, fset=_setValue, doc="Status code value")
1957       
1958
1959class Status(SAMLObject): 
1960    '''SAML 2.0 Core Status'''
1961   
1962    # Local Name of Status.
1963    DEFAULT_ELEMENT_LOCAL_NAME = "Status"
1964
1965    # Default element name.
1966    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
1967                                 DEFAULT_ELEMENT_LOCAL_NAME,
1968                                 SAMLConstants.SAML20P_PREFIX)
1969
1970    # Local name of the XSI type.
1971    TYPE_LOCAL_NAME = "StatusType"
1972
1973    # QName of the XSI type.
1974    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
1975                      TYPE_LOCAL_NAME,
1976                      SAMLConstants.SAML20P_PREFIX)
1977
1978    __slots__ = ('__statusCode', '__statusMessage', '__statusDetail', )
1979   
1980    def __init__(self, **kw):
1981        super(Status, self).__init__(**kw)
1982       
1983        # StatusCode element.
1984        self.__statusCode = None
1985   
1986        # StatusMessage element.
1987        self.__statusMessage = None
1988   
1989        # StatusDetail element.
1990        self.__statusDetail = None
1991       
1992    def __getstate__(self):
1993        '''Enable pickling
1994       
1995        @return: object's attribute dictionary
1996        @rtype: dict
1997        '''
1998
1999        _dict = super(Status, self).__getstate__()
2000        for attrName in Status.__slots__:
2001            # Ugly hack to allow for derived classes setting private member
2002            # variables
2003            if attrName.startswith('__'):
2004                attrName = "_Status" + attrName
2005               
2006            _dict[attrName] = getattr(self, attrName)
2007           
2008        return _dict
2009   
2010    def _getStatusCode(self):
2011        '''
2012        Gets the Code of this Status.
2013       
2014        @return: Status StatusCode
2015        '''
2016        return self.__statusCode
2017
2018    def _setStatusCode(self, value):
2019        '''
2020        Sets the Code of this Status.
2021       
2022        @param value: the Code of this Status
2023        '''
2024        if not isinstance(value, StatusCode):
2025            raise TypeError('"statusCode" must be a %r derived type, '
2026                            "got %r" % (StatusCode, type(value)))
2027           
2028        self.__statusCode = value
2029       
2030    statusCode = property(fget=_getStatusCode,
2031                          fset=_setStatusCode,
2032                          doc="status code object")
2033   
2034    def _getStatusMessage(self):
2035        '''
2036        Gets the Message of this Status.
2037       
2038        @return: Status StatusMessage
2039        '''
2040        return self.__statusMessage
2041
2042    def _setStatusMessage(self, value):
2043        '''
2044        Sets the Message of this Status.
2045       
2046        @param value: the Message of this Status
2047        '''
2048        if not isinstance(value, StatusMessage):
2049            raise TypeError('"statusMessage" must be a %r derived type, '
2050                            "got %r" % (StatusMessage, type(value)))
2051           
2052        self.__statusMessage = value
2053       
2054    statusMessage = property(fget=_getStatusMessage,
2055                             fset=_setStatusMessage,
2056                             doc="status message")
2057
2058    def _getStatusDetail(self):
2059        '''
2060        Gets the Detail of this Status.
2061       
2062        @return: Status StatusDetail
2063        '''
2064        return self.__statusDetail
2065   
2066    def _setStatusDetail(self, value):
2067        '''
2068        Sets the Detail of this Status.
2069       
2070        @param value: the Detail of this Status
2071        '''
2072        self.__statusDetail = value
2073       
2074    statusDetail = property(fget=_getStatusDetail,
2075                            fset=_setStatusDetail,
2076                            doc="status message")
2077
2078
2079class Action(SAMLObject): 
2080    '''SAML 2.0 Core Action'''
2081   
2082    # Element local name.
2083    DEFAULT_ELEMENT_LOCAL_NAME = "Action"
2084
2085    # Default element name.
2086    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2087                                 DEFAULT_ELEMENT_LOCAL_NAME,
2088                                 SAMLConstants.SAML20_PREFIX)
2089
2090    # Local name of the XSI type.
2091    TYPE_LOCAL_NAME = "ActionType"
2092
2093    # QName of the XSI type
2094    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
2095                      TYPE_LOCAL_NAME,
2096                      SAMLConstants.SAML20_PREFIX)
2097
2098    # Name of the Namespace attribute.
2099    NAMESPACE_ATTRIB_NAME = "Namespace"
2100
2101    # Read/Write/Execute/Delete/Control action namespace.
2102    RWEDC_NS_URI = "urn:oasis:names:tc:SAML:1.0:action:rwedc"
2103
2104    # Read/Write/Execute/Delete/Control negation action namespace.
2105    RWEDC_NEGATION_NS_URI = "urn:oasis:names:tc:SAML:1.0:action:rwedc-negation"
2106
2107    # Get/Head/Put/Post action namespace.
2108    GHPP_NS_URI = "urn:oasis:names:tc:SAML:1.0:action:ghpp"
2109
2110    # UNIX file permission action namespace.
2111    UNIX_NS_URI = "urn:oasis:names:tc:SAML:1.0:action:unix"
2112
2113    ACTION_NS_IDENTIFIERS = (
2114        RWEDC_NS_URI,
2115        RWEDC_NEGATION_NS_URI,   
2116        GHPP_NS_URI,
2117        UNIX_NS_URI       
2118    )
2119   
2120    # Read action.
2121    READ_ACTION = "Read"
2122
2123    # Write action.
2124    WRITE_ACTION = "Write"
2125
2126    # Execute action.
2127    EXECUTE_ACTION = "Execute"
2128
2129    # Delete action.
2130    DELETE_ACTION = "Delete"
2131
2132    # Control action.
2133    CONTROL_ACTION = "Control"
2134
2135    # Negated Read action.
2136    NEG_READ_ACTION = "~Read"
2137
2138    # Negated Write action.
2139    NEG_WRITE_ACTION = "~Write"
2140
2141    # Negated Execute action.
2142    NEG_EXECUTE_ACTION = "~Execute"
2143
2144    # Negated Delete action.
2145    NEG_DELETE_ACTION = "~Delete"
2146
2147    # Negated Control action.
2148    NEG_CONTROL_ACTION = "~Control"
2149
2150    # HTTP GET action.
2151    HTTP_GET_ACTION = "GET"
2152
2153    # HTTP HEAD action.
2154    HTTP_HEAD_ACTION = "HEAD"
2155
2156    # HTTP PUT action.
2157    HTTP_PUT_ACTION = "PUT"
2158
2159    # HTTP POST action.
2160    HTTP_POST_ACTION = "POST"
2161   
2162    ACTION_TYPES = {
2163        RWEDC_NS_URI: (READ_ACTION, WRITE_ACTION, EXECUTE_ACTION, DELETE_ACTION,
2164                       CONTROL_ACTION),
2165        RWEDC_NEGATION_NS_URI: (READ_ACTION, WRITE_ACTION, EXECUTE_ACTION, 
2166                                DELETE_ACTION, CONTROL_ACTION, NEG_READ_ACTION, 
2167                                NEG_WRITE_ACTION, NEG_EXECUTE_ACTION, 
2168                                NEG_CONTROL_ACTION),   
2169        GHPP_NS_URI: (HTTP_GET_ACTION, HTTP_HEAD_ACTION, HTTP_PUT_ACTION,
2170                      HTTP_POST_ACTION),
2171                     
2172        # This namespace uses octal bitmask for file permissions
2173        UNIX_NS_URI: ()   
2174    }
2175   
2176    __slots__ = ('__namespace', '__value', '__actionTypes')
2177   
2178    def __init__(self, **kw):
2179        '''Create an authorization action type
2180        '''
2181        super(Action, self).__init__(**kw)
2182
2183        # URI of the Namespace of this action.  Default to read/write/negation
2184        # type - 2.7.4.2 SAML 2 Core Spec. 15 March 2005
2185        self.__namespace = Action.RWEDC_NEGATION_NS_URI
2186
2187        # Action value
2188        self.__value = None       
2189   
2190        self.__actionTypes = Action.ACTION_TYPES
2191       
2192    def __getstate__(self):
2193        '''Enable pickling
2194       
2195        @return: object's attribute dictionary
2196        @rtype: dict
2197        '''
2198
2199        _dict = super(Action, self).__getstate__()
2200        for attrName in Action.__slots__:
2201            # Ugly hack to allow for derived classes setting private member
2202            # variables
2203            if attrName.startswith('__'):
2204                attrName = "_Action" + attrName
2205               
2206            _dict[attrName] = getattr(self, attrName)
2207           
2208        return _dict
2209   
2210    def _getActionTypes(self):
2211        return self.__actionTypes
2212
2213    def _setActionTypes(self, value):
2214        if not isinstance(value, dict):
2215            raise TypeError('Expecting list or tuple type for "actionTypes" '
2216                            'attribute; got %r' % type(value))
2217           
2218        for k, v in value.items():
2219            if not isinstance(v, (tuple, type(None))):
2220                raise TypeError('Expecting None or tuple type for '
2221                                '"actionTypes" dictionary values; got %r for '
2222                                '%r key' % (type(value), k))
2223        self.__actionTypes = value
2224
2225    actionTypes = property(_getActionTypes, 
2226                           _setActionTypes, 
2227                           doc="Restrict vocabulary of action types")
2228       
2229    def _getNamespace(self):
2230        '''
2231        gets the namespace scope of the specified value.
2232       
2233        @return: the namespace scope of the specified value
2234        '''
2235        return self.__namespace
2236
2237    def _setNamespace(self, value):
2238        '''Sets the namespace scope of the specified value.
2239       
2240        @param value: the namespace scope of the specified value
2241        '''
2242        if not isinstance(value, basestring):
2243            raise TypeError('Expecting string type for "namespace" '
2244                            'attribute; got %r' % type(value))
2245           
2246        if value not in self.__actionTypes.keys():
2247            raise AttributeError('"namespace" action type %r not recognised. '
2248                                 'It must be one of these action types: %r' % 
2249                                 self.__actionTypes.keys())
2250           
2251        self.__namespace = value
2252
2253    namespace = property(_getNamespace, _setNamespace, doc="Action Namespace")
2254
2255    def _getValue(self):
2256        '''gets the URI of the action to be performed.
2257       
2258        @return: the URI of the action to be performed
2259        '''
2260        return self.__value
2261
2262    def _setValue(self, value):
2263        '''Sets the URI of the action to be performed.
2264       
2265        @param value: the URI of the value to be performed
2266        '''
2267        # int and oct allow for UNIX file permissions action type
2268        if not isinstance(value, (basestring, int)):
2269            raise TypeError('Expecting string or int type for "action" '
2270                            'attribute; got %r' % type(value))
2271           
2272        # Default to read/write/negation type - 2.7.4.2 SAML 2 Core Spec.
2273        # 15 March 2005
2274        allowedActions = self.__actionTypes.get(self.__namespace,
2275                                                Action.RWEDC_NEGATION_NS_URI)
2276       
2277        # Only apply restriction for action type that has a restricted
2278        # vocabulary - UNIX type is missed out of this because its an octal
2279        # mask
2280        if len(allowedActions) > 0 and value not in allowedActions:
2281            raise AttributeError('%r action not recognised; known actions for '
2282                                 'the %r namespace identifier are: %r.  ' 
2283                                 'If this is not as expected make sure to set '
2284                                 'the "namespace" attribute to an alternative '
2285                                 'value first or override completely by '
2286                                 'explicitly setting the "allowTypes" '
2287                                 'attribute' % 
2288                                 (value, self.__namespace, allowedActions))
2289        self.__value = value
2290
2291    value = property(_getValue, _setValue, doc="Action string")
2292       
2293
2294class RequestAbstractType(SAMLObject): 
2295    '''SAML 2.0 Core RequestAbstractType'''
2296   
2297    # Local name of the XSI type.
2298    TYPE_LOCAL_NAME = "RequestAbstractType"
2299
2300    # QName of the XSI type.
2301    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
2302                      TYPE_LOCAL_NAME,
2303                      SAMLConstants.SAML20P_PREFIX)
2304
2305    # ID attribute name.
2306    ID_ATTRIB_NAME = "ID"
2307
2308    # Version attribute name.
2309    VERSION_ATTRIB_NAME = "Version"
2310
2311    # IssueInstant attribute name.
2312    ISSUE_INSTANT_ATTRIB_NAME = "IssueInstant"
2313
2314    # Destination attribute name.
2315    DESTINATION_ATTRIB_NAME = "Destination"
2316
2317    # Consent attribute name.
2318    CONSENT_ATTRIB_NAME = "Consent"
2319
2320    # Unspecified consent URI.
2321    UNSPECIFIED_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:unspecified"
2322
2323    # Obtained consent URI.
2324    OBTAINED_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:obtained"
2325
2326    # Prior consent URI.
2327    PRIOR_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:prior"
2328
2329    # Implicit consent URI.
2330    IMPLICIT_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:implicit"
2331
2332    # Explicit consent URI.
2333    EXPLICIT_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:explicit"
2334
2335    # Unavailable consent URI.
2336    UNAVAILABLE_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:unavailable"
2337
2338    # Inapplicable consent URI.
2339    INAPPLICABLE_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:inapplicable"
2340     
2341    __slots__ = (
2342        '__version',
2343        '__id',
2344        '__issueInstant',
2345        '__destination',
2346        '__consent',
2347        '__issuer',
2348        '__extensions'
2349    )
2350   
2351    def __init__(self, **kw):
2352        '''Request abstract type
2353        @type kw: dict
2354        @param kw: see SAMLObject.__init__
2355        '''
2356        super(RequestAbstractType, self).__init__(**kw)
2357       
2358        # SAML Version of the request.
2359        self.__version = None
2360   
2361        # Unique identifier of the request.
2362        self.__id = None
2363   
2364        # Date/time request was issued.
2365        self.__issueInstant = None
2366   
2367        # URI of the request destination.
2368        self.__destination = None
2369   
2370        # URI of the SAML user consent type.
2371        self.__consent = None
2372   
2373        # URI of the SAML user consent type.
2374        self.__issuer = None
2375   
2376        # Extensions child element.
2377        self.__extensions = None
2378
2379    def __getstate__(self):
2380        '''Enable pickling
2381       
2382        @return: object's attribute dictionary
2383        @rtype: dict
2384        '''
2385
2386        _dict = super(RequestAbstractType, self).__getstate__()
2387        for attrName in RequestAbstractType.__slots__:
2388            # Ugly hack to allow for derived classes setting private member
2389            # variables
2390            if attrName.startswith('__'):
2391                attrName = "_RequestAbstractType" + attrName
2392               
2393            _dict[attrName] = getattr(self, attrName)
2394           
2395        return _dict
2396   
2397    def _get_version(self):
2398        '''@return: the SAML Version of this assertion.
2399        '''
2400        return self.__version
2401   
2402    def _set_version(self, version):
2403        '''@param version: the SAML Version of this assertion
2404        '''
2405        if not isinstance(version, SAMLVersion):
2406            raise TypeError("Expecting SAMLVersion type got: %r" % 
2407                            version.__class__)
2408       
2409        self.__version = version
2410       
2411    version = property(fget=_get_version,
2412                       fset=_set_version,
2413                       doc="SAML Version of the assertion")
2414
2415    def _get_issueInstant(self):
2416        '''Gets the date/time the request was issued
2417       
2418        @return: the issue instance of this request'''
2419        return self.__issueInstant
2420   
2421    def _set_issueInstant(self, value):
2422        '''Sets the date/time the request was issued
2423       
2424        @param value: the issue instance of this request
2425        '''
2426        if not isinstance(value, datetime):
2427            raise TypeError('Expecting "datetime" type for "issueInstant", '
2428                            'got %r' % type(value))
2429           
2430        self.__issueInstant = value
2431       
2432    issueInstant = property(fget=_get_issueInstant, 
2433                            fset=_set_issueInstant,
2434                            doc="Issue instant of the request") 
2435
2436    def _get_id(self):
2437        '''Sets the unique identifier for this request.
2438       
2439        @return: the ID of this request
2440        '''
2441        return self.__id
2442   
2443    def _set_id(self, value):
2444        '''Sets the unique identifier for this request
2445       
2446        @param value: the ID of this assertion
2447        '''
2448        if not isinstance(value, basestring):
2449            raise TypeError('Expecting basestring derived type for "id", got '
2450                            '%r' % type(value))
2451        self.__id = value
2452       
2453    id = property(fget=_get_id, fset=_set_id, doc="ID of request")
2454
2455    def _get_destination(self):
2456        '''Gets the URI of the destination of the request.
2457       
2458        @return: the URI of the destination of the request
2459        '''
2460        return self.__destination
2461   
2462    def _set_destination(self, value):
2463        '''Sets the URI of the destination of the request.
2464       
2465        @param value: the URI of the destination of the request'''
2466        if not isinstance(value, basestring):
2467            raise TypeError('Expecting basestring derived type for '
2468                            '"destination", got %r' % type(value))
2469        self.__destination = value
2470       
2471    destination = property(fget=_get_destination, 
2472                           fset=_set_destination,
2473                           doc="Destination of request")
2474     
2475    def _get_consent(self):
2476        '''Gets the consent obtained from the principal for sending this
2477        request.
2478       
2479        @return: the consent obtained from the principal for sending this
2480        request
2481        '''
2482        return self.__consent
2483       
2484    def _set_consent(self, value):
2485        '''Sets the consent obtained from the principal for sending this
2486        request.
2487       
2488        @param value: the new consent obtained from the principal for
2489        sending this request
2490        ''' 
2491        if not isinstance(value, basestring):
2492            raise TypeError('Expecting basestring derived type for "consent", '
2493                            'got %r' % type(value))
2494        self.__consent = value
2495             
2496    consent = property(fget=_get_consent, 
2497                       fset=_set_consent,
2498                       doc="Consent for request")
2499   
2500    def _set_issuer(self, issuer):
2501        """Set issuer of request"""
2502        if not isinstance(issuer, Issuer):
2503            raise TypeError('"issuer" must be a %r, got %r' % (Issuer, 
2504                                                               type(issuer)))
2505       
2506        self.__issuer = issuer
2507   
2508    def _get_issuer(self):
2509        """Get the issuer name """
2510        return self.__issuer
2511
2512    issuer = property(fget=_get_issuer, 
2513                      fset=_set_issuer,
2514                      doc="Issuer of request")
2515 
2516    def _get_extensions(self):
2517        '''Gets the Extensions of this request.
2518       
2519        @return: the Status of this request
2520        '''
2521        return self.__extensions
2522     
2523    def _set_extensions(self, value):
2524        '''Sets the Extensions of this request.
2525       
2526        @param value: the Extensions of this request
2527        '''
2528        self.__extensions = value
2529       
2530    extensions = property(fget=_get_extensions, 
2531                          fset=_set_extensions,
2532                          doc="Request extensions")
2533
2534
2535class SubjectQuery(RequestAbstractType):
2536    """SAML 2.0 Core Subject Query type"""
2537   
2538    DEFAULT_ELEMENT_LOCAL_NAME = 'SubjectQuery'
2539   
2540    __slots__ = ('__subject', )
2541   
2542    def __init__(self):
2543        super(SubjectQuery, self).__init__()
2544        self.__subject = None
2545
2546    def __getstate__(self):
2547        '''Enable pickling
2548       
2549        @return: object's attribute dictionary
2550        @rtype: dict
2551        '''
2552
2553        _dict = super(SubjectQuery, self).__getstate__()
2554        for attrName in SubjectQuery.__slots__:
2555            # Ugly hack to allow for derived classes setting private member
2556            # variables
2557            if attrName.startswith('__'):
2558                attrName = "_SubjectQuery" + attrName
2559               
2560            _dict[attrName] = getattr(self, attrName)
2561           
2562        return _dict
2563           
2564    def _getSubject(self):
2565        '''Gets the Subject of this request.
2566       
2567        @return: the Subject of this request'''   
2568        return self.__subject
2569   
2570    def _setSubject(self, value):
2571        '''Sets the Subject of this request.
2572       
2573        @param value: the Subject of this request'''
2574        if not isinstance(value, Subject):
2575            raise TypeError('Setting "subject", got %r, expecting %r' %
2576                            (Subject, type(value)))
2577           
2578        self.__subject = value
2579       
2580    subject = property(fget=_getSubject, fset=_setSubject, doc="Query subject")
2581   
2582   
2583class AttributeQuery(SubjectQuery):
2584    '''SAML 2.0 AttributeQuery'''
2585   
2586    # Element local name.
2587    DEFAULT_ELEMENT_LOCAL_NAME = "AttributeQuery"
2588
2589    # Default element name.
2590    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
2591                                 DEFAULT_ELEMENT_LOCAL_NAME,
2592                                 SAMLConstants.SAML20P_PREFIX)
2593
2594    # Local name of the XSI type.
2595    TYPE_LOCAL_NAME = "AttributeQueryType"
2596
2597    # QName of the XSI type.
2598    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
2599                      TYPE_LOCAL_NAME,
2600                      SAMLConstants.SAML20P_PREFIX)
2601
2602    __slots__ = ('__attributes',)
2603   
2604    def __init__(self):
2605        super(AttributeQuery, self).__init__()
2606        self.__attributes = TypedList(Attribute)
2607
2608    def __getstate__(self):
2609        '''Enable pickling
2610       
2611        @return: object's attribute dictionary
2612        @rtype: dict
2613        '''
2614
2615        _dict = super(AttributeQuery, self).__getstate__()
2616        for attrName in AttributeQuery.__slots__:
2617            # Ugly hack to allow for derived classes setting private member
2618            # variables
2619            if attrName.startswith('__'):
2620                attrName = "_AttributeQuery" + attrName
2621               
2622            _dict[attrName] = getattr(self, attrName)
2623           
2624        return _dict
2625 
2626    def _getAttributes(self):
2627        '''Gets the Attributes of this query.
2628       
2629        @return: the list of Attributes of this query'''
2630        return self.__attributes
2631
2632    def _setAttributes(self, value):
2633        self.__attributes = value
2634
2635    attributes = property(fget=_getAttributes, 
2636                          fset=_setAttributes, 
2637                          doc="Attributes")
2638
2639
2640class Evidentiary(SAMLObject):
2641    """Base class for types set in an evidence object"""
2642    __slots__ = ()
2643
2644
2645class AssertionURIRef(Evidentiary):
2646    '''SAML 2.0 Core AssertionURIRef'''
2647    __slots__ = ('__assertionURI',)
2648   
2649    # Element local name
2650    DEFAULT_ELEMENT_LOCAL_NAME = "AssertionURIRef"
2651
2652    # Default element name
2653    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2654                                 DEFAULT_ELEMENT_LOCAL_NAME,
2655                                 SAMLConstants.SAML20_PREFIX)
2656   
2657    def __init__(self):
2658        '''Create assertion URI reference'''
2659        super(AssertionURIRef, self).__init__()
2660       
2661        # URI of the Assertion
2662        self.__assertionURI = None   
2663
2664    def __getstate__(self):
2665        '''Enable pickling
2666       
2667        @return: object's attribute dictionary
2668        @rtype: dict
2669        '''
2670
2671        _dict = super(AssertionURIRef, self).__getstate__()
2672        for attrName in AssertionURIRef.__slots__:
2673            # Ugly hack to allow for derived classes setting private member
2674            # variables
2675            if attrName.startswith('__'):
2676                attrName = "_AssertionURIRef" + attrName
2677               
2678            _dict[attrName] = getattr(self, attrName)
2679           
2680        return _dict
2681   
2682    def _getAssertionURI(self):
2683        return self.__assertionURI
2684
2685    def _setAssertionURI(self, value):
2686        if not isinstance(value, basestring):
2687            raise TypeError('Expecting string type for "assertionID" '
2688                            'attribute; got %r' % type(value))
2689        self.__assertionURI = value
2690
2691    def getOrderedChildren(self):
2692        return None
2693
2694    assertionURI = property(_getAssertionURI, _setAssertionURI, 
2695                            doc="Assertion URI")
2696   
2697   
2698class AssertionIDRef(Evidentiary):
2699    '''SAML 2.0 Core AssertionIDRef.'''
2700
2701    # Element local name.
2702    DEFAULT_ELEMENT_LOCAL_NAME = "AssertionIDRef"
2703
2704    # Default element name.
2705    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2706                                 DEFAULT_ELEMENT_LOCAL_NAME,
2707                                 SAMLConstants.SAML20_PREFIX)
2708   
2709    __slots__ = ("_AssertionID",)
2710   
2711    def __init__(self, namespaceURI, elementLocalName, namespacePrefix):
2712        '''
2713        @param namespaceURI: the namespace the element is in
2714        @param elementLocalName: the local name of the XML element this Object
2715        represents
2716        @param namespacePrefix: the prefix for the given namespace
2717        '''
2718        super(AssertionIDRef, self).__init__(namespaceURI, 
2719                                             elementLocalName, 
2720                                             namespacePrefix)
2721        self.__assertionID = None
2722
2723    def __getstate__(self):
2724        '''Enable pickling
2725       
2726        @return: object's attribute dictionary
2727        @rtype: dict
2728        '''
2729
2730        _dict = super(AssertionIDRef, self).__getstate__()
2731        for attrName in AssertionIDRef.__slots__:
2732            # Ugly hack to allow for derived classes setting private member
2733            # variables
2734            if attrName.startswith('__'):
2735                attrName = "_AssertionIDRef" + attrName
2736               
2737            _dict[attrName] = getattr(self, attrName)
2738           
2739        return _dict
2740       
2741    def _getAssertionID(self):
2742        '''Gets the ID of the assertion this references.
2743       
2744        @return: the ID of the assertion this references'''
2745        return self.__assertionID
2746       
2747    def _setAssertionID(self, value):
2748        '''Sets the ID of the assertion this references.
2749       
2750        @param value: the ID of the assertion this references'''
2751        if not isinstance(value, basestring):
2752            raise TypeError('Expecting string type for "assertionID" '
2753                            'attribute; got %r' % type(value))
2754        self.__assertionID = value
2755
2756    def getOrderedChildren(self):
2757        return None
2758
2759    assertionID = property(_getAssertionID, _setAssertionID, 
2760                           doc="Assertion ID")
2761       
2762   
2763class EncryptedElementType(SAMLObject):
2764    '''SAML 2.0 Core EncryptedElementType'''
2765   
2766    # Local name of the XSI type.
2767    TYPE_LOCAL_NAME = "EncryptedElementType"
2768       
2769    # QName of the XSI type.
2770    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
2771                      TYPE_LOCAL_NAME, 
2772                      SAMLConstants.SAML20_PREFIX)
2773   
2774    __slots__ = ()
2775   
2776    def _getEncryptedData(self):
2777        '''Get the EncryptedData child element.
2778       
2779        @return the EncryptedData child element'''
2780        raise NotImplementedError()
2781   
2782    def _setEncryptedData(self, value):
2783        '''Set the EncryptedData child element.
2784       
2785        @param newEncryptedData the new EncryptedData child element'''
2786        raise NotImplementedError()
2787   
2788    def _getEncryptedKeys(self):
2789        '''A list of EncryptedKey child elements.
2790       
2791        @return a list of EncryptedKey child elements'''
2792        raise NotImplementedError()
2793   
2794   
2795class EncryptedAssertion(EncryptedElementType, Evidentiary):
2796    '''SAML 2.0 Core EncryptedAssertion.'''
2797   
2798    # Element local name.
2799    DEFAULT_ELEMENT_LOCAL_NAME = "EncryptedAssertion"
2800
2801    # Default element name.
2802    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2803                                 DEFAULT_ELEMENT_LOCAL_NAME,
2804                                 SAMLConstants.SAML20_PREFIX) 
2805    __slots__ = ()
2806     
2807   
2808class Evidence(SAMLObject):
2809    '''SAML 2.0 Core Evidence.'''
2810   
2811    # Element local name.
2812    DEFAULT_ELEMENT_LOCAL_NAME = "Evidence"
2813   
2814    # Default element name.
2815    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2816                                 DEFAULT_ELEMENT_LOCAL_NAME, 
2817                                 SAMLConstants.SAML20_PREFIX)
2818   
2819    # Local name of the XSI type.
2820    TYPE_LOCAL_NAME = "EvidenceType" 
2821       
2822    # QName of the XSI type.
2823    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
2824                      TYPE_LOCAL_NAME, 
2825                      SAMLConstants.SAML20_PREFIX)
2826
2827    __slots__ = ('__values',)
2828   
2829    def __init__(self, **kw):
2830        '''Create an authorization evidence type
2831        '''
2832        super(Evidence, self).__init__(**kw)
2833
2834        # Assertion of the Evidence.
2835        self.__values = TypedList(Evidentiary) 
2836
2837    def __getstate__(self):
2838        '''Enable pickling
2839       
2840        @return: object's attribute dictionary
2841        @rtype: dict
2842        '''
2843
2844        _dict = super(Evidence, self).__getstate__()
2845        for attrName in Evidence.__slots__:
2846            # Ugly hack to allow for derived classes setting private member
2847            # variables
2848            if attrName.startswith('__'):
2849                attrName = "_Evidence" + attrName
2850               
2851            _dict[attrName] = getattr(self, attrName)
2852           
2853        return _dict   
2854         
2855    @property
2856    def assertionIDReferences(self):
2857        '''Gets the list of AssertionID references used as evidence.
2858   
2859        @return: the list of AssertionID references used as evidence'''
2860        return [i for i in self.__values
2861                if (getattr(i, "DEFAULT_ELEMENT_NAME") == 
2862                    AssertionIDRef.DEFAULT_ELEMENT_NAME)]
2863   
2864    @property
2865    def assertionURIReferences(self):
2866        '''Gets the list of AssertionURI references used as evidence.
2867       
2868        @return: the list of AssertionURI references used as evidence'''
2869        return [i for i in self.__values
2870                if (getattr(i, "DEFAULT_ELEMENT_NAME") == 
2871                    AssertionURIRef.DEFAULT_ELEMENT_NAME)]
2872   
2873    @property
2874    def assertions(self):
2875        '''Gets the list of Assertions used as evidence.
2876       
2877        @return: the list of Assertions used as evidence'''
2878        return [i for i in self.__values
2879                if (getattr(i, "DEFAULT_ELEMENT_NAME") == 
2880                    Assertion.DEFAULT_ELEMENT_NAME)]
2881   
2882    @property
2883    def encryptedAssertions(self):
2884        '''Gets the list of EncryptedAssertions used as evidence.
2885       
2886        @return: the list of EncryptedAssertions used as evidence'''
2887        return [i for i in self.__values
2888                if (getattr(i, "DEFAULT_ELEMENT_NAME") == 
2889                    EncryptedAssertion.DEFAULT_ELEMENT_NAME)]   
2890
2891    @property
2892    def values(self):
2893        '''Gets the list of all elements used as evidence.
2894       
2895        @return: the list of Evidentiary objects used as evidence'''
2896        return self.__values
2897   
2898    def getOrderedChildren(self):
2899        children = []
2900
2901        if len(self.__values) == 0:
2902            return None
2903
2904        children.extend(self.__values)
2905
2906        return tuple(children)
2907   
2908
2909class AuthzDecisionQuery(SubjectQuery):
2910    '''SAML 2.0 AuthzDecisionQuery.'''
2911
2912    # Element local name.
2913    DEFAULT_ELEMENT_LOCAL_NAME = "AuthzDecisionQuery"
2914
2915    # Default element name.
2916    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
2917                                 DEFAULT_ELEMENT_LOCAL_NAME,
2918                                 SAMLConstants.SAML20P_PREFIX)
2919
2920    # Local name of the XSI type.
2921    TYPE_LOCAL_NAME = "AuthzDecisionQueryType"
2922
2923    # QName of the XSI type.
2924    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
2925                      TYPE_LOCAL_NAME,
2926                      SAMLConstants.SAML20P_PREFIX)
2927
2928    # Resource attribute name.
2929    RESOURCE_ATTRIB_NAME = "Resource"
2930   
2931    __slots__ = (
2932       '__resource',
2933       '__evidence',
2934       '__actions',
2935       '__normalizeResource',
2936       '__safeNormalizationChars'
2937    )
2938   
2939    def __init__(self, normalizeResource=True, safeNormalizationChars='/%'):
2940        '''Create new authorisation decision query
2941        '''
2942        super(AuthzDecisionQuery, self).__init__()
2943
2944        # Resource attribute value.
2945        self.__resource = None
2946   
2947        # Evidence child element.
2948        self.__evidence = None
2949   
2950        # Action child elements.
2951        self.__actions = TypedList(Action)   
2952       
2953        # Tuning for normalization of resource URIs in property set method
2954        self.normalizeResource = normalizeResource
2955        self.safeNormalizationChars = safeNormalizationChars
2956
2957    def __getstate__(self):
2958        '''Enable pickling
2959       
2960        @return: object's attribute dictionary
2961        @rtype: dict
2962        '''
2963
2964        _dict = super(AuthzDecisionQuery, self).__getstate__()
2965        for attrName in AuthzDecisionQuery.__slots__:
2966            # Ugly hack to allow for derived classes setting private member
2967            # variables
2968            if attrName.startswith('__'):
2969                attrName = "_AuthzDecisionQuery" + attrName
2970               
2971            _dict[attrName] = getattr(self, attrName)
2972           
2973        return _dict
2974   
2975    def _getNormalizeResource(self):
2976        return self.__normalizeResource
2977
2978    def _setNormalizeResource(self, value):
2979        if not isinstance(value, bool):
2980            raise TypeError('Expecting bool type for "normalizeResource" '
2981                            'attribute; got %r instead' % type(value))
2982           
2983        self.__normalizeResource = value
2984
2985    normalizeResource = property(_getNormalizeResource, 
2986                                 _setNormalizeResource, 
2987                                 doc="Flag to normalize new resource value "
2988                                     "assigned to the \"resource\" property.  "
2989                                     "The setting only applies for URIs "
2990                                     'beginning with "http://" or "https://"')
2991
2992    def _getSafeNormalizationChars(self):
2993        return self.__safeNormalizationChars
2994
2995    def _setSafeNormalizationChars(self, value):
2996        if not isinstance(value, basestring):
2997            raise TypeError('Expecting string type for "normalizeResource" '
2998                            'attribute; got %r instead' % type(value))
2999           
3000        self.__safeNormalizationChars = value
3001
3002    safeNormalizationChars = property(_getSafeNormalizationChars, 
3003                                      _setSafeNormalizationChars, 
3004                                      doc="String containing a list of "
3005                                          "characters that should not be "
3006                                          "converted when Normalizing the "
3007                                          "resource URI.  These are passed to "
3008                                          "urllib.quote when the resource "
3009                                          "property is set.  The default "
3010                                          "characters are '/%'")
3011
3012    def _getResource(self):
3013        '''Gets the Resource attrib value of this query.
3014
3015        @return: the Resource attrib value of this query'''
3016        return self.__resource
3017   
3018    def _setResource(self, value):
3019        '''Sets the Resource attrib value of this query normalizing the path
3020        component, removing spurious port numbers (80 for HTTP and 443 for
3021        HTTPS) and converting the host component to lower case.
3022       
3023        @param value: the new Resource attrib value of this query'''
3024        if not isinstance(value, basestring):
3025            raise TypeError('Expecting string type for "resource" attribute; '
3026                            'got %r instead' % type(value))
3027       
3028        if (self.normalizeResource and 
3029            value.startswith('http://') or value.startswith('https://')):
3030            # Normalise the path, set the host name to lower case and remove
3031            # port redundant numbers 80 and 443
3032            splitResult = urlsplit(value)
3033            uriComponents = list(splitResult)
3034           
3035            # hostname attribute is lowercase
3036            uriComponents[1] = splitResult.hostname
3037           
3038            if splitResult.port is not None:
3039                isHttpWithStdPort = (splitResult.port == 80 and 
3040                                     splitResult.scheme == 'http')
3041               
3042                isHttpsWithStdPort = (splitResult.port == 443 and
3043                                      splitResult.scheme == 'https')
3044               
3045                if not isHttpWithStdPort and not isHttpsWithStdPort:
3046                    uriComponents[1] += ":%d" % splitResult.port
3047           
3048            uriComponents[2] = urllib.quote(splitResult.path, 
3049                                            self.safeNormalizationChars)
3050           
3051            self.__resource = urlunsplit(uriComponents)
3052        else:
3053            self.__resource = value
3054   
3055    resource = property(fget=_getResource, fset=_setResource,
3056                        doc="Resource for which authorisation is requested")
3057   
3058    @property
3059    def actions(self):
3060        '''The actions for which authorisation is requested
3061       
3062        @return: the Actions of this query'''
3063        return self.__actions
3064   
3065    def _getEvidence(self):
3066        '''Gets the Evidence of this query.
3067
3068        @return: the Evidence of this query'''
3069        return self.__evidence
3070
3071    def _setEvidence(self, value):
3072        '''Sets the Evidence of this query.
3073        @param newEvidence: the new Evidence of this query''' 
3074        if not isinstance(value, Evidence):
3075            raise TypeError('Expecting Evidence type for "evidence" '
3076                            'attribute; got %r' % type(value))
3077
3078        self.__evidence = value 
3079
3080    evidence = property(fget=_getEvidence, fset=_setEvidence, 
3081                        doc="A set of assertions which the Authority may use "
3082                            "to base its authorisation decision on")
3083   
3084    def getOrderedChildren(self):
3085        children = []
3086
3087        superChildren = super(AuthzDecisionQuery, self).getOrderedChildren()
3088        if superChildren:
3089            children.extend(superChildren)
3090
3091        children.extend(self.__actions)
3092       
3093        if self.__evidence is not None:
3094            children.extend(self.__evidence)
3095
3096        if len(children) == 0:
3097            return None
3098
3099        return tuple(children)
3100
3101
3102class StatusResponseType(SAMLObject):
3103    '''SAML 2.0 Core Status Response Type
3104    '''
3105
3106    # Local name of the XSI type.
3107    TYPE_LOCAL_NAME = "StatusResponseType"
3108
3109    # QName of the XSI type.
3110    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
3111                      TYPE_LOCAL_NAME,
3112                      SAMLConstants.SAML20P_PREFIX)
3113
3114    # ID attribute name
3115    ID_ATTRIB_NAME = "ID"
3116
3117    # InResponseTo attribute name
3118    IN_RESPONSE_TO_ATTRIB_NAME = "InResponseTo"
3119
3120    # Version attribute name
3121    VERSION_ATTRIB_NAME = "Version"
3122
3123    # IssueInstant attribute name
3124    ISSUE_INSTANT_ATTRIB_NAME = "IssueInstant"
3125
3126    # Destination attribute name
3127    DESTINATION_ATTRIB_NAME = "Destination"
3128
3129    # Consent attribute name.
3130    CONSENT_ATTRIB_NAME = "Consent"
3131
3132    # Unspecified consent URI
3133    UNSPECIFIED_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:unspecified"
3134
3135    # Obtained consent URI
3136    OBTAINED_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:obtained"
3137
3138    # Prior consent URI
3139    PRIOR_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:prior"
3140
3141    # Implicit consent URI
3142    IMPLICIT_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:implicit"
3143
3144    # Explicit consent URI
3145    EXPLICIT_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:explicit"
3146
3147    # Unavailable consent URI
3148    UNAVAILABLE_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:unavailable"
3149
3150    # Inapplicable consent URI
3151    INAPPLICABLE_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:inapplicable"
3152
3153    __slots__ = (   
3154        '__version',
3155        '__id',
3156        '__inResponseTo',
3157        '__issueInstant',
3158        '__destination',
3159        '__consent',
3160        '__issuer',
3161        '__status',
3162        '__extensions'               
3163    )
3164   
3165    def __init__(self, **kw):
3166        super(StatusResponseType, self).__init__(**kw)
3167       
3168        self.__version = SAMLVersion(SAMLVersion.VERSION_20)
3169        self.__id = None
3170        self.__inResponseTo = None
3171        self.__issueInstant = None
3172        self.__destination = None
3173        self.__consent = None
3174        self.__issuer = None
3175        self.__status = None
3176        self.__extensions = None
3177
3178    def __getstate__(self):
3179        '''Enable pickling
3180       
3181        @return: object's attribute dictionary
3182        @rtype: dict
3183        '''
3184
3185        _dict = super(StatusResponseType, self).__getstate__()
3186        for attrName in StatusResponseType.__slots__:
3187            # Ugly hack to allow for derived classes setting private member
3188            # variables
3189            if attrName.startswith('__'):
3190                attrName = "_StatusResponseType" + attrName
3191               
3192            _dict[attrName] = getattr(self, attrName)
3193           
3194        return _dict
3195   
3196    def _get_version(self):
3197        '''@return: the SAML Version of this response.
3198        '''
3199        return self.__version
3200   
3201    def _set_version(self, version):
3202        '''@param version: the SAML Version of this response
3203        '''
3204        if not isinstance(version, SAMLVersion):
3205            raise TypeError("Expecting SAMLVersion type got: %r" % 
3206                            version.__class__)
3207       
3208        self.__version = version
3209       
3210    version = property(fget=_get_version,
3211                       fset=_set_version,
3212                       doc="SAML Version of the response")
3213
3214    def _get_id(self):
3215        '''Sets the ID of this response.
3216       
3217        @return: the ID of this response
3218        '''
3219        return self.__id
3220   
3221    def _set_id(self, value):
3222        '''Sets the ID of this response.
3223       
3224        @param value: the ID of this response
3225        '''
3226        if not isinstance(value, basestring):
3227            raise TypeError('Expecting basestring derived type for "id", got '
3228                            '%r' % type(value))
3229        self.__id = value
3230       
3231    id = property(fget=_get_id, fset=_set_id, doc="ID of response")
3232
3233    def _getInResponseTo(self):
3234        '''Get the unique request identifier for which this is a response
3235       
3236        @return: the unique identifier of the originating
3237        request
3238        '''
3239        return self.__inResponseTo
3240   
3241    def _setInResponseTo(self, value):
3242        '''Set the unique request identifier for which this is a response
3243       
3244        @param value: the unique identifier of the originating
3245        request
3246        '''
3247        if not isinstance(value, basestring):
3248            raise TypeError('Expecting basestring derived type for '
3249                            '"inResponseTo", got %r' % type(value))
3250        self.__inResponseTo = value
3251       
3252    inResponseTo = property(fget=_getInResponseTo, 
3253                            fset=_setInResponseTo,
3254                            doc="unique request identifier for which this is "
3255                                "a response")
3256
3257    def _get_issueInstant(self):
3258        '''Gets the issue instance of this response.
3259       
3260        @return: the issue instance of this response'''
3261        return self.__issueInstant
3262   
3263    def _set_issueInstant(self, issueInstant):
3264        '''Sets the issue instance of this response.
3265       
3266        @param newIssueInstance: the issue instance of this response
3267        '''
3268        if not isinstance(issueInstant, datetime):
3269            raise TypeError('Expecting "datetime" type for "issueInstant", '
3270                            'got %r' % issueInstant.__class__)
3271           
3272        self.__issueInstant = issueInstant
3273       
3274    issueInstant = property(fget=_get_issueInstant, 
3275                            fset=_set_issueInstant,
3276                            doc="Issue instant of the response")
3277
3278    def _get_destination(self):
3279        '''Gets the URI of the destination of the response.
3280       
3281        @return: the URI of the destination of the response
3282        '''
3283        return self.__destination
3284   
3285    def _set_destination(self, value):
3286        '''Sets the URI of the destination of the response.
3287       
3288        @param value: the URI of the destination of the response'''
3289        if not isinstance(value, basestring):
3290            raise TypeError('Expecting basestring derived type for '
3291                            '"destination", got %r' % type(value))
3292        self.__destination = value
3293       
3294    destination = property(fget=_get_destination, 
3295                           fset=_set_destination,
3296                           doc="Destination of response")
3297     
3298    def _get_consent(self):
3299        '''Gets the consent obtained from the principal for sending this
3300        response.
3301       
3302        @return: the consent obtained from the principal for sending this
3303        response
3304        '''
3305        return self.__consent
3306       
3307    def _set_consent(self, value):
3308        '''Sets the consent obtained from the principal for sending this
3309        response.
3310       
3311        @param value: the new consent obtained from the principal for
3312        sending this response
3313        ''' 
3314        if not isinstance(value, basestring):
3315            raise TypeError('Expecting basestring derived type for "consent", '
3316                            'got %r' % type(value))
3317        self.__consent = value
3318             
3319    consent = property(fget=_get_consent, 
3320                       fset=_set_consent,
3321                       doc="Consent for response")
3322   
3323    def _set_issuer(self, issuer):
3324        """Set issuer of response"""
3325        if not isinstance(issuer, Issuer):
3326            raise TypeError('"issuer" must be a %r, got %r' % (Issuer,
3327                                                               type(issuer)))
3328        self.__issuer = issuer
3329   
3330    def _get_issuer(self):
3331        """Get the issuer name """
3332        return self.__issuer
3333
3334    issuer = property(fget=_get_issuer, 
3335                      fset=_set_issuer,
3336                      doc="Issuer of response")
3337   
3338    def _getStatus(self):
3339        '''Gets the Status of this response.
3340       
3341        @return: the Status of this response
3342        '''
3343        return self.__status
3344
3345    def _setStatus(self, value):
3346        '''Sets the Status of this response.
3347       
3348        @param newStatus: the Status of this response
3349        '''
3350        if not isinstance(value, Status):
3351            raise TypeError('"status" must be a %r, got %r' % (Status,
3352                                                               type(value)))
3353        self.__status = value
3354       
3355    status = property(fget=_getStatus, fset=_setStatus, doc="Response status")   
3356       
3357    def _get_extensions(self):
3358        '''Gets the Extensions of this response.
3359       
3360        @return: the Status of this response
3361        '''
3362        return self.__extensions
3363     
3364    def _set_extensions(self, value):
3365        '''Sets the Extensions of this response.
3366       
3367        @param value: the Extensions of this response
3368        '''
3369        if not isinstance(value, (list, tuple)):
3370            raise TypeError('Expecting list or tuple for "extensions", got %r'
3371                            % type(value))
3372        self.__extensions = value
3373       
3374    extensions = property(fget=_get_extensions, 
3375                          fset=_set_extensions,
3376                          doc="Response extensions")   
3377
3378
3379class Response(StatusResponseType):
3380    '''SAML2 Core Response'''
3381   
3382    # Element local name.
3383    DEFAULT_ELEMENT_LOCAL_NAME = "Response"
3384   
3385    # Default element name.
3386    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
3387                                 DEFAULT_ELEMENT_LOCAL_NAME, 
3388                                 SAMLConstants.SAML20P_PREFIX)
3389   
3390    # Local name of the XSI type.
3391    TYPE_LOCAL_NAME = "ResponseType"
3392       
3393    # QName of the XSI type.
3394    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
3395                      TYPE_LOCAL_NAME, 
3396                      SAMLConstants.SAML20P_PREFIX)
3397   
3398    __slots__ = ('__indexedChildren',)
3399   
3400    def __init__(self, **kw):
3401        '''''' 
3402        super(Response, self).__init__(**kw)
3403       
3404        # Assertion child elements
3405        self.__indexedChildren = []
3406
3407    def __getstate__(self):
3408        '''Enable pickling
3409       
3410        @return: object's attribute dictionary
3411        @rtype: dict
3412        '''
3413
3414        _dict = super(Response, self).__getstate__()
3415        for attrName in Response.__slots__:
3416            # Ugly hack to allow for derived classes setting private member
3417            # variables
3418            if attrName.startswith('__'):
3419                attrName = "_Response" + attrName
3420               
3421            _dict[attrName] = getattr(self, attrName)
3422           
3423        return _dict
3424       
3425    @property
3426    def assertions(self): 
3427        "Assertions contained in this response"
3428        return self.__indexedChildren
Note: See TracBrowser for help on using the repository browser.