Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
log.py217 linesDownload Raw Back to utils
1"""
2"""
3
4# Created on 2015.05.01
5#
6# Author: Giovanni Cannata
7#
8# Copyright 2015 - 2020 Giovanni Cannata
9#
10# This file is part of ldap3.
11#
12# ldap3 is free software: you can redistribute it and/or modify
13# it under the terms of the GNU Lesser General Public License as published
14# by the Free Software Foundation, either version 3 of the License, or
15# (at your option) any later version.
16#
17# ldap3 is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20# GNU Lesser General Public License for more details.
21#
22# You should have received a copy of the GNU Lesser General Public License
23# along with ldap3 in the COPYING and COPYING.LESSER files.
24# If not, see <http://www.gnu.org/licenses/>.
25
26from logging import getLogger, DEBUG
27from copy import deepcopy
28from pprint import pformat
29from ..protocol.rfc4511 import LDAPMessage
30
31# logging levels
32OFF = 0
33ERROR = 10
34BASIC = 20
35PROTOCOL = 30
36NETWORK = 40
37EXTENDED = 50
38
39_sensitive_lines = ('simple', 'credentials', 'serversaslcreds')  # must be a tuple, not a list, lowercase
40_sensitive_args = ('simple', 'password', 'sasl_credentials', 'saslcreds', 'server_creds')
41_sensitive_attrs = ('userpassword', 'unicodepwd')
42
43_hide_sensitive_data = None
44
45DETAIL_LEVELS = [OFF, ERROR, BASIC, PROTOCOL, NETWORK, EXTENDED]
46
47_max_line_length = 4096
48_logging_level = 0
49_detail_level = 0
50_logging_encoding = 'ascii'
51
52try:
53    from logging import NullHandler
54except ImportError:  # NullHandler not present in Python < 2.7
55    from logging import Handler
56
57    class NullHandler(Handler):
58        def handle(self, record):
59            pass
60
61        def emit(self, record):
62            pass
63
64        def createLock(self):
65            self.lock = None
66
67
68def _strip_sensitive_data_from_dict(d):
69    if not isinstance(d, dict):
70        return d
71
72    try:
73        d = deepcopy(d)
74    except Exception:  # if deepcopy goes wrong gives up and returns the dict unchanged
75        return d
76    for k in d.keys():
77        if isinstance(d[k], dict):
78            d[k] = _strip_sensitive_data_from_dict(d[k])
79        elif k.lower() in _sensitive_args and d[k]:
80            d[k] = '<stripped %d characters of sensitive data>' % len(d[k])
81
82    return d
83
84
85def get_detail_level_name(level_name):
86    if level_name == OFF:
87        return 'OFF'
88    elif level_name == ERROR:
89        return 'ERROR'
90    elif level_name == BASIC:
91        return 'BASIC'
92    elif level_name == PROTOCOL:
93        return 'PROTOCOL'
94    elif level_name == NETWORK:
95        return 'NETWORK'
96    elif level_name == EXTENDED:
97        return 'EXTENDED'
98    raise ValueError('unknown detail level')
99
100
101def log(detail, message, *args):
102    if detail <= _detail_level:
103        if _hide_sensitive_data:
104            args = tuple([_strip_sensitive_data_from_dict(arg) if isinstance(arg, dict) else arg for arg in args])
105
106        if str is not bytes:  # Python 3
107            encoded_message = (get_detail_level_name(detail) + ':' + message % args).encode(_logging_encoding, 'backslashreplace')
108            encoded_message = encoded_message.decode()
109        else:
110            try:
111                encoded_message = (get_detail_level_name(detail) + ':' + message % args).encode(_logging_encoding, 'replace')
112            except Exception:
113                encoded_message = (get_detail_level_name(detail) + ':' + message % args).decode(_logging_encoding, 'replace')
114
115        if len(encoded_message) > _max_line_length:
116            logger.log(_logging_level, encoded_message[:_max_line_length] + ' <removed %d remaining bytes in this log line>' % (len(encoded_message) - _max_line_length, ))
117        else:
118            logger.log(_logging_level, encoded_message)
119
120
121def log_enabled(detail):
122    if detail <= _detail_level:
123        if logger.isEnabledFor(_logging_level):
124            return True
125
126    return False
127
128
129def set_library_log_hide_sensitive_data(hide=True):
130    global _hide_sensitive_data
131    if hide:
132        _hide_sensitive_data = True
133    else:
134        _hide_sensitive_data = False
135    if log_enabled(ERROR):
136        log(ERROR, 'hide sensitive data set to ' + str(_hide_sensitive_data))
137
138
139def get_library_log_hide_sensitive_data():
140    return True if _hide_sensitive_data else False
141
142
143def set_library_log_activation_level(logging_level):
144    if isinstance(logging_level, int):
145        global _logging_level
146        _logging_level = logging_level
147    else:
148        if log_enabled(ERROR):
149            log(ERROR, 'invalid library log activation level <%s> ', logging_level)
150        raise ValueError('invalid library log activation level')
151
152
153def get_library_log_activation_lavel():
154    return _logging_level
155
156
157def set_library_log_max_line_length(length):
158    if isinstance(length, int):
159        global _max_line_length
160        _max_line_length = length
161    else:
162        if log_enabled(ERROR):
163            log(ERROR, 'invalid log max line length <%s> ', length)
164        raise ValueError('invalid library log max line length')
165
166
167def get_library_log_max_line_length():
168    return _max_line_length
169
170
171def set_library_log_detail_level(detail):
172    if detail in DETAIL_LEVELS:
173        global _detail_level
174        _detail_level = detail
175        if log_enabled(ERROR):
176            log(ERROR, 'detail level set to ' + get_detail_level_name(_detail_level))
177    else:
178        if log_enabled(ERROR):
179            log(ERROR, 'unable to set log detail level to <%s>', detail)
180        raise ValueError('invalid library log detail level')
181
182
183def get_library_log_detail_level():
184    return _detail_level
185
186
187def format_ldap_message(message, prefix):
188    if isinstance(message, LDAPMessage):
189        try:  # pyasn1 prettyprint raises exception in version 0.4.3
190            formatted = message.prettyPrint().split('\n')  # pyasn1 pretty print
191        except Exception as e:
192            formatted = ['pyasn1 exception', str(e)]
193    else:
194        formatted = pformat(message).split('\n')
195
196    prefixed = ''
197    for line in formatted:
198        if line:
199            if _hide_sensitive_data and line.strip().lower().startswith(_sensitive_lines):  # _sensitive_lines is a tuple. startswith() method checks each tuple element
200                tag, _, data = line.partition('=')
201                if data.startswith("b'") and data.endswith("'") or data.startswith('b"') and data.endswith('"'):
202                    prefixed += '\n' + prefix + tag + '=<stripped %d characters of sensitive data>' % (len(data) - 3, )
203                else:
204                    prefixed += '\n' + prefix + tag + '=<stripped %d characters of sensitive data>' % len(data)
205            else:
206                prefixed += '\n' + prefix + line
207    return prefixed
208
209# sets a logger for the library with NullHandler. It can be used by the application with its own logging configuration
210logger = getLogger('ldap3')
211logger.addHandler(NullHandler())
212
213# sets defaults for the library logging
214set_library_log_activation_level(DEBUG)
215set_library_log_detail_level(OFF)
216set_library_log_hide_sensitive_data(True)
217 
codekingpro/portable-devtools · Team Ai