• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SAML-Toolkits / python3-saml / 9634562133

23 Jun 2024 03:29PM UTC coverage: 95.19% (+3.7%) from 91.502%
9634562133

push

github

web-flow
Adjust README to pyproject.toml and fix coverage (#413)

* Adjust README to pyproject.toml

* Adjust coverage coveralls to pyproject.toml

1193 of 1364 branches covered (87.46%)

Branch coverage included in aggregate %.

6902 of 7140 relevant lines covered (96.67%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.41
/src/onelogin/saml2/xmlparser.py
1
# -*- coding: utf-8 -*-
2

3
# Based on the lxml example from defusedxml
4
# DTDForbidden, EntitiesForbidden, NotSupportedError are clones of the classes defined at defusedxml
5
#
6
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
7
# Licensed to PSF under a Contributor Agreement.
8
# See https://www.python.org/psf/license for licensing details.
9
"""lxml.etree protection"""
10

11
from __future__ import print_function, absolute_import
1✔
12

13
import threading
1✔
14

15
from lxml import etree as _etree
1✔
16

17
LXML3 = _etree.LXML_VERSION[0] >= 3
1✔
18

19
__origin__ = "lxml.etree"
1✔
20

21
tostring = _etree.tostring
1✔
22

23

24
class DTDForbidden(ValueError):
1✔
25
    """Document type definition is forbidden
26
    """
27

28
    def __init__(self, name, sysid, pubid):
1✔
29
        super(DTDForbidden, self).__init__()
×
30
        self.name = name
×
31
        self.sysid = sysid
×
32
        self.pubid = pubid
×
33

34
    def __str__(self):
1✔
35
        tpl = "DTDForbidden(name='{}', system_id={!r}, public_id={!r})"
×
36
        return tpl.format(self.name, self.sysid, self.pubid)
×
37

38

39
class EntitiesForbidden(ValueError):
1✔
40
    """Entity definition is forbidden
41
    """
42

43
    def __init__(self, name, value, base, sysid, pubid, notation_name):
1✔
44
        super(EntitiesForbidden, self).__init__()
×
45
        self.name = name
×
46
        self.value = value
×
47
        self.base = base
×
48
        self.sysid = sysid
×
49
        self.pubid = pubid
×
50
        self.notation_name = notation_name
×
51

52
    def __str__(self):
1✔
53
        tpl = "EntitiesForbidden(name='{}', system_id={!r}, public_id={!r})"
×
54
        return tpl.format(self.name, self.sysid, self.pubid)
×
55

56

57
class NotSupportedError(ValueError):
1✔
58
    """The operation is not supported
59
    """
60

61

62
class RestrictedElement(_etree.ElementBase):
1✔
63
    """A restricted Element class that filters out instances of some classes
64
    """
65

66
    __slots__ = ()
1✔
67
    blacklist = (_etree._Entity, _etree._ProcessingInstruction, _etree._Comment)
1✔
68

69
    def _filter(self, iterator):
1✔
70
        blacklist = self.blacklist
1✔
71
        for child in iterator:
1✔
72
            if isinstance(child, blacklist):
1!
73
                continue
×
74
            yield child
1✔
75

76
    def __iter__(self):
1✔
77
        iterator = super(RestrictedElement, self).__iter__()
×
78
        return self._filter(iterator)
×
79

80
    def iterchildren(self, tag=None, reversed=False):
1✔
81
        iterator = super(RestrictedElement, self).iterchildren(tag=tag, reversed=reversed)
1✔
82
        return self._filter(iterator)
1✔
83

84
    def iter(self, tag=None, *tags):
1✔
85
        iterator = super(RestrictedElement, self).iter(tag=tag, *tags)
×
86
        return self._filter(iterator)
×
87

88
    def iterdescendants(self, tag=None, *tags):
1✔
89
        iterator = super(RestrictedElement, self).iterdescendants(tag=tag, *tags)
1✔
90
        return self._filter(iterator)
1✔
91

92
    def itersiblings(self, tag=None, preceding=False):
1✔
93
        iterator = super(RestrictedElement, self).itersiblings(tag=tag, preceding=preceding)
×
94
        return self._filter(iterator)
×
95

96
    def getchildren(self):
1✔
97
        iterator = super(RestrictedElement, self).__iter__()
1✔
98
        return list(self._filter(iterator))
1✔
99

100
    def getiterator(self, tag=None):
1✔
101
        iterator = super(RestrictedElement, self).getiterator(tag)
×
102
        return self._filter(iterator)
×
103

104

105
class GlobalParserTLS(threading.local):
1✔
106
    """Thread local context for custom parser instances
107
    """
108

109
    parser_config = {
1✔
110
        "resolve_entities": False,
111
        'remove_comments': True,
112
        'no_network': True,
113
        'remove_pis': True,
114
        'huge_tree': False
115
    }
116

117
    element_class = RestrictedElement
1✔
118

119
    def createDefaultParser(self):
1✔
120
        parser = _etree.XMLParser(**self.parser_config)
1✔
121
        element_class = self.element_class
1✔
122
        if self.element_class is not None:
1!
123
            lookup = _etree.ElementDefaultClassLookup(element=element_class)
1✔
124
            parser.set_element_class_lookup(lookup)
1✔
125
        return parser
1✔
126

127
    def setDefaultParser(self, parser):
1✔
128
        self._default_parser = parser
1✔
129

130
    def getDefaultParser(self):
1✔
131
        parser = getattr(self, "_default_parser", None)
1✔
132
        if parser is None:
1✔
133
            parser = self.createDefaultParser()
1✔
134
            self.setDefaultParser(parser)
1✔
135
        return parser
1✔
136

137

138
_parser_tls = GlobalParserTLS()
1✔
139
getDefaultParser = _parser_tls.getDefaultParser
1✔
140

141

142
def check_docinfo(elementtree, forbid_dtd=False, forbid_entities=True):
1✔
143
    """Check docinfo of an element tree for DTD and entity declarations
144
    The check for entity declarations needs lxml 3 or newer. lxml 2.x does
145
    not support dtd.iterentities().
146
    """
147
    docinfo = elementtree.docinfo
1✔
148
    if docinfo.doctype:
1!
149
        if forbid_dtd:
×
150
            raise DTDForbidden(docinfo.doctype, docinfo.system_url, docinfo.public_id)
×
151
        if forbid_entities and not LXML3:
×
152
            # lxml < 3 has no iterentities()
153
            raise NotSupportedError("Unable to check for entity declarations " "in lxml 2.x")
×
154

155
    if forbid_entities:
1!
156
        for dtd in docinfo.internalDTD, docinfo.externalDTD:
1✔
157
            if dtd is None:
1!
158
                continue
1✔
159
            for entity in dtd.iterentities():
×
160
                raise EntitiesForbidden(entity.name, entity.content, None, None, None, None)
×
161

162

163
def parse(source, parser=None, base_url=None, forbid_dtd=True, forbid_entities=True):
1✔
164
    if parser is None:
×
165
        parser = getDefaultParser()
×
166
    elementtree = _etree.parse(source, parser, base_url=base_url)
×
167
    check_docinfo(elementtree, forbid_dtd, forbid_entities)
×
168
    return elementtree
×
169

170

171
def fromstring(text, parser=None, base_url=None, forbid_dtd=True, forbid_entities=True):
1✔
172
    if parser is None:
1!
173
        parser = getDefaultParser()
1✔
174
    rootelement = _etree.fromstring(text, parser, base_url=base_url)
1✔
175
    elementtree = rootelement.getroottree()
1✔
176
    check_docinfo(elementtree, forbid_dtd, forbid_entities)
1✔
177
    return rootelement
1✔
178

179

180
XML = fromstring
1✔
181

182

183
def iterparse(*args, **kwargs):
1✔
184
    raise NotSupportedError("iterparse not available")
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc