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

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/ndg_saml/ndg/saml/saml2/core.py@6902
Revision 6902, 114.2 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    @cvar DEFAULT_ELEMENT_LOCAL_NAME: Element local name
690    @type DEFAULT_ELEMENT_LOCAL_NAME: string
691    @cvar DEFAULT_ELEMENT_NAME: Default element name
692    @type DEFAULT_ELEMENT_NAME: ndg.saml.common.xml.QName
693    @cvar TYPE_LOCAL_NAME: Local name of the XSI type
694    @type TYPE_LOCAL_NAME: string
695    @cvar TYPE_NAME: QName of the XSI type
696    @type TYPE_NAME: ndg.saml.common.xml.QName
697    @cvar RESOURCE_ATTRIB_NAME: Resource attribute name
698    @type RESOURCE_ATTRIB_NAME: string
699    @cvar DECISION_ATTRIB_NAME: Decision attribute name
700    @type DECISION_ATTRIB_NAME: string
701   
702    @ivar __resource: identifier for the resource which is the subject of the
703    authorisation statement
704    @type __resource: basestring
705    @ivar __decision: decision type for this authorisation statement
706    @type __decision: ndg.saml.saml2.core.DecisionType
707    @ivar __actions: list of ndg.saml.saml2.core.Action elements
708    @type __actions: ndg.saml.utils.TypedList
709    @ivar __evidence: evidence (not currently implemented)
710    @type __evidence: None
711    @ivar __normalizeResource: set to True to normalize the URI object attribute
712    in the set property method (functionality likely to be deprecated)
713    @type __normalizeResource: bool
714    @ivar __safeNormalizationChars: acceptable characters for normalizing URIs
715    (functionality likely to be deprecated)
716    @type __safeNormalizationChars: string
717    '''
718   
719    # Element local name
720    DEFAULT_ELEMENT_LOCAL_NAME = "AuthzDecisionStatement"
721
722    # Default element name
723    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
724                                 DEFAULT_ELEMENT_LOCAL_NAME,
725                                 SAMLConstants.SAML20_PREFIX)
726
727    # Local name of the XSI type
728    TYPE_LOCAL_NAME = "AuthzDecisionStatementType"
729
730    # QName of the XSI type
731    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
732                      TYPE_LOCAL_NAME,
733                      SAMLConstants.SAML20_PREFIX)
734
735    # Resource attribute name
736    RESOURCE_ATTRIB_NAME = "Resource"
737
738    # Decision attribute name
739    DECISION_ATTRIB_NAME = "Decision"
740   
741    __slots__ = (
742        '__resource', 
743        '__decision', 
744        '__actions', 
745        '__evidence',
746        '__normalizeResource',
747        '__safeNormalizationChars'
748    )
749   
750    def __init__(self, 
751                 normalizeResource=True, 
752                 safeNormalizationChars='/%',
753                 **kw):
754        '''Create new authorisation decision statement
755        @param normalizeResource: set to True to normalize the URI object
756        attribute in the set property method (functionality likely to be
757        deprecated)
758        @type normalizeResource: bool
759        @param safeNormalizationChars: acceptable characters for normalizing
760        URIs (functionality likely to be deprecated)
761        @type safeNormalizationChars: string
762        @param **kw: keywords for the initialisation of the parent classes'
763        attributes
764        @type **kw: dict
765        '''
766        super(AuthzDecisionStatement, self).__init__(**kw)
767
768        # Resource attribute value.
769        self.__resource = None 
770       
771        self.__decision = DecisionType.INDETERMINATE   
772        self.__actions = TypedList(Action)
773        self.__evidence = None
774       
775        # Tuning for normalization of resource URIs in property set method
776        self.normalizeResource = normalizeResource
777        self.safeNormalizationChars = safeNormalizationChars
778
779    def __getstate__(self):
780        '''Enable pickling
781       
782        @return: object's attribute dictionary
783        @rtype: dict
784        '''
785
786        _dict = super(AuthzDecisionStatement, self).__getstate__()
787        for attrName in AuthzDecisionStatement.__slots__:
788            # Ugly hack to allow for derived classes setting private member
789            # variables
790            if attrName.startswith('__'):
791                attrName = "_AuthzDecisionStatement" + attrName
792               
793            _dict[attrName] = getattr(self, attrName)
794           
795        return _dict
796   
797    def _getNormalizeResource(self):
798        '''Get normalise resource flag
799        @return: flag value
800        @rtype: bool       
801        '''
802        return self.__normalizeResource
803
804    def _setNormalizeResource(self, value):
805        '''Set normalise resource flag
806        @param value: flag value
807        @type value: bool
808        @raise TypeError: input value is incorrect type
809        '''
810        if not isinstance(value, bool):
811            raise TypeError('Expecting bool type for "normalizeResource" '
812                            'attribute; got %r instead' % type(value))
813           
814        self.__normalizeResource = value
815
816    normalizeResource = property(_getNormalizeResource, 
817                                 _setNormalizeResource, 
818                                 doc="Flag to normalize new resource value "
819                                     "assigned to the \"resource\" property.  "
820                                     "The setting only applies for URIs "
821                                     'beginning with "http://" or "https://"')
822
823    def _getSafeNormalizationChars(self):
824        '''Get normalisation safe chars
825        @return: normalisation safe chars
826        @rtype value: basetring
827        '''
828        return self.__safeNormalizationChars
829
830    def _setSafeNormalizationChars(self, value):
831        '''Set normalisation safe chars
832        @param value: normalisation safe chars
833        @type value: basetring
834        @raise TypeError: input value is incorrect type
835        '''
836        if not isinstance(value, basestring):
837            raise TypeError('Expecting string type for "normalizeResource" '
838                            'attribute; got %r instead' % type(value))
839           
840        self.__safeNormalizationChars = value
841
842    safeNormalizationChars = property(_getSafeNormalizationChars, 
843                                      _setSafeNormalizationChars, 
844                                      doc="String containing a list of "
845                                          "characters that should not be "
846                                          "converted when Normalizing the "
847                                          "resource URI.  These are passed to "
848                                          "urllib.quote when the resource "
849                                          "property is set.  The default "
850                                          "characters are '/%'")
851
852    def _getResource(self):
853        '''Gets the Resource attrib value of this statement.
854
855        @return: the Resource attrib value of this statement
856        @rtype: basestring
857        '''
858        return self.__resource
859   
860    def _setResource(self, value):
861        '''Sets the Resource attrib value of this statement normalizing the path
862        component, removing spurious port numbers (80 for HTTP and 443 for
863        HTTPS) and converting the host component to lower case.
864       
865        @param value: the new Resource attrib value of this statement
866        @type: basestring
867        @raise TypeError: input value is incorrect type
868        '''
869        if not isinstance(value, basestring):
870            raise TypeError('Expecting string type for "resource" attribute; '
871                            'got %r instead' % type(value))
872       
873        if (self.normalizeResource and 
874            value.startswith('http://') or value.startswith('https://')):
875            # Normalise the path, set the host name to lower case and remove
876            # port redundant numbers 80 and 443
877            splitResult = urlsplit(value)
878            uriComponents = list(splitResult)
879           
880            # hostname attribute is lowercase
881            uriComponents[1] = splitResult.hostname
882           
883            if splitResult.port is not None:
884                isHttpWithStdPort = (splitResult.port == 80 and 
885                                     splitResult.scheme == 'http')
886               
887                isHttpsWithStdPort = (splitResult.port == 443 and
888                                      splitResult.scheme == 'https')
889               
890                if not isHttpWithStdPort and not isHttpsWithStdPort:
891                    uriComponents[1] += ":%d" % splitResult.port
892           
893            uriComponents[2] = urllib.quote(splitResult.path, 
894                                            self.safeNormalizationChars)
895           
896            self.__resource = urlunsplit(uriComponents)
897        else:
898            self.__resource = value
899   
900    resource = property(fget=_getResource, fset=_setResource,
901                        doc="Resource for which authorisation was requested")
902
903    def _getDecision(self):
904        '''
905        Gets the decision of the authorization request.
906       
907        @return: the decision of the authorization request
908        '''
909        return self.__decision
910
911    def _setDecision(self, value):
912        '''
913        Sets the decision of the authorization request.
914       
915        @param value: the decision of the authorization request
916        @raise TypeError: input value is incorrect type
917        '''
918        if not isinstance(value, DecisionType):
919            raise TypeError('Expecting %r type for "decision" attribute; '
920                            'got %r instead' % (DecisionType, type(value)))
921        self.__decision = value
922
923    decision = property(_getDecision, _setDecision, 
924                        doc="Authorization decision as a DecisionType instance")
925   
926    @property
927    def actions(self):
928        '''The actions for which authorisation is requested
929       
930        @return: the Actions of this statement
931        @rtype: TypedList
932        '''
933        return self.__actions
934   
935    def _getEvidence(self):
936        '''Gets the Evidence of this statement.  Evidence attribute
937        functionality is not currently implemented in this class
938
939        @return: the Evidence of this statement
940        @rtype: None'''
941        return self.__evidence
942
943    def _setEvidence(self, value):
944        '''Sets the Evidence of this statement.  Evidence attribute
945        functionality is not currently implemented in this class
946       
947        @param value: the new Evidence of this statement
948        @type value: None
949        @raise TypeError: input value is incorrect type
950        '''
951        if not isinstance(value, Evidence):
952            raise TypeError('Expecting Evidence type for "evidence" '
953                            'attribute; got %r' % type(value))
954
955        self.__evidence = value 
956
957    evidence = property(fget=_getEvidence, fset=_setEvidence, 
958                        doc="A set of assertions which the Authority may use "
959                            "to base its authorisation decision on")
960   
961    def getOrderedChildren(self):
962        """Get ordered children
963        @return: list actions and evidence for this statement
964        @rtype: tuple
965        """
966        children = []
967
968        superChildren = super(AuthzDecisionStatement, self).getOrderedChildren()
969        if superChildren:
970            children.extend(superChildren)
971
972        children.extend(self.__actions)
973       
974        if self.__evidence is not None:
975            children.extend(self.__evidence)
976
977        if len(children) == 0:
978            return None
979
980        return tuple(children)
981       
982
983class Subject(SAMLObject):
984    '''Implementation of SAML 2.0 Subject
985   
986    @cvar DEFAULT_ELEMENT_LOCAL_NAME: Element local name.
987    @type DEFAULT_ELEMENT_LOCAL_NAME: string
988    @cvar DEFAULT_ELEMENT_NAME: Default element name.
989    @type DEFAULT_ELEMENT_NAME: ndg.saml.common.xml.QName
990    @cvar TYPE_LOCAL_NAME: Local name of the XSI type.
991    @type TYPE_LOCAL_NAME: string
992    @cvar TYPE_NAME: QName of the XSI type.
993    @type TYPE_NAME: ndg.saml.common.xml.QName
994   
995    @ivar __baseID:
996    @type __baseID:
997    @ivar __nameID:
998    @type __nameID:
999    @ivar __encryptedID:
1000    @type __encryptedID:
1001    @ivar __subjectConfirmations:
1002    @type __subjectConfirmations:   
1003    '''
1004   
1005    # Element local name.
1006    DEFAULT_ELEMENT_LOCAL_NAME = "Subject"
1007
1008    # Default element name.
1009    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1010                                 DEFAULT_ELEMENT_LOCAL_NAME,
1011                                 SAMLConstants.SAML20_PREFIX)
1012
1013    # Local name of the XSI type.
1014    TYPE_LOCAL_NAME = "SubjectType"
1015
1016    # QName of the XSI type.
1017    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
1018                      TYPE_LOCAL_NAME,
1019                      SAMLConstants.SAML20_PREFIX)
1020   
1021    __slots__ = (
1022        '__baseID',
1023        '__nameID',
1024        '__encryptedID',
1025        '__subjectConfirmations'
1026    )
1027   
1028    def __init__(self, **kw):
1029        super(Subject, self).__init__(**kw)
1030       
1031        # BaseID child element.
1032        self.__baseID = None
1033   
1034        # NameID child element.
1035        self.__nameID = None
1036   
1037        # EncryptedID child element.
1038        self.__encryptedID = None
1039   
1040        # Subject Confirmations of the Subject.
1041        self.__subjectConfirmations = []
1042
1043    def __getstate__(self):
1044        '''Enable pickling
1045       
1046        @return: object's attribute dictionary
1047        @rtype: dict
1048        '''
1049        _dict = super(Subject, self).__getstate__()
1050        for attrName in Subject.__slots__:
1051            # Ugly hack to allow for derived classes setting private member
1052            # variables
1053            if attrName.startswith('__'):
1054                attrName = "_Subject" + attrName
1055               
1056            _dict[attrName] = getattr(self, attrName)
1057           
1058        return _dict
1059   
1060    def _getBaseID(self): 
1061        return self.__baseID
1062
1063    def _setBaseID(self, value):
1064        if not isinstance(value, basestring):
1065            raise TypeError("Expecting %r type for \"baseID\" got %r" %
1066                            (basestring, value.__class__))
1067        self.__baseID = value
1068
1069    baseID = property(fget=_getBaseID, 
1070                      fset=_setBaseID, 
1071                      doc="Base identifier")
1072     
1073    def _getNameID(self):
1074        return self.__nameID
1075   
1076    def _setNameID(self, value):
1077        if not isinstance(value, NameID):
1078            raise TypeError("Expecting %r type for \"nameID\" got %r" %
1079                            (NameID, type(value)))
1080        self.__nameID = value
1081
1082    nameID = property(fget=_getNameID, 
1083                      fset=_setNameID, 
1084                      doc="Name identifier")
1085   
1086    def _getEncryptedID(self):
1087        return self.__encryptedID
1088   
1089    def _setEncryptedID(self, value): 
1090        self.__encryptedID = value
1091
1092    encryptedID = property(fget=_getEncryptedID, 
1093                           fset=_setEncryptedID, 
1094                           doc="EncryptedID's Docstring")
1095   
1096    def _getSubjectConfirmations(self): 
1097        return self.__subjectConfirmations
1098
1099    subjectConfirmations = property(fget=_getSubjectConfirmations, 
1100                                    doc="Subject Confirmations")   
1101   
1102    def getOrderedChildren(self): 
1103        children = []
1104
1105        if self.baseID is not None:
1106            children.append(self.baseID)
1107       
1108        if self.nameID is not None: 
1109            children.append(self.nameID)
1110       
1111        if self.encryptedID is not None: 
1112            children.append(self.encryptedID)
1113       
1114        children += self.subjectConfirmations
1115
1116        return tuple(children)
1117
1118
1119class AbstractNameIDType(SAMLObject):
1120    '''Abstract implementation of NameIDType'''
1121
1122    # SPNameQualifier attribute name.
1123    SP_NAME_QUALIFIER_ATTRIB_NAME = "SPNameQualifier"
1124
1125    # Format attribute name.
1126    FORMAT_ATTRIB_NAME = "Format"
1127
1128    # SPProviderID attribute name.
1129    SPPROVIDED_ID_ATTRIB_NAME = "SPProvidedID"
1130
1131    # URI for unspecified name format.
1132    UNSPECIFIED = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
1133
1134    # URI for email name format.
1135    EMAIL = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
1136
1137    # URI for X509 subject name format.
1138    X509_SUBJECT = "urn:oasis:names:tc:SAML:1.1:nameid-format:x509SubjectName"
1139
1140    # URI for windows domain qualified name name format.
1141    WIN_DOMAIN_QUALIFIED = \
1142        "urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName"
1143
1144    # URI for kerberos name format.
1145    KERBEROS = "urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos"
1146
1147    # URI for SAML entity name format.
1148    ENTITY = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
1149
1150    # URI for persistent name format.
1151    PERSISTENT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
1152
1153    # URI for transient name format.
1154    TRANSIENT = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
1155
1156    # Special URI used by NameIDPolicy to indicate a NameID should be encrypted
1157    ENCRYPTED = "urn:oasis:names:tc:SAML:2.0:nameid-format:encrypted"
1158   
1159    __slots__ = (
1160        '__name',
1161        '__nameQualifier',
1162        '__spNameQualifier',
1163        '__format',
1164        '__spProvidedID',
1165        '__value'
1166    )
1167   
1168    def __init__(self, **kw): 
1169        '''@param namespaceURI: the namespace the element is in
1170        @param elementLocalName: the local name of the XML element this Object
1171        represents
1172        @param namespacePrefix: the prefix for the given namespace
1173        '''
1174        super(AbstractNameIDType, self).__init__(**kw)
1175   
1176        # Name of the Name ID.
1177        self.__name = None
1178       
1179        # Name Qualifier of the Name ID.
1180        self.__nameQualifier = None
1181   
1182        # SP Name Qualifier of the Name ID.
1183        self.__spNameQualifier = None
1184   
1185        # Format of the Name ID.
1186        self.__format = None
1187   
1188        # SP ProvidedID of the NameID.
1189        self.__spProvidedID = None
1190
1191        self.__value = None
1192
1193    def __getstate__(self):
1194        '''Enable pickling
1195       
1196        @return: object's attribute dictionary
1197        @rtype: dict
1198        '''
1199
1200        _dict = super(AbstractNameIDType, self).__getstate__()
1201        for attrName in AbstractNameIDType.__slots__:
1202            # Ugly hack to allow for derived classes setting private member
1203            # variables
1204            if attrName.startswith('__'):
1205                attrName = "_AbstractNameIDType" + attrName
1206               
1207            _dict[attrName] = getattr(self, attrName)
1208           
1209        return _dict
1210             
1211    def _getValue(self):
1212        return self.__value
1213       
1214    def _setValue(self, value):
1215        if not isinstance(value, basestring):
1216            raise TypeError("\"value\" must be a basestring derived type, "
1217                            "got %r" % value.__class__)
1218           
1219        self.__value = value
1220
1221    value = property(fget=_getValue, fset=_setValue, doc="string value") 
1222   
1223    def _getNameQualifier(self): 
1224        return self.__nameQualifier
1225   
1226    def _setNameQualifier(self, value): 
1227        self.__nameQualifier = value
1228
1229    nameQualifier = property(fget=_getNameQualifier, 
1230                             fset=_setNameQualifier, 
1231                             doc="Name qualifier")   
1232
1233    def _getSPNameQualifier(self): 
1234        return self.__spNameQualifier
1235   
1236    def _setSPNameQualifier(self, value): 
1237        self.__spNameQualifier = value
1238
1239    spNameQualifier = property(fget=_getSPNameQualifier, 
1240                               fset=_setSPNameQualifier, 
1241                               doc="SP Name qualifier")   
1242   
1243    def _getFormat(self):
1244        return self.__format
1245       
1246    def _setFormat(self, format):
1247        if not isinstance(format, basestring):
1248            raise TypeError("\"format\" must be a basestring derived type, "
1249                            "got %r" % format.__class__)
1250           
1251        self.__format = format
1252
1253    format = property(fget=_getFormat, fset=_setFormat, doc="Name format") 
1254   
1255    def _getSPProvidedID(self): 
1256        return self.__spProvidedID
1257   
1258    def _setSPProvidedID(self, value): 
1259        self.__spProvidedID = value
1260
1261    spProvidedID = property(fget=_getSPProvidedID, fset=_setSPProvidedID, 
1262                            doc="SP Provided Identifier") 
1263   
1264    def getOrderedChildren(self): 
1265        raise NotImplementedError()
1266
1267   
1268class Issuer(AbstractNameIDType):
1269    """SAML 2.0 Core Issuer type"""
1270   
1271    # Element local name.
1272    DEFAULT_ELEMENT_LOCAL_NAME = "Issuer"
1273
1274    # Default element name.
1275    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1276                                 DEFAULT_ELEMENT_LOCAL_NAME,
1277                                 SAMLConstants.SAML20_PREFIX)
1278
1279    # Local name of the XSI type.
1280    TYPE_LOCAL_NAME = "IssuerType"
1281
1282    # QName of the XSI type.
1283    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
1284                      TYPE_LOCAL_NAME,
1285                      SAMLConstants.SAML20_PREFIX) 
1286   
1287    __slots__ = ()
1288
1289     
1290class NameID(AbstractNameIDType):
1291    '''SAML 2.0 Core NameID'''
1292    # Element local name.
1293    DEFAULT_ELEMENT_LOCAL_NAME = "NameID"
1294
1295    # Default element name.
1296    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1297                                 DEFAULT_ELEMENT_LOCAL_NAME,
1298                                 SAMLConstants.SAML20_PREFIX)
1299
1300    # Local name of the XSI type.
1301    TYPE_LOCAL_NAME = "NameIDType"
1302
1303    # QName of the XSI type.
1304    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
1305                      TYPE_LOCAL_NAME,
1306                      SAMLConstants.SAML20_PREFIX)
1307   
1308    __slots__ = ()
1309   
1310
1311class Conditions(SAMLObject): 
1312    '''SAML 2.0 Core Conditions.'''
1313   
1314    # Element local name.
1315    DEFAULT_ELEMENT_LOCAL_NAME = "Conditions"
1316
1317    # Default element name.
1318    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1319                                 DEFAULT_ELEMENT_LOCAL_NAME,
1320                                 SAMLConstants.SAML20_PREFIX)
1321
1322    # Local name of the XSI type.
1323    TYPE_LOCAL_NAME = "ConditionsType"
1324
1325    # QName of the XSI type.
1326    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
1327                      TYPE_LOCAL_NAME,
1328                      SAMLConstants.SAML20_PREFIX)
1329
1330    # NotBefore attribute name.
1331    NOT_BEFORE_ATTRIB_NAME = "NotBefore"
1332
1333    # NotOnOrAfter attribute name.
1334    NOT_ON_OR_AFTER_ATTRIB_NAME = "NotOnOrAfter"
1335
1336    __slots__ = (
1337        '__conditions',
1338        '__notBefore',
1339        '__notOnOrAfter'
1340    )
1341   
1342    def __init__(self, **kw):
1343        super(Conditions, self).__init__(**kw)
1344       
1345        # A Condition.
1346        self.__conditions = []
1347   
1348        # Not Before conditions.
1349        self.__notBefore = None
1350   
1351        # Not On Or After conditions.
1352        self.__notOnOrAfter = None
1353
1354    def __getstate__(self):
1355        '''Enable pickling
1356       
1357        @return: object's attribute dictionary
1358        @rtype: dict
1359        '''
1360
1361        _dict = super(Conditions, self).__getstate__()
1362        for attrName in Conditions.__slots__:
1363            # Ugly hack to allow for derived classes setting private member
1364            # variables
1365            if attrName.startswith('__'):
1366                attrName = "_Conditions" + attrName
1367               
1368            _dict[attrName] = getattr(self, attrName)
1369           
1370        return _dict
1371   
1372    def _getNotBefore(self):
1373        '''Get the date/time before which the assertion is invalid.
1374       
1375        @return: the date/time before which the assertion is invalid'''
1376        return self.__notBefore
1377   
1378    def _setNotBefore(self, value):
1379        '''Sets the date/time before which the assertion is invalid.
1380       
1381        @param value: the date/time before which the assertion is invalid
1382        '''
1383        if not isinstance(value, datetime):
1384            raise TypeError('Expecting "datetime" type for "notBefore", '
1385                            'got %r' % type(value))
1386        self.__notBefore = value
1387
1388    def _getNotOnOrAfter(self):
1389        '''Gets the date/time on, or after, which the assertion is invalid.
1390       
1391        @return: the date/time on, or after, which the assertion is invalid'
1392        '''
1393        return self.__notOnOrAfter
1394   
1395    def _setNotOnOrAfter(self, value):
1396        '''Sets the date/time on, or after, which the assertion is invalid.
1397       
1398        @param value: the date/time on, or after, which the assertion
1399        is invalid
1400        '''
1401        if not isinstance(value, datetime):
1402            raise TypeError('Expecting "datetime" type for "notOnOrAfter", '
1403                            'got %r' % type(value))
1404        self.__notOnOrAfter = value 
1405
1406    notBefore = property(_getNotBefore, _setNotBefore, 
1407                         doc="Not before time restriction")
1408
1409    notOnOrAfter = property(_getNotOnOrAfter, _setNotOnOrAfter, 
1410                            doc="Not on or after time restriction")
1411
1412    @property
1413    def conditions(self):
1414        '''All the conditions on the assertion.
1415       
1416        @return: all the conditions on the assertion
1417        '''
1418        return self.__conditions
1419   
1420    def _getAudienceRestrictions(self):
1421        '''Gets the audience restriction conditions for the assertion.
1422       
1423        @return: the audience restriction conditions for the assertion
1424        '''
1425        raise NotImplementedError()
1426
1427    def _getOneTimeUse(self):
1428        '''Gets the OneTimeUse condition for the assertion.
1429       
1430        @return: the OneTimeUse condition for the assertion
1431        '''
1432        raise NotImplementedError()
1433
1434    def _getProxyRestriction(self):   
1435        '''Gets the ProxyRestriction condition for the assertion.
1436       
1437        @return: the ProxyRestriction condition for the assertion
1438        '''
1439        raise NotImplementedError()
1440   
1441   
1442class Advice(SAMLObject):
1443    '''SAML 2.0 Core Advice.
1444    '''
1445
1446    # Element local name
1447    DEFAULT_ELEMENT_LOCAL_NAME = "Advice"
1448
1449    # Default element name.
1450    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1451                                 DEFAULT_ELEMENT_LOCAL_NAME,
1452                                 SAMLConstants.SAML20_PREFIX)
1453
1454    # Local name of the XSI type
1455    TYPE_LOCAL_NAME = "AdviceType"
1456
1457    # QName of the XSI type
1458    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
1459                      TYPE_LOCAL_NAME,
1460                      SAMLConstants.SAML20_PREFIX)
1461
1462    __slots__ = ()
1463   
1464    def _getChildren(self, typeOrName=None):
1465        '''
1466        Gets the list of all child elements attached to this advice.
1467       
1468        @return: the list of all child elements attached to this advice
1469        '''
1470        raise NotImplementedError()
1471
1472    def _getAssertionIDReferences(self):
1473        '''Gets the list of AssertionID references used as advice.
1474       
1475        @return: the list of AssertionID references used as advice
1476        '''
1477        raise NotImplementedError()
1478
1479    def _getAssertionURIReferences(self):
1480        '''Gets the list of AssertionURI references used as advice.
1481       
1482        @return: the list of AssertionURI references used as advice
1483        '''
1484        raise NotImplementedError()
1485   
1486    def _getAssertions(self):
1487        '''Gets the list of Assertions used as advice.
1488       
1489        @return: the list of Assertions used as advice
1490        '''
1491        raise NotImplementedError()
1492   
1493    def _getEncryptedAssertions(self):
1494        '''Gets the list of EncryptedAssertions used as advice.
1495       
1496        @return: the list of EncryptedAssertions used as advice
1497        '''
1498        raise NotImplementedError()
1499       
1500
1501class Assertion(SAMLObject):
1502    """SAML 2.0 Attribute Assertion for use with NERC DataGrid   
1503    """   
1504    # Element local name.
1505    DEFAULT_ELEMENT_LOCAL_NAME = "Assertion"
1506
1507    # Default element name.
1508    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1509                                 DEFAULT_ELEMENT_LOCAL_NAME,
1510                                 SAMLConstants.SAML20_PREFIX)
1511
1512    # Local name of the XSI type.
1513    TYPE_LOCAL_NAME = "AssertionType"
1514
1515    # QName of the XSI type.
1516    TYPE_NAME = QName(SAMLConstants.SAML20_NS, TYPE_LOCAL_NAME,
1517                      SAMLConstants.SAML20_PREFIX)
1518
1519    # Version attribute name.
1520    VERSION_ATTRIB_NAME = "Version"
1521
1522    # IssueInstant attribute name.
1523    ISSUE_INSTANT_ATTRIB_NAME = "IssueInstant"
1524
1525    # ID attribute name.
1526    ID_ATTRIB_NAME = "ID"
1527
1528    __slots__ = (
1529        '__version',
1530        '__issueInstant',
1531        '__id',
1532        '__issuer',
1533        '__subject',
1534        '__conditions',
1535        '__advice',
1536        '__statements',
1537        '__authnStatements',
1538        '__authzDecisionStatements',
1539        '__attributeStatements'
1540    )
1541   
1542    def __init__(self):
1543        # Base class initialisation
1544        super(Assertion, self).__init__()
1545       
1546        self.__version = None
1547        self.__issueInstant = None
1548        self.__id = None
1549        self.__issuer = None
1550        self.__subject = None
1551       
1552        self.__conditions = None
1553        self.__advice = None
1554        self.__statements = TypedList(Statement)
1555       
1556        # TODO: Implement AuthnStatement and AuthzDecisionStatement classes
1557        self.__authnStatements = []
1558        self.__authzDecisionStatements = TypedList(AuthzDecisionStatement)
1559        self.__attributeStatements = TypedList(AttributeStatement)
1560
1561    def __getstate__(self):
1562        '''Enable pickling
1563       
1564        @return: object's attribute dictionary
1565        @rtype: dict
1566        '''
1567
1568        _dict = super(Assertion, self).__getstate__()
1569        for attrName in Assertion.__slots__:
1570            # Ugly hack to allow for derived classes setting private member
1571            # variables
1572            if attrName.startswith('__'):
1573                attrName = "_Assertion" + attrName
1574               
1575            _dict[attrName] = getattr(self, attrName)
1576           
1577        return _dict   
1578                 
1579    def _get_version(self):
1580        '''@return: the SAML Version of this assertion.
1581        '''
1582        return self.__version
1583   
1584    def _set_version(self, version):
1585        '''@param version: the SAML Version of this assertion
1586        '''
1587        if not isinstance(version, SAMLVersion):
1588            raise TypeError("Expecting SAMLVersion type got: %r" % 
1589                            version.__class__)
1590       
1591        self.__version = version
1592       
1593    version = property(fget=_get_version,
1594                       fset=_set_version,
1595                       doc="SAML Version of the assertion")
1596
1597    def _get_issueInstant(self):
1598        '''Gets the issue instance of this assertion.
1599       
1600        @return: the issue instance of this assertion'''
1601        return self.__issueInstant
1602   
1603    def _set_issueInstant(self, issueInstant):
1604        '''Sets the issue instance of this assertion.
1605       
1606        @param issueInstant: the issue instance of this assertion
1607        '''
1608        if not isinstance(issueInstant, datetime):
1609            raise TypeError('Expecting "datetime" type for "issueInstant", '
1610                            'got %r' % issueInstant.__class__)
1611           
1612        self.__issueInstant = issueInstant
1613       
1614    issueInstant = property(fget=_get_issueInstant, 
1615                            fset=_set_issueInstant,
1616                            doc="Issue instant of the assertion")
1617
1618    def _get_id(self):
1619        '''Sets the ID of this assertion.
1620       
1621        @return: the ID of this assertion
1622        '''
1623        return self.__id
1624   
1625    def _set_id(self, _id):
1626        '''Sets the ID of this assertion.
1627       
1628        @param _id: the ID of this assertion
1629        '''
1630        if not isinstance(_id, basestring):
1631            raise TypeError('Expecting basestring derived type for "id", got '
1632                            '%r' % _id.__class__)
1633        self.__id = _id
1634       
1635    id = property(fget=_get_id, fset=_set_id, doc="ID of assertion")
1636   
1637    def _set_issuer(self, issuer):
1638        """Set issuer"""
1639        if not isinstance(issuer, Issuer):
1640            raise TypeError("issuer must be %r, got %r" % (Issuer, 
1641                                                           type(issuer)))
1642        self.__issuer = issuer
1643   
1644    def _get_issuer(self):
1645        """Get the issuer name """
1646        return self.__issuer
1647
1648    issuer = property(fget=_get_issuer, 
1649                      fset=_set_issuer,
1650                      doc="Issuer of assertion")
1651   
1652    def _set_subject(self, subject):
1653        """Set subject string."""
1654        if not isinstance(subject, Subject):
1655            raise TypeError("subject must be %r, got %r" % (Subject, 
1656                                                            type(subject)))
1657
1658        self.__subject = subject
1659   
1660    def _get_subject(self):
1661        """Get subject string."""
1662        return self.__subject
1663
1664    subject = property(fget=_get_subject,
1665                       fset=_set_subject, 
1666                       doc="Attribute Assertion subject")
1667   
1668    def _get_conditions(self):
1669        """Get conditions string."""
1670        return self.__conditions
1671   
1672    def _set_conditions(self, value):
1673        """Get conditions string."""
1674        if not isinstance(value, Conditions):
1675            raise TypeError("Conditions must be %r, got %r" % (Conditions, 
1676                                                               type(value)))
1677
1678        self.__conditions = value
1679
1680    conditions = property(fget=_get_conditions,
1681                          fset=_set_conditions,
1682                          doc="Attribute Assertion conditions")
1683   
1684    def _set_advice(self, advice):
1685        """Set advice string."""
1686        if not isinstance(advice, basestring):
1687            raise TypeError("advice must be a string")
1688
1689        self.__advice = advice
1690   
1691    def _get_advice(self):
1692        """Get advice string."""
1693        return self.__advice
1694
1695    advice = property(fget=_get_advice,
1696                      fset=_set_advice, 
1697                      doc="Attribute Assertion advice")
1698   
1699    @property
1700    def statements(self):
1701        """Attribute Assertion statements"""
1702        return self.__statements
1703   
1704    @property
1705    def authnStatements(self):
1706        """Attribute Assertion authentication"""
1707        return self.__authnStatements
1708   
1709    @property
1710    def authzDecisionStatements(self):
1711        """Attribute Assertion authorisation decision statements"""
1712        return self.__authzDecisionStatements
1713   
1714    @property
1715    def attributeStatements(self):
1716        """Attribute Assertion attribute statements"""
1717        return self.__attributeStatements
1718   
1719
1720class AttributeValue(SAMLObject):
1721    """Base class for Attribute Value type"""
1722   
1723    # Element name, no namespace
1724    DEFAULT_ELEMENT_LOCAL_NAME = "AttributeValue"
1725
1726    # Default element name
1727    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
1728                                 DEFAULT_ELEMENT_LOCAL_NAME,
1729                                 SAMLConstants.SAML20_PREFIX)
1730    __slots__ = ()
1731
1732
1733class XSStringAttributeValue(AttributeValue):
1734    """XML XS:String Attribute Value type"""
1735   
1736    # Local name of the XSI type
1737    TYPE_LOCAL_NAME = "string"
1738       
1739    # QName of the XSI type
1740    TYPE_NAME = QName(SAMLConstants.XSD_NS, 
1741                      TYPE_LOCAL_NAME, 
1742                      SAMLConstants.XSD_PREFIX)
1743   
1744    DEFAULT_FORMAT = "%s#%s" % (SAMLConstants.XSD_NS, TYPE_LOCAL_NAME)
1745 
1746    __slots__ = ('__value',)
1747   
1748    def __init__(self, **kw):
1749        super(XSStringAttributeValue, self).__init__(**kw)
1750        self.__value = None
1751
1752    def __getstate__(self):
1753        '''Enable pickling
1754       
1755        @return: object's attribute dictionary
1756        @rtype: dict
1757        '''
1758
1759        _dict = super(XSStringAttributeValue, self).__getstate__()
1760        for attrName in XSStringAttributeValue.__slots__:
1761            # Ugly hack to allow for derived classes setting private member
1762            # variables
1763            if attrName.startswith('__'):
1764                attrName = "_XSStringAttributeValue" + attrName
1765               
1766            _dict[attrName] = getattr(self, attrName)
1767           
1768        return _dict
1769           
1770    def _getValue(self):
1771        return self.__value
1772       
1773    def _setValue(self, value):
1774        if not isinstance(value, basestring):
1775            raise TypeError("Input must be a basestring derived type, got %r" %
1776                            value.__class__)
1777           
1778        self.__value = value
1779
1780    value = property(fget=_getValue, fset=_setValue, doc="string value") 
1781
1782
1783class StatusDetail(SAMLObject):
1784    '''Implementation of SAML 2.0 StatusDetail'''
1785   
1786    # Local Name of StatusDetail.
1787    DEFAULT_ELEMENT_LOCAL_NAME = "StatusDetail"
1788
1789    # Default element name.
1790    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
1791                                 DEFAULT_ELEMENT_LOCAL_NAME,
1792                                 SAMLConstants.SAML20P_PREFIX)
1793
1794    # Local name of the XSI type.
1795    TYPE_LOCAL_NAME = "StatusDetailType"
1796
1797    # QName of the XSI type.
1798    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
1799                      TYPE_LOCAL_NAME,
1800                      SAMLConstants.SAML20P_PREFIX)
1801   
1802    __slots__ = ('__unknownChildren', )
1803   
1804    def __init__(self, **kw):
1805        super(StatusDetail, self).__init__(**kw)
1806       
1807        # child "any" elements.
1808        self.__unknownChildren = TypedList(SAMLObject)         
1809
1810    def __getstate__(self):
1811        '''Enable pickling
1812       
1813        @return: object's attribute dictionary
1814        @rtype: dict
1815        '''
1816
1817        _dict = super(StatusDetail, self).__getstate__()
1818        for attrName in StatusDetail.__slots__:
1819            # Ugly hack to allow for derived classes setting private member
1820            # variables
1821            if attrName.startswith('__'):
1822                attrName = "_StatusDetail" + attrName
1823               
1824            _dict[attrName] = getattr(self, attrName)
1825           
1826        return _dict
1827   
1828    def getUnknownXMLTypes(self, qname=None): 
1829        if qname is not None:
1830            if not isinstance(qname, QName):
1831                raise TypeError("\"qname\" must be a %r derived type, "
1832                                "got %r" % (QName, type(qname)))
1833               
1834            children = []
1835            for child in self.__unknownChildren:
1836                childQName = getattr(child, "qname", None)
1837                if childQName is not None:
1838                    if childQName.namespaceURI == qname.namespaceURI or \
1839                       childQName.localPart == qname.localPart:
1840                        children.append(child)
1841                       
1842            return children
1843        else:
1844            return self.__unknownChildren
1845   
1846    unknownChildren = property(fget=getUnknownXMLTypes,
1847                               doc="Child objects of Status Detail - may be "
1848                                   "any type")
1849   
1850
1851class StatusMessage(SAMLObject):
1852    '''Implementation of SAML 2.0 Status Message'''
1853
1854    DEFAULT_ELEMENT_LOCAL_NAME = "StatusMessage"
1855    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
1856                                 DEFAULT_ELEMENT_LOCAL_NAME,
1857                                 SAMLConstants.SAML20P_PREFIX)
1858   
1859    __slots__ = ('__value', )
1860   
1861    def __init__(self, **kw):
1862        super(StatusMessage, self).__init__(**kw)
1863       
1864        # Value attribute URI.
1865        self.__value = None       
1866
1867    def __getstate__(self):
1868        '''Enable pickling
1869       
1870        @return: object's attribute dictionary
1871        @rtype: dict
1872        '''
1873
1874        _dict = super(StatusMessage, self).__getstate__()
1875        for attrName in StatusMessage.__slots__:
1876            # Ugly hack to allow for derived classes setting private member
1877            # variables
1878            if attrName.startswith('__'):
1879                attrName = "_StatusMessage" + attrName
1880               
1881            _dict[attrName] = getattr(self, attrName)
1882           
1883        return _dict
1884   
1885    def _getValue(self):
1886        return self.__value
1887       
1888    def _setValue(self, value):
1889        if not isinstance(value, basestring):
1890            raise TypeError("\"value\" must be a basestring derived type, "
1891                            "got %r" % type(value))
1892           
1893        self.__value = value
1894
1895    value = property(fget=_getValue, fset=_setValue, doc="Status message value")
1896
1897
1898class StatusCode(SAMLObject):
1899    '''Implementation of SAML 2.0 StatusCode.'''
1900   
1901    # Local Name of StatusCode.
1902    DEFAULT_ELEMENT_LOCAL_NAME = "StatusCode"
1903
1904    # Default element name.
1905    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
1906                                 DEFAULT_ELEMENT_LOCAL_NAME,
1907                                 SAMLConstants.SAML20P_PREFIX)
1908
1909    # Local name of the XSI type.
1910    TYPE_LOCAL_NAME = "StatusCodeType"
1911
1912    # QName of the XSI type.
1913    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
1914                      TYPE_LOCAL_NAME,
1915                      SAMLConstants.SAML20P_PREFIX)
1916
1917    # Local Name of the Value attribute.
1918    VALUE_ATTRIB_NAME = "Value"
1919
1920    # URI for Success status code.
1921    SUCCESS_URI = "urn:oasis:names:tc:SAML:2.0:status:Success"
1922
1923    # URI for Requester status code.
1924    REQUESTER_URI = "urn:oasis:names:tc:SAML:2.0:status:Requester"
1925
1926    # URI for Responder status code.
1927    RESPONDER_URI = "urn:oasis:names:tc:SAML:2.0:status:Responder"
1928
1929    # URI for VersionMismatch status code.
1930    VERSION_MISMATCH_URI = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch"
1931
1932    # URI for AuthnFailed status code.
1933    AUTHN_FAILED_URI = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"
1934
1935    # URI for InvalidAttrNameOrValue status code.
1936    INVALID_ATTR_NAME_VALUE_URI = \
1937                "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue"
1938
1939    # URI for InvalidNameIDPolicy status code.
1940    INVALID_NAMEID_POLICY_URI = \
1941                "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"
1942
1943    # URI for NoAuthnContext status code.
1944    NO_AUTHN_CONTEXT_URI = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext"
1945
1946    # URI for NoAvailableIDP status code.
1947    NO_AVAILABLE_IDP_URI = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP"
1948
1949    # URI for NoPassive status code.
1950    NO_PASSIVE_URI = "urn:oasis:names:tc:SAML:2.0:status:NoPassive"
1951
1952    # URI for NoSupportedIDP status code.
1953    NO_SUPPORTED_IDP_URI = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP"
1954
1955    # URI for PartialLogout status code.
1956    PARTIAL_LOGOUT_URI = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout"
1957
1958    # URI for ProxyCountExceeded status code.
1959    PROXY_COUNT_EXCEEDED_URI = \
1960                "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded"
1961
1962    # URI for RequestDenied status code.
1963    REQUEST_DENIED_URI = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied"
1964
1965    # URI for RequestUnsupported status code.
1966    REQUEST_UNSUPPORTED_URI = \
1967                "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported"
1968
1969    # URI for RequestVersionDeprecated status code.
1970    REQUEST_VERSION_DEPRECATED_URI = \
1971                "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated"
1972
1973    # URI for RequestVersionTooHigh status code.
1974    REQUEST_VERSION_TOO_HIGH_URI = \
1975                "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh"
1976   
1977    # URI for RequestVersionTooLow status code.
1978    REQUEST_VERSION_TOO_LOW_URI = \
1979                "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow"
1980
1981    # URI for ResourceNotRecognized status code.
1982    RESOURCE_NOT_RECOGNIZED_URI = \
1983                "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized"
1984
1985    # URI for TooManyResponses status code.
1986    TOO_MANY_RESPONSES = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses"
1987
1988    # URI for UnknownAttrProfile status code.
1989    UNKNOWN_ATTR_PROFILE_URI = \
1990                "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile"
1991
1992    # URI for UnknownPrincipal status code.
1993    UNKNOWN_PRINCIPAL_URI = \
1994                "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal"
1995
1996    # URI for UnsupportedBinding status code.
1997    UNSUPPORTED_BINDING_URI = \
1998                "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding"
1999
2000    __slots__ = ('__value', '__childStatusCode',)
2001   
2002    def __init__(self, **kw):
2003        super(StatusCode, self).__init__(**kw)
2004       
2005        # Value attribute URI.
2006        self.__value = None
2007   
2008        # Nested secondary StatusCode child element.
2009        self.__childStatusCode = None
2010
2011    def __getstate__(self):
2012        '''Enable pickling
2013       
2014        @return: object's attribute dictionary
2015        @rtype: dict
2016        '''
2017
2018        _dict = super(StatusCode, self).__getstate__()
2019        for attrName in StatusCode.__slots__:
2020            # Ugly hack to allow for derived classes setting private member
2021            # variables
2022            if attrName.startswith('__'):
2023                attrName = "_StatusCode" + attrName
2024               
2025            _dict[attrName] = getattr(self, attrName)
2026           
2027        return _dict
2028   
2029    def _getStatusCode(self): 
2030        return self.__childStatusCode
2031   
2032    def _setStatusCode(self, value):
2033        if not isinstance(value, StatusCode):
2034            raise TypeError('Child "statusCode" must be a %r derived type, '
2035                            "got %r" % (StatusCode, type(value)))
2036           
2037        self.__childStatusCode = value
2038
2039    value = property(fget=_getStatusCode, 
2040                     fset=_setStatusCode, 
2041                     doc="Child Status code")
2042             
2043    def _getValue(self):
2044        return self.__value
2045       
2046    def _setValue(self, value):
2047        if not isinstance(value, basestring):
2048            raise TypeError("\"value\" must be a basestring derived type, "
2049                            "got %r" % value.__class__)
2050           
2051        self.__value = value
2052
2053    value = property(fget=_getValue, fset=_setValue, doc="Status code value")
2054       
2055
2056class Status(SAMLObject): 
2057    '''SAML 2.0 Core Status'''
2058   
2059    # Local Name of Status.
2060    DEFAULT_ELEMENT_LOCAL_NAME = "Status"
2061
2062    # Default element name.
2063    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
2064                                 DEFAULT_ELEMENT_LOCAL_NAME,
2065                                 SAMLConstants.SAML20P_PREFIX)
2066
2067    # Local name of the XSI type.
2068    TYPE_LOCAL_NAME = "StatusType"
2069
2070    # QName of the XSI type.
2071    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
2072                      TYPE_LOCAL_NAME,
2073                      SAMLConstants.SAML20P_PREFIX)
2074
2075    __slots__ = ('__statusCode', '__statusMessage', '__statusDetail', )
2076   
2077    def __init__(self, **kw):
2078        super(Status, self).__init__(**kw)
2079       
2080        # StatusCode element.
2081        self.__statusCode = None
2082   
2083        # StatusMessage element.
2084        self.__statusMessage = None
2085   
2086        # StatusDetail element.
2087        self.__statusDetail = None
2088       
2089    def __getstate__(self):
2090        '''Enable pickling
2091       
2092        @return: object's attribute dictionary
2093        @rtype: dict
2094        '''
2095
2096        _dict = super(Status, self).__getstate__()
2097        for attrName in Status.__slots__:
2098            # Ugly hack to allow for derived classes setting private member
2099            # variables
2100            if attrName.startswith('__'):
2101                attrName = "_Status" + attrName
2102               
2103            _dict[attrName] = getattr(self, attrName)
2104           
2105        return _dict
2106   
2107    def _getStatusCode(self):
2108        '''
2109        Gets the Code of this Status.
2110       
2111        @return: Status StatusCode
2112        '''
2113        return self.__statusCode
2114
2115    def _setStatusCode(self, value):
2116        '''
2117        Sets the Code of this Status.
2118       
2119        @param value: the Code of this Status
2120        '''
2121        if not isinstance(value, StatusCode):
2122            raise TypeError('"statusCode" must be a %r derived type, '
2123                            "got %r" % (StatusCode, type(value)))
2124           
2125        self.__statusCode = value
2126       
2127    statusCode = property(fget=_getStatusCode,
2128                          fset=_setStatusCode,
2129                          doc="status code object")
2130   
2131    def _getStatusMessage(self):
2132        '''
2133        Gets the Message of this Status.
2134       
2135        @return: Status StatusMessage
2136        '''
2137        return self.__statusMessage
2138
2139    def _setStatusMessage(self, value):
2140        '''
2141        Sets the Message of this Status.
2142       
2143        @param value: the Message of this Status
2144        '''
2145        if not isinstance(value, StatusMessage):
2146            raise TypeError('"statusMessage" must be a %r derived type, '
2147                            "got %r" % (StatusMessage, type(value)))
2148           
2149        self.__statusMessage = value
2150       
2151    statusMessage = property(fget=_getStatusMessage,
2152                             fset=_setStatusMessage,
2153                             doc="status message")
2154
2155    def _getStatusDetail(self):
2156        '''
2157        Gets the Detail of this Status.
2158       
2159        @return: Status StatusDetail
2160        '''
2161        return self.__statusDetail
2162   
2163    def _setStatusDetail(self, value):
2164        '''
2165        Sets the Detail of this Status.
2166       
2167        @param value: the Detail of this Status
2168        '''
2169        self.__statusDetail = value
2170       
2171    statusDetail = property(fget=_getStatusDetail,
2172                            fset=_setStatusDetail,
2173                            doc="status message")
2174
2175
2176class Action(SAMLObject): 
2177    '''SAML 2.0 Core Action'''
2178   
2179    # Element local name.
2180    DEFAULT_ELEMENT_LOCAL_NAME = "Action"
2181
2182    # Default element name.
2183    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2184                                 DEFAULT_ELEMENT_LOCAL_NAME,
2185                                 SAMLConstants.SAML20_PREFIX)
2186
2187    # Local name of the XSI type.
2188    TYPE_LOCAL_NAME = "ActionType"
2189
2190    # QName of the XSI type
2191    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
2192                      TYPE_LOCAL_NAME,
2193                      SAMLConstants.SAML20_PREFIX)
2194
2195    # Name of the Namespace attribute.
2196    NAMESPACE_ATTRIB_NAME = "Namespace"
2197
2198    # Read/Write/Execute/Delete/Control action namespace.
2199    RWEDC_NS_URI = "urn:oasis:names:tc:SAML:1.0:action:rwedc"
2200
2201    # Read/Write/Execute/Delete/Control negation action namespace.
2202    RWEDC_NEGATION_NS_URI = "urn:oasis:names:tc:SAML:1.0:action:rwedc-negation"
2203
2204    # Get/Head/Put/Post action namespace.
2205    GHPP_NS_URI = "urn:oasis:names:tc:SAML:1.0:action:ghpp"
2206
2207    # UNIX file permission action namespace.
2208    UNIX_NS_URI = "urn:oasis:names:tc:SAML:1.0:action:unix"
2209
2210    ACTION_NS_IDENTIFIERS = (
2211        RWEDC_NS_URI,
2212        RWEDC_NEGATION_NS_URI,   
2213        GHPP_NS_URI,
2214        UNIX_NS_URI       
2215    )
2216   
2217    # Read action.
2218    READ_ACTION = "Read"
2219
2220    # Write action.
2221    WRITE_ACTION = "Write"
2222
2223    # Execute action.
2224    EXECUTE_ACTION = "Execute"
2225
2226    # Delete action.
2227    DELETE_ACTION = "Delete"
2228
2229    # Control action.
2230    CONTROL_ACTION = "Control"
2231
2232    # Negated Read action.
2233    NEG_READ_ACTION = "~Read"
2234
2235    # Negated Write action.
2236    NEG_WRITE_ACTION = "~Write"
2237
2238    # Negated Execute action.
2239    NEG_EXECUTE_ACTION = "~Execute"
2240
2241    # Negated Delete action.
2242    NEG_DELETE_ACTION = "~Delete"
2243
2244    # Negated Control action.
2245    NEG_CONTROL_ACTION = "~Control"
2246
2247    # HTTP GET action.
2248    HTTP_GET_ACTION = "GET"
2249
2250    # HTTP HEAD action.
2251    HTTP_HEAD_ACTION = "HEAD"
2252
2253    # HTTP PUT action.
2254    HTTP_PUT_ACTION = "PUT"
2255
2256    # HTTP POST action.
2257    HTTP_POST_ACTION = "POST"
2258   
2259    ACTION_TYPES = {
2260        RWEDC_NS_URI: (READ_ACTION, WRITE_ACTION, EXECUTE_ACTION, DELETE_ACTION,
2261                       CONTROL_ACTION),
2262        RWEDC_NEGATION_NS_URI: (READ_ACTION, WRITE_ACTION, EXECUTE_ACTION, 
2263                                DELETE_ACTION, CONTROL_ACTION, NEG_READ_ACTION, 
2264                                NEG_WRITE_ACTION, NEG_EXECUTE_ACTION, 
2265                                NEG_CONTROL_ACTION),   
2266        GHPP_NS_URI: (HTTP_GET_ACTION, HTTP_HEAD_ACTION, HTTP_PUT_ACTION,
2267                      HTTP_POST_ACTION),
2268                     
2269        # This namespace uses octal bitmask for file permissions
2270        UNIX_NS_URI: ()   
2271    }
2272   
2273    __slots__ = ('__namespace', '__value', '__actionTypes')
2274   
2275    def __init__(self, **kw):
2276        '''Create an authorization action type
2277        '''
2278        super(Action, self).__init__(**kw)
2279
2280        # URI of the Namespace of this action.  Default to read/write/negation
2281        # type - 2.7.4.2 SAML 2 Core Spec. 15 March 2005
2282        self.__namespace = Action.RWEDC_NEGATION_NS_URI
2283
2284        # Action value
2285        self.__value = None       
2286   
2287        self.__actionTypes = Action.ACTION_TYPES
2288       
2289    def __getstate__(self):
2290        '''Enable pickling
2291       
2292        @return: object's attribute dictionary
2293        @rtype: dict
2294        '''
2295
2296        _dict = super(Action, self).__getstate__()
2297        for attrName in Action.__slots__:
2298            # Ugly hack to allow for derived classes setting private member
2299            # variables
2300            if attrName.startswith('__'):
2301                attrName = "_Action" + attrName
2302               
2303            _dict[attrName] = getattr(self, attrName)
2304           
2305        return _dict
2306   
2307    def _getActionTypes(self):
2308        return self.__actionTypes
2309
2310    def _setActionTypes(self, value):
2311        if not isinstance(value, dict):
2312            raise TypeError('Expecting list or tuple type for "actionTypes" '
2313                            'attribute; got %r' % type(value))
2314           
2315        for k, v in value.items():
2316            if not isinstance(v, (tuple, type(None))):
2317                raise TypeError('Expecting None or tuple type for '
2318                                '"actionTypes" dictionary values; got %r for '
2319                                '%r key' % (type(value), k))
2320        self.__actionTypes = value
2321
2322    actionTypes = property(_getActionTypes, 
2323                           _setActionTypes, 
2324                           doc="Restrict vocabulary of action types")
2325       
2326    def _getNamespace(self):
2327        '''
2328        gets the namespace scope of the specified value.
2329       
2330        @return: the namespace scope of the specified value
2331        '''
2332        return self.__namespace
2333
2334    def _setNamespace(self, value):
2335        '''Sets the namespace scope of the specified value.
2336       
2337        @param value: the namespace scope of the specified value
2338        '''
2339        if not isinstance(value, basestring):
2340            raise TypeError('Expecting string type for "namespace" '
2341                            'attribute; got %r' % type(value))
2342           
2343        if value not in self.__actionTypes.keys():
2344            raise AttributeError('"namespace" action type %r not recognised. '
2345                                 'It must be one of these action types: %r' % 
2346                                 self.__actionTypes.keys())
2347           
2348        self.__namespace = value
2349
2350    namespace = property(_getNamespace, _setNamespace, doc="Action Namespace")
2351
2352    def _getValue(self):
2353        '''gets the URI of the action to be performed.
2354       
2355        @return: the URI of the action to be performed
2356        '''
2357        return self.__value
2358
2359    def _setValue(self, value):
2360        '''Sets the URI of the action to be performed.
2361       
2362        @param value: the URI of the value to be performed
2363        '''
2364        # int and oct allow for UNIX file permissions action type
2365        if not isinstance(value, (basestring, int)):
2366            raise TypeError('Expecting string or int type for "action" '
2367                            'attribute; got %r' % type(value))
2368           
2369        # Default to read/write/negation type - 2.7.4.2 SAML 2 Core Spec.
2370        # 15 March 2005
2371        allowedActions = self.__actionTypes.get(self.__namespace,
2372                                                Action.RWEDC_NEGATION_NS_URI)
2373       
2374        # Only apply restriction for action type that has a restricted
2375        # vocabulary - UNIX type is missed out of this because its an octal
2376        # mask
2377        if len(allowedActions) > 0 and value not in allowedActions:
2378            raise AttributeError('%r action not recognised; known actions for '
2379                                 'the %r namespace identifier are: %r.  ' 
2380                                 'If this is not as expected make sure to set '
2381                                 'the "namespace" attribute to an alternative '
2382                                 'value first or override completely by '
2383                                 'explicitly setting the "allowTypes" '
2384                                 'attribute' % 
2385                                 (value, self.__namespace, allowedActions))
2386        self.__value = value
2387
2388    value = property(_getValue, _setValue, doc="Action string")
2389       
2390
2391class RequestAbstractType(SAMLObject): 
2392    '''SAML 2.0 Core RequestAbstractType'''
2393   
2394    # Local name of the XSI type.
2395    TYPE_LOCAL_NAME = "RequestAbstractType"
2396
2397    # QName of the XSI type.
2398    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
2399                      TYPE_LOCAL_NAME,
2400                      SAMLConstants.SAML20P_PREFIX)
2401
2402    # ID attribute name.
2403    ID_ATTRIB_NAME = "ID"
2404
2405    # Version attribute name.
2406    VERSION_ATTRIB_NAME = "Version"
2407
2408    # IssueInstant attribute name.
2409    ISSUE_INSTANT_ATTRIB_NAME = "IssueInstant"
2410
2411    # Destination attribute name.
2412    DESTINATION_ATTRIB_NAME = "Destination"
2413
2414    # Consent attribute name.
2415    CONSENT_ATTRIB_NAME = "Consent"
2416
2417    # Unspecified consent URI.
2418    UNSPECIFIED_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:unspecified"
2419
2420    # Obtained consent URI.
2421    OBTAINED_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:obtained"
2422
2423    # Prior consent URI.
2424    PRIOR_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:prior"
2425
2426    # Implicit consent URI.
2427    IMPLICIT_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:implicit"
2428
2429    # Explicit consent URI.
2430    EXPLICIT_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:explicit"
2431
2432    # Unavailable consent URI.
2433    UNAVAILABLE_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:unavailable"
2434
2435    # Inapplicable consent URI.
2436    INAPPLICABLE_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:inapplicable"
2437     
2438    __slots__ = (
2439        '__version',
2440        '__id',
2441        '__issueInstant',
2442        '__destination',
2443        '__consent',
2444        '__issuer',
2445        '__extensions'
2446    )
2447   
2448    def __init__(self, **kw):
2449        '''Request abstract type
2450        @type kw: dict
2451        @param kw: see SAMLObject.__init__
2452        '''
2453        super(RequestAbstractType, self).__init__(**kw)
2454       
2455        # SAML Version of the request.
2456        self.__version = None
2457   
2458        # Unique identifier of the request.
2459        self.__id = None
2460   
2461        # Date/time request was issued.
2462        self.__issueInstant = None
2463   
2464        # URI of the request destination.
2465        self.__destination = None
2466   
2467        # URI of the SAML user consent type.
2468        self.__consent = None
2469   
2470        # URI of the SAML user consent type.
2471        self.__issuer = None
2472   
2473        # Extensions child element.
2474        self.__extensions = None
2475
2476    def __getstate__(self):
2477        '''Enable pickling
2478       
2479        @return: object's attribute dictionary
2480        @rtype: dict
2481        '''
2482
2483        _dict = super(RequestAbstractType, self).__getstate__()
2484        for attrName in RequestAbstractType.__slots__:
2485            # Ugly hack to allow for derived classes setting private member
2486            # variables
2487            if attrName.startswith('__'):
2488                attrName = "_RequestAbstractType" + attrName
2489               
2490            _dict[attrName] = getattr(self, attrName)
2491           
2492        return _dict
2493   
2494    def _get_version(self):
2495        '''@return: the SAML Version of this assertion.
2496        '''
2497        return self.__version
2498   
2499    def _set_version(self, version):
2500        '''@param version: the SAML Version of this assertion
2501        '''
2502        if not isinstance(version, SAMLVersion):
2503            raise TypeError("Expecting SAMLVersion type got: %r" % 
2504                            version.__class__)
2505       
2506        self.__version = version
2507       
2508    version = property(fget=_get_version,
2509                       fset=_set_version,
2510                       doc="SAML Version of the assertion")
2511
2512    def _get_issueInstant(self):
2513        '''Gets the date/time the request was issued
2514       
2515        @return: the issue instance of this request'''
2516        return self.__issueInstant
2517   
2518    def _set_issueInstant(self, value):
2519        '''Sets the date/time the request was issued
2520       
2521        @param value: the issue instance of this request
2522        '''
2523        if not isinstance(value, datetime):
2524            raise TypeError('Expecting "datetime" type for "issueInstant", '
2525                            'got %r' % type(value))
2526           
2527        self.__issueInstant = value
2528       
2529    issueInstant = property(fget=_get_issueInstant, 
2530                            fset=_set_issueInstant,
2531                            doc="Issue instant of the request") 
2532
2533    def _get_id(self):
2534        '''Sets the unique identifier for this request.
2535       
2536        @return: the ID of this request
2537        '''
2538        return self.__id
2539   
2540    def _set_id(self, value):
2541        '''Sets the unique identifier for this request
2542       
2543        @param value: the ID of this assertion
2544        '''
2545        if not isinstance(value, basestring):
2546            raise TypeError('Expecting basestring derived type for "id", got '
2547                            '%r' % type(value))
2548        self.__id = value
2549       
2550    id = property(fget=_get_id, fset=_set_id, doc="ID of request")
2551
2552    def _get_destination(self):
2553        '''Gets the URI of the destination of the request.
2554       
2555        @return: the URI of the destination of the request
2556        '''
2557        return self.__destination
2558   
2559    def _set_destination(self, value):
2560        '''Sets the URI of the destination of the request.
2561       
2562        @param value: the URI of the destination of the request'''
2563        if not isinstance(value, basestring):
2564            raise TypeError('Expecting basestring derived type for '
2565                            '"destination", got %r' % type(value))
2566        self.__destination = value
2567       
2568    destination = property(fget=_get_destination, 
2569                           fset=_set_destination,
2570                           doc="Destination of request")
2571     
2572    def _get_consent(self):
2573        '''Gets the consent obtained from the principal for sending this
2574        request.
2575       
2576        @return: the consent obtained from the principal for sending this
2577        request
2578        '''
2579        return self.__consent
2580       
2581    def _set_consent(self, value):
2582        '''Sets the consent obtained from the principal for sending this
2583        request.
2584       
2585        @param value: the new consent obtained from the principal for
2586        sending this request
2587        ''' 
2588        if not isinstance(value, basestring):
2589            raise TypeError('Expecting basestring derived type for "consent", '
2590                            'got %r' % type(value))
2591        self.__consent = value
2592             
2593    consent = property(fget=_get_consent, 
2594                       fset=_set_consent,
2595                       doc="Consent for request")
2596   
2597    def _set_issuer(self, issuer):
2598        """Set issuer of request"""
2599        if not isinstance(issuer, Issuer):
2600            raise TypeError('"issuer" must be a %r, got %r' % (Issuer, 
2601                                                               type(issuer)))
2602       
2603        self.__issuer = issuer
2604   
2605    def _get_issuer(self):
2606        """Get the issuer name """
2607        return self.__issuer
2608
2609    issuer = property(fget=_get_issuer, 
2610                      fset=_set_issuer,
2611                      doc="Issuer of request")
2612 
2613    def _get_extensions(self):
2614        '''Gets the Extensions of this request.
2615       
2616        @return: the Status of this request
2617        '''
2618        return self.__extensions
2619     
2620    def _set_extensions(self, value):
2621        '''Sets the Extensions of this request.
2622       
2623        @param value: the Extensions of this request
2624        '''
2625        self.__extensions = value
2626       
2627    extensions = property(fget=_get_extensions, 
2628                          fset=_set_extensions,
2629                          doc="Request extensions")
2630
2631
2632class SubjectQuery(RequestAbstractType):
2633    """SAML 2.0 Core Subject Query type"""
2634   
2635    DEFAULT_ELEMENT_LOCAL_NAME = 'SubjectQuery'
2636   
2637    __slots__ = ('__subject', )
2638   
2639    def __init__(self):
2640        super(SubjectQuery, self).__init__()
2641        self.__subject = None
2642
2643    def __getstate__(self):
2644        '''Enable pickling
2645       
2646        @return: object's attribute dictionary
2647        @rtype: dict
2648        '''
2649
2650        _dict = super(SubjectQuery, self).__getstate__()
2651        for attrName in SubjectQuery.__slots__:
2652            # Ugly hack to allow for derived classes setting private member
2653            # variables
2654            if attrName.startswith('__'):
2655                attrName = "_SubjectQuery" + attrName
2656               
2657            _dict[attrName] = getattr(self, attrName)
2658           
2659        return _dict
2660           
2661    def _getSubject(self):
2662        '''Gets the Subject of this request.
2663       
2664        @return: the Subject of this request'''   
2665        return self.__subject
2666   
2667    def _setSubject(self, value):
2668        '''Sets the Subject of this request.
2669       
2670        @param value: the Subject of this request'''
2671        if not isinstance(value, Subject):
2672            raise TypeError('Setting "subject", got %r, expecting %r' %
2673                            (Subject, type(value)))
2674           
2675        self.__subject = value
2676       
2677    subject = property(fget=_getSubject, fset=_setSubject, doc="Query subject")
2678   
2679   
2680class AttributeQuery(SubjectQuery):
2681    '''SAML 2.0 AttributeQuery'''
2682   
2683    # Element local name.
2684    DEFAULT_ELEMENT_LOCAL_NAME = "AttributeQuery"
2685
2686    # Default element name.
2687    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
2688                                 DEFAULT_ELEMENT_LOCAL_NAME,
2689                                 SAMLConstants.SAML20P_PREFIX)
2690
2691    # Local name of the XSI type.
2692    TYPE_LOCAL_NAME = "AttributeQueryType"
2693
2694    # QName of the XSI type.
2695    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
2696                      TYPE_LOCAL_NAME,
2697                      SAMLConstants.SAML20P_PREFIX)
2698
2699    __slots__ = ('__attributes',)
2700   
2701    def __init__(self):
2702        super(AttributeQuery, self).__init__()
2703        self.__attributes = TypedList(Attribute)
2704
2705    def __getstate__(self):
2706        '''Enable pickling
2707       
2708        @return: object's attribute dictionary
2709        @rtype: dict
2710        '''
2711
2712        _dict = super(AttributeQuery, self).__getstate__()
2713        for attrName in AttributeQuery.__slots__:
2714            # Ugly hack to allow for derived classes setting private member
2715            # variables
2716            if attrName.startswith('__'):
2717                attrName = "_AttributeQuery" + attrName
2718               
2719            _dict[attrName] = getattr(self, attrName)
2720           
2721        return _dict
2722 
2723    def _getAttributes(self):
2724        '''Gets the Attributes of this query.
2725       
2726        @return: the list of Attributes of this query'''
2727        return self.__attributes
2728
2729    def _setAttributes(self, value):
2730        self.__attributes = value
2731
2732    attributes = property(fget=_getAttributes, 
2733                          fset=_setAttributes, 
2734                          doc="Attributes")
2735
2736
2737class Evidentiary(SAMLObject):
2738    """Base class for types set in an evidence object"""
2739    __slots__ = ()
2740
2741
2742class AssertionURIRef(Evidentiary):
2743    '''SAML 2.0 Core AssertionURIRef'''
2744    __slots__ = ('__assertionURI',)
2745   
2746    # Element local name
2747    DEFAULT_ELEMENT_LOCAL_NAME = "AssertionURIRef"
2748
2749    # Default element name
2750    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2751                                 DEFAULT_ELEMENT_LOCAL_NAME,
2752                                 SAMLConstants.SAML20_PREFIX)
2753   
2754    def __init__(self):
2755        '''Create assertion URI reference'''
2756        super(AssertionURIRef, self).__init__()
2757       
2758        # URI of the Assertion
2759        self.__assertionURI = None   
2760
2761    def __getstate__(self):
2762        '''Enable pickling
2763       
2764        @return: object's attribute dictionary
2765        @rtype: dict
2766        '''
2767
2768        _dict = super(AssertionURIRef, self).__getstate__()
2769        for attrName in AssertionURIRef.__slots__:
2770            # Ugly hack to allow for derived classes setting private member
2771            # variables
2772            if attrName.startswith('__'):
2773                attrName = "_AssertionURIRef" + attrName
2774               
2775            _dict[attrName] = getattr(self, attrName)
2776           
2777        return _dict
2778   
2779    def _getAssertionURI(self):
2780        return self.__assertionURI
2781
2782    def _setAssertionURI(self, value):
2783        if not isinstance(value, basestring):
2784            raise TypeError('Expecting string type for "assertionID" '
2785                            'attribute; got %r' % type(value))
2786        self.__assertionURI = value
2787
2788    def getOrderedChildren(self):
2789        return None
2790
2791    assertionURI = property(_getAssertionURI, _setAssertionURI, 
2792                            doc="Assertion URI")
2793   
2794   
2795class AssertionIDRef(Evidentiary):
2796    '''SAML 2.0 Core AssertionIDRef.'''
2797
2798    # Element local name.
2799    DEFAULT_ELEMENT_LOCAL_NAME = "AssertionIDRef"
2800
2801    # Default element name.
2802    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2803                                 DEFAULT_ELEMENT_LOCAL_NAME,
2804                                 SAMLConstants.SAML20_PREFIX)
2805   
2806    __slots__ = ("_AssertionID",)
2807   
2808    def __init__(self, namespaceURI, elementLocalName, namespacePrefix):
2809        '''
2810        @param namespaceURI: the namespace the element is in
2811        @param elementLocalName: the local name of the XML element this Object
2812        represents
2813        @param namespacePrefix: the prefix for the given namespace
2814        '''
2815        super(AssertionIDRef, self).__init__(namespaceURI, 
2816                                             elementLocalName, 
2817                                             namespacePrefix)
2818        self.__assertionID = None
2819
2820    def __getstate__(self):
2821        '''Enable pickling
2822       
2823        @return: object's attribute dictionary
2824        @rtype: dict
2825        '''
2826
2827        _dict = super(AssertionIDRef, self).__getstate__()
2828        for attrName in AssertionIDRef.__slots__:
2829            # Ugly hack to allow for derived classes setting private member
2830            # variables
2831            if attrName.startswith('__'):
2832                attrName = "_AssertionIDRef" + attrName
2833               
2834            _dict[attrName] = getattr(self, attrName)
2835           
2836        return _dict
2837       
2838    def _getAssertionID(self):
2839        '''Gets the ID of the assertion this references.
2840       
2841        @return: the ID of the assertion this references'''
2842        return self.__assertionID
2843       
2844    def _setAssertionID(self, value):
2845        '''Sets the ID of the assertion this references.
2846       
2847        @param value: the ID of the assertion this references'''
2848        if not isinstance(value, basestring):
2849            raise TypeError('Expecting string type for "assertionID" '
2850                            'attribute; got %r' % type(value))
2851        self.__assertionID = value
2852
2853    def getOrderedChildren(self):
2854        return None
2855
2856    assertionID = property(_getAssertionID, _setAssertionID, 
2857                           doc="Assertion ID")
2858       
2859   
2860class EncryptedElementType(SAMLObject):
2861    '''SAML 2.0 Core EncryptedElementType'''
2862   
2863    # Local name of the XSI type.
2864    TYPE_LOCAL_NAME = "EncryptedElementType"
2865       
2866    # QName of the XSI type.
2867    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
2868                      TYPE_LOCAL_NAME, 
2869                      SAMLConstants.SAML20_PREFIX)
2870   
2871    __slots__ = ()
2872   
2873    def _getEncryptedData(self):
2874        '''Get the EncryptedData child element.
2875       
2876        @return the EncryptedData child element'''
2877        raise NotImplementedError()
2878   
2879    def _setEncryptedData(self, value):
2880        '''Set the EncryptedData child element.
2881       
2882        @param newEncryptedData the new EncryptedData child element'''
2883        raise NotImplementedError()
2884   
2885    def _getEncryptedKeys(self):
2886        '''A list of EncryptedKey child elements.
2887       
2888        @return a list of EncryptedKey child elements'''
2889        raise NotImplementedError()
2890   
2891   
2892class EncryptedAssertion(EncryptedElementType, Evidentiary):
2893    '''SAML 2.0 Core EncryptedAssertion.'''
2894   
2895    # Element local name.
2896    DEFAULT_ELEMENT_LOCAL_NAME = "EncryptedAssertion"
2897
2898    # Default element name.
2899    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2900                                 DEFAULT_ELEMENT_LOCAL_NAME,
2901                                 SAMLConstants.SAML20_PREFIX) 
2902    __slots__ = ()
2903     
2904   
2905class Evidence(SAMLObject):
2906    '''SAML 2.0 Core Evidence.'''
2907   
2908    # Element local name.
2909    DEFAULT_ELEMENT_LOCAL_NAME = "Evidence"
2910   
2911    # Default element name.
2912    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20_NS, 
2913                                 DEFAULT_ELEMENT_LOCAL_NAME, 
2914                                 SAMLConstants.SAML20_PREFIX)
2915   
2916    # Local name of the XSI type.
2917    TYPE_LOCAL_NAME = "EvidenceType" 
2918       
2919    # QName of the XSI type.
2920    TYPE_NAME = QName(SAMLConstants.SAML20_NS, 
2921                      TYPE_LOCAL_NAME, 
2922                      SAMLConstants.SAML20_PREFIX)
2923
2924    __slots__ = ('__values',)
2925   
2926    def __init__(self, **kw):
2927        '''Create an authorization evidence type
2928        '''
2929        super(Evidence, self).__init__(**kw)
2930
2931        # Assertion of the Evidence.
2932        self.__values = TypedList(Evidentiary) 
2933
2934    def __getstate__(self):
2935        '''Enable pickling
2936       
2937        @return: object's attribute dictionary
2938        @rtype: dict
2939        '''
2940
2941        _dict = super(Evidence, self).__getstate__()
2942        for attrName in Evidence.__slots__:
2943            # Ugly hack to allow for derived classes setting private member
2944            # variables
2945            if attrName.startswith('__'):
2946                attrName = "_Evidence" + attrName
2947               
2948            _dict[attrName] = getattr(self, attrName)
2949           
2950        return _dict   
2951         
2952    @property
2953    def assertionIDReferences(self):
2954        '''Gets the list of AssertionID references used as evidence.
2955   
2956        @return: the list of AssertionID references used as evidence'''
2957        return [i for i in self.__values
2958                if (getattr(i, "DEFAULT_ELEMENT_NAME") == 
2959                    AssertionIDRef.DEFAULT_ELEMENT_NAME)]
2960   
2961    @property
2962    def assertionURIReferences(self):
2963        '''Gets the list of AssertionURI references used as evidence.
2964       
2965        @return: the list of AssertionURI references used as evidence'''
2966        return [i for i in self.__values
2967                if (getattr(i, "DEFAULT_ELEMENT_NAME") == 
2968                    AssertionURIRef.DEFAULT_ELEMENT_NAME)]
2969   
2970    @property
2971    def assertions(self):
2972        '''Gets the list of Assertions used as evidence.
2973       
2974        @return: the list of Assertions used as evidence'''
2975        return [i for i in self.__values
2976                if (getattr(i, "DEFAULT_ELEMENT_NAME") == 
2977                    Assertion.DEFAULT_ELEMENT_NAME)]
2978   
2979    @property
2980    def encryptedAssertions(self):
2981        '''Gets the list of EncryptedAssertions used as evidence.
2982       
2983        @return: the list of EncryptedAssertions used as evidence'''
2984        return [i for i in self.__values
2985                if (getattr(i, "DEFAULT_ELEMENT_NAME") == 
2986                    EncryptedAssertion.DEFAULT_ELEMENT_NAME)]   
2987
2988    @property
2989    def values(self):
2990        '''Gets the list of all elements used as evidence.
2991       
2992        @return: the list of Evidentiary objects used as evidence'''
2993        return self.__values
2994   
2995    def getOrderedChildren(self):
2996        children = []
2997
2998        if len(self.__values) == 0:
2999            return None
3000
3001        children.extend(self.__values)
3002
3003        return tuple(children)
3004   
3005
3006class AuthzDecisionQuery(SubjectQuery):
3007    '''SAML 2.0 AuthzDecisionQuery.'''
3008
3009    # Element local name.
3010    DEFAULT_ELEMENT_LOCAL_NAME = "AuthzDecisionQuery"
3011
3012    # Default element name.
3013    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
3014                                 DEFAULT_ELEMENT_LOCAL_NAME,
3015                                 SAMLConstants.SAML20P_PREFIX)
3016
3017    # Local name of the XSI type.
3018    TYPE_LOCAL_NAME = "AuthzDecisionQueryType"
3019
3020    # QName of the XSI type.
3021    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
3022                      TYPE_LOCAL_NAME,
3023                      SAMLConstants.SAML20P_PREFIX)
3024
3025    # Resource attribute name.
3026    RESOURCE_ATTRIB_NAME = "Resource"
3027   
3028    __slots__ = (
3029       '__resource',
3030       '__evidence',
3031       '__actions',
3032       '__normalizeResource',
3033       '__safeNormalizationChars'
3034    )
3035   
3036    def __init__(self, normalizeResource=True, safeNormalizationChars='/%'):
3037        '''Create new authorisation decision query
3038        '''
3039        super(AuthzDecisionQuery, self).__init__()
3040
3041        # Resource attribute value.
3042        self.__resource = None
3043   
3044        # Evidence child element.
3045        self.__evidence = None
3046   
3047        # Action child elements.
3048        self.__actions = TypedList(Action)   
3049       
3050        # Tuning for normalization of resource URIs in property set method
3051        self.normalizeResource = normalizeResource
3052        self.safeNormalizationChars = safeNormalizationChars
3053
3054    def __getstate__(self):
3055        '''Enable pickling
3056       
3057        @return: object's attribute dictionary
3058        @rtype: dict
3059        '''
3060
3061        _dict = super(AuthzDecisionQuery, self).__getstate__()
3062        for attrName in AuthzDecisionQuery.__slots__:
3063            # Ugly hack to allow for derived classes setting private member
3064            # variables
3065            if attrName.startswith('__'):
3066                attrName = "_AuthzDecisionQuery" + attrName
3067               
3068            _dict[attrName] = getattr(self, attrName)
3069           
3070        return _dict
3071   
3072    def _getNormalizeResource(self):
3073        return self.__normalizeResource
3074
3075    def _setNormalizeResource(self, value):
3076        if not isinstance(value, bool):
3077            raise TypeError('Expecting bool type for "normalizeResource" '
3078                            'attribute; got %r instead' % type(value))
3079           
3080        self.__normalizeResource = value
3081
3082    normalizeResource = property(_getNormalizeResource, 
3083                                 _setNormalizeResource, 
3084                                 doc="Flag to normalize new resource value "
3085                                     "assigned to the \"resource\" property.  "
3086                                     "The setting only applies for URIs "
3087                                     'beginning with "http://" or "https://"')
3088
3089    def _getSafeNormalizationChars(self):
3090        return self.__safeNormalizationChars
3091
3092    def _setSafeNormalizationChars(self, value):
3093        if not isinstance(value, basestring):
3094            raise TypeError('Expecting string type for "normalizeResource" '
3095                            'attribute; got %r instead' % type(value))
3096           
3097        self.__safeNormalizationChars = value
3098
3099    safeNormalizationChars = property(_getSafeNormalizationChars, 
3100                                      _setSafeNormalizationChars, 
3101                                      doc="String containing a list of "
3102                                          "characters that should not be "
3103                                          "converted when Normalizing the "
3104                                          "resource URI.  These are passed to "
3105                                          "urllib.quote when the resource "
3106                                          "property is set.  The default "
3107                                          "characters are '/%'")
3108
3109    def _getResource(self):
3110        '''Gets the Resource attrib value of this query.
3111
3112        @return: the Resource attrib value of this query'''
3113        return self.__resource
3114   
3115    def _setResource(self, value):
3116        '''Sets the Resource attrib value of this query normalizing the path
3117        component, removing spurious port numbers (80 for HTTP and 443 for
3118        HTTPS) and converting the host component to lower case.
3119       
3120        @param value: the new Resource attrib value of this query'''
3121        if not isinstance(value, basestring):
3122            raise TypeError('Expecting string type for "resource" attribute; '
3123                            'got %r instead' % type(value))
3124       
3125        if (self.normalizeResource and 
3126            value.startswith('http://') or value.startswith('https://')):
3127            # Normalise the path, set the host name to lower case and remove
3128            # port redundant numbers 80 and 443
3129            splitResult = urlsplit(value)
3130            uriComponents = list(splitResult)
3131           
3132            # hostname attribute is lowercase
3133            uriComponents[1] = splitResult.hostname
3134           
3135            if splitResult.port is not None:
3136                isHttpWithStdPort = (splitResult.port == 80 and 
3137                                     splitResult.scheme == 'http')
3138               
3139                isHttpsWithStdPort = (splitResult.port == 443 and
3140                                      splitResult.scheme == 'https')
3141               
3142                if not isHttpWithStdPort and not isHttpsWithStdPort:
3143                    uriComponents[1] += ":%d" % splitResult.port
3144           
3145            uriComponents[2] = urllib.quote(splitResult.path, 
3146                                            self.safeNormalizationChars)
3147           
3148            self.__resource = urlunsplit(uriComponents)
3149        else:
3150            self.__resource = value
3151   
3152    resource = property(fget=_getResource, fset=_setResource,
3153                        doc="Resource for which authorisation is requested")
3154   
3155    @property
3156    def actions(self):
3157        '''The actions for which authorisation is requested
3158       
3159        @return: the Actions of this query'''
3160        return self.__actions
3161   
3162    def _getEvidence(self):
3163        '''Gets the Evidence of this query.
3164
3165        @return: the Evidence of this query'''
3166        return self.__evidence
3167
3168    def _setEvidence(self, value):
3169        '''Sets the Evidence of this query.
3170        @param newEvidence: the new Evidence of this query''' 
3171        if not isinstance(value, Evidence):
3172            raise TypeError('Expecting Evidence type for "evidence" '
3173                            'attribute; got %r' % type(value))
3174
3175        self.__evidence = value 
3176
3177    evidence = property(fget=_getEvidence, fset=_setEvidence, 
3178                        doc="A set of assertions which the Authority may use "
3179                            "to base its authorisation decision on")
3180   
3181    def getOrderedChildren(self):
3182        children = []
3183
3184        superChildren = super(AuthzDecisionQuery, self).getOrderedChildren()
3185        if superChildren:
3186            children.extend(superChildren)
3187
3188        children.extend(self.__actions)
3189       
3190        if self.__evidence is not None:
3191            children.extend(self.__evidence)
3192
3193        if len(children) == 0:
3194            return None
3195
3196        return tuple(children)
3197
3198
3199class StatusResponseType(SAMLObject):
3200    '''SAML 2.0 Core Status Response Type
3201    '''
3202
3203    # Local name of the XSI type.
3204    TYPE_LOCAL_NAME = "StatusResponseType"
3205
3206    # QName of the XSI type.
3207    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
3208                      TYPE_LOCAL_NAME,
3209                      SAMLConstants.SAML20P_PREFIX)
3210
3211    # ID attribute name
3212    ID_ATTRIB_NAME = "ID"
3213
3214    # InResponseTo attribute name
3215    IN_RESPONSE_TO_ATTRIB_NAME = "InResponseTo"
3216
3217    # Version attribute name
3218    VERSION_ATTRIB_NAME = "Version"
3219
3220    # IssueInstant attribute name
3221    ISSUE_INSTANT_ATTRIB_NAME = "IssueInstant"
3222
3223    # Destination attribute name
3224    DESTINATION_ATTRIB_NAME = "Destination"
3225
3226    # Consent attribute name.
3227    CONSENT_ATTRIB_NAME = "Consent"
3228
3229    # Unspecified consent URI
3230    UNSPECIFIED_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:unspecified"
3231
3232    # Obtained consent URI
3233    OBTAINED_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:obtained"
3234
3235    # Prior consent URI
3236    PRIOR_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:prior"
3237
3238    # Implicit consent URI
3239    IMPLICIT_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:implicit"
3240
3241    # Explicit consent URI
3242    EXPLICIT_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:explicit"
3243
3244    # Unavailable consent URI
3245    UNAVAILABLE_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:unavailable"
3246
3247    # Inapplicable consent URI
3248    INAPPLICABLE_CONSENT = "urn:oasis:names:tc:SAML:2.0:consent:inapplicable"
3249
3250    __slots__ = (   
3251        '__version',
3252        '__id',
3253        '__inResponseTo',
3254        '__issueInstant',
3255        '__destination',
3256        '__consent',
3257        '__issuer',
3258        '__status',
3259        '__extensions'               
3260    )
3261   
3262    def __init__(self, **kw):
3263        super(StatusResponseType, self).__init__(**kw)
3264       
3265        self.__version = SAMLVersion(SAMLVersion.VERSION_20)
3266        self.__id = None
3267        self.__inResponseTo = None
3268        self.__issueInstant = None
3269        self.__destination = None
3270        self.__consent = None
3271        self.__issuer = None
3272        self.__status = None
3273        self.__extensions = None
3274
3275    def __getstate__(self):
3276        '''Enable pickling
3277       
3278        @return: object's attribute dictionary
3279        @rtype: dict
3280        '''
3281
3282        _dict = super(StatusResponseType, self).__getstate__()
3283        for attrName in StatusResponseType.__slots__:
3284            # Ugly hack to allow for derived classes setting private member
3285            # variables
3286            if attrName.startswith('__'):
3287                attrName = "_StatusResponseType" + attrName
3288               
3289            _dict[attrName] = getattr(self, attrName)
3290           
3291        return _dict
3292   
3293    def _get_version(self):
3294        '''@return: the SAML Version of this response.
3295        '''
3296        return self.__version
3297   
3298    def _set_version(self, version):
3299        '''@param version: the SAML Version of this response
3300        '''
3301        if not isinstance(version, SAMLVersion):
3302            raise TypeError("Expecting SAMLVersion type got: %r" % 
3303                            version.__class__)
3304       
3305        self.__version = version
3306       
3307    version = property(fget=_get_version,
3308                       fset=_set_version,
3309                       doc="SAML Version of the response")
3310
3311    def _get_id(self):
3312        '''Sets the ID of this response.
3313       
3314        @return: the ID of this response
3315        '''
3316        return self.__id
3317   
3318    def _set_id(self, value):
3319        '''Sets the ID of this response.
3320       
3321        @param value: the ID of this response
3322        '''
3323        if not isinstance(value, basestring):
3324            raise TypeError('Expecting basestring derived type for "id", got '
3325                            '%r' % type(value))
3326        self.__id = value
3327       
3328    id = property(fget=_get_id, fset=_set_id, doc="ID of response")
3329
3330    def _getInResponseTo(self):
3331        '''Get the unique request identifier for which this is a response
3332       
3333        @return: the unique identifier of the originating
3334        request
3335        '''
3336        return self.__inResponseTo
3337   
3338    def _setInResponseTo(self, value):
3339        '''Set the unique request identifier for which this is a response
3340       
3341        @param value: the unique identifier of the originating
3342        request
3343        '''
3344        if not isinstance(value, basestring):
3345            raise TypeError('Expecting basestring derived type for '
3346                            '"inResponseTo", got %r' % type(value))
3347        self.__inResponseTo = value
3348       
3349    inResponseTo = property(fget=_getInResponseTo, 
3350                            fset=_setInResponseTo,
3351                            doc="unique request identifier for which this is "
3352                                "a response")
3353
3354    def _get_issueInstant(self):
3355        '''Gets the issue instance of this response.
3356       
3357        @return: the issue instance of this response'''
3358        return self.__issueInstant
3359   
3360    def _set_issueInstant(self, issueInstant):
3361        '''Sets the issue instance of this response.
3362       
3363        @param newIssueInstance: the issue instance of this response
3364        '''
3365        if not isinstance(issueInstant, datetime):
3366            raise TypeError('Expecting "datetime" type for "issueInstant", '
3367                            'got %r' % issueInstant.__class__)
3368           
3369        self.__issueInstant = issueInstant
3370       
3371    issueInstant = property(fget=_get_issueInstant, 
3372                            fset=_set_issueInstant,
3373                            doc="Issue instant of the response")
3374
3375    def _get_destination(self):
3376        '''Gets the URI of the destination of the response.
3377       
3378        @return: the URI of the destination of the response
3379        '''
3380        return self.__destination
3381   
3382    def _set_destination(self, value):
3383        '''Sets the URI of the destination of the response.
3384       
3385        @param value: the URI of the destination of the response'''
3386        if not isinstance(value, basestring):
3387            raise TypeError('Expecting basestring derived type for '
3388                            '"destination", got %r' % type(value))
3389        self.__destination = value
3390       
3391    destination = property(fget=_get_destination, 
3392                           fset=_set_destination,
3393                           doc="Destination of response")
3394     
3395    def _get_consent(self):
3396        '''Gets the consent obtained from the principal for sending this
3397        response.
3398       
3399        @return: the consent obtained from the principal for sending this
3400        response
3401        '''
3402        return self.__consent
3403       
3404    def _set_consent(self, value):
3405        '''Sets the consent obtained from the principal for sending this
3406        response.
3407       
3408        @param value: the new consent obtained from the principal for
3409        sending this response
3410        ''' 
3411        if not isinstance(value, basestring):
3412            raise TypeError('Expecting basestring derived type for "consent", '
3413                            'got %r' % type(value))
3414        self.__consent = value
3415             
3416    consent = property(fget=_get_consent, 
3417                       fset=_set_consent,
3418                       doc="Consent for response")
3419   
3420    def _set_issuer(self, issuer):
3421        """Set issuer of response"""
3422        if not isinstance(issuer, Issuer):
3423            raise TypeError('"issuer" must be a %r, got %r' % (Issuer,
3424                                                               type(issuer)))
3425        self.__issuer = issuer
3426   
3427    def _get_issuer(self):
3428        """Get the issuer name """
3429        return self.__issuer
3430
3431    issuer = property(fget=_get_issuer, 
3432                      fset=_set_issuer,
3433                      doc="Issuer of response")
3434   
3435    def _getStatus(self):
3436        '''Gets the Status of this response.
3437       
3438        @return: the Status of this response
3439        '''
3440        return self.__status
3441
3442    def _setStatus(self, value):
3443        '''Sets the Status of this response.
3444       
3445        @param newStatus: the Status of this response
3446        '''
3447        if not isinstance(value, Status):
3448            raise TypeError('"status" must be a %r, got %r' % (Status,
3449                                                               type(value)))
3450        self.__status = value
3451       
3452    status = property(fget=_getStatus, fset=_setStatus, doc="Response status")   
3453       
3454    def _get_extensions(self):
3455        '''Gets the Extensions of this response.
3456       
3457        @return: the Status of this response
3458        '''
3459        return self.__extensions
3460     
3461    def _set_extensions(self, value):
3462        '''Sets the Extensions of this response.
3463       
3464        @param value: the Extensions of this response
3465        '''
3466        if not isinstance(value, (list, tuple)):
3467            raise TypeError('Expecting list or tuple for "extensions", got %r'
3468                            % type(value))
3469        self.__extensions = value
3470       
3471    extensions = property(fget=_get_extensions, 
3472                          fset=_set_extensions,
3473                          doc="Response extensions")   
3474
3475
3476class Response(StatusResponseType):
3477    '''SAML2 Core Response'''
3478   
3479    # Element local name.
3480    DEFAULT_ELEMENT_LOCAL_NAME = "Response"
3481   
3482    # Default element name.
3483    DEFAULT_ELEMENT_NAME = QName(SAMLConstants.SAML20P_NS, 
3484                                 DEFAULT_ELEMENT_LOCAL_NAME, 
3485                                 SAMLConstants.SAML20P_PREFIX)
3486   
3487    # Local name of the XSI type.
3488    TYPE_LOCAL_NAME = "ResponseType"
3489       
3490    # QName of the XSI type.
3491    TYPE_NAME = QName(SAMLConstants.SAML20P_NS, 
3492                      TYPE_LOCAL_NAME, 
3493                      SAMLConstants.SAML20P_PREFIX)
3494   
3495    __slots__ = ('__indexedChildren',)
3496   
3497    def __init__(self, **kw):
3498        '''''' 
3499        super(Response, self).__init__(**kw)
3500       
3501        # Assertion child elements
3502        self.__indexedChildren = []
3503
3504    def __getstate__(self):
3505        '''Enable pickling
3506       
3507        @return: object's attribute dictionary
3508        @rtype: dict
3509        '''
3510
3511        _dict = super(Response, self).__getstate__()
3512        for attrName in Response.__slots__:
3513            # Ugly hack to allow for derived classes setting private member
3514            # variables
3515            if attrName.startswith('__'):
3516                attrName = "_Response" + attrName
3517               
3518            _dict[attrName] = getattr(self, attrName)
3519           
3520        return _dict
3521       
3522    @property
3523    def assertions(self): 
3524        "Assertions contained in this response"
3525        return self.__indexedChildren
Note: See TracBrowser for help on using the repository browser.