| Home | Trees | Indices | Help |
|
|---|
|
|
1 """Implementation of SAML 2.0 for NDG Security - ElementTree module for
2 ElementTree representation of SAML objects
3
4 NERC DataGrid Project
5
6 This implementation is adapted from the Java OpenSAML implementation. The
7 copyright and licence information are included here:
8
9 Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
10
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 """
23 __author__ = "P J Kershaw"
24 __date__ = "23/07/09"
25 __copyright__ = "(C) 2009 Science and Technology Facilities Council"
26 __contact__ = "Philip.Kershaw@stfc.ac.uk"
27 __license__ = "http://www.apache.org/licenses/LICENSE-2.0"
28 __contact__ = "Philip.Kershaw@stfc.ac.uk"
29 __revision__ = "$Id: etree.py 8009 2012-01-30 16:19:43Z rwilkinson $"
30 import logging
31 log = logging.getLogger(__name__)
32 import re
33
34 from ndg.saml import Config, importElementTree
35 ElementTree = importElementTree()
36
37 from ndg.saml.saml2.core import (SAMLObject, Attribute, AttributeStatement,
38 AuthnStatement, AuthzDecisionStatement,
39 Assertion, Conditions, AttributeValue,
40 AttributeQuery, AuthzDecisionQuery, Subject,
41 NameID, Issuer, Response, Status, StatusCode,
42 StatusMessage, StatusDetail, Advice, Action,
43 Evidence, DecisionType, XSStringAttributeValue)
44
45 from ndg.saml.common import SAMLVersion
46 from ndg.saml.common.xml import SAMLConstants
47 from ndg.saml.common.xml import QName as GenericQName
48 from ndg.saml.xml import XMLTypeParseError, UnknownAttrProfile
49 from ndg.saml.utils import SAMLDateTime
50
51 # Map of QName to ElementTree parsing class to be used in addition to those
52 # defined in this module.
53 _extensionElementTreeMap = {}
54
55 if Config.use_lxml:
57 """Makes an ElementTree element handling namespaces in the way
58 appropriate for the ElementTree implementation in use.
59 """
60 elem = ElementTree.Element(tag, {ns_prefix: ns_uri}, attrib, **extra)
61 return elem
62 else:
64 """Makes an ElementTree element handling namespaces in the way
65 appropriate for the ElementTree implementation in use.
66 """
67 elem = ElementTree.Element(tag, attrib, **extra)
68 ElementTree._namespace_map[ns_uri] = ns_prefix
69 return elem
70
73 """Extend ElementTree implementation for improved attribute access support
74 """
75
76 # ElementTree tag is of the form {namespace}localPart. getNs extracts the
77 # namespace from within the brackets but if not found returns ''
78 getNs = staticmethod(lambda tag: getattr(re.search('(?<=\{).+(?=\})', tag),
79 'group',
80 str)())
81
82 getLocalPart = staticmethod(lambda tag: tag.rsplit('}', 1)[-1])
83
85 """
86 @type input: basestring
87 @param input: ElementTree style namespace URI + tag name -
88 {namespace URI}tag - OR if tag keyword is set, the namespace URI alone
89 @type tag: basestring / None
90 @param tag: element tag name. If None, input must contain the
91 namespace URI and tag name in the ElementTree form {namespace URI}tag.
92 @type prefix: basestring / None
93 @param prefix: namespace prefix
94 """
95
96 ElementTree.QName.__init__(self, input, tag=tag)
97
98 if tag:
99 self.namespaceURI = input
100 self.localPart = tag
101 else:
102 # No tag provided namespace and localPart of QN must be parsed from
103 # the namespace
104 self.namespaceURI = QName.getNs(input)
105 self.localPart = QName.getLocalPart(input)
106
107 self.prefix = prefix
108
114
120
121 prefix = property(_getPrefix, _setPrefix, None, "Prefix")
122
128
134
135 localPart = property(_getLocalPart, _setLocalPart, None, "LocalPart")
136
142
148
149 namespaceURI = property(_getNamespaceURI, _setNamespaceURI, None,
150 "Namespace URI'")
151
153 """Enable equality check for QName. Note that prefixes don't need to
154 match
155
156 @type qname: ndg.security.common.utils.etree.QName
157 @param qname: Qualified Name to compare with self
158
159 @return: True if the qualified names match, False otherwise
160 @rtype: bool
161 """
162 if not isinstance(qname, QName):
163 raise TypeError('Expecting %r; got %r' % (QName, type(qname)))
164
165 # Nb. prefixes don't need to agree!
166 return (self.namespaceURI, self.localPart) == \
167 (qname.namespaceURI, qname.localPart)
168
170 """Enable equality check for QName. Note that prefixes don't need to
171 match
172
173 @type qname: ndg.security.common.utils.etree.QName
174 @param qname: Qualified Name to compare with self
175 @return: True if the qualified names don't match, False otherwise
176 @rtype: bool
177 """
178 return not self.__eq__(qname)
179
180 @classmethod
182 '''Cast the generic QName type in ndg.saml.common.xml to this
183 ElementTree specific implementation
184
185 @param genericQName: SAML core qualified name type
186 @type genericQName: ndg.saml.common.xml.QName
187 @return: ElementTree specific qualified name type
188 @rtype: ndg.saml.xml.etree.QName
189 '''
190 if not isinstance(genericQName, GenericQName):
191 raise TypeError("Expecting %r for QName, got %r" % (GenericQName,
192 type(genericQName)))
193
194 qname = cls(genericQName.namespaceURI,
195 tag=genericQName.localPart,
196 prefix=genericQName.prefix)
197 return qname
198
201 '''Lightweight pretty printing of ElementTree elements. This function
202 wraps the PrettyPrint class
203
204 @param arg: arguments to pretty print function
205 @type arg: tuple
206 @param kw: keyword arguments to pretty print function
207 @type kw: dict
208 '''
209
210 # Keep track of namespace declarations made so they're not repeated
211 declaredNss = []
212 if not Config.use_lxml:
213 mappedPrefixes = dict.fromkeys(ElementTree._namespace_map.values(), True)
214 namespace_map_backup = ElementTree._namespace_map.copy()
215 else:
216 mappedPrefixes = {}
217
218 _prettyPrint = _PrettyPrint(declaredNss, mappedPrefixes)
219 result = _prettyPrint(*arg, **kw)
220
221 if not Config.use_lxml:
222 ElementTree._namespace_map = namespace_map_backup
223
224 return result
225
228 '''Class for lightweight pretty printing of ElementTree elements'''
229 MAX_NS_TRIES = 256
231 """
232 @param declaredNss: declared namespaces
233 @type declaredNss: iterable of string elements
234 @param mappedPrefixes: map of namespace URIs to prefixes
235 @type mappedPrefixes: map of string to string
236 """
237 self.declaredNss = declaredNss
238 self.mappedPrefixes = mappedPrefixes
239
240 @staticmethod
242 '''Utility to remove unwanted leading and trailing whitespace
243
244 @param elem: ElementTree element
245 @type elem: ElementTree.Element
246 @return: element content with whitespace removed
247 @rtype: basestring'''
248 if elem is None:
249 return ''
250 else:
251 # just in case the elem is another simple type - e.g. int -
252 # wrapper it as a string
253 return str(elem).strip()
254
256 '''Most of the work done in this wrapped function - wrapped so that
257 state can be maintained for declared namespace declarations during
258 recursive calls using "declaredNss" above
259
260 @param elem: ElementTree element
261 @type elem: ElementTree.Element
262 @param indent: set indent for output
263 @type indent: basestring
264 @param space: set output spacing
265 @type space: basestring
266 @return: pretty print format for doc
267 @rtype: basestring
268 '''
269 strAttribs = []
270 for attr, attrVal in elem.attrib.items():
271 nsDeclaration = ''
272
273 attrNamespace = QName.getNs(attr)
274 if attrNamespace:
275 nsPrefix = self._getNamespacePrefix(elem, attrNamespace)
276
277 attr = "%s:%s" % (nsPrefix, QName.getLocalPart(attr))
278
279 if attrNamespace not in self.declaredNss:
280 nsDeclaration = ' xmlns:%s="%s"' % (nsPrefix,attrNamespace)
281 self.declaredNss.append(attrNamespace)
282
283 strAttribs.append('%s %s="%s"' % (nsDeclaration, attr, attrVal))
284
285 strAttrib = ''.join(strAttribs)
286
287 namespace = QName.getNs(elem.tag)
288 nsPrefix = self._getNamespacePrefix(elem, namespace)
289
290 tag = "%s:%s" % (nsPrefix, QName.getLocalPart(elem.tag))
291
292 # Put in namespace declaration if one doesn't already exist
293 # FIXME: namespace declaration handling is wrong for handling child
294 # element scope
295 if namespace in self.declaredNss:
296 nsDeclaration = ''
297 else:
298 nsDeclaration = ' xmlns:%s="%s"' % (nsPrefix, namespace)
299 self.declaredNss.append(namespace)
300
301 result = '%s<%s%s%s>%s' % (indent, tag, nsDeclaration, strAttrib,
302 _PrettyPrint.estrip(elem.text))
303
304 children = len(elem)
305 if children:
306 for child in elem:
307 declaredNss = self.declaredNss[:]
308 _prettyPrint = _PrettyPrint(declaredNss, self.mappedPrefixes)
309 result += '\n'+ _prettyPrint(child, indent=indent+space)
310
311 result += '\n%s%s</%s>' % (indent,
312 _PrettyPrint.estrip(child.tail),
313 tag)
314 else:
315 result += '</%s>' % tag
316
317 return result
318
319 if Config.use_lxml:
321 for nsPrefix, ns in elem.nsmap.iteritems():
322 if ns == namespace:
323 return nsPrefix
324 raise KeyError('prettyPrint: missing namespace "%s" for '
325 'elem.nsmap' % namespace)
326 else:
328 nsPrefix = self._allocNsPrefix(namespace)
329 if nsPrefix is None:
330 raise KeyError('prettyPrint: missing namespace "%s" for '
331 'ElementTree._namespace_map' % namespace)
332 return nsPrefix
333
335 """Allocate a namespace prefix if one is not already set for the given
336 Namespace URI
337 """
338 nsPrefix = ElementTree._namespace_map.get(nsURI)
339 if nsPrefix is not None:
340 return nsPrefix
341
342 for i in range(self.__class__.MAX_NS_TRIES):
343 nsPrefix = "ns%d" % i
344 if nsPrefix not in self.mappedPrefixes:
345 ElementTree._namespace_map[nsURI] = nsPrefix
346 self.mappedPrefixes[nsPrefix] = True
347 break
348
349 if nsURI not in ElementTree._namespace_map:
350 raise KeyError('prettyPrint: error adding namespace '
351 '"%s" to ElementTree._namespace_map' %
352 nsURI)
353
354 return nsPrefix
355
358 """ElementTree based XML representation of Conditions class
359 """
360
361 @classmethod
363 """Make a tree of a XML elements based on the assertion conditions
364
365 @type conditions: saml.saml2.core.Conditions
366 @param conditions: Assertion conditions to be represented as an
367 ElementTree Element
368 @rtype: ElementTree.Element
369 @return: ElementTree Element
370 """
371 if not isinstance(conditions, Conditions):
372 raise TypeError("Expecting %r type got: %r" % (Conditions,
373 conditions))
374
375 notBeforeStr = SAMLDateTime.toString(conditions.notBefore)
376 notOnOrAfterStr = SAMLDateTime.toString(conditions.notOnOrAfter)
377 attrib = {
378 cls.NOT_BEFORE_ATTRIB_NAME: notBeforeStr,
379 cls.NOT_ON_OR_AFTER_ATTRIB_NAME: notOnOrAfterStr,
380 }
381
382 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
383 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
384 cls.DEFAULT_ELEMENT_NAME.namespaceURI,
385 **attrib)
386
387 for condition in conditions.conditions:
388 raise NotImplementedError("Conditions list creation is not "
389 "implemented")
390
391 return elem
392
393 @classmethod
395 """Parse an ElementTree SAML Conditions element into an
396 Conditions object
397
398 @type elem: ElementTree.Element
399 @param elem: ElementTree element containing the conditions
400 @rtype: saml.saml2.core.Conditions
401 @return: Conditions object
402 """
403
404 if not ElementTree.iselement(elem):
405 raise TypeError("Expecting %r input type for parsing; got %r" %
406 (ElementTree.Element, elem))
407
408 localName = QName.getLocalPart(elem.tag)
409 if localName != cls.DEFAULT_ELEMENT_LOCAL_NAME:
410 raise XMLTypeParseError("No \"%s\" element found" %
411 cls.DEFAULT_ELEMENT_LOCAL_NAME)
412
413
414 if len(elem) > 0:
415 raise NotImplementedError("Conditions list parsing is not "
416 "implemented")
417
418 conditions = Conditions()
419 notBefore = elem.attrib.get(Conditions.NOT_BEFORE_ATTRIB_NAME)
420 if notBefore is not None:
421 conditions.notBefore = SAMLDateTime.fromString(notBefore)
422
423 notOnOrAfter = elem.attrib.get(Conditions.NOT_ON_OR_AFTER_ATTRIB_NAME)
424 if notBefore is not None:
425 conditions.notOnOrAfter = SAMLDateTime.fromString(notOnOrAfter)
426
427 return conditions
428
431 """ElementTree based XML representation of Assertion class
432 """
433
434 @classmethod
436 """Make a tree of a XML elements based on the assertion
437
438 @type assertion: saml.saml2.core.Assertion
439 @param assertion: Assertion to be represented as an ElementTree Element
440 @type attributeValueElementTreeFactoryKw: dict
441 @param attributeValueElementTreeFactoryKw: keywords for AttributeValue
442 factory
443 @rtype: ElementTree.Element
444 @return: ElementTree Element
445 """
446
447 if not isinstance(assertion, Assertion):
448 raise TypeError("Expecting %r type got: %r"%(Assertion, assertion))
449
450 issueInstant = SAMLDateTime.toString(assertion.issueInstant)
451 attrib = {
452 cls.ID_ATTRIB_NAME: assertion.id,
453 cls.ISSUE_INSTANT_ATTRIB_NAME: issueInstant,
454
455 # Nb. Version is a SAMLVersion instance and requires explicit cast
456 cls.VERSION_ATTRIB_NAME: str(assertion.version)
457 }
458 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
459 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
460 cls.DEFAULT_ELEMENT_NAME.namespaceURI,
461 **attrib)
462
463 if assertion.issuer is not None:
464 issuerElem = IssuerElementTree.toXML(assertion.issuer)
465 elem.append(issuerElem)
466
467 if assertion.subject is not None:
468 subjectElem = SubjectElementTree.toXML(assertion.subject)
469 elem.append(subjectElem)
470
471 if assertion.advice:
472 raise NotImplementedError("Assertion Advice creation is not "
473 "implemented")
474
475 if assertion.conditions is not None:
476 conditionsElem = ConditionsElementTree.toXML(assertion.conditions)
477 elem.append(conditionsElem)
478
479 for statement in assertion.statements:
480 qname = statement.qname
481 etreeImpl = _getElementTreeImplementationForQName(qname)
482 if etreeImpl is None:
483 raise NotImplementedError("No ElementTree implementation for "
484 "QName {%s}%s" %
485 (qname.namespaceURI, qname.localPart))
486 statementElem = etreeImpl.toXML(statement)
487 elem.append(statementElem)
488
489 for authnStatement in assertion.authnStatements:
490 raise NotImplementedError("Assertion Authentication Statement "
491 "creation is not implemented")
492
493 for authzDecisionStatement in assertion.authzDecisionStatements:
494 authzDecisionStatementElem = \
495 AuthzDecisionStatementElementTree.toXML(authzDecisionStatement)
496 elem.append(authzDecisionStatementElem)
497
498 for attributeStatement in assertion.attributeStatements:
499 attributeStatementElem = AttributeStatementElementTree.toXML(
500 attributeStatement,
501 **attributeValueElementTreeFactoryKw)
502 elem.append(attributeStatementElem)
503
504 return elem
505
506 @classmethod
508 """Parse an ElementTree representation of an Assertion into an
509 Assertion object
510
511 @type elem: ElementTree.Element
512 @param elem: ElementTree element containing the assertion
513 @type attributeValueElementTreeFactoryKw: dict
514 @param attributeValueElementTreeFactoryKw: keywords for AttributeValue
515 @rtype: saml.saml2.core.Assertion
516 @return: Assertion object
517 """
518 if not ElementTree.iselement(elem):
519 raise TypeError("Expecting %r input type for parsing; got %r" %
520 (ElementTree.Element, elem))
521
522 localName = QName.getLocalPart(elem.tag)
523 if localName != cls.DEFAULT_ELEMENT_LOCAL_NAME:
524 raise XMLTypeParseError("No \"%s\" element found" %
525 cls.DEFAULT_ELEMENT_LOCAL_NAME)
526
527
528 # Unpack attributes from top-level element
529 attributeValues = []
530 for attributeName in (cls.VERSION_ATTRIB_NAME,
531 cls.ISSUE_INSTANT_ATTRIB_NAME,
532 cls.ID_ATTRIB_NAME):
533 attributeValue = elem.attrib.get(attributeName)
534 if attributeValue is None:
535 raise XMLTypeParseError('No "%s" attribute found in "%s" '
536 'element' %
537 (attributeName,
538 cls.DEFAULT_ELEMENT_LOCAL_NAME))
539
540 attributeValues.append(attributeValue)
541
542 assertion = cls()
543 assertion.version = SAMLVersion(attributeValues[0])
544 if assertion.version != SAMLVersion.VERSION_20:
545 raise NotImplementedError("Parsing for %r is implemented for "
546 "SAML version %s only; version %s is "
547 "not supported" %
548 (cls,
549 SAMLVersion(SAMLVersion.VERSION_20),
550 SAMLVersion(assertion.version)))
551
552 assertion.issueInstant = SAMLDateTime.fromString(attributeValues[1])
553 assertion.id = attributeValues[2]
554
555 for childElem in elem:
556 localName = QName.getLocalPart(childElem.tag)
557
558 statementElementTree = _getElementTreeImplementationForQName(QName(childElem.tag))
559
560 if localName == Issuer.DEFAULT_ELEMENT_LOCAL_NAME:
561 # Parse Issuer
562 assertion.issuer = IssuerElementTree.fromXML(childElem)
563
564 elif localName == Subject.DEFAULT_ELEMENT_LOCAL_NAME:
565 # Parse subject
566 assertion.subject = SubjectElementTree.fromXML(childElem)
567
568 elif localName == Advice.DEFAULT_ELEMENT_LOCAL_NAME:
569 raise NotImplementedError("Assertion Advice parsing is not "
570 "implemented")
571
572 elif localName == Conditions.DEFAULT_ELEMENT_LOCAL_NAME:
573 assertion.conditions = ConditionsElementTree.fromXML(childElem)
574
575 elif statementElementTree is not None:
576 statement = statementElementTree.fromXML(childElem)
577 assertion.statements.append(statement)
578
579 elif localName == AuthnStatement.DEFAULT_ELEMENT_LOCAL_NAME:
580 raise NotImplementedError("Assertion Authentication Statement "
581 "parsing is not implemented")
582
583 elif localName == AuthzDecisionStatement.DEFAULT_ELEMENT_LOCAL_NAME:
584 authzDecisionStatement = \
585 AuthzDecisionStatementElementTree.fromXML(childElem)
586 assertion.authzDecisionStatements.append(authzDecisionStatement)
587
588 elif localName == AttributeStatement.DEFAULT_ELEMENT_LOCAL_NAME:
589 attributeStatement = AttributeStatementElementTree.fromXML(
590 childElem,
591 **attributeValueElementTreeFactoryKw)
592 assertion.attributeStatements.append(attributeStatement)
593 else:
594 raise XMLTypeParseError('Assertion child element name "%s" '
595 'not recognised' % localName)
596
597 return assertion
598
601 """ElementTree XML representation of AttributeStatement"""
602
603 @classmethod
605 """Make a tree of a XML elements based on the attribute statement
606
607 @type attributeStatement: saml.saml2.core.AttributeStatement
608 @param attributeStatement: Attribute Statement to be represented as an
609 ElementTree Element
610 @type attributeValueElementTreeFactoryKw: dict
611 @param attributeValueElementTreeFactoryKw: keywords for AttributeValue
612 factory
613 @rtype: ElementTree.Element
614 @return: ElementTree Element
615 """
616 if not isinstance(attributeStatement, AttributeStatement):
617 raise TypeError("Expecting %r type got: %r" % (AttributeStatement,
618 attributeStatement))
619
620 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
621 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
622 cls.DEFAULT_ELEMENT_NAME.namespaceURI)
623
624 for attribute in attributeStatement.attributes:
625 # Factory enables support for multiple attribute types
626 attributeElem = AttributeElementTree.toXML(attribute,
627 **attributeValueElementTreeFactoryKw)
628 elem.append(attributeElem)
629
630 return elem
631
632 @classmethod
634 """Parse an ElementTree SAML AttributeStatement element into an
635 AttributeStatement object
636
637 @type elem: ElementTree.Element
638 @param elem: ElementTree element containing the AttributeStatement
639 @type attributeValueElementTreeFactoryKw: dict
640 @param attributeValueElementTreeFactoryKw: keywords for AttributeValue
641 factory
642 @rtype: saml.saml2.core.AttributeStatement
643 @return: Attribute Statement
644 """
645
646 if not ElementTree.iselement(elem):
647 raise TypeError("Expecting %r input type for parsing; got %r" %
648 (ElementTree.Element, elem))
649
650 localName = QName.getLocalPart(elem.tag)
651 if localName != cls.DEFAULT_ELEMENT_LOCAL_NAME:
652 raise XMLTypeParseError("No \"%s\" element found" %
653 cls.DEFAULT_ELEMENT_LOCAL_NAME)
654
655
656 attributeStatement = AttributeStatement()
657
658 for childElem in elem:
659 # Factory enables support for multiple attribute types
660 attribute = AttributeElementTree.fromXML(childElem,
661 **attributeValueElementTreeFactoryKw)
662 attributeStatement.attributes.append(attribute)
663
664 return attributeStatement
665
668 """ElementTree XML representation of AuthzDecisionStatement"""
669
670 @classmethod
672 """Make a tree of a XML elements based on the authzDecision statement
673
674 @type authzDecisionStatement: saml.saml2.core.AuthzDecisionStatement
675 @param authzDecisionStatement: AuthzDecision Statement to be represented
676 as an ElementTree Element
677 @rtype: ElementTree.Element
678 @return: ElementTree Element
679 """
680 if not isinstance(authzDecisionStatement, AuthzDecisionStatement):
681 raise TypeError("Expecting %r type got: %r" %
682 (AuthzDecisionStatement, authzDecisionStatement))
683
684 if not authzDecisionStatement.resource:
685 raise AttributeError("Resource for AuthzDecisionStatement is not "
686 "set")
687
688 attrib = {
689 cls.DECISION_ATTRIB_NAME: str(authzDecisionStatement.decision),
690 cls.RESOURCE_ATTRIB_NAME: authzDecisionStatement.resource
691 }
692
693 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
694 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
695 cls.DEFAULT_ELEMENT_NAME.namespaceURI,
696 **attrib)
697
698 for action in authzDecisionStatement.actions:
699 # Factory enables support for multiple authzDecision types
700 actionElem = ActionElementTree.toXML(action)
701 elem.append(actionElem)
702
703 if (authzDecisionStatement.evidence and
704 len(authzDecisionStatement.evidence.values) > 0):
705 raise NotImplementedError("authzDecisionStatementElementTree does "
706 "not currently support the Evidence type")
707
708 return elem
709
710 @classmethod
712 """Parse an ElementTree SAML AuthzDecisionStatement element into an
713 AuthzDecisionStatement object
714
715 @type elem: ElementTree.Element
716 @param elem: ElementTree element containing the AuthzDecisionStatement
717 @rtype: saml.saml2.core.AuthzDecisionStatement
718 @return: AuthzDecision Statement"""
719
720 if not ElementTree.iselement(elem):
721 raise TypeError("Expecting %r input type for parsing; got %r" %
722 (ElementTree.Element, elem))
723
724 localName = QName.getLocalPart(elem.tag)
725 if localName != cls.DEFAULT_ELEMENT_LOCAL_NAME:
726 raise XMLTypeParseError("No \"%s\" element found" %
727 cls.DEFAULT_ELEMENT_LOCAL_NAME)
728
729 # Unpack attributes from top-level element
730 attributeValues = []
731 for attributeName in (cls.DECISION_ATTRIB_NAME,
732 cls.RESOURCE_ATTRIB_NAME):
733 attributeValue = elem.attrib.get(attributeName)
734 if attributeValue is None:
735 raise XMLTypeParseError('No "%s" attribute found in "%s" '
736 'element' %
737 (attributeName,
738 cls.DEFAULT_ELEMENT_LOCAL_NAME))
739
740 attributeValues.append(attributeValue)
741
742 authzDecisionStatement = AuthzDecisionStatement()
743 authzDecisionStatement.decision = DecisionType(attributeValues[0])
744 authzDecisionStatement.resource = attributeValues[1]
745
746 for childElem in elem:
747 localName = QName.getLocalPart(childElem.tag)
748
749 if localName == Action.DEFAULT_ELEMENT_LOCAL_NAME:
750 action = ActionElementTree.fromXML(childElem)
751 authzDecisionStatement.actions.append(action)
752
753 elif localName == Evidence.DEFAULT_ELEMENT_LOCAL_NAME:
754 raise NotImplementedError("XML parse of %s element is not "
755 "implemented" %
756 Evidence.DEFAULT_ELEMENT_LOCAL_NAME)
757 else:
758 raise XMLTypeParseError("AuthzDecisionStatement child element "
759 "name %r not recognised" % localName)
760
761 return authzDecisionStatement
762
765 """ElementTree XML representation of SAML Attribute object. Extend
766 to make Attribute types"""
767
768 @classmethod
770 """Make a tree of a XML elements based on the Attribute
771
772 @type attribute: saml.saml2.core.Attribute
773 @param attribute: Attribute to be represented as an ElementTree Element
774 @type attributeValueElementTreeFactoryKw: dict
775 @param attributeValueElementTreeFactoryKw: keywords for AttributeValue
776 factory
777 @rtype: ElementTree.Element
778 @return: ElementTree Element
779 """
780 if not isinstance(attribute, Attribute):
781 raise TypeError("Expecting %r type got: %r"%(Attribute, attribute))
782
783 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
784 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
785 cls.DEFAULT_ELEMENT_NAME.namespaceURI)
786
787 if attribute.friendlyName:
788 elem.set(cls.FRIENDLY_NAME_ATTRIB_NAME, attribute.friendlyName)
789
790 if attribute.name:
791 elem.set(cls.NAME_ATTRIB_NAME, attribute.name)
792
793 if attribute.nameFormat:
794 elem.set(cls.NAME_FORMAT_ATTRIB_NAME, attribute.nameFormat)
795
796 for attributeValue in attribute.attributeValues:
797 factory = AttributeValueElementTreeFactory(
798 **attributeValueElementTreeFactoryKw)
799
800 attributeValueElementTree = factory(attributeValue)
801
802 attributeValueElem = attributeValueElementTree.toXML(attributeValue)
803 elem.append(attributeValueElem)
804
805 return elem
806
807 @classmethod
809 """Parse ElementTree element into a SAML Attribute object
810
811 @type elem: ElementTree.Element
812 @param elem: Attribute as ElementTree XML element
813 @type attributeValueElementTreeFactoryKw: dict
814 @param attributeValueElementTreeFactoryKw: keywords for AttributeValue
815 factory
816 @rtype: saml.saml2.core.Attribute
817 @return: SAML Attribute
818 """
819 if not ElementTree.iselement(elem):
820 raise TypeError("Expecting %r input type for parsing; got %r" %
821 (ElementTree.Element, elem))
822
823 if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
824 raise XMLTypeParseError("No \"%s\" element found" %
825 cls.DEFAULT_ELEMENT_LOCAL_NAME)
826
827 attribute = Attribute()
828
829 # Name is mandatory in the schema
830 name = elem.attrib.get(cls.NAME_ATTRIB_NAME)
831 if name is None:
832 raise XMLTypeParseError('No "%s" attribute found in the "%s" '
833 'element' %
834 (cls.NAME_ATTRIB_NAME,
835 cls.DEFAULT_ELEMENT_LOCAL_NAME))
836 attribute.name = name
837
838 friendlyName = elem.attrib.get(cls.FRIENDLY_NAME_ATTRIB_NAME)
839 if friendlyName is not None:
840 attribute.friendlyName = friendlyName
841
842 nameFormat = elem.attrib.get(cls.NAME_FORMAT_ATTRIB_NAME)
843 if nameFormat is not None:
844 attribute.nameFormat = nameFormat
845
846 # Factory to handle the different Attribute Value types
847 factory = AttributeValueElementTreeFactory(
848 **attributeValueElementTreeFactoryKw)
849
850 for childElem in elem:
851 localName = QName.getLocalPart(childElem.tag)
852 if localName != AttributeValue.DEFAULT_ELEMENT_LOCAL_NAME:
853 raise XMLTypeParseError('Expecting "%s" element; found "%s"'%
854 (AttributeValue.DEFAULT_ELEMENT_LOCAL_NAME,
855 localName))
856
857 attributeValueElementTreeClass = factory(childElem)
858 attributeValue = attributeValueElementTreeClass.fromXML(childElem)
859 attribute.attributeValues.append(attributeValue)
860
861 return attribute
862
865 """Base class ElementTree XML representation of SAML Attribute Value"""
866
867 @classmethod
869 """Make a tree of a XML elements based on the Attribute value
870
871 @type attributeValue: saml.saml2.core.AttributeValue
872 @param attributeValue: Assertion to be represented as an ElementTree
873 Element
874 @rtype: ElementTree.Element
875 @return: ElementTree Element
876 """
877 if not isinstance(attributeValue, AttributeValue):
878 raise TypeError("Expecting %r type got: %r" % (AttributeValue,
879 attributeValue))
880
881 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
882 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
883 cls.DEFAULT_ELEMENT_NAME.namespaceURI)
884
885 return elem
886
887
888 -class XSStringAttributeValueElementTree(AttributeValueElementTreeBase,
889 XSStringAttributeValue):
890 """ElementTree XML representation of SAML String type Attribute Value"""
891
892 @classmethod
894 """Create an XML representation of the input SAML Attribute Value
895
896 @type attributeValue: saml.saml2.core.XSStringAttributeValue
897 @param attributeValue: xs:string to be represented as an ElementTree
898 Element
899 @rtype: ElementTree.Element
900 @return: ElementTree Element
901 """
902 elem = AttributeValueElementTreeBase.toXML(attributeValue)
903
904 if not isinstance(attributeValue, XSStringAttributeValue):
905 raise TypeError("Expecting %r type got: %r" %
906 (XSStringAttributeValue, attributeValue))
907
908 if Config.use_lxml:
909 elem.set(("{%s}%s" % (SAMLConstants.XSI_NS, 'type')),
910 "%s:%s" % (SAMLConstants.XSD_PREFIX,
911 cls.TYPE_LOCAL_NAME))
912 else:
913 # Have to explicitly add namespace declaration here rather use
914 # ElementTree._namespace_map because the prefixes are used for
915 # attributes not element names
916 elem.set("%s:%s" % (SAMLConstants.XMLNS_PREFIX,
917 SAMLConstants.XSD_PREFIX),
918 SAMLConstants.XSD_NS)
919
920 elem.set("%s:%s" % (SAMLConstants.XMLNS_PREFIX,
921 SAMLConstants.XSI_PREFIX),
922 SAMLConstants.XSI_NS)
923
924 elem.set("%s:%s" % (SAMLConstants.XSI_PREFIX, 'type'),
925 "%s:%s" % (SAMLConstants.XSD_PREFIX,
926 cls.TYPE_LOCAL_NAME))
927
928 elem.text = attributeValue.value
929
930 return elem
931
932 @classmethod
934 """Parse ElementTree xs:string element into a SAML
935 XSStringAttributeValue object
936
937 @type elem: ElementTree.Element
938 @param elem: Attribute value as ElementTree XML element
939 @rtype: saml.saml2.core.AttributeValue
940 @return: SAML Attribute value
941 """
942 if not ElementTree.iselement(elem):
943 raise TypeError("Expecting %r input type for parsing; got %r" %
944 (ElementTree.Element, elem))
945
946 localName = QName.getLocalPart(elem.tag)
947 if localName != cls.DEFAULT_ELEMENT_LOCAL_NAME:
948 raise XMLTypeParseError("No \"%s\" element found" %
949 cls.DEFAULT_ELEMENT_LOCAL_NAME)
950
951 # Parse the attribute type checking that it is set to the expected
952 # string type
953 typeQName = QName(SAMLConstants.XSI_NS, tag='type')
954
955 typeValue = elem.attrib.get(str(typeQName), '')
956 typeValueLocalName = typeValue.split(':')[-1]
957 if typeValueLocalName != cls.TYPE_LOCAL_NAME:
958 raise XMLTypeParseError('Expecting "%s" type; got "%s"' %
959 (cls.TYPE_LOCAL_NAME,
960 typeValueLocalName))
961
962 # Update namespace map as an XSI type has been referenced. This will
963 # ensure the correct prefix is applied if it is re-serialised.
964 if not Config.use_lxml:
965 ElementTree._namespace_map[SAMLConstants.XSI_NS
966 ] = SAMLConstants.XSI_PREFIX
967
968 attributeValue = XSStringAttributeValue()
969 if elem.text is not None:
970 attributeValue.value = elem.text.strip()
971
972 return attributeValue
973
976 """Class factory for AttributeValue ElementTree classes. These classes are
977 used to represent SAML Attribute value types
978
979 @type toXMLTypeMap: dict
980 @cvar toXMLTypeMap: mapping between SAML AttributeValue class and its
981 ElementTree handler class
982 @type toSAMLTypeMap: dict
983 @cvar toSAMLTypeMap: mapping between SAML AttributeValue string identifier
984 and its ElementTree handler class
985 """
986 toXMLTypeMap = {
987 XSStringAttributeValue: XSStringAttributeValueElementTree
988 }
989
991 """Match function for xs:string type attribute.
992
993 @type elem: ElementTree.Element
994 @param elem: Attribute Value element to be checked
995 @rtype: XSStringAttributeValueElementTree/None
996 @return: Parsing class if this element is an xs:string Attribute Value,
997 None otherwise.
998 """
999 # Iterate through the attributes searching for a type attribute set to
1000 # xs:string
1001 for attribName, attribVal in elem.attrib.items():
1002 qname = QName(attribName)
1003 if qname.localPart == "type":
1004 typeLocalName = attribVal.split(':')[-1]
1005
1006 if typeLocalName == XSStringAttributeValue.TYPE_LOCAL_NAME:
1007 return XSStringAttributeValueElementTree
1008 else:
1009 return None
1010
1011 # No type attribute was found for this Attribute element
1012 return None
1013
1014 toSAMLTypeMap = [xsstringMatch]
1015 xsstringMatch = staticmethod(toSAMLTypeMap[0])
1016
1018 """Set-up a SAML class to ElementTree mapping
1019
1020 @type customToXMLTypeMap: dict
1021 @param customToXMLTypeMap: mapping for custom SAML AttributeValue
1022 classes to their respective ElementTree based representations. This
1023 appends to self.__toXMLTypeMap
1024 @type customToSAMLTypeMap: dict
1025 @param customToSAMLTypeMap: string ID based mapping for custom SAML
1026 AttributeValue classes to their respective ElementTree based
1027 representations. As with customToXMLTypeMap, this appends to
1028 to the respective self.__toSAMLTypeMap
1029 """
1030 if customToXMLTypeMap is None:
1031 customToXMLTypeMap = {}
1032
1033 if customToSAMLTypeMap is None:
1034 customToSAMLTypeMap = []
1035
1036 self.__toXMLTypeMap = AttributeValueElementTreeFactory.toXMLTypeMap
1037 if not isinstance(customToXMLTypeMap, dict):
1038 raise TypeError('Expecting dict type for "customToXMLTypeMap"')
1039
1040 for samlClass, etreeClass in customToXMLTypeMap.items():
1041 if not issubclass(samlClass, AttributeValue):
1042 raise TypeError("Input custom class must be derived from %r, "
1043 "got %r instead" % (Attribute, samlClass))
1044
1045 self.__toXMLTypeMap[samlClass] = etreeClass
1046
1047 if not isinstance(customToSAMLTypeMap, (list, tuple)):
1048 raise TypeError('Expecting list or tuple type for '
1049 '"customToSAMLTypeMap"')
1050
1051 self.__toSAMLTypeMap = AttributeValueElementTreeFactory.toSAMLTypeMap[:]
1052 for func in customToSAMLTypeMap:
1053 if not callable(func):
1054 raise TypeError('"customToSAMLTypeMap" items must be callable')
1055
1056 self.__toSAMLTypeMap += customToSAMLTypeMap
1057
1059 """Create an ElementTree object based on the Attribute class type
1060 passed in
1061
1062 @type input: saml.saml2.core.AttributeValue or basestring
1063 @param input: pass an AttributeValue derived type or a string. If
1064 an AttributeValue type, then self.__toXMLTypeMap is checked for a
1065 matching AttributeValue class entry, if a string is passed,
1066 self.__toSAMLTypeMap is checked for a matching string ID. In both
1067 cases, if a match is found an ElementTree class is returned which can
1068 render or parse the relevant AttributeValue class
1069 """
1070 if isinstance(input, AttributeValue):
1071 XMLTypeClass = self.__toXMLTypeMap.get(input.__class__)
1072 if XMLTypeClass is None:
1073 raise UnknownAttrProfile("no matching XMLType class "
1074 "representation for class %r" %
1075 input.__class__)
1076
1077 elif ElementTree.iselement(input):
1078 XMLTypeClasses = []
1079 for matchFunc in self.__toSAMLTypeMap:
1080 cls = matchFunc(input)
1081 if cls is None:
1082 continue
1083 elif issubclass(cls, AttributeValue):
1084 XMLTypeClasses.append(cls)
1085 else:
1086 raise TypeError("Expecting AttributeValue derived type "
1087 "for XML class; got %r" % cls)
1088
1089 nXMLTypeClasses = len(XMLTypeClasses)
1090 if nXMLTypeClasses == 0:
1091 raise UnknownAttrProfile("no matching XMLType class "
1092 "representation for SAML "
1093 "AttributeValue type %r" % input)
1094 elif nXMLTypeClasses > 1:
1095 raise TypeError("Multiple XMLType classes %r matched for "
1096 "for SAML AttributeValue type %r" %
1097 (XMLTypeClasses, input))
1098
1099 XMLTypeClass = XMLTypeClasses[0]
1100 else:
1101 raise TypeError("Expecting %r class got %r" % (AttributeValue,
1102 type(input)))
1103 return XMLTypeClass
1104
1107 """Represent a SAML Issuer element in XML using ElementTree"""
1108
1109 @classmethod
1111 """Create an XML representation of the input SAML issuer object
1112
1113 @type issuer: saml.saml2.core.Issuer
1114 @param issuer: Assertion object
1115 @rtype: ElementTree.Element
1116 @return: ElementTree element containing the assertion
1117 """
1118 if not isinstance(issuer, Issuer):
1119 raise TypeError("Expecting %r class got %r" % (Issuer,
1120 type(issuer)))
1121
1122 # Issuer format may be omitted from a response: saml-profiles-2.0-os,
1123 # Section 4.1.4.2
1124 attrib = {}
1125 if issuer.format is not None:
1126 attrib[cls.FORMAT_ATTRIB_NAME] = issuer.format
1127
1128 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
1129 elem = makeEtreeElement(tag, issuer.qname.prefix,
1130 issuer.qname.namespaceURI,
1131 **attrib)
1132
1133 elem.text = issuer.value
1134
1135 return elem
1136
1137 @classmethod
1139 """Parse ElementTree element into a SAML Issuer instance
1140
1141 @type elem: ElementTree.Element
1142 @param elem: ElementTree element containing the assertion
1143 @rtype: saml.saml2.core.Issuer
1144 @return: Assertion object"""
1145 if not ElementTree.iselement(elem):
1146 raise TypeError("Expecting %r input type for parsing; got %r" %
1147 (ElementTree.Element, elem))
1148
1149 if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
1150 raise XMLTypeParseError('No "%s" element found' %
1151 cls.DEFAULT_ELEMENT_LOCAL_NAME)
1152
1153 issuerFormat = elem.attrib.get(cls.FORMAT_ATTRIB_NAME)
1154 issuer = Issuer()
1155
1156 # Issuer format may be omitted from a response: saml-profiles-2.0-os,
1157 # Section 4.1.4.2
1158 if issuerFormat is not None:
1159 issuer.format = issuerFormat
1160
1161 if elem.text is None:
1162 raise XMLTypeParseError('No SAML issuer value set')
1163
1164 issuer.value = elem.text.strip()
1165
1166 return issuer
1167
1170 """Represent a SAML Name Identifier in XML using ElementTree"""
1171
1172 @classmethod
1174 """Create an XML representation of the input SAML Name Identifier
1175 object
1176 @type nameID: saml.saml2.core.NameID
1177 @param nameID: SAML name ID
1178 @rtype: ElementTree.Element
1179 @return: Name ID as ElementTree XML element
1180 """
1181
1182 if not isinstance(nameID, NameID):
1183 raise TypeError("Expecting %r class got %r" % (NameID,
1184 type(nameID)))
1185 attrib = {
1186 cls.FORMAT_ATTRIB_NAME: nameID.format
1187 }
1188 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
1189 elem = makeEtreeElement(tag, nameID.qname.prefix,
1190 nameID.qname.namespaceURI,
1191 **attrib)
1192
1193 elem.text = nameID.value
1194
1195 return elem
1196
1197 @classmethod
1199 """Parse ElementTree element into a SAML NameID object
1200
1201 @type elem: ElementTree.Element
1202 @param elem: Name ID as ElementTree XML element
1203 @rtype: saml.saml2.core.NameID
1204 @return: SAML Name ID
1205 """
1206 if not ElementTree.iselement(elem):
1207 raise TypeError("Expecting %r input type for parsing; got %r" %
1208 (ElementTree.Element, elem))
1209
1210 if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
1211 raise XMLTypeParseError("No \"%s\" element found" %
1212 cls.DEFAULT_ELEMENT_LOCAL_NAME)
1213
1214 format = elem.attrib.get(cls.FORMAT_ATTRIB_NAME)
1215 if format is None:
1216 raise XMLTypeParseError('No "%s" attribute found in "%s" '
1217 'element' %
1218 (cls.FORMAT_ATTRIB_NAME,
1219 cls.DEFAULT_ELEMENT_LOCAL_NAME))
1220 nameID = NameID()
1221 nameID.format = format
1222 if elem.text is None:
1223 nameID.value = ''
1224 else:
1225 nameID.value = elem.text.strip()
1226
1227 return nameID
1228
1231 """Represent a SAML Subject in XML using ElementTree"""
1232
1233 @classmethod
1235 """Create an XML representation of the input SAML subject object
1236 @type subject: saml.saml2.core.Subject
1237 @param subject: SAML subject
1238 @rtype: ElementTree.Element
1239 @return: subject as ElementTree XML element
1240 """
1241 if not isinstance(subject, Subject):
1242 raise TypeError("Expecting %r class got %r" % (Subject,
1243 type(subject)))
1244
1245 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
1246 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
1247 cls.DEFAULT_ELEMENT_NAME.namespaceURI)
1248
1249 nameIdElem = NameIdElementTree.toXML(subject.nameID)
1250 elem.append(nameIdElem)
1251
1252 return elem
1253
1254 @classmethod
1256 """Parse ElementTree element into a SAML Subject object
1257
1258 @type elem: ElementTree.Element
1259 @param elem: subject as ElementTree XML element
1260 @rtype: saml.saml2.core.Subject
1261 @return: SAML subject
1262 """
1263 if not ElementTree.iselement(elem):
1264 raise TypeError("Expecting %r input type for parsing; got %r" %
1265 (ElementTree.Element, elem))
1266
1267 if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
1268 raise XMLTypeParseError("No \"%s\" element found" %
1269 cls.DEFAULT_ELEMENT_LOCAL_NAME)
1270
1271 if len(elem) != 1:
1272 raise XMLTypeParseError("Expecting single Name ID child element "
1273 "for SAML Subject element")
1274
1275 subject = Subject()
1276 subject.nameID = NameIdElementTree.fromXML(elem[0])
1277
1278 return subject
1279
1282 """Represent a SAML Status Code in XML using ElementTree"""
1283
1284 @classmethod
1286 """Create an XML representation of the input SAML Name Status Code
1287
1288 @type statusCode: saml.saml2.core.StatusCode
1289 @param statusCode: SAML Status Code
1290 @rtype: ElementTree.Element
1291 @return: Status Code as ElementTree XML element
1292 """
1293
1294 if not isinstance(statusCode, StatusCode):
1295 raise TypeError("Expecting %r class got %r" % (StatusCode,
1296 type(statusCode)))
1297
1298 attrib = {
1299 cls.VALUE_ATTRIB_NAME: statusCode.value
1300 }
1301 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
1302 elem = makeEtreeElement(tag, statusCode.qname.prefix,
1303 statusCode.qname.namespaceURI,
1304 **attrib)
1305
1306 return elem
1307
1308 @classmethod
1310 """Parse ElementTree element into a SAML StatusCode object
1311
1312 @type elem: ElementTree.Element
1313 @param elem: Status Code as ElementTree XML element
1314 @rtype: saml.saml2.core.StatusCode
1315 @return: SAML Status Code
1316 """
1317 if not ElementTree.iselement(elem):
1318 raise TypeError("Expecting %r input type for parsing; got %r" %
1319 (ElementTree.Element, elem))
1320
1321 if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
1322 raise XMLTypeParseError('No "%s" element found' %
1323 cls.DEFAULT_ELEMENT_LOCAL_NAME)
1324
1325 statusCode = StatusCode()
1326
1327 value = elem.attrib.get(cls.VALUE_ATTRIB_NAME)
1328 if value is None:
1329 raise XMLTypeParseError('No "%s" attribute found in "%s" element' %
1330 (cls.VALUE_ATTRIB_NAME,
1331 cls.DEFAULT_ELEMENT_LOCAL_NAME))
1332 statusCode.value = value
1333
1334 return statusCode
1335
1338 """Represent a SAML Status Message in XML using ElementTree"""
1339
1340 @classmethod
1342 """Create an XML representation of the input SAML Name Status Message
1343
1344 @type statusMessage: saml.saml2.core.StatusMessage
1345 @param statusMessage: SAML Status Message
1346 @rtype: ElementTree.Element
1347 @return: Status Code as ElementTree XML element
1348 """
1349
1350 if not isinstance(statusMessage, StatusMessage):
1351 raise TypeError("Expecting %r class got %r" % (StatusMessage,
1352 type(statusMessage)))
1353
1354 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
1355 elem = makeEtreeElement(tag, statusMessage.qname.prefix,
1356 statusMessage.qname.namespaceURI)
1357
1358 elem.text = statusMessage.value
1359
1360 return elem
1361
1362 @classmethod
1364 """Parse ElementTree element into a SAML StatusMessage object
1365
1366 @type elem: ElementTree.Element
1367 @param elem: Status Code as ElementTree XML element
1368 @rtype: saml.saml2.core.StatusMessage
1369 @return: SAML Status Message
1370 """
1371 if not ElementTree.iselement(elem):
1372 raise TypeError("Expecting %r input type for parsing; got %r" %
1373 (ElementTree.Element, elem))
1374
1375 if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
1376 raise XMLTypeParseError('No "%s" element found' %
1377 cls.DEFAULT_ELEMENT_LOCAL_NAME)
1378
1379 statusMessage = StatusMessage()
1380 if elem.text is not None:
1381 statusMessage.value = elem.text.strip()
1382
1383 return statusMessage
1384
1387 """Represent a SAML Status in XML using ElementTree"""
1388
1389 @classmethod
1391 """Create an XML representation of the input SAML subject object
1392 @type status: saml.saml2.core.Status
1393 @param status: SAML subject
1394 @rtype: ElementTree.Element
1395 @return: subject as ElementTree XML element
1396 """
1397 if not isinstance(status, Status):
1398 raise TypeError("Expecting %r class got %r" % (status,
1399 type(Status)))
1400
1401 tag = str(QName.fromGeneric(Status.DEFAULT_ELEMENT_NAME))
1402 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
1403 cls.DEFAULT_ELEMENT_NAME.namespaceURI)
1404
1405 statusCodeElem = StatusCodeElementTree.toXML(status.statusCode)
1406 elem.append(statusCodeElem)
1407
1408 # Status message is optional
1409 if status.statusMessage is not None and \
1410 status.statusMessage.value is not None:
1411 statusMessageElem = StatusMessageElementTree.toXML(
1412 status.statusMessage)
1413 elem.append(statusMessageElem)
1414
1415 if status.statusDetail is not None:
1416 raise NotImplementedError("StatusDetail XML serialisation is not "
1417 "implemented")
1418
1419 return elem
1420
1421 @classmethod
1423 """Parse ElementTree element into a SAML Status object
1424
1425 @type elem: ElementTree.Element
1426 @param elem: subject as ElementTree XML element
1427 @rtype: saml.saml2.core.Status
1428 @return: SAML subject
1429 """
1430 if not ElementTree.iselement(elem):
1431 raise TypeError("Expecting %r input type for parsing; got %r" %
1432 (ElementTree.Element, elem))
1433
1434 if QName.getLocalPart(elem.tag) != Status.DEFAULT_ELEMENT_LOCAL_NAME:
1435 raise XMLTypeParseError('No "%s" element found' %
1436 Status.DEFAULT_ELEMENT_LOCAL_NAME)
1437
1438 if len(elem) < 1:
1439 raise XMLTypeParseError("Expecting a StatusCode child element for "
1440 "SAML Status element")
1441
1442 status = Status()
1443 for childElem in elem:
1444 localName = QName.getLocalPart(childElem.tag)
1445 if localName == StatusCode.DEFAULT_ELEMENT_LOCAL_NAME:
1446 status.statusCode = StatusCodeElementTree.fromXML(childElem)
1447
1448 elif localName == StatusMessage.DEFAULT_ELEMENT_LOCAL_NAME:
1449 status.statusMessage = StatusMessageElementTree.fromXML(
1450 childElem)
1451 elif localName == StatusDetail.DEFAULT_ELEMENT_LOCAL_NAME:
1452 raise NotImplementedError("XML parse of %s element is not "
1453 "implemented" %
1454 StatusDetail.DEFAULT_ELEMENT_LOCAL_NAME)
1455 else:
1456 raise XMLTypeParseError("Status child element name %r not "
1457 "recognised" % localName)
1458
1459 return status
1460
1463 """Represent a SAML Attribute Query in XML using ElementTree"""
1464
1465 @classmethod
1467 """Create an XML representation of the input SAML Attribute Query
1468 object
1469
1470 @type attributeQuery: saml.saml2.core.AttributeQuery
1471 @param attributeQuery: SAML Attribute Query
1472 @type attributeValueElementTreeFactoryKw: dict
1473 @param attributeValueElementTreeFactoryKw: keywords for AttributeValue
1474 factory
1475 @rtype: ElementTree.Element
1476 @return: Attribute Query as ElementTree XML element
1477 """
1478 if not isinstance(attributeQuery, AttributeQuery):
1479 raise TypeError("Expecting %r class got %r" % (AttributeQuery,
1480 type(attributeQuery)))
1481
1482
1483 issueInstant = SAMLDateTime.toString(attributeQuery.issueInstant)
1484 attrib = {
1485 cls.ID_ATTRIB_NAME: attributeQuery.id,
1486 cls.ISSUE_INSTANT_ATTRIB_NAME: issueInstant,
1487
1488 # Nb. Version is a SAMLVersion instance and requires explicit cast
1489 cls.VERSION_ATTRIB_NAME: str(attributeQuery.version)
1490 }
1491
1492 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
1493 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
1494 cls.DEFAULT_ELEMENT_NAME.namespaceURI,
1495 **attrib)
1496
1497 issuerElem = IssuerElementTree.toXML(attributeQuery.issuer)
1498 elem.append(issuerElem)
1499
1500 subjectElem = SubjectElementTree.toXML(attributeQuery.subject)
1501 elem.append(subjectElem)
1502
1503 for attribute in attributeQuery.attributes:
1504 # Factory enables support for multiple attribute types
1505 attributeElem = AttributeElementTree.toXML(attribute,
1506 **attributeValueElementTreeFactoryKw)
1507 elem.append(attributeElem)
1508
1509 return elem
1510
1511 @classmethod
1513 """Parse ElementTree element into a SAML AttributeQuery object
1514
1515 @type elem: ElementTree.Element
1516 @param elem: XML element containing the AttributeQuery
1517 @rtype: saml.saml2.core.AttributeQuery
1518 @return: AttributeQuery object
1519 """
1520 if not ElementTree.iselement(elem):
1521 raise TypeError("Expecting %r input type for parsing; got %r" %
1522 (ElementTree.Element, elem))
1523
1524 if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
1525 raise XMLTypeParseError("No \"%s\" element found" %
1526 cls.DEFAULT_ELEMENT_LOCAL_NAME)
1527
1528 # Unpack attributes from top-level element
1529 attributeValues = []
1530 for attributeName in (cls.VERSION_ATTRIB_NAME,
1531 cls.ISSUE_INSTANT_ATTRIB_NAME,
1532 cls.ID_ATTRIB_NAME):
1533 attributeValue = elem.attrib.get(attributeName)
1534 if attributeValue is None:
1535 raise XMLTypeParseError('No "%s" attribute found in "%s" '
1536 'element' %
1537 (attributeName,
1538 cls.DEFAULT_ELEMENT_LOCAL_NAME))
1539
1540 attributeValues.append(attributeValue)
1541
1542 attributeQuery = AttributeQuery()
1543 attributeQuery.version = SAMLVersion(attributeValues[0])
1544 if attributeQuery.version != SAMLVersion.VERSION_20:
1545 raise NotImplementedError("Parsing for %r is implemented for "
1546 "SAML version %s only; version %s is "
1547 "not supported" %
1548 (cls,
1549 SAMLVersion(SAMLVersion.VERSION_20),
1550 SAMLVersion(attributeQuery.version)))
1551
1552 attributeQuery.issueInstant = SAMLDateTime.fromString(
1553 attributeValues[1])
1554 attributeQuery.id = attributeValues[2]
1555
1556 for childElem in elem:
1557 localName = QName.getLocalPart(childElem.tag)
1558 if localName == Issuer.DEFAULT_ELEMENT_LOCAL_NAME:
1559 # Parse Issuer
1560 attributeQuery.issuer = IssuerElementTree.fromXML(childElem)
1561
1562 elif localName == Subject.DEFAULT_ELEMENT_LOCAL_NAME:
1563 # Parse Subject
1564 attributeQuery.subject = SubjectElementTree.fromXML(childElem)
1565
1566 elif localName == Attribute.DEFAULT_ELEMENT_LOCAL_NAME:
1567 attribute = AttributeElementTree.fromXML(childElem)
1568 attributeQuery.attributes.append(attribute)
1569 else:
1570 raise XMLTypeParseError("Unrecognised AttributeQuery child "
1571 "element \"%s\"" % localName)
1572
1573 return attributeQuery
1574
1577 """Represent a SAML Response in XML using ElementTree"""
1578
1579 @classmethod
1581 """Create an XML representation of the input SAML Response
1582 object
1583
1584 @type response: saml.saml2.core.Response
1585 @param response: SAML Response
1586 @type attributeValueElementTreeFactoryKw: dict
1587 @param attributeValueElementTreeFactoryKw: keywords for AttributeValue
1588 factory
1589 @rtype: ElementTree.Element
1590 @return: Response as ElementTree XML element
1591 """
1592 if not isinstance(response, Response):
1593 raise TypeError("Expecting %r class, got %r" % (Response,
1594 type(response)))
1595
1596 if response.id is None:
1597 raise TypeError("SAML Response id is not set")
1598
1599 if response.issueInstant is None:
1600 raise TypeError("SAML Response issueInstant is not set")
1601
1602 # TODO: Does inResponseTo have to be set? This implementation
1603 # currently enforces this ...
1604 if response.inResponseTo is None:
1605 raise TypeError("SAML Response inResponseTo identifier is not set")
1606
1607 issueInstant = SAMLDateTime.toString(response.issueInstant)
1608 attrib = {
1609 cls.ID_ATTRIB_NAME: response.id,
1610 cls.ISSUE_INSTANT_ATTRIB_NAME: issueInstant,
1611 cls.IN_RESPONSE_TO_ATTRIB_NAME: response.inResponseTo,
1612
1613 # Nb. Version is a SAMLVersion instance and requires explicit cast
1614 cls.VERSION_ATTRIB_NAME: str(response.version)
1615 }
1616
1617 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
1618 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
1619 cls.DEFAULT_ELEMENT_NAME.namespaceURI,
1620 **attrib)
1621
1622 # Issuer may be omitted: saml-profiles-2.0-os Section 4.1.4.2
1623 if response.issuer is not None:
1624 issuerElem = IssuerElementTree.toXML(response.issuer)
1625 elem.append(issuerElem)
1626
1627 statusElem = StatusElementTree.toXML(response.status)
1628 elem.append(statusElem)
1629
1630 for assertion in response.assertions:
1631 # Factory enables support for multiple attribute types
1632 assertionElem = AssertionElementTree.toXML(assertion,
1633 **attributeValueElementTreeFactoryKw)
1634 elem.append(assertionElem)
1635
1636 return elem
1637
1638 @classmethod
1640 """Parse ElementTree element into a SAML Response object
1641
1642 @type elem: ElementTree.Element
1643 @param elem: XML element containing the Response
1644 @type attributeValueElementTreeFactoryKw: dict
1645 @param attributeValueElementTreeFactoryKw: keywords for AttributeValue
1646 @rtype: saml.saml2.core.Response
1647 @return: Response object
1648 """
1649 if not ElementTree.iselement(elem):
1650 raise TypeError("Expecting %r input type for parsing; got %r" %
1651 (ElementTree.Element, elem))
1652
1653 if QName.getLocalPart(elem.tag) != Response.DEFAULT_ELEMENT_LOCAL_NAME:
1654 raise XMLTypeParseError("No \"%s\" element found" %
1655 Response.DEFAULT_ELEMENT_LOCAL_NAME)
1656
1657 # Unpack attributes from top-level element
1658 attributeValues = []
1659 for attributeName in (Response.VERSION_ATTRIB_NAME,
1660 Response.ISSUE_INSTANT_ATTRIB_NAME,
1661 Response.ID_ATTRIB_NAME,
1662 Response.IN_RESPONSE_TO_ATTRIB_NAME):
1663 attributeValue = elem.attrib.get(attributeName)
1664 if attributeValue is None:
1665 raise XMLTypeParseError('No "%s" attribute found in "%s" '
1666 'element' %
1667 (attributeName,
1668 Response.DEFAULT_ELEMENT_LOCAL_NAME))
1669
1670 attributeValues.append(attributeValue)
1671
1672 response = Response()
1673 response.version = SAMLVersion(attributeValues[0])
1674 if response.version != SAMLVersion.VERSION_20:
1675 raise NotImplementedError("Parsing for %r is implemented for "
1676 "SAML version %s only; version %s is "
1677 "not supported" %
1678 (cls,
1679 SAMLVersion(SAMLVersion.VERSION_20),
1680 SAMLVersion(response.version)))
1681
1682 response.issueInstant = SAMLDateTime.fromString(attributeValues[1])
1683 response.id = attributeValues[2]
1684 response.inResponseTo = attributeValues[3]
1685
1686 for childElem in elem:
1687 localName = QName.getLocalPart(childElem.tag)
1688 if localName == Issuer.DEFAULT_ELEMENT_LOCAL_NAME:
1689 # Parse Issuer
1690 response.issuer = IssuerElementTree.fromXML(childElem)
1691
1692 elif localName == Status.DEFAULT_ELEMENT_LOCAL_NAME:
1693 # Get status of response
1694 response.status = StatusElementTree.fromXML(childElem)
1695
1696 elif localName == Subject.DEFAULT_ELEMENT_LOCAL_NAME:
1697 # Parse Subject
1698 response.subject = SubjectElementTree.fromXML(childElem)
1699
1700 elif localName == Assertion.DEFAULT_ELEMENT_LOCAL_NAME:
1701 assertion = AssertionElementTree.fromXML(childElem,
1702 **attributeValueElementTreeFactoryKw)
1703 response.assertions.append(assertion)
1704 else:
1705 raise XMLTypeParseError('Unrecognised Response child '
1706 'element "%s"' % localName)
1707
1708 return response
1709
1712 """Represent a SAML authorization action in XML using ElementTree"""
1713
1714 @classmethod
1716 """Create an XML representation of the input SAML Name Identifier
1717 object
1718 @type action: saml.saml2.core.Action
1719 @param action: SAML subject
1720 @rtype: ElementTree.Element
1721 @return: Name ID as ElementTree XML element
1722 """
1723
1724 if not isinstance(action, Action):
1725 raise TypeError("Expecting %r class got %r" % (Action,
1726 type(action)))
1727
1728 if not action.namespace:
1729 raise AttributeError("No action namespace set")
1730
1731 attrib = {
1732 cls.NAMESPACE_ATTRIB_NAME: action.namespace
1733 }
1734 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
1735 elem = makeEtreeElement(tag, action.qname.prefix,
1736 action.qname.namespaceURI,
1737 **attrib)
1738 elem = ElementTree.Element(tag, **attrib)
1739
1740 if not action.value:
1741 raise AttributeError("No action name set")
1742
1743 elem.text = action.value
1744
1745 return elem
1746
1747 @classmethod
1749 """Parse ElementTree element into a SAML Action object
1750
1751 @type elem: ElementTree.Element
1752 @param elem: Name ID as ElementTree XML element
1753 @rtype: saml.saml2.core.Action
1754 @return: SAML Name ID
1755 """
1756 if not ElementTree.iselement(elem):
1757 raise TypeError("Expecting %r input type for parsing; got %r" %
1758 (ElementTree.Element, elem))
1759
1760 if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
1761 raise XMLTypeParseError("No \"%s\" element found" %
1762 cls.DEFAULT_ELEMENT_LOCAL_NAME)
1763
1764 action = Action()
1765 namespace = elem.attrib.get(cls.NAMESPACE_ATTRIB_NAME)
1766 if namespace is None:
1767 log.warning('No "%s" attribute found in "%s" element assuming '
1768 '%r action namespace' %
1769 (cls.NAMESPACE_ATTRIB_NAME,
1770 cls.DEFAULT_ELEMENT_LOCAL_NAME,
1771 action.namespace))
1772 else:
1773 action.namespace = namespace
1774
1775 action.value = elem.text.strip()
1776
1777 return action
1778
1781 """Represent a SAML Attribute Query in XML using ElementTree"""
1782
1783 @classmethod
1785 """Create an XML representation of the input SAML Authorization
1786 Decision Query object
1787
1788 @type authzDecisionQuery: saml.saml2.core.AuthzDecisionQuery
1789 @param authzDecisionQuery: SAML Authorization Decision Query
1790 @rtype: ElementTree.Element
1791 @return: Attribute Query as ElementTree XML element
1792 """
1793 if not isinstance(authzDecisionQuery, AuthzDecisionQuery):
1794 raise TypeError("Expecting %r class got %r" % (AuthzDecisionQuery,
1795 type(authzDecisionQuery)))
1796
1797 if not authzDecisionQuery.resource:
1798 raise AttributeError("No resource has been set for the "
1799 "AuthzDecisionQuery")
1800
1801 issueInstant = SAMLDateTime.toString(authzDecisionQuery.issueInstant)
1802 attrib = {
1803 cls.ID_ATTRIB_NAME: authzDecisionQuery.id,
1804 cls.ISSUE_INSTANT_ATTRIB_NAME: issueInstant,
1805
1806 # Nb. Version is a SAMLVersion instance and requires explicit cast
1807 cls.VERSION_ATTRIB_NAME: str(authzDecisionQuery.version),
1808
1809 cls.RESOURCE_ATTRIB_NAME: authzDecisionQuery.resource
1810 }
1811
1812 tag = str(QName.fromGeneric(cls.DEFAULT_ELEMENT_NAME))
1813 elem = makeEtreeElement(tag, cls.DEFAULT_ELEMENT_NAME.prefix,
1814 cls.DEFAULT_ELEMENT_NAME.namespaceURI,
1815 **attrib)
1816
1817 issuerElem = IssuerElementTree.toXML(authzDecisionQuery.issuer)
1818 elem.append(issuerElem)
1819
1820 subjectElem = SubjectElementTree.toXML(authzDecisionQuery.subject)
1821 elem.append(subjectElem)
1822
1823 for action in authzDecisionQuery.actions:
1824 # Factory enables support for multiple attribute types
1825 actionElem = ActionElementTree.toXML(action)
1826 elem.append(actionElem)
1827
1828 if (authzDecisionQuery.evidence and
1829 len(authzDecisionQuery.evidence.evidence) > 0):
1830 raise NotImplementedError("Conversion of AuthzDecisionQuery "
1831 "Evidence type to ElementTree Element is "
1832 "not currently supported")
1833
1834 return elem
1835
1836 @classmethod
1838 """Parse ElementTree element into a SAML AuthzDecisionQuery object
1839
1840 @type elem: ElementTree.Element
1841 @param elem: XML element containing the AuthzDecisionQuery
1842 @rtype: saml.saml2.core.AuthzDecisionQuery
1843 @return: AuthzDecisionQuery object
1844 """
1845 if not ElementTree.iselement(elem):
1846 raise TypeError("Expecting %r input type for parsing; got %r" %
1847 (ElementTree.Element, elem))
1848
1849 if QName.getLocalPart(elem.tag) != cls.DEFAULT_ELEMENT_LOCAL_NAME:
1850 raise XMLTypeParseError("No \"%s\" element found" %
1851 cls.DEFAULT_ELEMENT_LOCAL_NAME)
1852
1853 # Unpack attributes from top-level element
1854 attributeValues = []
1855 for attributeName in (cls.VERSION_ATTRIB_NAME,
1856 cls.ISSUE_INSTANT_ATTRIB_NAME,
1857 cls.ID_ATTRIB_NAME,
1858 cls.RESOURCE_ATTRIB_NAME):
1859 attributeValue = elem.attrib.get(attributeName)
1860 if attributeValue is None:
1861 raise XMLTypeParseError('No "%s" attribute found in "%s" '
1862 'element' %
1863 (attributeName,
1864 cls.DEFAULT_ELEMENT_LOCAL_NAME))
1865
1866 attributeValues.append(attributeValue)
1867
1868 authzDecisionQuery = AuthzDecisionQuery()
1869 authzDecisionQuery.version = SAMLVersion(attributeValues[0])
1870 if authzDecisionQuery.version != SAMLVersion.VERSION_20:
1871 raise NotImplementedError("Parsing for %r is implemented for "
1872 "SAML version %s only; version %s is "
1873 "not supported" %
1874 (cls,
1875 SAMLVersion(SAMLVersion.VERSION_20),
1876 SAMLVersion(authzDecisionQuery.version)))
1877
1878 authzDecisionQuery.issueInstant = SAMLDateTime.fromString(
1879 attributeValues[1])
1880 authzDecisionQuery.id = attributeValues[2]
1881 authzDecisionQuery.resource = attributeValues[3]
1882
1883 for childElem in elem:
1884 localName = QName.getLocalPart(childElem.tag)
1885 if localName == Issuer.DEFAULT_ELEMENT_LOCAL_NAME:
1886 # Parse Issuer
1887 authzDecisionQuery.issuer = IssuerElementTree.fromXML(childElem)
1888
1889 elif localName == Subject.DEFAULT_ELEMENT_LOCAL_NAME:
1890 # Parse Subject
1891 authzDecisionQuery.subject = SubjectElementTree.fromXML(childElem)
1892
1893 elif localName == Action.DEFAULT_ELEMENT_LOCAL_NAME:
1894 action = ActionElementTree.fromXML(childElem)
1895 authzDecisionQuery.actions.append(action)
1896 else:
1897 raise XMLTypeParseError("Unrecognised AuthzDecisionQuery child "
1898 "element \"%s\"" % localName)
1899
1900 return authzDecisionQuery
1901
1903 key = ("{%s}%s" % (qname.namespaceURI, qname.localPart))
1904 return _extensionElementTreeMap.get(key)
1905
1907 key = ("{%s}%s" % (qname.namespaceURI, qname.localPart))
1908 _extensionElementTreeMap[key] = impl
1909
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Wed Apr 4 22:19:44 2012 | http://epydoc.sourceforge.net |