Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
sasl.py172 linesDownload Raw Back to sasl
1"""
2"""
3
4# Created on 2013.09.11
5#
6# Author: Giovanni Cannata
7#
8# Copyright 2013 - 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
26import stringprep
27from unicodedata import ucd_3_2_0 as unicode32
28from os import urandom
29from binascii import hexlify
30
31from ... import SASL
32from ...core.results import RESULT_AUTH_METHOD_NOT_SUPPORTED
33from ...core.exceptions import LDAPSASLPrepError, LDAPPasswordIsMandatoryError
34
35
36def sasl_prep(data):
37    """
38    implement SASLPrep profile as per RFC4013:
39    it defines the "SASLprep" profile of the "stringprep" algorithm [StringPrep].
40    The profile is designed for use in Simple Authentication and Security
41    Layer ([SASL]) mechanisms, such as [PLAIN], [CRAM-MD5], and
42    [DIGEST-MD5].  It may be applicable where simple user names and
43    passwords are used.  This profile is not intended for use in
44    preparing identity strings that are not simple user names (e.g.,
45    email addresses, domain names, distinguished names), or where
46    identity or password strings that are not character data, or require
47    different handling (e.g., case folding).
48    """
49
50    # mapping
51    prepared_data = ''
52    for c in data:
53        if stringprep.in_table_c12(c):
54            # non-ASCII space characters [StringPrep, C.1.2] that can be mapped to SPACE (U+0020)
55            prepared_data += ' '
56        elif stringprep.in_table_b1(c):
57            # the "commonly mapped to nothing" characters [StringPrep, B.1] that can be mapped to nothing.
58            pass
59        else:
60            prepared_data += c
61
62    # normalizing
63    # This profile specifies using Unicode normalization form KC
64    # The repertoire is Unicode 3.2 as per RFC 4013 (2)
65
66    prepared_data = unicode32.normalize('NFKC', prepared_data)
67
68    if not prepared_data:
69        raise LDAPSASLPrepError('SASLprep error: unable to normalize string')
70
71    # prohibit
72    for c in prepared_data:
73        if stringprep.in_table_c12(c):
74            # Non-ASCII space characters [StringPrep, C.1.2]
75            raise LDAPSASLPrepError('SASLprep error: non-ASCII space character present')
76        elif stringprep.in_table_c21(c):
77            # ASCII control characters [StringPrep, C.2.1]
78            raise LDAPSASLPrepError('SASLprep error: ASCII control character present')
79        elif stringprep.in_table_c22(c):
80            # Non-ASCII control characters [StringPrep, C.2.2]
81            raise LDAPSASLPrepError('SASLprep error: non-ASCII control character present')
82        elif stringprep.in_table_c3(c):
83            # Private Use characters [StringPrep, C.3]
84            raise LDAPSASLPrepError('SASLprep error: private character present')
85        elif stringprep.in_table_c4(c):
86            # Non-character code points [StringPrep, C.4]
87            raise LDAPSASLPrepError('SASLprep error: non-character code point present')
88        elif stringprep.in_table_c5(c):
89            # Surrogate code points [StringPrep, C.5]
90            raise LDAPSASLPrepError('SASLprep error: surrogate code point present')
91        elif stringprep.in_table_c6(c):
92            # Inappropriate for plain text characters [StringPrep, C.6]
93            raise LDAPSASLPrepError('SASLprep error: inappropriate for plain text character present')
94        elif stringprep.in_table_c7(c):
95            # Inappropriate for canonical representation characters [StringPrep, C.7]
96            raise LDAPSASLPrepError('SASLprep error: inappropriate for canonical representation character present')
97        elif stringprep.in_table_c8(c):
98            # Change display properties or deprecated characters [StringPrep, C.8]
99            raise LDAPSASLPrepError('SASLprep error: change display property or deprecated character present')
100        elif stringprep.in_table_c9(c):
101            # Tagging characters [StringPrep, C.9]
102            raise LDAPSASLPrepError('SASLprep error: tagging character present')
103
104    # check bidi
105    # if a string contains any r_and_al_cat character, the string MUST NOT contain any l_cat character.
106    flag_r_and_al_cat = False
107    flag_l_cat = False
108    for c in prepared_data:
109        if stringprep.in_table_d1(c):
110            flag_r_and_al_cat = True
111        elif stringprep.in_table_d2(c):
112            flag_l_cat = True
113
114        if flag_r_and_al_cat and flag_l_cat:
115            raise LDAPSASLPrepError('SASLprep error: string cannot contain (R or AL) and L bidirectional chars')
116
117    # If a string contains any r_and_al_cat character, a r_and_al_cat character MUST be the first character of the string
118    # and a r_and_al_cat character MUST be the last character of the string.
119    if flag_r_and_al_cat and not stringprep.in_table_d1(prepared_data[0]) and not stringprep.in_table_d2(prepared_data[-1]):
120        raise LDAPSASLPrepError('r_and_al_cat character present, must be first and last character of the string')
121
122    return prepared_data
123
124
125def validate_simple_password(password, accept_empty=False):
126    """
127    validate simple password as per RFC4013 using sasl_prep:
128    """
129
130    if accept_empty and not password:
131        return password
132    elif not password:
133        raise LDAPPasswordIsMandatoryError("simple password can't be empty")
134
135    if not isinstance(password, bytes):  # bytes are returned raw, as per RFC (4.2)
136        password = sasl_prep(password)
137        if not isinstance(password, bytes):
138            password = password.encode('utf-8')
139
140    return password
141
142
143def abort_sasl_negotiation(connection, controls):
144    from ...operation.bind import bind_operation
145
146    request = bind_operation(connection.version, SASL, None, None, '', None)
147    response = connection.post_send_single_response(connection.send('bindRequest', request, controls))
148    if connection.strategy.sync:
149        result = connection.result
150    else:
151        result = connection.get_response(response)[0][0]
152
153    return True if result['result'] == RESULT_AUTH_METHOD_NOT_SUPPORTED else False
154
155
156def send_sasl_negotiation(connection, controls, payload):
157    from ...operation.bind import bind_operation
158
159    request = bind_operation(connection.version, SASL, None, None, connection.sasl_mechanism, payload)
160    response = connection.post_send_single_response(connection.send('bindRequest', request, controls))
161
162    if connection.strategy.sync:
163        result = connection.result
164    else:
165        _, result = connection.get_response(response)
166
167    return result
168
169
170def random_hex_string(size):
171    return str(hexlify(urandom(size)).decode('ascii'))  # str fix for Python 2
172 
codekingpro/portable-devtools · Team Ai