python3-ldap-0.9.4.2/ 0000777 0000000 0000000 00000000000 12355117540 012343 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/COPYING.LESSER.txt 0000666 0000000 0000000 00000017206 12355103746 015221 0 ustar 0000000 0000000 GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library. python3-ldap-0.9.4.2/COPYING.txt 0000666 0000000 0000000 00000105753 12355103746 014232 0 ustar 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
. python3-ldap-0.9.4.2/LICENSE.txt 0000666 0000000 0000000 00000001253 12355103746 014172 0 ustar 0000000 0000000 This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program in the COPYING and COPYING.LESSER files.
If not, see . python3-ldap-0.9.4.2/MANIFEST.in 0000666 0000000 0000000 00000000120 12355103746 014075 0 ustar 0000000 0000000 include COPYING.txt COPYING.LESSER.txt LICENSE.txt README.txt requirements.txt
python3-ldap-0.9.4.2/PKG-INFO 0000666 0000000 0000000 00000001754 12355117540 013447 0 ustar 0000000 0000000 Metadata-Version: 1.1
Name: python3-ldap
Version: 0.9.4.2
Summary: A strictly RFC 4511 conforming LDAP V3 pure Python 3 client - Python 2 compatible
Home-page: https://www.assembla.com/spaces/python3-ldap
Author: Giovanni Cannata
Author-email: python3ldap@gmail.com
License: LGPL v3
Description: UNKNOWN
Keywords: python3 python2 ldap
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP
python3-ldap-0.9.4.2/python3-ldap/ 0000777 0000000 0000000 00000000000 12355117540 014665 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/ 0000777 0000000 0000000 00000000000 12355117540 015670 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/ 0000777 0000000 0000000 00000000000 12355117540 017473 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/attrDef.py 0000666 0000000 0000000 00000006735 12355103746 021454 0 ustar 0000000 0000000 """
Created on 2014.01.11
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..core.exceptions import LDAPKeyError
class AttrDef(object):
"""
Attribute definition for abstract layer:
'name' is the real attribute name
'key' is the friendly name to use in query and while accessing the attribute, if not set is the same of name
'default' is the value returned if the attribute is not present
'validate' is an optional callable, called to check if the value in the query is valid, the callable is called with the value parameter
'preQuery' is an optional callable, called to transform values to be searched
'postQuery' is an optional callable, called to transform values returned by search
'dereference_dn' is a reference to an ObjectDef instance. When the attribute value contains a dn it will be searched and substituted in the entry
AttrDef('name') creates an AttrDef object for attribute 'name' with all default values
"""
def __init__(self, name, key=None, validate=None, pre_query=None, post_query=None, default=None, dereference_dn=None):
self.name = name
self.key = ''.join(key.split()) if key else name # key set to name if not present
self.validate = validate
self.pre_query = pre_query
self.post_query = post_query
self.default = default
self.dereference_dn = dereference_dn
def __repr__(self):
r = 'AttrDef(key={0.key!r}'.format(self)
r += ', name={0.name!r}'.format(self)
r += '' if self.validate is None else ', validate={0.validate!r}'.format(self)
r += '' if self.pre_query is None else ', pre_query={0.pre_query!r}'.format(self)
r += '' if self.post_query is None else ', post_query={0.post_query!r}'.format(self)
r += '' if self.default is None else ', default={0.default!r}'.format(self)
r += '' if self.dereference_dn is None else ', dereference_dn={0.dereference_dn!r}'.format(self)
r += ')'
return r
def __str__(self):
return self.__repr__()
def __eq__(self, other):
if isinstance(other, AttrDef):
return self.key == other.key
return False
def __lt__(self, other):
if isinstance(other, AttrDef):
return self.key < other.key
return False
def __hash__(self):
if self.key:
return hash(self.key)
else:
return id(self) # unique for each instance
def __setattr__(self, key, value):
if hasattr(self, 'key') and key == 'key': # key cannot be changed because is being used for __hash__
raise LDAPKeyError('key already set')
else:
object.__setattr__(self, key, value)
python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/attribute.py 0000666 0000000 0000000 00000004733 12355103746 022062 0 ustar 0000000 0000000 """
Created on 2014.01.06
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from os import linesep
from ..core.exceptions import LDAPAttributeError
# noinspection PyUnresolvedReferences
class Attribute(object):
"""
Attribute/values object, it includes the search result (after post_query transformation) of each attribute in an entry
Attribute object is read only
'values' contains the processed attribute values
'raw_values' contains the unprocessed attribute values
"""
def __init__(self, attr_def, entry):
self.__dict__['key'] = attr_def.key
self.__dict__['definition'] = attr_def
self.__dict__['values'] = []
self.__dict__['raw_values'] = []
self.__dict__['entry'] = entry
def __repr__(self):
if len(self.values) == 1:
r = self.key + ': ' + str(self.values[0])
elif len(self.values) > 1:
r = self.key + ': ' + str(self.values[0])
filler = ' ' * (len(self.key) + 6)
for value in sorted(self.values[1:]):
r += linesep + filler + str(value)
else:
r = ''
return r
def __str__(self):
if len(self.values) == 1:
return self.values[0]
else:
return str(self.values)
def __len__(self):
return len(self.values)
def __iter__(self):
return self.values.__iter__()
def __getitem__(self, item):
return self.values[item]
def __setattr__(self, item, value):
raise LDAPAttributeError('attribute is read only')
@property
def value(self):
return self.__dict__['values'][0] if len(self.__dict__['values']) == 1 else self.__dict__['values']
python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/entry.py 0000666 0000000 0000000 00000007511 12355103746 021215 0 ustar 0000000 0000000 """
Created on 2014.01.06
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from os import linesep
from ..core.exceptions import LDAPKeyError, LDAPAttributeError, LDAPEntryError
class Entry(object):
"""
The Entry object contains a single entry from the result of an LDAP
search. Attributes can be accessed either by sequence, by assignment
or as dictionary keys. Keys are not case sensitive.
- The DN is retrieved by get_entry_dn()
- The Reader reference is in get_entry_reader()
- Raw attributes values are retrieved by the get_raw_attributes() and
get_raw_attribute() methods
The Entry object is read only
"""
def __init__(self, dn, reader):
self.__dict__['_attributes'] = dict()
self.__dict__['_dn'] = dn
self.__dict__['_raw_attributes'] = None
self.__dict__['_reader'] = reader
def __repr__(self):
if self._dn:
r = 'DN: ' + str(self._dn) + linesep
if self._attributes:
for attr in sorted(self._attributes):
r += ' ' * 4 + repr(self._attributes[attr]) + linesep
return r
else:
return object.__repr__(self)
def __str__(self):
return self.__repr__()
def __iter__(self):
for attribute in self._attributes:
yield self._attributes[attribute]
raise StopIteration
def __contains__(self, item):
return True if self.__getitem__(item) else False
def __getattr__(self, item):
if isinstance(item, str):
item = ''.join(item.split()).lower()
for attr in self._attributes:
if item == attr.lower():
break
else:
raise LDAPKeyError('key not found')
return self._attributes[attr]
raise LDAPKeyError('key must be a string')
def __setattr__(self, item, value):
if item in self._attributes:
raise LDAPAttributeError('attribute is read only')
else:
raise LDAPEntryError('entry is read only')
def __getitem__(self, item):
return self.__getattr__(item)
def __eq__(self, other):
if isinstance(other, Entry):
return self._dn == other.get_entry_dn()
return False
def __lt__(self, other):
if isinstance(other, Entry):
return self._dn <= other.get_entry_dn()
return False
def get_entry_dn(self):
return self._dn
def get_entry_reader(self):
return self._reader
def get_raw_attributes(self):
return self._raw_attributes
def get_raw_attribute(self, name):
return self._raw_attributes[name] if name in self._raw_attributes else None
# noinspection PyProtectedMember
def refresh(self):
temp_entry = self.get_entry_reader().search_object(self.get_entry_dn())
self.__dict__['_attributes'] = temp_entry._attributes
self.__dict__['_raw_attributes'] = temp_entry._raw_attributes
del temp_entry
return self
python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/objectDef.py 0000666 0000000 0000000 00000010310 12355103746 021730 0 ustar 0000000 0000000 """
Created on 2014.02.02
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from os import linesep
from .attrDef import AttrDef
from ..core.exceptions import LDAPKeyError, LDAPObjectError, LDAPAttributeError, LDAPTypeError
class ObjectDef(object):
"""
AttrDefs are stored in a dictionary; the key is the friendly name defined
in AttrDef
AttrDefs can be added and removed using the += ad -= operators
ObjectDef can be accessed either as a sequence and a dictionary. When
accessed the whole AttrDef instance is returned
"""
def __init__(self, object_class=None):
self.__dict__['object_class'] = object_class
self.__dict__['_attributes'] = dict()
def __repr__(self):
r = 'object_class: ' + str(self.object_class) if self.object_class else ''
for attr in self._attributes:
r += linesep + ' ' + self._attributes[attr].__repr__() + ', '
return r[:-2] if r[-2] == ',' else r
def __str__(self):
return self.__repr__()
def __getitem__(self, item):
return self.__getattr__(item)
def __getattr__(self, item):
item = ''.join(item.split()).lower()
for attr in self._attributes:
if item == attr.lower():
break
else:
raise LDAPKeyError('key not present')
return self._attributes[attr]
def __setattr__(self, key, value):
raise LDAPObjectError('object is read only')
def __iadd__(self, other):
self.add(other)
return self
def __isub__(self, other):
if isinstance(other, AttrDef):
self.remove(other.key)
elif isinstance(other, str):
self.remove(other)
return self
def __iter__(self):
for attribute in self._attributes:
yield self._attributes[attribute]
def __len__(self):
return len(self._attributes)
def __contains__(self, item):
try:
self.__getitem__(item)
except KeyError:
return False
return True
def add(self, definition=None):
if isinstance(definition, str):
element = AttrDef(definition)
self.add(element)
elif isinstance(definition, AttrDef):
key = definition.key
for attr in self._attributes:
if key.lower() == attr.lower():
raise LDAPAttributeError('attribute already present')
self._attributes[key] = definition
self.__dict__[key] = definition
elif isinstance(definition, (list, tuple)):
for element in definition:
self.add(element)
else:
raise LDAPObjectError('unable to add element to object definition')
def remove(self, item):
key = None
if isinstance(item, str):
key = ''.join(item.split()).lower()
elif isinstance(item, AttrDef):
key = item.key
if key:
for attr in self._attributes:
if item == attr.lower():
del self._attributes[attr]
break
else:
raise LDAPKeyError('key ' + str(key) + 'not present')
else:
raise LDAPTypeError('key must be str or AttrDef not ' + str(type(key)))
def clear(self):
self.__dict__['object_class'] = None
self.__dict__['_attributes'] = dict()
python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/operationalAttribute.py 0000666 0000000 0000000 00000003630 12355103746 024253 0 ustar 0000000 0000000 """
Created on 2014.02.09
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from os import linesep
from .attribute import Attribute
# noinspection PyUnresolvedReferences,PyMissingConstructor
class OperationalAttribute(Attribute):
"""
Operational attribute/values object, it includes the search result of an
operational attribute in an entry
Attribute object is read only
'values' contains the processed attribute values
'raw_values' contains the unprocessed attribute values
It doesn't have any AttrDef
"""
def __init__(self, key, entry):
self.__dict__['key'] = key
self.__dict__['entry'] = entry
self.__dict__['values'] = []
self.__dict__['raw_values'] = []
def __repr__(self):
if len(self.values) == 1:
r = self.key + ' [OPERATIONAL]: ' + str(self.values[0])
elif len(self.values) > 1:
r = self.key + ' [OPERATIONAL]: ' + str(self.values[0])
filler = ' ' * (len(self.key) + 6)
for value in sorted(self.values[1:]):
r += linesep + filler + str(value)
else:
r = ''
return r
python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/reader.py 0000666 0000000 0000000 00000044332 12355103746 021320 0 ustar 0000000 0000000 """
Created on 2014.01.06
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from datetime import datetime
from os import linesep
from .. import SEARCH_SCOPE_WHOLE_SUBTREE, SEARCH_SCOPE_SINGLE_LEVEL, SEARCH_DEREFERENCE_ALWAYS, SEARCH_SCOPE_BASE_OBJECT, ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX
from .attribute import Attribute
from .entry import Entry
from ..core.exceptions import LDAPReaderError
from .operationalAttribute import OperationalAttribute
def _ret_search_value(value):
return value[0] + '=' + value[1:] if value[0] in '<>~' and value[1] != '=' else value
def _create_query_dict(query_text):
"""
Create a dictionary with query key:value definitions
query_text is a comma delimited key:value sequence
"""
query_dict = dict()
if query_text:
for arg_value_str in query_text.split(','):
if ':' in arg_value_str:
arg_value_list = arg_value_str.split(':')
query_dict[arg_value_list[0].strip()] = arg_value_list[1].strip()
return query_dict
class Reader(object):
"""
Reader object perform the search with the requested parameters:
'connection': the connection to use
'object_def': the definition of the LDAP object to be returned
'query': the simplified query to be transformed in an LDAP filter
'base': starting base of the DIT
'components_in_and': specify if components of query mus be all satisfied or not (AND/OR)
'sub_tree': a boolean to specify if the search must be performed ad Single Level (False) or Whole SubTree (True)
'get_operational_attributes': a boolean to specify if operational attributes are returned or not
'controls': controls to be used in search
"""
def __init__(self, connection, object_def, query, base, components_in_and=True, sub_tree=True, get_operational_attributes=False, controls=None):
self.connection = connection
self._definition = object_def
self.base = base
self._components_in_and = components_in_and
self.attributes = sorted([attr.name for attr in self._definition])
self.get_operational_attributes = get_operational_attributes
self.controls = controls
self.sub_tree = sub_tree
self._query = query
self.dereference_aliases = SEARCH_DEREFERENCE_ALWAYS
self.size_limit = 0
self.time_limit = 0
self.types_only = False
self.paged_size = None
self.paged_criticality = False
self.validated_query = None
self._query_dict = dict()
self._validated_query_dict = dict()
self.execution_time = None
self.query_filter = None
self.entries = []
self.paged_cookie = None
self.last_sub_tree = None
self.reset()
@property
def definition(self):
return self._definition
@property
def query(self):
return self._query
@query.setter
def query(self, value):
self._query = value
self.reset()
@property
def components_in_and(self):
return self._components_in_and
@components_in_and.setter
def components_in_and(self, value):
self._components_in_and = value
self.reset()
def __repr__(self):
r = 'CONN : ' + str(self.connection) + linesep
r += 'BASE : ' + repr(self.base) + (' [SUB]' if self.sub_tree else ' [LEVEL]') + linesep
r += 'DEFS : ' + repr(self._definition.object_class) + ' ['
for attr_def in sorted(self._definition):
r += (attr_def.key if attr_def.key == attr_def.name else (attr_def.key + ' <' + attr_def.name + '>')) + ', '
if r[-2] == ',':
r = r[:-2]
r += ']' + linesep
r += 'QUERY : ' + repr(self._query) + (' [AND]' if self.components_in_and else ' [OR]') + linesep
r += 'PARSED : ' + repr(self.validated_query) + (' [AND]' if self.components_in_and else ' [OR]') + linesep
r += 'ATTRS : ' + repr(self.attributes) + (' [OPERATIONAL]' if self.get_operational_attributes else '') + linesep
r += 'FILTER : ' + repr(self.query_filter) + linesep
if self.execution_time:
r += 'ENTRIES: ' + str(len(self.entries))
r += ' [SUB]' if self.last_sub_tree else ' [level]'
r += ' [SIZE LIMIT: ' + str(self.size_limit) + ']' if self.size_limit else ''
r += ' [TIME LIMIT: ' + str(self.time_limit) + ']' if self.time_limit else ''
r += ' [executed at: ' + str(self.execution_time.isoformat()) + ']' + linesep
return r
def __str__(self):
return self.__repr__()
def clear(self):
self.dereference_aliases = SEARCH_DEREFERENCE_ALWAYS
self.size_limit = 0
self.time_limit = 0
self.types_only = False
self.paged_size = None
self.paged_criticality = False
def reset(self):
self.clear()
self.validated_query = None
self._query_dict = dict()
self._validated_query_dict = dict()
self.execution_time = None
self.query_filter = None
self.entries = []
self.paged_cookie = None
self.last_sub_tree = None
self._create_query_filter()
def __iter__(self):
return self.entries.__iter__()
def __getitem__(self, item):
return self.entries[item]
def __len__(self):
return len(self.entries)
def _validate_query(self):
"""
Processes the text query and verifies that the requested friendly names are in the Reader dictionary
If the AttrDef has a 'validate' property the callable is executed and if it returns False an Exception is raised
"""
if not self._query_dict:
self._query_dict = _create_query_dict(self._query)
query = ''
for d in sorted(self._query_dict):
attr = d[1:] if d[0] in '&|' else d
for attr_def in self._definition:
if ''.join(attr.split()).lower() == attr_def.key.lower():
attr = attr_def.key
break
if attr in self._definition:
vals = sorted(self._query_dict[d].split(';'))
query += (d[0] + attr if d[0] in '&|' else attr) + ': '
for val in vals:
val = val.strip()
val_not = True if val[0] == '!' else False
val_search_operator = '=' # default
if val_not:
if val[1:].lstrip()[0] not in '=<>~':
value = val[1:].lstrip()
else:
val_search_operator = val[1:].lstrip()[0]
value = val[1:].lstrip()[1:]
else:
if val[0] not in '=<>~':
value = val.lstrip()
else:
val_search_operator = val[0]
value = val[1:].lstrip()
if self._definition[attr].validate:
if not self._definition[attr].validate(self._definition[attr].key, value):
raise LDAPReaderError('validation failed for attribute %s and value %s' % (d, val))
if val_not:
query += '!' + val_search_operator + value
else:
query += val_search_operator + value
query += ';'
query = query[:-1] + ', '
self.validated_query = query[:-2]
self._validated_query_dict = _create_query_dict(self.validated_query)
def _create_query_filter(self):
"""
Converts the query dictionary in the filter text
"""
if self._query and self._query.startswith('(') and self._query.stopswith(')'): # query is already an LDAP filter
self.query_filter = self._query
return
self.query_filter = ''
if self._definition.object_class:
self.query_filter += '(&'
if isinstance(self._definition.object_class, str):
self.query_filter += '(objectClass=' + self._definition.object_class + ')'
elif isinstance(self._definition.object_class, (list, tuple)):
self.query_filter += '(&'
for object_class in self._definition.object_class:
self.query_filter += '(objectClass=' + object_class + ')'
self.query_filter += ')'
else:
raise LDAPReaderError('object_class must be a string or a list')
if not self.components_in_and:
self.query_filter += '(|'
elif not self._definition.object_class:
self.query_filter += '(&'
self._validate_query()
attr_counter = 0
for attr in sorted(self._validated_query_dict):
attr_counter += 1
multi = True if ';' in self._validated_query_dict[attr] else False
vals = sorted(self._validated_query_dict[attr].split(';'))
attr_def = self._definition[attr[1:]] if attr[0] in '&|' else self._definition[attr]
if attr_def.pre_query:
modvals = []
for val in vals:
modvals.append(val[0] + attr_def.pre_query(attr_def.key, val[1:]))
vals = modvals
if multi:
if attr[0] in '&|':
self.query_filter += '(' + attr[0]
else:
self.query_filter += '(|'
for val in vals:
if val[0] == '!':
self.query_filter += '(!(' + attr_def.name + _ret_search_value(val[1:]) + '))'
else:
self.query_filter += '(' + attr_def.name + _ret_search_value(val) + ')'
if multi:
self.query_filter += ')'
if not self.components_in_and:
self.query_filter += '))'
else:
self.query_filter += ')'
if not self._definition.object_class and attr_counter == 1: # remove unneeded starting filter
self.query_filter = self.query_filter[2:-1]
def _get_attributes(self, result, attr_defs, entry):
"""
Assign the result of the LDAP query to the Entry object dictionary.
If the optional 'post_query' callable is present in the AttrDef it is called with each value of the attribute and the callable result is stored in the attribute
Returns the default value for missing attributes
If the 'dereference_dn' in AttrDef is a ObjectDef then the attribute values are treated as distinguished name and the relevant entry is retrieved and stored in the attribute value
"""
attributes = dict()
used_attribute_names = []
for attr_def in attr_defs:
name = None
for attr_name in result['attributes']:
if attr_def.name.lower() == attr_name.lower():
name = attr_name
break
if name or attr_def.default: # attribute value found in result or default value present
attribute = Attribute(attr_def, entry)
attribute.__dict__['raw_values'] = result['raw_attributes'][name] if name else None
if attr_def.post_query and attr_def.name in result['attributes']:
attribute.__dict__['values'] = attr_def.post_query(attr_def.key, result['attributes'][name])
else:
attribute.__dict__['values'] = result['attributes'][name] if name else (attr_def.default if isinstance(attr_def.default, (list, tuple)) else [attr_def.default])
if attr_def.dereference_dn: # try to get object referenced in value
# noinspection PyUnresolvedReferences
if attribute.values:
temp_reader = Reader(self.connection, attr_def.dereference_dn, query=None, base=None, get_operational_attributes=self.get_operational_attributes, controls=self.controls)
temp_values = []
# noinspection PyUnresolvedReferences
for element in attribute.values:
temp_values.append(temp_reader.search_object(element))
del temp_reader # remove the temporary Reader
attribute.__dict__['values'] = temp_values
# noinspection PyUnresolvedReferences
attributes[attribute.key] = attribute
used_attribute_names.append(name)
for name in result['attributes']:
if name not in used_attribute_names:
attribute = OperationalAttribute(ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX + name, entry)
attribute.__dict__['raw_values'] = result['raw_attributes'][name]
attribute.__dict__['values'] = result['attributes'][name]
if (ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX + name) not in attributes:
attributes[ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX + name] = attribute
return attributes
def _get_entry(self, result):
if not result['type'] == 'searchResEntry':
return None
entry = Entry(result['dn'], self)
entry.__dict__['_attributes'] = self._get_attributes(result, self._definition, entry)
entry.__dict__['_raw_attributes'] = result['raw_attributes']
for attr in entry: # returns the whole attribute object
attr_name = attr.key
entry.__dict__[attr_name] = attr
return entry
def _execute_query(self, query_scope):
if not self.connection:
raise LDAPReaderError('no connection established')
self._create_query_filter()
with self.connection:
result = self.connection.search(search_base=self.base,
search_filter=self.query_filter,
search_scope=query_scope,
dereference_aliases=self.dereference_aliases,
attributes=self.attributes,
size_limit=self.size_limit,
time_limit=self.time_limit,
types_only=self.types_only,
get_operational_attributes=self.get_operational_attributes,
controls=self.controls,
paged_size=self.paged_size,
paged_criticality=self.paged_criticality,
paged_cookie=self.paged_cookie)
if not self.connection.strategy.sync:
response, _ = self.connection.get_response(result)
else:
response = self.connection.response
self.entries = []
for r in response:
entry = self._get_entry(r)
self.entries.append(entry)
self.last_sub_tree = self.sub_tree
self.execution_time = datetime.now()
def search(self):
self.clear()
query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL
self._execute_query(query_scope)
return self.entries
def search_level(self):
self.clear()
self._execute_query(SEARCH_SCOPE_SINGLE_LEVEL)
return self.entries
def search_subtree(self):
self.clear()
self._execute_query(SEARCH_SCOPE_WHOLE_SUBTREE)
return self.entries
def search_object(self, entry_dn=None): # base must be a single dn
self.clear()
if entry_dn:
old_base = self.base
self.base = entry_dn
self._execute_query(SEARCH_SCOPE_BASE_OBJECT)
self.base = old_base
else:
self._execute_query(SEARCH_SCOPE_BASE_OBJECT)
return self.entries[0] if len(self.entries) > 0 else None
def search_size_limit(self, size_limit):
self.clear()
self.size_limit = size_limit
query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL
self._execute_query(query_scope)
return self.entries
def search_time_limit(self, time_limit):
self.clear()
self.time_limit = time_limit
query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL
self._execute_query(query_scope)
return self.entries
def search_types_only(self):
self.clear()
self.types_only = True
query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL
self._execute_query(query_scope)
return self.entries
def search_paged(self, paged_size, paged_criticality=True):
if not self.paged_cookie:
self.clear()
self.paged_size = paged_size
self.paged_criticality = paged_criticality
query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL
self._execute_query(query_scope)
if self.entries:
yield self.entries
else:
raise StopIteration
python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/__init__.py 0000666 0000000 0000000 00000002010 12355103746 021600 0 ustar 0000000 0000000 """
Created on 2014.01.06
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from .attribute import Attribute
from .operationalAttribute import OperationalAttribute
from .attrDef import AttrDef
from .objectDef import ObjectDef
from .entry import Entry
from .reader import Reader
python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/ 0000777 0000000 0000000 00000000000 12355117540 017153 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/connection.py 0000666 0000000 0000000 00000007126 12355103746 021675 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..core.connection import Connection as newConnection
from .. import SEARCH_SCOPE_WHOLE_SUBTREE, SEARCH_DEREFERENCE_ALWAYS, STRATEGY_SYNC
# noinspection PyPep8Naming
class Connection(newConnection):
"""
Proxy class (with camel case parameters) to new Connection class (pep8
compliant)
"""
def __init__(self, server, user=None, password=None, autoBind=False, version=3, authentication=None, clientStrategy=STRATEGY_SYNC, autoReferrals=True, saslMechanism=None, saslCredentials=None, collectUsage=False, readOnly=False, lazy=False):
newConnection.__init__(self, server, user, password, autoBind, version, authentication, clientStrategy, autoReferrals, saslMechanism, saslCredentials, collectUsage, readOnly, lazy)
def search(self, searchBase, searchFilter, searchScope=SEARCH_SCOPE_WHOLE_SUBTREE, dereferenceAliases=SEARCH_DEREFERENCE_ALWAYS, attributes=None, sizeLimit=0, timeLimit=0, typesOnly=False, getOperationalAttributes=False, controls=None,
pagedSize=None, pagedCriticality=False, pagedCookie=None):
return newConnection.search(self, searchBase, searchFilter, searchScope, dereferenceAliases, attributes, sizeLimit, timeLimit, typesOnly, getOperationalAttributes, controls, pagedSize, pagedCriticality, pagedCookie)
def add(self, dn, objectClass=None, attributes=None, controls=None):
"""
Add DN to the DIB, objectClass is None, a class name or a list of class
names.
attributes is a dictionary in the form 'attr': 'val' or 'attr':
['val1', 'val2', 'valN'] for multivalued types.
"""
return newConnection.add(dn, objectClass, attributes, controls)
def modifyDn(self, dn, relativeDn, deleteOldDn=True, newSuperior=None, controls=None):
"""
Modify DN of the entry and optionally performs a move of the entry in
the DIB.
"""
return newConnection.modify_dn(self, dn, relativeDn, deleteOldDn, newSuperior, controls)
def abandon(self, messageId, controls=None):
"""
Abandon the operation indicated by messageId.
"""
return newConnection.abandon(self, messageId, controls)
def extended(self, requestName, requestValue=None, controls=None):
"""
Perform an extended operation.
"""
return newConnection.extended(self, requestName, requestValue, controls)
def startTls(self):
return newConnection.start_tls(self)
def doSaslBind(self, controls):
return newConnection.do_sasl_bind(self, controls)
def refreshDsaInfo(self):
return newConnection.refresh_dsa_info(self)
def responseToLdif(self, searchResult=None, allBase64=False):
return newConnection.response_to_ldif(self, searchResult, allBase64)
python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/server.py 0000666 0000000 0000000 00000002146 12355103746 021041 0 ustar 0000000 0000000 """
Created on 2014.03.10
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..core.server import Server as newServer
# noinspection PyPep8Naming
class Server(newServer):
def __init__(self, host, port=389, useSsl=False, allowedReferralHosts=None, getInfo=None, tls=None):
newServer.__init__(self, host, port, useSsl, allowedReferralHosts, getInfo, tls)
python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/tls.py 0000666 0000000 0000000 00000003020 12355103746 020325 0 ustar 0000000 0000000 """
Created on 2014.03.10
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..core.exceptions import LDAPSSLNotSupportedError
from ..core.tls import Tls as newTls
try:
# noinspection PyUnresolvedReferences
import ssl
except ImportError:
raise LDAPSSLNotSupportedError('SSL not supported in this Python interpreter')
# noinspection PyPep8Naming
class Tls(newTls):
"""
tls/ssl configuration for Server object
"""
def __init__(self, localPrivateKeyFile=None, localCertificateFile=None, validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1, caCertsFile=None):
newTls.__init__(self, localPrivateKeyFile, localCertificateFile, validate, version, caCertsFile)
def startTls(self, connection):
return newTls.start_tls(self, connection)
python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/__init__.py 0000666 0000000 0000000 00000000000 12355103746 021255 0 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/core/ 0000777 0000000 0000000 00000000000 12355117540 016620 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/core/connection.py 0000666 0000000 0000000 00000066400 12355110215 021327 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from os import linesep
from pyasn1.codec.ber import encoder
from .. import AUTH_ANONYMOUS, AUTH_SIMPLE, AUTH_SASL, MODIFY_ADD, MODIFY_DELETE, MODIFY_REPLACE, SEARCH_DEREFERENCE_ALWAYS, SEARCH_SCOPE_WHOLE_SUBTREE, STRATEGY_ASYNC_THREADED, STRATEGY_SYNC, CLIENT_STRATEGIES, RESULT_SUCCESS, \
RESULT_COMPARE_TRUE, NO_ATTRIBUTES, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, MODIFY_INCREMENT, STRATEGY_LDIF_PRODUCER, SASL_AVAILABLE_MECHANISMS, STRATEGY_SYNC_RESTARTABLE, POOLING_STRATEGY_ROUND_ROBIN, \
STRATEGY_REUSABLE_THREADED, DEFAULT_POOL_NAME
from ..extend import ExtendedOperationsContainer
from .pooling import ServerPool
from .server import Server
from ..strategy.reusableThreaded import ReusableThreadedStrategy
from ..operation.abandon import abandon_operation
from ..operation.add import add_operation
from ..operation.bind import bind_operation
from ..operation.compare import compare_operation
from ..operation.delete import delete_operation
from ..operation.extended import extended_operation
from ..operation.modify import modify_operation
from ..operation.modifyDn import modify_dn_operation
from ..operation.search import search_operation
from ..protocol.rfc2849 import operation_to_ldif, add_ldif_header
from ..protocol.sasl.digestMd5 import sasl_digest_md5
from ..protocol.sasl.external import sasl_external
from ..strategy.asyncThreaded import AsyncThreadedStrategy
from ..strategy.ldifProducer import LdifProducerStrategy
from ..strategy.syncWait import SyncWaitStrategy
from ..strategy.syncWaitRestartable import SyncWaitRestartableStrategy
from ..operation.unbind import unbind_operation
from ..protocol.rfc2696 import RealSearchControlValue, Cookie, Size
from .usage import ConnectionUsage
from .tls import Tls
from .exceptions import LDAPUnknownStrategyError, LDAPBindError, LDAPUnknownAuthenticationMethodError, LDAPInvalidServerError, LDAPSASLMechanismNotSupportedError, LDAPObjectClassError, LDAPConnectionIsReadOnlyError, LDAPChangesError, LDAPExceptionError
from ..utils.conv import prepare_for_stream
# noinspection PyProtectedMember
class Connection(object):
"""
Main ldap connection class.
Controls, if used, must be a list of tuples. Each tuple must have 3
elements, the control OID, a boolean meaning if the control is
critical, a value.
If the boolean is set to True the server must honor the control or
refuse the operation
Mixing controls must be defined in controls specification (as per
RFC 4511.)
"""
def __init__(self,
server,
user=None,
password=None,
auto_bind=False,
version=3,
authentication=None,
client_strategy=STRATEGY_SYNC,
auto_referrals=True,
sasl_mechanism=None,
sasl_credentials=None,
check_names=True,
collect_usage=False,
read_only=False,
lazy=False,
raise_exceptions=False,
pool_name=None,
pool_size=None,
pool_lifetime=None):
if client_strategy not in CLIENT_STRATEGIES:
self.last_error = 'unknown client connection strategy'
raise LDAPUnknownStrategyError(self.last_error)
self.strategy_type = client_strategy
self.user = user
self.password = password
if self.user and self.password and not authentication:
self.authentication = AUTH_SIMPLE
elif not authentication:
self.authentication = AUTH_ANONYMOUS
elif authentication in [AUTH_SIMPLE, AUTH_ANONYMOUS, AUTH_SASL]:
self.authentication = authentication
else:
self.last_error = 'unknown authentication method'
raise LDAPUnknownAuthenticationMethodError(self.last_error)
self.version = version
self.auto_referrals = True if auto_referrals else False
self.request = None
self.response = None
self.result = None
self.bound = False
self.listening = False
self.closed = True
self.last_error = None
self.auto_bind = True if auto_bind else False
self.sasl_mechanism = sasl_mechanism
self.sasl_credentials = sasl_credentials
self._usage = ConnectionUsage() if collect_usage else None
self.socket = None
self.tls_started = False
self.sasl_in_progress = False
self.read_only = read_only
self._context_state = []
self._deferred_open = False
self._deferred_bind = False
self._deferred_start_tls = False
self._bind_controls = None
self._executing_deferred = False
self.lazy = lazy
self.pool_name = pool_name if pool_name else DEFAULT_POOL_NAME
self.pool_size = pool_size
self.pool_lifetime = pool_lifetime
self.starting_tls = False
self.check_names = check_names
self.raise_exceptions = raise_exceptions
self.extend = ExtendedOperationsContainer(self)
if isinstance(server, str):
server = Server(server)
if isinstance(server, (list, tuple)):
server = ServerPool(server, POOLING_STRATEGY_ROUND_ROBIN, active=True, exhaust=True)
if isinstance(server, ServerPool):
self.server_pool = server
self.server_pool.initialize(self)
self.server = self.server_pool.get_current_server(self)
else:
self.server_pool = None
self.server = server
if self.strategy_type == STRATEGY_SYNC:
self.strategy = SyncWaitStrategy(self)
elif self.strategy_type == STRATEGY_ASYNC_THREADED:
self.strategy = AsyncThreadedStrategy(self)
elif self.strategy_type == STRATEGY_LDIF_PRODUCER:
self.strategy = LdifProducerStrategy(self)
elif self.strategy_type == STRATEGY_SYNC_RESTARTABLE:
self.strategy = SyncWaitRestartableStrategy(self)
elif self.strategy_type == STRATEGY_REUSABLE_THREADED:
self.strategy = ReusableThreadedStrategy(self)
else:
self.last_error = 'unknown strategy'
raise LDAPUnknownStrategyError(self.last_error)
# map strategy functions to connection functions
self.send = self.strategy.send
self.open = self.strategy.open
self.get_response = self.strategy.get_response
self.post_send_single_response = self.strategy.post_send_single_response
self.post_send_search = self.strategy.post_send_search
if not self.strategy.no_real_dsa and self.server.is_valid():
if self.auto_bind:
self.open()
self.bind()
if not self.bound:
self.last_error = 'automatic bind not successful' + (' - ' + self.last_error if self.last_error else '')
raise LDAPBindError(self.last_error)
elif self.strategy.no_real_dsa:
self.server = None
else:
self.last_error = 'invalid LDAP server'
raise LDAPInvalidServerError(self.last_error)
def __str__(self):
s = [
str(self.server) if self.server and self.server.is_valid else 'None',
'user: ' + str(self.user),
'unbound' if not self.bound else ('deferred bind' if self._deferred_bind else 'bound'),
'closed' if self.closed else ('deferred open' if self._deferred_open else 'open'),
'tls not started' if not self.tls_started else('deferred start_tls' if self._deferred_start_tls else 'tls started'),
'listening' if self.listening else 'not listening',
self.strategy.__class__.__name__
]
return ' - '.join(s)
def __repr__(self):
if self.server_pool:
r = 'Connection(server={0.server_pool!r}'.format(self)
else:
r = 'Connection(server={0.server!r}'.format(self)
r += '' if self.user is None else ', user={0.user!r}'.format(self)
r += '' if self.password is None else ', password={0.password!r}'.format(self)
r += '' if self.auto_bind is None else ', auto_bind={0.auto_bind!r}'.format(self)
r += '' if self.version is None else ', version={0.version!r}'.format(self)
r += '' if self.authentication is None else ', authentication={0.authentication!r}'.format(self)
r += '' if self.strategy_type is None else ', client_strategy={0.strategy_type!r}'.format(self)
r += '' if self.auto_referrals is None else ', auto_referrals={0.auto_referrals!r}'.format(self)
r += '' if self.sasl_mechanism is None else ', sasl_mechanism={0.auto_sasl_mechanism!r}'.format(self)
r += '' if self.sasl_credentials is None else ', sasl_credentials={0.sasl_credentials!r}'.format(self)
r += '' if self.check_names is None else ', check_names={0.check_names!r}'.format(self)
r += '' if self.usage is None else (', collect_usage=' + 'True' if self.usage else 'False')
r += '' if self.read_only is None else ', read_only={0.read_only!r}'.format(self)
r += '' if self.lazy is None else ', lazy={0.lazy!r}'.format(self)
r += '' if self.raise_exceptions is None else ', raise_exceptions={0.raise_exceptions!r}'.format(self)
r += '' if (self.pool_name is None or self.pool_name == DEFAULT_POOL_NAME) else ', pool_name={0.pool_name!r}'.format(self)
r += '' if self.pool_size is None else ', pool_size={0.pool_size!r}'.format(self)
r += '' if self.pool_lifetime is None else ', pool_lifetime={0.pool_lifetime!r}'.format(self)
r += ')'
return r
@property
def stream(self):
"""
returns a reference to the response stream if defined in the strategy.
Used in the LDIFProducer to accumulate the ldif-change operations with a single LDIF header
"""
return self.strategy.get_stream() if self.strategy.can_stream else None
@stream.setter
def stream(self, value):
if self.strategy.can_stream:
self.strategy.set_stream(value)
@property
def usage(self):
if not self._usage:
return None
if self.strategy.pooled:
self._usage.reset()
for connection in self.strategy.pool.connections:
self._usage += connection.connection.usage
self._usage += self.strategy.pool.terminated_usage
return self._usage
def __enter__(self):
self._context_state.append((self.bound, self.closed)) # save status out of context as a tuple in a list
if self.closed:
self.open()
if not self.bound:
self.bind()
return self
# noinspection PyUnusedLocal
def __exit__(self, exc_type, exc_val, exc_tb):
context_bound, context_closed = self._context_state.pop()
if (not context_bound and self.bound) or self.stream: # restore status prior to entering context
try:
self.unbind()
except LDAPExceptionError:
pass
if not context_closed and self.closed:
self.open()
if not exc_type is None:
return False # re-raise LDAPExceptionError
def bind(self,
controls=None):
"""
Bind to ldap with the user defined in Server object
"""
if self.lazy and not self._executing_deferred:
self._deferred_bind = True
self._bind_controls = controls
self.bound = True
else:
self._deferred_bind = False
self._bind_controls = None
if self.closed: # try to open connection if closed
self.open()
if self.authentication == AUTH_ANONYMOUS:
request = bind_operation(self.version, self.authentication, '', '')
response = self.post_send_single_response(self.send('bindRequest', request, controls))
elif self.authentication == AUTH_SIMPLE:
request = bind_operation(self.version, self.authentication, self.user, self.password)
response = self.post_send_single_response(self.send('bindRequest', request, controls))
elif self.authentication == AUTH_SASL:
if self.sasl_mechanism in SASL_AVAILABLE_MECHANISMS:
response = self.do_sasl_bind(controls)
else:
self.last_error = 'requested SASL mechanism not supported'
raise LDAPSASLMechanismNotSupportedError(self.last_error)
else:
self.last_error = 'unknown authentication method'
raise LDAPUnknownAuthenticationMethodError(self.last_error)
if not self.strategy.sync and self.authentication != AUTH_SASL: # get response if async except for sasl that return the bind result even for async
response, result = self.get_response(response)
else:
result = self.result
if result is None:
self.bound = True if self.strategy_type == STRATEGY_REUSABLE_THREADED else False
else:
self.bound = True if result['result'] == RESULT_SUCCESS else False
if not self.bound and result and result['description']:
self.last_error = result['description']
if self.bound and not self.strategy.pooled:
self.refresh_dsa_info()
return self.bound
def unbind(self,
controls=None):
"""
Unbinds the connected user
Unbind implies closing session as per RFC4511 (4.3)
"""
if self.lazy and not self._executing_deferred and (self._deferred_bind or self._deferred_open): # clear deferred status
self.strategy.close()
self._deferred_open = False
self._deferred_bind = False
self._deferred_start_tls = False
elif not self.closed:
request = unbind_operation()
self.send('unbindRequest', request, controls)
self.strategy.close()
return True
def search(self,
search_base,
search_filter,
search_scope=SEARCH_SCOPE_WHOLE_SUBTREE,
dereference_aliases=SEARCH_DEREFERENCE_ALWAYS,
attributes=None,
size_limit=0,
time_limit=0,
types_only=False,
get_operational_attributes=False,
controls=None,
paged_size=None,
paged_criticality=False,
paged_cookie=None):
"""
Perform an ldap search:
- If attributes is empty no attribute is returned
- If attributes is ALL_ATTRIBUTES all attributes are returned
- If paged_size is an int greater than 0 a simple paged search
is tried as described in RFC2696 with the specified size
- If paged is 0 and cookie is present the search is abandoned on
server
- Cookie is an opaque string received in the last paged search
and must be used on the next paged search response
- If lazy = True open and bind will be deferred until another
LDAP operation is performed
"""
self._fire_deferred()
if not attributes:
attributes = [NO_ATTRIBUTES]
elif attributes == ALL_ATTRIBUTES:
attributes = ['*']
if get_operational_attributes:
attributes.append(ALL_OPERATIONAL_ATTRIBUTES)
if isinstance(paged_size, int):
real_search_control_value = RealSearchControlValue()
real_search_control_value['size'] = Size(paged_size)
real_search_control_value['cookie'] = Cookie(paged_cookie) if paged_cookie else Cookie('')
if controls is None:
controls = []
controls.append(('1.2.840.113556.1.4.319', paged_criticality if isinstance(paged_criticality, bool) else False, encoder.encode(real_search_control_value)))
request = search_operation(search_base, search_filter, search_scope, dereference_aliases, attributes, size_limit, time_limit, types_only, self.server.schema if self.server and self.check_names else None)
response = self.post_send_search(self.send('searchRequest', request, controls))
if isinstance(response, int):
return response
if self.result['type'] == 'searchResDone' and len(response) > 0:
return True
return False
def compare(self,
dn,
attribute,
value,
controls=None):
"""
Perform a compare operation
"""
self._fire_deferred()
request = compare_operation(dn, attribute, value, self.server.schema if self.server and self.check_names else None)
response = self.post_send_single_response(self.send('compareRequest', request, controls))
if isinstance(response, int):
return response
return True if self.result['type'] == 'compareResponse' and self.result['result'] == RESULT_COMPARE_TRUE else False
def add(self,
dn,
object_class=None,
attributes=None,
controls=None):
"""
Add dn to the DIT, object_class is None, a class name or a list
of class names.
Attributes is a dictionary in the form 'attr': 'val' or 'attr':
['val1', 'val2', ...] for multivalued attributes
"""
self._fire_deferred()
attr_object_class = []
if object_class is None:
parm_object_class = []
else:
parm_object_class = object_class if isinstance(object_class, (list, tuple)) else [object_class]
object_class_attr_name = ''
if attributes:
for attr in attributes:
if attr.lower() == 'objectclass':
object_class_attr_name = attr
attr_object_class = attributes[object_class_attr_name] if isinstance(attributes[object_class_attr_name], (list, tuple)) else [attributes[object_class_attr_name]]
else:
attributes = dict()
if not object_class_attr_name:
object_class_attr_name = 'objectClass'
attributes[object_class_attr_name] = list(set([object_class.lower() for object_class in parm_object_class + attr_object_class])) # remove duplicate ObjectClasses
if not attributes[object_class_attr_name]:
self.last_error = 'ObjectClass attribute is mandatory'
raise LDAPObjectClassError(self.last_error)
request = add_operation(dn, attributes, self.server.schema if self.server and self.check_names else None)
response = self.post_send_single_response(self.send('addRequest', request, controls))
if isinstance(response, (int, str)):
return response
return True if self.result['type'] == 'addResponse' and self.result['result'] == RESULT_SUCCESS else False
def delete(self,
dn,
controls=None):
"""
Delete the entry identified by the DN from the DIB.
"""
self._fire_deferred()
if self.read_only:
self.last_error = 'connection is read-only'
raise LDAPConnectionIsReadOnlyError(self.last_error)
request = delete_operation(dn)
response = self.post_send_single_response(self.send('delRequest', request, controls))
if isinstance(response, (int, str)):
return response
return True if self.result['type'] == 'delResponse' and self.result['result'] == RESULT_SUCCESS else False
def modify(self,
dn,
changes,
controls=None):
"""
Modify attributes of entry
- Changes is a dictionary in the form {'attribute1':
(operation, [val1, val2]), 'attribute2': (operation, [val1, val2])}
- Operation is 0 (MODIFY_ADD), 1 (MODIFY_DELETE), 2 (MODIFY_REPLACE), 3 (MODIFY_INCREMENT)
"""
self._fire_deferred()
if self.read_only:
self.last_error = 'connection is read-only'
raise LDAPConnectionIsReadOnlyError(self.last_error)
if not isinstance(changes, dict):
self.last_error = 'changes must be a dictionary'
raise LDAPChangesError(self.last_error)
if not changes:
self.last_error = 'no changes in modify request'
raise LDAPChangesError(self.last_error)
for change in changes:
if len(changes[change]) != 2:
self.last_error = 'malformed change'
raise LDAPChangesError(self.last_error)
elif changes[change][0] not in [MODIFY_ADD, MODIFY_DELETE, MODIFY_REPLACE, MODIFY_INCREMENT]:
self.last_error = 'unknown change type'
raise LDAPChangesError(self.last_error)
request = modify_operation(dn, changes, self.server.schema if self.server and self.check_names else None)
response = self.post_send_single_response(self.send('modifyRequest', request, controls))
if isinstance(response, (int, str)):
return response
return True if self.result['type'] == 'modifyResponse' and self.result['result'] == RESULT_SUCCESS else False
def modify_dn(self,
dn,
relative_dn,
delete_old_dn=True,
new_superior=None,
controls=None):
"""
Modify DN of the entry or performs a move of the entry in the
DIT.
"""
self._fire_deferred()
if self.read_only:
self.last_error = 'connection is read-only'
raise LDAPConnectionIsReadOnlyError(self.last_error)
if new_superior and not dn.startswith(relative_dn): # as per RFC4511 (4.9)
self.last_error = 'DN cannot change while moving'
raise LDAPChangesError(self.last_error)
request = modify_dn_operation(dn, relative_dn, delete_old_dn, new_superior)
response = self.post_send_single_response(self.send('modDNRequest', request, controls))
if isinstance(response, (int, str)):
return response
return True if self.result['type'] == 'modDNResponse' and self.result['result'] == RESULT_SUCCESS else False
def abandon(self,
message_id,
controls=None):
"""
Abandon the operation indicated by message_id
"""
self._fire_deferred()
if self.strategy._outstanding:
if message_id in self.strategy._outstanding and self.strategy._outstanding[message_id]['type'] not in ['abandonRequest', 'bindRequest', 'unbindRequest']:
request = abandon_operation(message_id)
self.send('abandonRequest', request, controls)
self.response = None
self.result = None
return True
return False
def extended(self,
request_name,
request_value=None,
controls=None):
"""
Performs an extended operation
"""
self._fire_deferred()
request = extended_operation(request_name, request_value)
response = self.post_send_single_response(self.send('extendedReq', request, controls))
if isinstance(response, int):
return response
return True if self.result['type'] == 'extendedResp' and self.result['result'] == RESULT_SUCCESS else False
def start_tls(self): # as per RFC4511. Removal of TLS is defined as MAY in RFC4511 so the client can't implement a generic stop_tls method0
if not self.server.tls:
self.server.tls = Tls()
if self.lazy and not self._executing_deferred:
self._deferred_start_tls = True
self.tls_started = True
return True
else:
self._deferred_start_tls = False
if self.server.tls.start_tls(self):
self.refresh_dsa_info() # refresh server info as per RFC4515 (3.1.5)
return True
return False
def do_sasl_bind(self,
controls):
response = None
if not self.sasl_in_progress:
self.sasl_in_progress = True
if self.sasl_mechanism == 'EXTERNAL':
response = sasl_external(self, controls)
elif self.sasl_mechanism == 'DIGEST-MD5':
response = sasl_digest_md5(self, controls)
self.sasl_in_progress = False
return response
def refresh_dsa_info(self):
if not self.closed:
self.server.get_info_from_server(self)
def response_to_ldif(self,
search_result=None,
all_base64=False,
line_separator=None,
sort_order=None,
stream=None):
if search_result is None:
search_result = self.response
if isinstance(search_result, (list, tuple)):
ldif_lines = operation_to_ldif('searchResponse', search_result, all_base64, sort_order=sort_order)
ldif_lines = add_ldif_header(ldif_lines)
line_separator = line_separator or linesep
ldif_output = line_separator.join(ldif_lines)
if stream:
if stream.tell() == 0:
header = add_ldif_header(['-'])[0]
stream.write(prepare_for_stream(header + line_separator + line_separator))
stream.write(prepare_for_stream(ldif_output + line_separator + line_separator))
return ldif_output
return None
def _fire_deferred(self):
if self.lazy:
self._executing_deferred = True
try:
if self._deferred_open:
self.open()
if self._deferred_bind:
self.bind(self._bind_controls)
if self._deferred_start_tls:
self.start_tls()
except LDAPExceptionError:
raise # re-raise LDAPExceptionError
finally:
self._executing_deferred = False
python3-ldap-0.9.4.2/python3-ldap/ldap3/core/exceptions.py 0000666 0000000 0000000 00000035763 12355103746 021374 0 ustar 0000000 0000000 """
Created on 2014.05.14
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from .. import RESULT_OPERATIONS_ERROR, RESULT_PROTOCOL_ERROR, RESULT_TIME_LIMIT_EXCEEDED, RESULT_SIZE_LIMIT_EXCEEDED, \
RESULT_STRONGER_AUTH_REQUIRED, RESULT_REFERRAL, RESULT_ADMIN_LIMIT_EXCEEDED, RESULT_UNAVAILABLE_CRITICAL_EXTENSION, \
RESULT_AUTH_METHOD_NOT_SUPPORTED, RESULT_UNDEFINED_ATTRIBUTE_TYPE, RESULT_NO_SUCH_ATTRIBUTE, \
RESULT_SASL_BIND_IN_PROGRESS, RESULT_CONFIDENTIALITY_REQUIRED, RESULT_INAPPROPRIATE_MATCHING, \
RESULT_CONSTRAINT_VIOLATION, \
RESULT_ATTRIBUTE_OR_VALUE_EXISTS, RESULT_INVALID_ATTRIBUTE_SYNTAX, RESULT_NO_SUCH_OBJECT, RESULT_ALIAS_PROBLEM, \
RESULT_INVALID_DN_SYNTAX, RESULT_ALIAS_DEREFERENCING_PROBLEM, RESULT_INVALID_CREDENTIALS, RESULT_LOOP_DETECTED, \
RESULT_ENTRY_ALREADY_EXISTS, RESULT_LCUP_SECURITY_VIOLATION, RESULT_CANCELED, RESULT_E_SYNC_REFRESH_REQUIRED, \
RESULT_NO_SUCH_OPERATION, RESULT_LCUP_INVALID_DATA, RESULT_OBJECT_CLASS_MODS_PROHIBITED, RESULT_NAMING_VIOLATION, \
RESULT_INSUFFICIENT_ACCESS_RIGHTS, RESULT_OBJECT_CLASS_VIOLATION, RESULT_TOO_LATE, RESULT_CANNOT_CANCEL, \
RESULT_LCUP_UNSUPPORTED_SCHEME, RESULT_BUSY, RESULT_AFFECT_MULTIPLE_DSAS, RESULT_UNAVAILABLE, \
RESULT_NOT_ALLOWED_ON_NON_LEAF, \
RESULT_UNWILLING_TO_PERFORM, RESULT_OTHER, RESULT_LCUP_RELOAD_REQUIRED, RESULT_ASSERTION_FAILED, \
RESULT_AUTHORIZATION_DENIED, RESULT_LCUP_RESOURCES_EXHAUSTED, RESULT_NOT_ALLOWED_ON_RDN, \
RESULT_INAPPROPRIATE_AUTHENTICATION
import socket
# LDAPException hierarchy
class LDAPException(Exception):
pass
class LDAPOperationResult(LDAPException):
def __new__(cls, result=None, description=None, dn=None, message=None, response_type=None, response=None):
if cls is LDAPOperationResult and result and result in exception_table:
exc = super(LDAPOperationResult, exception_table[result]).__new__(
exception_table[result]) # create an exception of the required result error
exc.result = result
exc.description = description
exc.dn = dn
exc.message = message
exc.type = response_type
exc.response = response
else:
exc = super(LDAPOperationResult, cls).__new__(cls)
return exc
def __init__(self, result=None, description=None, dn=None, message=None, response_type=None, response=None):
self.result = result
self.description = description
self.dn = dn
self.message = message
self.type = response_type
self.response = response
def __str__(self):
s = [self.__class__.__name__,
str(self.result) if self.result else None,
self.description if self.description else None,
self.dn if self.dn else None,
self.message if self.message else None,
self.type if self.type else None,
self.response if self.response else None]
return ' - '.join(filter(None, s))
def __repr__(self):
return self.__str__()
class LDAPOperationsErrorResult(LDAPOperationResult):
pass
class LDAPProtocolErrorResult(LDAPOperationResult):
pass
class LDAPTimeLimitExceededResult(LDAPOperationResult):
pass
class LDAPSizeLimitExceededResult(LDAPOperationResult):
pass
class LDAPAuthMethodNotSupportedResult(LDAPOperationResult):
pass
class LDAPStrongerAuthRequiredResult(LDAPOperationResult):
pass
class LDAPReferralResult(LDAPOperationResult):
pass
class LDAPAdminLimitExceededResult(LDAPOperationResult):
pass
class LDAPUnavailableCriticalExtensionResult(LDAPOperationResult):
pass
class LDAPConfidentialityRequiredResult(LDAPOperationResult):
pass
class LDAPSASLBindInProgressResult(LDAPOperationResult):
pass
class LDAPNoSuchAttributeResult(LDAPOperationResult):
pass
class LDAPUndefinedAttributeTypeResult(LDAPOperationResult):
pass
class LDAPInappropriateMatchingResult(LDAPOperationResult):
pass
class LDAPConstraintViolationResult(LDAPOperationResult):
pass
class LDAPAttributeOrValueExistsResult(LDAPOperationResult):
pass
class LDAPInvalidAttributeSyntaxResult(LDAPOperationResult):
pass
class LDAPNoSuchObjectResult(LDAPOperationResult):
pass
class LDAPAliasProblemResult(LDAPOperationResult):
pass
class LDAPInvalidDNSyntaxResult(LDAPOperationResult):
pass
class LDAPAliasDereferencingProblemResult(LDAPOperationResult):
pass
class LDAPInappropriateAuthenticationResult(LDAPOperationResult):
pass
class LDAPInvalidCredentialsResult(LDAPOperationResult):
pass
class LDAPInsufficientAccessRightsResult(LDAPOperationResult):
pass
class LDAPBusyResult(LDAPOperationResult):
pass
class LDAPUnavailableResult(LDAPOperationResult):
pass
class LDAPUnwillingToPerformResult(LDAPOperationResult):
pass
class LDAPLoopDetectedResult(LDAPOperationResult):
pass
class LDAPNamingViolationResult(LDAPOperationResult):
pass
class LDAPObjectClassViolationResult(LDAPOperationResult):
pass
class LDAPNotAllowedOnNotLeafResult(LDAPOperationResult):
pass
class LDAPNotAllowedOnRDNResult(LDAPOperationResult):
pass
class LDAPEntryAlreadyExistsResult(LDAPOperationResult):
pass
class LDAPObjectClassModsProhibitedResult(LDAPOperationResult):
pass
class LDAPAffectMultipleDSASResult(LDAPOperationResult):
pass
class LDAPOtherResult(LDAPOperationResult):
pass
class LDAPLCUPResourcesExhaustedResult(LDAPOperationResult):
pass
class LDAPLCUPSecurityViolationResult(LDAPOperationResult):
pass
class LDAPLCUPInvalidDataResult(LDAPOperationResult):
pass
class LDAPLCUPUnsupportedSchemeResult(LDAPOperationResult):
pass
class LDAPLCUPReloadRequiredResult(LDAPOperationResult):
pass
class LDAPCanceledResult(LDAPOperationResult):
pass
class LDAPNoSuchOperationResult(LDAPOperationResult):
pass
class LDAPTooLateResult(LDAPOperationResult):
pass
class LDAPCannotCancelResult(LDAPOperationResult):
pass
class LDAPAssertionFailedResult(LDAPOperationResult):
pass
class LDAPAuthorizationDeniedResult(LDAPOperationResult):
pass
class LDAPESyncRefreshRequiredResult(LDAPOperationResult):
pass
exception_table = {RESULT_OPERATIONS_ERROR: LDAPOperationsErrorResult,
RESULT_PROTOCOL_ERROR: LDAPProtocolErrorResult,
RESULT_TIME_LIMIT_EXCEEDED: LDAPTimeLimitExceededResult,
RESULT_SIZE_LIMIT_EXCEEDED: LDAPSizeLimitExceededResult,
RESULT_AUTH_METHOD_NOT_SUPPORTED: LDAPAuthMethodNotSupportedResult,
RESULT_STRONGER_AUTH_REQUIRED: LDAPStrongerAuthRequiredResult,
RESULT_REFERRAL: LDAPReferralResult,
RESULT_ADMIN_LIMIT_EXCEEDED: LDAPAdminLimitExceededResult,
RESULT_UNAVAILABLE_CRITICAL_EXTENSION: LDAPUnavailableCriticalExtensionResult,
RESULT_CONFIDENTIALITY_REQUIRED: LDAPConfidentialityRequiredResult,
RESULT_SASL_BIND_IN_PROGRESS: LDAPSASLBindInProgressResult,
RESULT_NO_SUCH_ATTRIBUTE: LDAPNoSuchAttributeResult,
RESULT_UNDEFINED_ATTRIBUTE_TYPE: LDAPUndefinedAttributeTypeResult,
RESULT_INAPPROPRIATE_MATCHING: LDAPInappropriateMatchingResult,
RESULT_CONSTRAINT_VIOLATION: LDAPConstraintViolationResult,
RESULT_ATTRIBUTE_OR_VALUE_EXISTS: LDAPAttributeOrValueExistsResult,
RESULT_INVALID_ATTRIBUTE_SYNTAX: LDAPInvalidAttributeSyntaxResult,
RESULT_NO_SUCH_OBJECT: LDAPNoSuchObjectResult,
RESULT_ALIAS_PROBLEM: LDAPAliasProblemResult,
RESULT_INVALID_DN_SYNTAX: LDAPInvalidDNSyntaxResult,
RESULT_ALIAS_DEREFERENCING_PROBLEM: LDAPAliasDereferencingProblemResult,
RESULT_INAPPROPRIATE_AUTHENTICATION: LDAPInappropriateAuthenticationResult,
RESULT_INVALID_CREDENTIALS: LDAPInvalidCredentialsResult,
RESULT_INSUFFICIENT_ACCESS_RIGHTS: LDAPInsufficientAccessRightsResult,
RESULT_BUSY: LDAPBusyResult,
RESULT_UNAVAILABLE: LDAPUnavailableResult,
RESULT_UNWILLING_TO_PERFORM: LDAPUnwillingToPerformResult,
RESULT_LOOP_DETECTED: LDAPLoopDetectedResult,
RESULT_NAMING_VIOLATION: LDAPNamingViolationResult,
RESULT_OBJECT_CLASS_VIOLATION: LDAPObjectClassViolationResult,
RESULT_NOT_ALLOWED_ON_NON_LEAF: LDAPNotAllowedOnNotLeafResult,
RESULT_NOT_ALLOWED_ON_RDN: LDAPNotAllowedOnRDNResult,
RESULT_ENTRY_ALREADY_EXISTS: LDAPEntryAlreadyExistsResult,
RESULT_OBJECT_CLASS_MODS_PROHIBITED: LDAPObjectClassModsProhibitedResult,
RESULT_AFFECT_MULTIPLE_DSAS: LDAPAffectMultipleDSASResult,
RESULT_OTHER: LDAPOtherResult,
RESULT_LCUP_RESOURCES_EXHAUSTED: LDAPLCUPResourcesExhaustedResult,
RESULT_LCUP_SECURITY_VIOLATION: LDAPLCUPSecurityViolationResult,
RESULT_LCUP_INVALID_DATA: LDAPLCUPInvalidDataResult,
RESULT_LCUP_UNSUPPORTED_SCHEME: LDAPLCUPUnsupportedSchemeResult,
RESULT_LCUP_RELOAD_REQUIRED: LDAPLCUPReloadRequiredResult,
RESULT_CANCELED: LDAPCanceledResult,
RESULT_NO_SUCH_OPERATION: LDAPNoSuchOperationResult,
RESULT_TOO_LATE: LDAPTooLateResult,
RESULT_CANNOT_CANCEL: LDAPCannotCancelResult,
RESULT_ASSERTION_FAILED: LDAPAssertionFailedResult,
RESULT_AUTHORIZATION_DENIED: LDAPAuthorizationDeniedResult,
RESULT_E_SYNC_REFRESH_REQUIRED: LDAPESyncRefreshRequiredResult}
class LDAPExceptionError(LDAPException):
pass
# abstract layer exceptions
class LDAPKeyError(LDAPExceptionError, KeyError):
pass
class LDAPAttributeError(LDAPExceptionError, AttributeError):
pass
class LDAPEntryError(LDAPExceptionError):
pass
class LDAPObjectError(LDAPExceptionError, ValueError):
pass
class LDAPTypeError(LDAPExceptionError, TypeError):
pass
class LDAPReaderError(LDAPExceptionError):
pass
# tls exceptions
class LDAPSSLNotSupportedError(LDAPExceptionError, ImportError):
pass
# connection exceptions
class LDAPUnknownStrategyError(LDAPExceptionError):
pass
class LDAPUnknownAuthenticationMethodError(LDAPExceptionError):
pass
class LDAPBindError(LDAPExceptionError):
pass
class LDAPInvalidServerError(LDAPExceptionError):
pass
class LDAPSASLMechanismNotSupportedError(LDAPExceptionError):
pass
class LDAPConnectionIsReadOnlyError(LDAPExceptionError):
pass
class LDAPChangesError(LDAPExceptionError, ValueError):
pass
class LDAPServerPoolError(LDAPExceptionError):
pass
class LDAPServerPoolExhaustedError(LDAPExceptionError):
pass
class LDAPInvalidPort(LDAPExceptionError):
pass
class LDAPSSLConfigurationError(LDAPExceptionError):
pass
class LDAPStartTLSError(LDAPExceptionError):
pass
class LDAPCertificateError(LDAPExceptionError):
pass
class LDAPPasswordIsMandatoryError(LDAPExceptionError):
pass
class LDAPInvalidFilterError(LDAPExceptionError):
pass
class LDAPInvalidScopeError(LDAPExceptionError, ValueError):
pass
class LDAPInvalidDereferenceAliasesError(LDAPExceptionError, ValueError):
pass
class LDAPControlsError(LDAPExceptionError, ValueError):
pass
class LDAPExtensionError(LDAPExceptionError, ValueError):
pass
class LDAPLDIFError(LDAPExceptionError):
pass
class LDAPSchemaError(LDAPExceptionError):
pass
class LDAPSASLPrepError(LDAPExceptionError):
pass
class LDAPSASLBindInProgressError(LDAPExceptionError):
pass
class LDAPMetricsError(LDAPExceptionError):
pass
class LDAPObjectClassError(LDAPExceptionError):
pass
# communication exceptions
class LDAPCommunicationError(LDAPExceptionError):
pass
class LDAPSocketOpenError(LDAPCommunicationError):
pass
class LDAPSocketCloseError(LDAPCommunicationError):
pass
class LDAPSocketReceiveError(LDAPCommunicationError, socket.error):
pass
class LDAPSocketSendError(LDAPCommunicationError, socket.error):
pass
class LDAPSessionTerminatedByServer(LDAPCommunicationError):
pass
class LDAPUnknownResponseError(LDAPCommunicationError):
pass
class LDAPUnknownRequestError(LDAPCommunicationError):
pass
class LDAPReferralError(LDAPCommunicationError):
pass
# pooling exceptions
class LDAPConnectionPoolNameIsMandatoryError(LDAPExceptionError):
pass
class LDAPConnectionPoolNotStartedError(LDAPExceptionError):
pass
# restartable strategy
class LDAPMaximumRetriesError(LDAPExceptionError):
def __str__(self):
if self.args:
if isinstance(self.args, tuple):
if len(self.args) > 0:
print('Error: ' + self.args[0])
if len(self.args) > 1:
print('Exceptions history:')
for i, exc in enumerate(self.args[1]): # args[1] contains exception history
print(str(i).rjust(5), str(exc[0]), ':', exc[1], '-', exc[2])
if len(self.args) > 2:
print('Maximum number of retries reached: ' + str(self.args[2]))
# exception factories
def communication_exception_factory(exc_to_raise, exc):
"""
Generates a new exception class of the requested type (subclass of LDAPCommunication) merged with the exception raised by the interpreter
"""
if exc_to_raise.__name__ in [cls.__name__ for cls in LDAPCommunicationError.__subclasses__()]:
return type(exc_to_raise.__name__, (type(exc), LDAPCommunicationError), dict())
else:
raise LDAPExceptionError('unable to generate exception type ' + str(exc_to_raise))
python3-ldap-0.9.4.2/python3-ldap/ldap3/core/pooling.py 0000666 0000000 0000000 00000021663 12355103746 020654 0 ustar 0000000 0000000 """
Created on 2014.03.14
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from datetime import datetime
from os import linesep
from random import randint
from .. import POOLING_STRATEGY_FIRST, POOLING_STRATEGY_ROUND_ROBIN, POOLING_STRATEGY_RANDOM, POOLING_STRATEGIES
from .exceptions import LDAPUnknownStrategyError, LDAPServerPoolError, LDAPServerPoolExhaustedError
from .server import Server
class ServerPoolState(object):
def __init__(self, server_pool):
self.servers = []
self.strategy = server_pool.strategy
self.server_pool = server_pool
self.refresh()
self.initialize_time = datetime.now()
self.last_used_server = randint(0, len(self.servers)-1)
def __str__(self):
s = 'servers: '
if self.servers:
for server in self.servers:
s += str(server) + linesep
else:
s += 'None'
s += 'Pool strategy: ' + str(self.strategy)
s += ' - Last used server: ' + ('None' if self.last_used_server == -1 else str(self.servers[self.last_used_server]))
return s
def refresh(self):
self.servers = []
for server in self.server_pool.servers:
self.servers.append(server)
self.last_used_server = randint(0, len(self.servers) - 1)
def get_current_server(self):
return self.servers[self.last_used_server]
def get_server(self):
if self.servers:
if self.server_pool.strategy == POOLING_STRATEGY_FIRST:
if self.server_pool.active:
# returns the first active server
self.last_used_server = self.find_active_server(starting=0, exhaust=self.server_pool.exhaust)
else:
# returns always the first server - no pooling
self.last_used_server = 0
elif self.server_pool.strategy == POOLING_STRATEGY_ROUND_ROBIN:
if self.server_pool.active:
# returns the next active server in a circular range
self.last_used_server = self.find_active_server(self.last_used_server + 1, exhaust=self.server_pool.exhaust)
else:
# returns the next server in a circular range
self.last_used_server = self.last_used_server + 1 if (self.last_used_server + 1) < len(self.servers) else 0
elif self.server_pool.strategy == POOLING_STRATEGY_RANDOM:
if self.server_pool.active:
self.last_used_server = self.find_active_random_server(exhaust=self.server_pool.exhaust)
else:
# returns a random server in the pool
self.last_used_server = randint(0, len(self.servers))
else:
raise LDAPUnknownStrategyError('unknown server pooling strategy')
return self.servers[self.last_used_server]
else:
raise LDAPServerPoolError('no servers in server pool')
def find_active_random_server(self, exhaust=True):
while True:
temp_list = self.servers[:] # copy
while temp_list:
# pops a random server from a temp list and checks its
# availability, if not available tries another one
server = temp_list.pop(randint(0, len(temp_list) - 1))
if server.check_availability():
# returns a random active server in the pool
return self.servers.index(server)
if exhaust:
raise LDAPServerPoolExhaustedError('no random active server in server pool')
def find_active_server(self, starting=0, exhaust=True):
while True:
index = starting
while index < len(self.servers):
if self.servers[index].check_availability():
break
index += 1
else:
# if no server found in the list (from starting index)
# checks starting from the base of the list
index = 0
while index < starting:
if self.servers[index].check_availability():
break
index += 1
else:
if exhaust:
raise LDAPServerPoolExhaustedError('no active server available in server pool')
else:
continue
return index
def __len__(self):
return len(self.servers)
class ServerPool(object):
def __init__(self,
servers=None,
pool_strategy=POOLING_STRATEGY_ROUND_ROBIN,
active=True,
exhaust=False):
if pool_strategy not in POOLING_STRATEGIES:
raise LDAPUnknownStrategyError('unknown pooling strategy')
if exhaust and not active:
raise LDAPServerPoolError('pools can be exhausted only when checking for active servers')
self.servers = []
self.pool_states = dict()
self.active = active
self.exhaust = exhaust
if isinstance(servers, (list, tuple)):
for server in servers:
self.add(server)
elif isinstance(servers, Server):
self.add(servers)
self.strategy = pool_strategy
def __str__(self):
s = 'servers: '
if self.servers:
for server in self.servers:
s += str(server) + linesep
else:
s += 'None'
s += 'Pool strategy: ' + str(self.strategy)
s += ' - ' + 'active only: ' + ('True' if self.active else 'False')
s += ' - ' + 'exhaust pool: ' + ('True' if self.exhaust else 'False')
return s
def __repr__(self):
r = 'ServerPool(servers='
if self.servers:
r += '['
for server in self.servers:
r += server.__repr__() + ', '
r = r[:-2] + ']'
else:
r += 'None'
r += ', pool_strategy={0.strategy!r}'.format(self)
r += ', active={0.active!r}'.format(self)
r += ', exhaust={0.exhaust!r}'.format(self)
r += ')'
return r
def __len__(self):
return len(self.servers)
def __getitem__(self, item):
return self.servers[item]
def __iter__(self):
return self.servers.__iter__()
def add(self, servers):
if isinstance(servers, Server):
if servers not in self.servers:
self.servers.append(servers)
elif isinstance(servers, (list, tuple)):
for server in servers:
if isinstance(server, Server):
self.servers.append(server)
else:
raise LDAPServerPoolError('server in ServerPool must be a Server')
else:
raise LDAPServerPoolError('server must be a Server or a list of Server')
for connection in self.pool_states:
# notifies connections using this pool to refresh
self.pool_states[connection].refresh()
def remove(self, server):
if server in self.servers:
self.servers.remove(server)
else:
raise LDAPServerPoolError('server not in server pool')
for connection in self.pool_states:
# notifies connections using this pool to refresh
self.pool_states[connection].refresh()
def initialize(self, connection):
pool_state = ServerPoolState(self)
# registers pool_state in ServerPool object
self.pool_states[connection] = pool_state
def get_server(self, connection):
if connection in self.pool_states:
return self.pool_states[connection].get_server()
else:
raise LDAPServerPoolError('connection not in ServerPoolState')
def get_current_server(self, connection):
if connection in self.pool_states:
return self.pool_states[connection].get_current_server()
else:
raise LDAPServerPoolError('connection not in ServerPoolState')
python3-ldap-0.9.4.2/python3-ldap/ldap3/core/server.py 0000666 0000000 0000000 00000021551 12355103746 020507 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from socket import getaddrinfo, gaierror
from .. import GET_NO_INFO, GET_DSA_INFO, GET_SCHEMA_INFO, GET_ALL_INFO, ALL_ATTRIBUTES, SEARCH_SCOPE_BASE_OBJECT, LDAP_MAX_INT
from threading import Lock
from .exceptions import LDAPInvalidPort
from ..protocol.rfc4512 import SchemaInfo, DsaInfo
from .tls import Tls
import socket
class Server(object):
"""
LDAP Server definition class
Allowed_referral_hosts can be None (default), or a list of tuples of
allowed servers ip address or names to contact while redirecting
search to referrals.
The second element of the tuple is a boolean to indicate if
authentication to that server is allowed; if False only anonymous
bind will be used.
Per RFC 4516. Use ('*', False) to allow any host with anonymous
bind, use ('*', True) to allow any host with same authentication of
Server.
"""
_real_servers = dict() # dictionary of real servers currently active, the key is the host part of the server address
# and the value is the messageId counter for all connection to that host)
def __init__(self,
host,
port=None,
use_ssl=False,
allowed_referral_hosts=None,
get_info=GET_NO_INFO,
tls=None):
if not use_ssl and not port:
port = 389
elif use_ssl and not port:
port = 636
if host.startswith('ldap://'):
self.host = host[7:]
elif host.startswith('ldaps://'):
self.host = host[8:]
else:
self.host = host
try:
self.address = getaddrinfo(self.host, port)[0][4][0]
except gaierror:
self.address = self.host
if isinstance(port, int):
self.port = port
else:
raise LDAPInvalidPort('port must be an integer')
if isinstance(allowed_referral_hosts, (list, tuple)):
self.allowed_referral_hosts = []
for refServer in allowed_referral_hosts:
if isinstance(refServer, tuple):
if isinstance(refServer[1], bool):
self.allowed_referral_hosts.append(refServer)
elif isinstance(allowed_referral_hosts, tuple):
if isinstance(allowed_referral_hosts[1], bool):
self.allowed_referral_hosts = [allowed_referral_hosts]
else:
self.allowed_referral_hosts = []
self.ssl = True if use_ssl else False
self.tls = Tls() if self.ssl and not tls else tls
self.name = ('ldaps' if self.ssl else 'ldap') + '://' + self.host + ':' + str(self.port)
self.get_info = get_info
self._dsa_info = None
self._schema_info = None
self.lock = Lock()
self.message_id_lock = Lock()
def __str__(self):
if self.host:
s = self.name + (' - ssl' if self.ssl else ' - cleartext')
else:
s = object.__str__(self)
return s
def __repr__(self):
r = 'Server(host={0.host!r}, port={0.port!r}, use_ssl={0.ssl!r}'.format(self)
r += '' if not self.allowed_referral_hosts else ', allowed_referral_hosts={0.allowed_referral_hosts!r}'.format(self)
r += '' if self.tls is None else ', tls={0.tls!r}'.format(self)
r += '' if not self.get_info else ', get_info={0.get_info!r}'.format(self)
r += ')'
return r
def is_valid(self):
return True if self.address else False
def check_availability(self):
"""
Tries to open, connect and close a socket to specified address
and port to check availability.
"""
available = True
temp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
temp_socket.connect((self.host, self.port))
except socket.error:
available = False
finally:
try:
temp_socket.shutdown(socket.SHUT_RDWR)
temp_socket.close()
except socket.error:
available = False
return available
def next_message_id(self):
"""
messageId is unique in all connections to the server.
"""
with self.message_id_lock:
if self.address and self.address in Server._real_servers:
Server._real_servers[self.address] += 1
if Server._real_servers[self.address] >= LDAP_MAX_INT: # wrap as per MAXINT (2147483647) in RFC4511 specification
Server._real_servers[self.address] = 1 # 0 is reserved for Unsolicited messages
else:
Server._real_servers[self.address] = 1
return Server._real_servers[self.address]
def _get_dsa_info(self, connection):
"""
Retrieve DSE operational attribute as per RFC4512 (5.1).
"""
result = connection.search('', '(objectClass=*)', SEARCH_SCOPE_BASE_OBJECT, attributes=ALL_ATTRIBUTES, get_operational_attributes=True)
self._dsa_info = None
with self.lock:
if isinstance(result, bool): # sync request
self._dsa_info = DsaInfo(connection.response[0]['attributes']) if result else None
elif result: # async request, must check if attributes in response
results, _ = connection.get_response(result)
if len(results) == 1 and 'attributes' in results[0]:
self._dsa_info = DsaInfo(results[0]['attributes'])
def _get_schema_info(self, connection, entry=''):
"""
Retrieve schema from subschemaSubentry DSE attribute, per RFC
4512 (4.4 and 5.1); entry = '' means DSE.
"""
schema_entry = None
if self._dsa_info and entry == '': # subschemaSubentry already present in dsaInfo
schema_entry = self._dsa_info.schema_entry[0] if self._dsa_info.schema_entry else None
else:
result = connection.search(entry, '(objectClass=*)', SEARCH_SCOPE_BASE_OBJECT, attributes=['subschemaSubentry'], get_operational_attributes=True)
if isinstance(result, bool): # sync request
schema_entry = connection.response[0]['attributes']['subschemaSubentry'][0] if result else None
else: # async request, must check if subschemaSubentry in attributes
results, _ = connection.get_response(result)
if len(results) == 1 and 'attributes' in results[0] and 'subschemaSubentry' in results[0]['attributes']:
schema_entry = results[0]['attributes']['subschemaSubentry'][0]
result = None
if schema_entry:
result = connection.search(schema_entry, search_filter='(objectClass=subschema)', search_scope=SEARCH_SCOPE_BASE_OBJECT, attributes=ALL_ATTRIBUTES, get_operational_attributes=True)
with self.lock:
self._schema_info = None
if result:
if isinstance(result, bool): # sync request
self._schema_info = SchemaInfo(schema_entry, connection.response[0]['attributes']) if result else None
else: # async request, must check if attributes in response
results, _ = connection.get_response(result)
if len(results) == 1 and 'attributes' in results[0]:
self._schema_info = SchemaInfo(schema_entry, results[0]['attributes'])
def get_info_from_server(self, connection):
"""
read info from DSE and from subschema
"""
if not connection.closed:
if self.get_info in [GET_DSA_INFO, GET_ALL_INFO]:
self._get_dsa_info(connection)
if self.get_info in [GET_SCHEMA_INFO, GET_ALL_INFO]:
self._get_schema_info(connection)
connection.response = None
connection.result = None
@property
def info(self):
return self._dsa_info
@property
def schema(self):
return self._schema_info
python3-ldap-0.9.4.2/python3-ldap/ldap3/core/tls.py 0000666 0000000 0000000 00000031673 12355110261 017777 0 ustar 0000000 0000000 """
Created on 2013.08.05
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
import re
from .exceptions import LDAPSSLNotSupportedError, LDAPSSLConfigurationError, LDAPStartTLSError, LDAPCertificateError
try:
# noinspection PyUnresolvedReferences
import ssl
except ImportError:
raise LDAPSSLNotSupportedError('SSL not supported in this Python interpreter')
try:
# noinspection PyUnresolvedReferences
from ssl import CertificateError
except ImportError:
class CertificateError(ValueError): # fix for Python 2, code from Python 3.3 standard library
pass
try:
# noinspection PyUnresolvedReferences
from ssl import create_default_context, Purpose # defined in Python 3.4
use_ssl_context = True
except ImportError:
use_ssl_context = False
from os import path
# noinspection PyProtectedMember
class Tls(object):
"""
tls/ssl configuration for Server object
Starting from python 3-4 it uses the SSLContext object
that tries to read the CAs defined at system level
ca_certs_path and ca_certs_data are valid only when using SSLContext
local_private_key_password is valid only when using SSLContext
"""
def __init__(self,
local_private_key_file=None,
local_certificate_file=None,
validate=ssl.CERT_NONE,
version=None,
ca_certs_file=None,
valid_names=None,
ca_certs_path=None,
ca_certs_data=None,
local_private_key_password=None):
if validate in [ssl.CERT_NONE, ssl.CERT_OPTIONAL, ssl.CERT_REQUIRED]:
self.validate = validate
elif validate:
raise LDAPSSLConfigurationError('invalid validate parameter')
if ca_certs_file and path.exists(ca_certs_file):
self.ca_certs_file = ca_certs_file
elif ca_certs_file:
raise LDAPSSLConfigurationError('invalid CA public key file')
else:
self.ca_certs_file = None
if ca_certs_path and use_ssl_context and path.exists(ca_certs_path):
self.ca_certs_path = ca_certs_path
elif ca_certs_path and not use_ssl_context:
raise LDAPSSLNotSupportedError('cannot use CA public keys path, SSLContext not available')
elif ca_certs_path:
raise LDAPSSLConfigurationError('invalid CA public keys path')
else:
self.ca_certs_path = None
if ca_certs_data and use_ssl_context:
self.ca_certs_data = ca_certs_data
elif ca_certs_data:
raise LDAPSSLNotSupportedError('cannot use CA data, SSLContext not available')
else:
self.ca_certs_data = None
if local_private_key_password and use_ssl_context:
self.private_key_password = local_private_key_password
elif local_private_key_password:
raise LDAPSSLNotSupportedError('cannot use local private key password, SSLContext is not available')
else:
self.private_key_password = None
self.version = version
self.private_key_file = local_private_key_file
self.certificate_file = local_certificate_file
self.valid_names = valid_names
def __str__(self):
s = [
'protocol: ' + str(self.version),
'client private key: ' + ('present ' if self.private_key_file else 'not present'),
'client certificate: ' + ('present ' if self.certificate_file else 'not present'),
'private key password: ' + ('present ' if self.private_key_password else 'not present'),
'CA certificates file: ' + ('present ' if self.ca_certs_file else 'not present'),
'CA certificates path: ' + ('present ' if self.ca_certs_path else 'not present'),
'CA certificates data: ' + ('present ' if self.ca_certs_data else 'not present'),
'verify mode: ' + str(self.validate),
'valid names: ' + str(self.valid_names)
]
return ' - '.join(s)
def __repr__(self):
r = '' if self.private_key_file is None else ', local_private_key_file={0.private_key_file!r}'.format(self)
r += '' if self.certificate_file is None else ', local_certificate_file={0.certificate_file!r}'.format(self)
r += '' if self.validate is None else ', validate={0.validate!r}'.format(self)
r += '' if self.version is None else ', version={0.version!r}'.format(self)
r += '' if self.ca_certs_file is None else ', ca_certs_file={0.ca_certs_file!r}'.format(self)
r += '' if self.ca_certs_path is None else ', ca_certs_path={0.ca_certs_path!r}'.format(self)
r += '' if self.ca_certs_data is None else ', ca_certs_data={0.ca_certs_data!r}'.format(self)
r = 'Tls(' + r[2:] + ')'
return r
def wrap_socket(self, connection, do_handshake=False):
"""
Adds TLS to the connection socket
"""
if use_ssl_context:
ssl_context = create_default_context(purpose=Purpose.SERVER_AUTH, cafile=self.ca_certs_file, capath=self.ca_certs_path, cadata=self.ca_certs_data)
if self.private_key_file:
ssl_context.load_cert_chain(self.certificate_file, keyfile=self.private_key_file, password=self.private_key_password)
ssl_context.check_hostname = False
ssl_context.verify_mode = self.validate
if not self.version is None: # if version is present overrides the default context version
ssl_context.protocol = self.version
wrapped_socket = ssl_context.wrap_socket(connection.socket, server_side=False, do_handshake_on_connect=do_handshake)
else:
if self.version is None:
self.version = ssl.PROTOCOL_SSLv23
wrapped_socket = ssl.wrap_socket(connection.socket,
keyfile=self.private_key_file,
certfile=self.certificate_file,
server_side=False,
cert_reqs=self.validate,
ssl_version=self.version,
ca_certs=self.ca_certs_file,
do_handshake_on_connect=do_handshake)
if do_handshake and (self.validate == ssl.CERT_REQUIRED or self.validate == ssl.CERT_OPTIONAL):
check_hostname(wrapped_socket, connection.server.host, self.valid_names)
connection.socket = wrapped_socket
return
def start_tls(self, connection):
if connection.server.ssl: # ssl already established at server level
return False
if (connection.tls_started and not connection._executing_deferred) or connection.strategy._outstanding or connection.sasl_in_progress:
# Per RFC 4513 (3.1.1)
return False
connection.starting_tls = True
result = connection.extended('1.3.6.1.4.1.1466.20037')
if not connection.strategy.sync:
# async - _start_tls must be executed by the strategy
connection.get_response(result)
return True
else:
if connection.result['description'] not in ['success']:
# startTLS failed
connection.last_error = 'startTLS failed - ' + str(connection.result['description'])
raise LDAPStartTLSError(connection.last_error)
return self._start_tls(connection)
def _start_tls(self, connection):
self.wrap_socket(connection, do_handshake=True)
if connection.usage:
connection._usage.wrapped_sockets += 1
connection.starting_tls = False
connection.tls_started = True
return True
def _dnsname_match_backport(dn, hostname, max_wildcards=1):
"""Matching according to RFC 6125, section 6.4.3
http://tools.ietf.org/html/rfc6125#section-6.4.3
"""
pats = []
if not dn:
return False
dn_array = dn.split(r'.')
leftmost = dn_array[0]
remainder = dn_array[1:]
wildcards = leftmost.count('*')
if wildcards > max_wildcards:
# Issue #17980: avoid denials of service by refusing more
# than one wildcard per fragment. A survery of established
# policy among SSL implementations showed it to be a
# reasonable choice.
raise CertificateError(
"too many wildcards in certificate DNS name: " + repr(dn))
# speed up common case w/o wildcards
if not wildcards:
return dn.lower() == hostname.lower()
# RFC 6125, section 6.4.3, subitem 1.
# The client SHOULD NOT attempt to match a presented identifier in which
# the wildcard character comprises a label other than the left-most label.
if leftmost == '*':
# When '*' is a fragment by itself, it matches a non-empty dotless
# fragment.
pats.append('[^.]+')
elif leftmost.startswith('xn--') or hostname.startswith('xn--'):
# RFC 6125, section 6.4.3, subitem 3.
# The client SHOULD NOT attempt to match a presented identifier
# where the wildcard character is embedded within an A-label or
# U-label of an internationalized domain name.
pats.append(re.escape(leftmost))
else:
# Otherwise, '*' matches any dotless string, e.g. www*
pats.append(re.escape(leftmost).replace(r'\*', '[^.]*'))
# add the remaining fragments, ignore any wildcards
for frag in remainder:
pats.append(re.escape(frag))
pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
return pat.match(hostname)
def match_hostname_backport(cert, hostname):
"""
Fix for Python2; code from Python 3.4.1 standard library.
Verify that *cert* (in decoded format as returned by
SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125
rules are followed, but IP addresses are not accepted for *hostname*.
CertificateError is raised on failure. On success, the function
returns nothing.
"""
if not cert:
raise ValueError("empty or no certificate, match_hostname needs a "
"SSL socket or SSL context with either "
"CERT_OPTIONAL or CERT_REQUIRED")
dnsnames = []
san = cert.get('subjectAltName', ())
for key, value in san:
if key == 'DNS':
if _dnsname_match_backport(value, hostname):
return
dnsnames.append(value)
if not dnsnames:
# The subject is only checked when there is no dNSName entry
# in subjectAltName
for sub in cert.get('subject', ()):
for key, value in sub:
# XXX according to RFC 2818, the most specific Common Name
# must be used.
if key == 'commonName':
if _dnsname_match_backport(value, hostname):
return
dnsnames.append(value)
if len(dnsnames) > 1:
raise CertificateError("hostname %r doesn't match either of %s" % (hostname, ', '.join(map(repr, dnsnames))))
elif len(dnsnames) == 1:
raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0]))
else:
raise CertificateError("no appropriate commonName or subjectAltName fields were found")
def check_hostname(sock, server_name, additional_names):
server_certificate = sock.getpeercert()
host_names = [server_name] + (additional_names if isinstance(additional_names, (list, tuple)) else [additional_names])
for host_name in host_names:
if host_name is None:
continue
elif host_name == '*':
return
try:
ssl.match_hostname(server_certificate, host_name) # raise CertificateError if certificate doesn't match server name
return
except AttributeError:
match_hostname_backport(server_certificate, host_name)
return
except CertificateError:
pass
raise LDAPCertificateError("hostname doesn't match")
python3-ldap-0.9.4.2/python3-ldap/ldap3/core/usage.py 0000666 0000000 0000000 00000022153 12355103746 020304 0 ustar 0000000 0000000 """
Created on 2014.03.15
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from datetime import datetime, timedelta
from os import linesep
from .exceptions import LDAPMetricsError
class ConnectionUsage(object):
"""
Collect statistics on connection usage
"""
def reset(self):
self.opened_sockets = 0
self.closed_sockets = 0
self.wrapped_sockets = 0
self.bytes_transmitted = 0
self.bytes_received = 0
self.messages_transmitted = 0
self.messages_received = 0
self.operations = 0
self.abandon_operations = 0
self.add_operations = 0
self.bind_operations = 0
self.compare_operations = 0
self.delete_operations = 0
self.extended_operations = 0
self.modify_operations = 0
self.modify_dn_operations = 0
self.search_operations = 0
self.unbind_operations = 0
self.referrals_received = 0
self.referrals_followed = 0
self.restartable_failures = 0
self.restartable_successes = 0
self.servers_from_pool = 0
def __init__(self):
self.initial_connection_start_time = None
self.open_socket_start_time = None
self.connection_stop_time = None
self.opened_sockets = 0
self.closed_sockets = 0
self.wrapped_sockets = 0
self.bytes_transmitted = 0
self.bytes_received = 0
self.messages_transmitted = 0
self.messages_received = 0
self.operations = 0
self.abandon_operations = 0
self.add_operations = 0
self.bind_operations = 0
self.compare_operations = 0
self.delete_operations = 0
self.extended_operations = 0
self.modify_operations = 0
self.modify_dn_operations = 0
self.search_operations = 0
self.unbind_operations = 0
self.referrals_received = 0
self.referrals_followed = 0
self.restartable_failures = 0
self.restartable_successes = 0
self.servers_from_pool = 0
def __repr__(self):
r = 'Connection Usage:' + linesep
r += ' Time: [elapsed: ' + str(self.elapsed_time) + ']' + linesep
r += ' Initial start time: ' + (str(self.initial_connection_start_time.isoformat()) if self.initial_connection_start_time else '') + linesep
r += ' Open socket time: ' + (str(self.open_socket_start_time.isoformat()) if self.open_socket_start_time else '') + linesep
r += ' Close socket time: ' + (str(self.connection_stop_time.isoformat()) if self.connection_stop_time else '') + linesep
r += ' Server:' + linesep
r += ' Servers from pool: ' + str(self.servers_from_pool) + linesep
r += ' Sockets opened: ' + str(self.opened_sockets) + linesep
r += ' Sockets closed: ' + str(self.closed_sockets) + linesep
r += ' Sockets wrapped: ' + str(self.wrapped_sockets) + linesep
r += ' Bytes: ' + str(self.bytes_transmitted + self.bytes_received) + linesep
r += ' Transmitted: ' + str(self.bytes_transmitted) + linesep
r += ' Received: ' + str(self.bytes_received) + linesep
r += ' Messages: ' + str(self.messages_transmitted + self.messages_received) + linesep
r += ' Transmitted: ' + str(self.messages_transmitted) + linesep
r += ' Received: ' + str(self.messages_received) + linesep
r += ' Operations: ' + str(self.operations) + linesep
r += ' Abandon: ' + str(self.abandon_operations) + linesep
r += ' Bind: ' + str(self.bind_operations) + linesep
r += ' Compare: ' + str(self.compare_operations) + linesep
r += ' Delete: ' + str(self.delete_operations) + linesep
r += ' Extended: ' + str(self.extended_operations) + linesep
r += ' Modify: ' + str(self.modify_operations) + linesep
r += ' ModifyDn: ' + str(self.modify_dn_operations) + linesep
r += ' Search: ' + str(self.search_operations) + linesep
r += ' Unbind: ' + str(self.unbind_operations) + linesep
r += ' Referrals: ' + linesep
r += ' Received: ' + str(self.referrals_received) + linesep
r += ' Followed: ' + str(self.referrals_followed) + linesep
r += ' Restartable tries: ' + str(self.restartable_failures + self.restartable_successes) + linesep
r += ' Failed restarts: ' + str(self.restartable_failures) + linesep
r += ' Successful restarts: ' + str(self.restartable_successes) + linesep
return r
def __str__(self):
return self.__repr__()
def __iadd__(self, other):
if not isinstance(other, ConnectionUsage):
raise LDAPMetricsError('unable to add to ConnectionUsage')
self.opened_sockets += other.opened_sockets
self.closed_sockets += other.closed_sockets
self.wrapped_sockets += other.wrapped_sockets
self.bytes_transmitted += other.bytes_transmitted
self.bytes_received += other.bytes_received
self.messages_transmitted += other.messages_transmitted
self.messages_received += other.messages_received
self.operations += other.operations
self.abandon_operations += other.abandon_operations
self.add_operations += other.add_operations
self.bind_operations += other.bind_operations
self.compare_operations += other.compare_operations
self.delete_operations += other.delete_operations
self.extended_operations += other.extended_operations
self.modify_operations += other.modify_operations
self.modify_dn_operations += other.modify_dn_operations
self.search_operations += other.search_operations
self.unbind_operations += other.unbind_operations
self.referrals_received += other.referrals_received
self.referrals_followed += other.referrals_followed
self.restartable_failures += other.restartable_failures
self.restartable_successes += other.restartable_successes
self.servers_from_pool += other.servers_from_pool
return self
def transmitted_message(self, message, length):
self.bytes_transmitted += length
self.operations += 1
self.messages_transmitted += 1
if message['type'] == 'abandonRequest':
self.abandon_operations += 1
elif message['type'] == 'addRequest':
self.add_operations += 1
elif message['type'] == 'bindRequest':
self.bind_operations += 1
elif message['type'] == 'compareRequest':
self.compare_operations += 1
elif message['type'] == 'delRequest':
self.delete_operations += 1
elif message['type'] == 'extendedReq':
self.extended_operations += 1
elif message['type'] == 'modifyRequest':
self.modify_operations += 1
elif message['type'] == 'modDNRequest':
self.modify_dn_operations += 1
elif message['type'] == 'searchRequest':
self.search_operations += 1
elif message['type'] == 'unbindRequest':
self.unbind_operations += 1
else:
raise LDAPMetricsError('unable to collect usage for unknown message type')
def received_message(self, length):
self.bytes_received += length
self.messages_received += 1
def start(self, reset=True):
if reset:
self.reset()
self.open_socket_start_time = datetime.now()
self.connection_stop_time = None
if not self.initial_connection_start_time:
self.initial_connection_start_time = self.open_socket_start_time
def stop(self):
if self.open_socket_start_time:
self.connection_stop_time = datetime.now()
@property
def elapsed_time(self):
if self.connection_stop_time:
return self.connection_stop_time - self.open_socket_start_time
else:
# noinspection PyTypeChecker
return (datetime.now() - self.open_socket_start_time) if self.open_socket_start_time else timedelta(0)
python3-ldap-0.9.4.2/python3-ldap/ldap3/core/__init__.py 0000666 0000000 0000000 00000001466 12355103746 020743 0 ustar 0000000 0000000 """
Created on 2014.03.14
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
python3-ldap-0.9.4.2/python3-ldap/ldap3/extend/ 0000777 0000000 0000000 00000000000 12355117540 017157 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/extend/getBindDn.py 0000666 0000000 0000000 00000003274 12355110214 021364 0 ustar 0000000 0000000 """
Created on 2014.04.30
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..core.exceptions import LDAPExtensionError
from ..protocol.novell import Identity
from pyasn1.codec.ber import decoder
def get_bind_dn(connection):
resp = connection.extended('2.16.840.1.113719.1.27.100.31', None)
if not connection.strategy.sync:
_, result = connection.get_response(resp)
else:
result = connection.result
connection.response = decode_response(result)
populate_result_dict(result, connection.response)
return connection.response
def populate_result_dict(result, value):
result['identity'] = value
def decode_response(result):
if result['responseValue']:
decoded, unprocessed = decoder.decode(result['responseValue'], asn1Spec=Identity())
if unprocessed:
raise LDAPExtensionError('error decoding extended response value')
return str(decoded)
return None
python3-ldap-0.9.4.2/python3-ldap/ldap3/extend/modifyPassword.py 0000666 0000000 0000000 00000004367 12355110214 022544 0 ustar 0000000 0000000 """
Created on 2014.04.30
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..core.exceptions import LDAPExtensionError
from ..protocol.rfc3062 import PasswdModifyRequestValue, PasswdModifyResponseValue
from pyasn1.codec.ber import decoder
def modify_password(connection, user=None, old_password=None, new_password=None):
request = PasswdModifyRequestValue()
if user:
request['userIdentity'] = user
if old_password:
request['oldPasswd'] = old_password
if new_password:
request['newPasswd'] = new_password
resp = connection.extended('1.3.6.1.4.1.4203.1.11.1', request)
if not connection.strategy.sync:
_, result = connection.get_response(resp)
else:
result = connection.result
connection.response = decode_response(result)
populate_result_dict(result, connection.response)
return connection.response
def populate_result_dict(result, value):
result['genPasswd'] = value
def modify_password_request_to_dict(request):
return {'userIdentity': str(request['userIdentity']),
'oldPasswd': str(request['oldPasswd']),
'newPasswd': str(request['newPasswd'])}
def decode_response(result):
if result['responseValue']:
decoded, unprocessed = decoder.decode(result['responseValue'], asn1Spec=PasswdModifyResponseValue())
if unprocessed:
raise LDAPExtensionError('error decoding extended response value')
return str(decoded['genPasswd'])
return None
python3-ldap-0.9.4.2/python3-ldap/ldap3/extend/whoAmI.py 0000666 0000000 0000000 00000002666 12355106765 020736 0 ustar 0000000 0000000 """
Created on 2014.04.30
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
# implements rfc4532
def who_am_i(connection):
resp = connection.extended('1.3.6.1.4.1.4203.1.11.3', None)
if not connection.strategy.sync:
_, result = connection.get_response(resp)
else:
result = connection.result
connection.response = decode_response(result)
populate_result_dict(result, connection.response)
return connection.response
def populate_result_dict(result, value):
result['AuthzId'] = value
def decode_response(result):
if result['responseValue']:
decoded = result['responseValue'].decode('utf-8')
return decoded
return None python3-ldap-0.9.4.2/python3-ldap/ldap3/extend/__init__.py 0000666 0000000 0000000 00000003465 12355103746 021303 0 ustar 0000000 0000000 """
Created on 2014.04.28
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..extend.whoAmI import who_am_i
from ..extend.getBindDn import get_bind_dn
from ..extend.modifyPassword import modify_password
class ExtendedOperationsContainer(object):
class StandardExtendedOperations(object):
def __init__(self, container):
self._container = container
def who_am_i(self):
return who_am_i(self._container.connection)
def modify_password(self, user=None, old_password=None, new_password=None):
return modify_password(self._container.connection, user, old_password, new_password)
class NovellExtendedOperations(object):
def __init__(self, container):
self._container = container
def get_bind_dn(self):
return get_bind_dn(self._container.connection)
def __init__(self, connection):
self.connection = connection
self.novell = self.NovellExtendedOperations(self)
self.standard = self.StandardExtendedOperations(self) python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/ 0000777 0000000 0000000 00000000000 12355117540 017670 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/abandon.py 0000666 0000000 0000000 00000002152 12355103746 021647 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..protocol.rfc4511 import AbandonRequest, MessageID
# AbandonRequest ::= [APPLICATION 16] MessageID
def abandon_operation(msg_id):
request = AbandonRequest(MessageID(msg_id))
return request
def abandon_request_to_dict(request):
return {'messageId': str(request[0]), }
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/add.py 0000666 0000000 0000000 00000004750 12355103746 021003 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..protocol.rfc4511 import AddRequest, LDAPDN, AttributeList, Attribute, AttributeDescription, ValsAtLeast1, ResultCode
from ..protocol.convert import referrals_to_list, attributes_to_dict, validate_attribute_value
# AddRequest ::= [APPLICATION 8] SEQUENCE {
# entry LDAPDN,
# attributes AttributeList }
def add_operation(dn,
attributes,
schema=None):
# attributes is a dictionary in the form 'attribute': ['val1', 'val2', 'valN']
attribute_list = AttributeList()
for pos, attribute in enumerate(attributes):
attribute_list[pos] = Attribute()
attribute_list[pos]['type'] = AttributeDescription(attribute)
vals = ValsAtLeast1()
if isinstance(attributes[attribute], (list, tuple)):
for index, value in enumerate(attributes[attribute]):
vals.setComponentByPosition(index, validate_attribute_value(schema, attribute, value))
else:
vals.setComponentByPosition(0, validate_attribute_value(schema, attribute, attributes[attribute]))
attribute_list[pos]['vals'] = vals
request = AddRequest()
request['entry'] = LDAPDN(dn)
request['attributes'] = attribute_list
return request
def add_request_to_dict(request):
return {'entry': str(request['entry']), 'attributes': attributes_to_dict(request['attributes'])}
def add_response_to_dict(response):
return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']), 'referrals': referrals_to_list(response['referral']), }
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/bind.py 0000666 0000000 0000000 00000006246 12355103746 021171 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from .. import AUTH_SIMPLE, AUTH_ANONYMOUS, AUTH_SASL
from ..core.exceptions import LDAPPasswordIsMandatoryError, LDAPUnknownAuthenticationMethodError
from ..protocol.sasl.sasl import validate_simple_password
from ..protocol.rfc4511 import Version, AuthenticationChoice, Simple, BindRequest, ResultCode, SaslCredentials
from ..protocol.convert import authentication_choice_to_dict, referrals_to_list
# BindRequest ::= [APPLICATION 0] SEQUENCE {
# version INTEGER (1 .. 127),
# name LDAPDN,
# authentication AuthenticationChoice }
def bind_operation(version,
authentication,
name='',
password=None,
sasl_mechanism=None,
sasl_credentials=None):
request = BindRequest()
request['version'] = Version(version)
if name is None:
name = ''
request['name'] = name
if authentication == AUTH_SIMPLE:
if password:
request['authentication'] = AuthenticationChoice().setComponentByName('simple', Simple(validate_simple_password(password)))
else:
raise LDAPPasswordIsMandatoryError('password is mandatory')
elif authentication == AUTH_SASL:
sasl_creds = SaslCredentials()
sasl_creds['mechanism'] = sasl_mechanism
if sasl_credentials:
sasl_creds['credentials'] = sasl_credentials
request['authentication'] = AuthenticationChoice().setComponentByName('sasl', sasl_creds)
elif authentication == AUTH_ANONYMOUS:
request['name'] = ''
request['authentication'] = AuthenticationChoice().setComponentByName('simple', Simple(''))
else:
raise LDAPUnknownAuthenticationMethodError('unknown authentication method')
return request
def bind_request_to_dict(request):
return {'version': int(request['version']), 'name': str(request['name']), 'authentication': authentication_choice_to_dict(request['authentication'])}
def bind_response_to_dict(response):
return {'result': int(response['resultCode']), 'description': ResultCode().getNamedValues().getName(response['resultCode']), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']),
'referrals': referrals_to_list(response['referral']), 'saslCreds': str(response['serverSaslCreds'])}
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/compare.py 0000666 0000000 0000000 00000004142 12355103746 021674 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..protocol.convert import validate_attribute_value
from ..protocol.rfc4511 import CompareRequest, AttributeValueAssertion, AttributeDescription, LDAPDN, AssertionValue, ResultCode
from ..operation.search import ava_to_dict
from ..operation.bind import referrals_to_list
# CompareRequest ::= [APPLICATION 14] SEQUENCE {
# entry LDAPDN,
# ava AttributeValueAssertion }
def compare_operation(dn,
attribute,
value,
schema=None):
ava = AttributeValueAssertion()
ava['attributeDesc'] = AttributeDescription(attribute)
ava['assertionValue'] = AssertionValue(validate_attribute_value(schema, attribute, value))
request = CompareRequest()
request['entry'] = LDAPDN(dn)
request['ava'] = ava
return request
def compare_request_to_dict(request):
ava = ava_to_dict(request['ava'])
return {'entry': str(request['entry']), 'attribute': ava['attribute'], 'value': ava['value']}
def compare_response_to_dict(response):
return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']), 'referrals': referrals_to_list(response['referral']), }
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/delete.py 0000666 0000000 0000000 00000002635 12355103746 021515 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..protocol.rfc4511 import DelRequest, LDAPDN, ResultCode
from ..operation.bind import referrals_to_list
# DelRequest ::= [APPLICATION 10] LDAPDN
def delete_operation(dn):
request = DelRequest(LDAPDN(dn))
return request
def delete_request_to_dict(request):
return {'entry': str(request)}
def delete_response_to_dict(response):
return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']), 'referrals': referrals_to_list(response['referral']), }
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/extended.py 0000666 0000000 0000000 00000005207 12355106663 022052 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from pyasn1.type.univ import OctetString
from ..core.exceptions import LDAPExtensionError
from ..protocol.rfc4511 import ExtendedRequest, RequestName, ResultCode, RequestValue
from ..protocol.convert import decode_referrals
from pyasn1.codec.ber import encoder
# ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
# requestName [0] LDAPOID,
# requestValue [1] OCTET STRING OPTIONAL }
def extended_operation(request_name,
request_value=None):
request = ExtendedRequest()
request['requestName'] = RequestName(request_name)
if request_value and not isinstance(request_value, (str, bytes, bytearray)):
request['requestValue'] = RequestValue(encoder.encode(request_value))
elif request_value and isinstance(request_value, (str, bytes, bytearray)):
request['requestValue'] = RequestValue(encoder.encode(OctetString(request_value)))
elif request_value is not None:
raise LDAPExtensionError('unable to encode value for extended operation')
return request
def extended_request_to_dict(request):
return {'name': str(request['requestName']), 'value': str(request['requestValue']) if request['requestValue'] else None}
def extended_response_to_dict(response):
return {'result': int(response[0]), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']), 'description': ResultCode().getNamedValues().getName(response[0]), 'referrals': decode_referrals(response['referral']),
'responseName': str(response['responseName']), 'responseValue': bytes(response['responseValue']) if response['responseValue'] else bytes()}
def intermediate_response_to_dict(response):
return {'responseName': str(response['responseName']), 'responseValue': bytes(response['responseValue']) if response['responseValue'] else bytes()}
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/modify.py 0000666 0000000 0000000 00000006060 12355103747 021537 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..protocol.rfc4511 import ModifyRequest, LDAPDN, Changes, Change, Operation, PartialAttribute, AttributeDescription, Vals, ResultCode
from ..operation.bind import referrals_to_list
from ..protocol.convert import changes_to_list, validate_attribute_value
# ModifyRequest ::= [APPLICATION 6] SEQUENCE {
# object LDAPDN,
# changes SEQUENCE OF change SEQUENCE {
# operation ENUMERATED {
# add (0),
# delete (1),
# replace (2),
# ... },
# modification PartialAttribute } }
def modify_operation(dn,
changes,
schema=None):
# changes is a dictionary in the form {'attribute1': (operation, [val1, val2, ...]], 'attribute2': (operation, [val1, val2, ...]), ...}
# operation is 0 (add), 1 (delete), 2 (replace), 3 (increment)
# increment as per RFC4525
change_list = Changes()
for pos, attribute in enumerate(changes):
partial_attribute = PartialAttribute()
partial_attribute['type'] = AttributeDescription(attribute)
partial_attribute['vals'] = Vals()
if isinstance(changes[attribute][1], (list, tuple)):
for index, value in enumerate(changes[attribute][1]):
partial_attribute['vals'].setComponentByPosition(index, validate_attribute_value(schema, attribute, value))
else:
partial_attribute['vals'].setComponentByPosition(0, validate_attribute_value(schema, attribute, changes[attribute][1]))
change = Change()
change['operation'] = Operation(changes[attribute][0])
change['modification'] = partial_attribute
change_list[pos] = change
request = ModifyRequest()
request['object'] = LDAPDN(dn)
request['changes'] = change_list
return request
def modify_request_to_dict(request):
return {'entry': str(request['object']), 'changes': changes_to_list(request['changes'])}
def modify_response_to_dict(response):
return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'message': str(response['diagnosticMessage']), 'dn': str(response['matchedDN']), 'referrals': referrals_to_list(response['referral']), }
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/modifyDn.py 0000666 0000000 0000000 00000004205 12355103747 022020 0 ustar 0000000 0000000 """
Created on 2013.05.31
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..protocol.rfc4511 import ModifyDNRequest, LDAPDN, RelativeLDAPDN, DeleteOldRDN, NewSuperior, ResultCode
from ..operation.bind import referrals_to_list
# ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
# entry LDAPDN,
# newrdn RelativeLDAPDN,
# deleteoldrdn BOOLEAN,
# newSuperior [0] LDAPDN OPTIONAL }
def modify_dn_operation(dn,
new_relative_dn,
delete_old_rdn=True,
new_superior=None):
request = ModifyDNRequest()
request['entry'] = LDAPDN(dn)
request['newrdn'] = RelativeLDAPDN(new_relative_dn)
request['deleteoldrdn'] = DeleteOldRDN(delete_old_rdn)
if new_superior:
request['newSuperior'] = NewSuperior(new_superior)
return request
def modify_dn_request_to_dict(request):
return {'entry': str(request['entry']), 'newRdn': str(request['newrdn']), 'deleteOldRdn': bool(request['deleteoldrdn']), 'newSuperior': str(request['newSuperior']) if request['newSuperior'] else None}
def modify_dn_response_to_dict(response):
return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'dn': str(response['matchedDN']), 'referrals': referrals_to_list(response['referral']), 'message': str(response['diagnosticMessage']), }
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/search.py 0000666 0000000 0000000 00000051075 12355103747 021523 0 ustar 0000000 0000000 """
Created on 2013.06.02
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from string import whitespace
from os import linesep
from .. import SEARCH_NEVER_DEREFERENCE_ALIASES, SEARCH_SCOPE_BASE_OBJECT, SEARCH_SCOPE_SINGLE_LEVEL, SEARCH_SCOPE_WHOLE_SUBTREE, SEARCH_DEREFERENCE_IN_SEARCHING, SEARCH_DEREFERENCE_FINDING_BASE_OBJECT, SEARCH_DEREFERENCE_ALWAYS, NO_ATTRIBUTES
from ..core.exceptions import LDAPInvalidFilterError, LDAPAttributeError, LDAPInvalidScopeError, LDAPInvalidDereferenceAliasesError
from ..protocol.rfc4511 import SearchRequest, LDAPDN, Scope, DerefAliases, Integer0ToMax, TypesOnly, AttributeSelection, Selector, EqualityMatch, AttributeDescription, AssertionValue, Filter, Not, And, Or, ApproxMatch, GreaterOrEqual, LessOrEqual, \
ExtensibleMatch, Present, SubstringFilter, Substrings, Final, Initial, Any, ResultCode, Substring, MatchingRule, Type, MatchValue, DnAttributes
from ..operation.bind import referrals_to_list
from ..protocol.convert import ava_to_dict, attributes_to_list, search_refs_to_list, validate_assertion_value
# SearchRequest ::= [APPLICATION 3] SEQUENCE {
# baseObject LDAPDN,
# scope ENUMERATED {
# baseObject (0),
# singleLevel (1),
# wholeSubtree (2),
# ... },
# derefAliases ENUMERATED {
# neverDerefAliases (0),
# derefInSearching (1),
# derefFindingBaseObj (2),
# derefAlways (3) },
# sizeLimit INTEGER (0 .. maxInt),
# timeLimit INTEGER (0 .. maxInt),
# typesOnly BOOLEAN,
# filter Filter,
# attributes AttributeSelection }
ROOT = 0
AND = 1
OR = 2
NOT = 3
MATCH_APPROX = 4
MATCH_GREATER_OR_EQUAL = 5
MATCH_LESS_OR_EQUAL = 6
MATCH_EXTENSIBLE = 7
MATCH_PRESENT = 8
MATCH_SUBSTRING = 9
MATCH_EQUAL = 10
SEARCH_OPEN = 20
SEARCH_OPEN_OR_CLOSE = 21
SEARCH_MATCH_OR_CLOSE = 22
SEARCH_MATCH_OR_CONTROL = 23
class FilterNode():
def __init__(self, tag=None, assertion=None):
self.tag = tag
self.parent = None
self.assertion = assertion
self.elements = []
def append(self, filter_node):
filter_node.parent = self
self.elements.append(filter_node)
return filter_node
def __str__(self, pos=0):
self.__repr__(pos)
def __repr__(self, pos=0):
node_tags = ['ROOT', 'AND', 'OR', 'NOT', 'MATCH_APPROX', 'MATCH_GREATER_OR_EQUAL', 'MATCH_LESS_OR_EQUAL', 'MATCH_EXTENSIBLE', 'MATCH_PRESENT', 'MATCH_SUBSTRING', 'MATCH_EQUAL']
representation = ' ' * pos + 'tag: ' + node_tags[self.tag] + ' - assertion: ' + str(self.assertion)
if self.elements:
representation += ' - elements: ' + str(len(self.elements))
for element in self.elements:
representation += linesep + ' ' * pos + element.__repr__(pos + 2)
return representation
def evaluate_match(match, schema):
match = match.strip()
if '~=' in match:
tag = MATCH_APPROX
left_part, _, right_part = match.split('~=')
left_part = left_part.strip()
right_part = right_part.strip()
assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part)}
elif '>=' in match:
tag = MATCH_GREATER_OR_EQUAL
left_part, _, right_part = match.partition('>=')
left_part = left_part.strip()
right_part = right_part.strip()
assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part)}
elif '<=' in match:
tag = MATCH_LESS_OR_EQUAL
left_part, _, right_part = match.partition('<=')
left_part = left_part.strip()
right_part = right_part.strip()
assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part)}
elif ':=' in match:
tag = MATCH_EXTENSIBLE
left_part, _, right_part = match.partition(':=')
left_part = left_part.strip()
right_part = right_part.strip()
extended_filter_list = left_part.split(':')
matching_rule = None
dn_attributes = None
attribute_name = None
if extended_filter_list[0] == '': # extensible filter format [:dn]:matchingRule:=assertionValue
if len(extended_filter_list) == 2 and extended_filter_list[1].lower().strip() != 'dn':
matching_rule = extended_filter_list[1]
elif len(extended_filter_list) == 3 and extended_filter_list[1].lower().strip() == 'dn':
dn_attributes = True
matching_rule = extended_filter_list[2]
else:
raise LDAPInvalidFilterError('invalid extensible filter')
elif len(extended_filter_list) <= 3: # extensible filter format attr[:dn][:matchingRule]:=assertionValue
if len(extended_filter_list) == 1:
attribute_name = extended_filter_list[0]
elif len(extended_filter_list) == 2:
attribute_name = extended_filter_list[0]
if extended_filter_list[1].lower().strip() == 'dn':
dn_attributes = True
else:
matching_rule = extended_filter_list[1]
elif len(extended_filter_list) == 3 and extended_filter_list[1].lower().strip() == 'dn':
attribute_name = extended_filter_list[0]
dn_attributes = True
matching_rule = extended_filter_list[2]
else:
raise LDAPInvalidFilterError('invalid extensible filter')
if not attribute_name and not matching_rule:
raise LDAPInvalidFilterError('invalid extensible filter')
attribute_name = attribute_name.strip() if attribute_name else None
matching_rule = matching_rule.strip() if matching_rule else None
assertion = {'attr': attribute_name, 'value': validate_assertion_value(schema, attribute_name, right_part), 'matchingRule': matching_rule, 'dnAttributes': dn_attributes}
elif match.endswith('=*'):
tag = MATCH_PRESENT
assertion = {'attr': match[:-2]}
elif '=' in match and '*' in match:
tag = MATCH_SUBSTRING
left_part, _, right_part = match.partition('=')
left_part = left_part.strip()
right_part = right_part.strip()
substrings = right_part.split('*')
initial = validate_assertion_value(schema, left_part, substrings[0]) if substrings[0] else None
final = validate_assertion_value(schema, left_part, substrings[-1]) if substrings[-1] else None
any_string = [validate_assertion_value(schema, left_part, substring) for substring in substrings[1:-1] if substring]
assertion = {'attr': left_part, 'initial': initial, 'any': any_string, 'final': final}
elif '=' in match:
tag = MATCH_EQUAL
left_part, _, right_part = match.partition('=')
left_part = left_part.strip()
right_part = right_part.strip()
assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part)}
else:
raise LDAPInvalidFilterError('invalid matching assertion')
return FilterNode(tag, assertion)
def parse_filter(search_filter, schema):
search_filter = search_filter.strip()
if search_filter and search_filter.count('(') == search_filter.count(')') and search_filter.startswith('(') and search_filter.endswith(')'):
state = SEARCH_OPEN_OR_CLOSE
root = FilterNode(ROOT)
current_node = root
start_pos = None
skip_white_space = True
just_closed = False
for pos, c in enumerate(search_filter):
if skip_white_space and c in whitespace:
continue
elif (state == SEARCH_OPEN or state == SEARCH_OPEN_OR_CLOSE) and c == '(':
state = SEARCH_MATCH_OR_CONTROL
just_closed = False
elif state == SEARCH_MATCH_OR_CONTROL and c in '&!|':
if c == '&':
current_node = current_node.append(FilterNode(AND))
elif c == '|':
current_node = current_node.append(FilterNode(OR))
elif c == '!':
current_node = current_node.append(FilterNode(NOT))
state = SEARCH_OPEN
elif (state == SEARCH_MATCH_OR_CLOSE or state == SEARCH_OPEN_OR_CLOSE) and c == ')':
if just_closed:
current_node = current_node.parent
else:
just_closed = True
skip_white_space = True
end_pos = pos
if start_pos:
if current_node.tag == NOT and len(current_node.elements) > 0:
raise LDAPInvalidFilterError('not clause in filter cannot be multiple')
current_node.append(evaluate_match(search_filter[start_pos:end_pos], schema))
start_pos = None
state = SEARCH_OPEN_OR_CLOSE
elif (state == SEARCH_MATCH_OR_CLOSE or state == SEARCH_MATCH_OR_CONTROL) and c not in '()':
skip_white_space = False
if not start_pos:
start_pos = pos
state = SEARCH_MATCH_OR_CLOSE
else:
raise LDAPInvalidFilterError('malformed filter')
if len(root.elements) != 1:
raise LDAPInvalidFilterError('missing boolean operator in filter')
return root
else:
raise LDAPInvalidFilterError('invalid filter')
def compile_filter(filter_node):
compiled_filter = Filter()
if filter_node.tag == AND:
boolean_filter = And()
pos = 0
for element in filter_node.elements:
boolean_filter[pos] = compile_filter(element)
pos += 1
compiled_filter['and'] = boolean_filter
elif filter_node.tag == OR:
boolean_filter = Or()
pos = 0
for element in filter_node.elements:
boolean_filter[pos] = compile_filter(element)
pos += 1
compiled_filter['or'] = boolean_filter
elif filter_node.tag == NOT:
boolean_filter = Not()
boolean_filter['innerNotFilter'] = compile_filter(filter_node.elements[0])
compiled_filter['notFilter'] = boolean_filter
elif filter_node.tag == MATCH_APPROX:
matching_filter = ApproxMatch()
matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
matching_filter['assertionValue'] = AssertionValue(filter_node.assertion['value'])
compiled_filter['approxMatch'] = matching_filter
elif filter_node.tag == MATCH_GREATER_OR_EQUAL:
matching_filter = GreaterOrEqual()
matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
matching_filter['assertionValue'] = AssertionValue(filter_node.assertion['value'])
compiled_filter['greaterOrEqual'] = matching_filter
elif filter_node.tag == MATCH_LESS_OR_EQUAL:
matching_filter = LessOrEqual()
matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
matching_filter['assertionValue'] = AssertionValue(filter_node.assertion['value'])
compiled_filter['lessOrEqual'] = matching_filter
elif filter_node.tag == MATCH_EXTENSIBLE:
matching_filter = ExtensibleMatch()
if filter_node.assertion['matchingRule']:
matching_filter['matchingRule'] = MatchingRule(filter_node.assertion['matchingRule'])
if filter_node.assertion['attr']:
matching_filter['type'] = Type(filter_node.assertion['attr'])
matching_filter['matchValue'] = MatchValue(filter_node.assertion['value'])
matching_filter['dnAttributes'] = DnAttributes(filter_node.assertion['dnAttributes'])
compiled_filter['extensibleMatch'] = matching_filter
elif filter_node.tag == MATCH_PRESENT:
matching_filter = Present(AttributeDescription(filter_node.assertion['attr']))
compiled_filter['present'] = matching_filter
elif filter_node.tag == MATCH_SUBSTRING:
matching_filter = SubstringFilter()
matching_filter['type'] = AttributeDescription(filter_node.assertion['attr'])
substrings = Substrings()
pos = 0
if filter_node.assertion['initial']:
substrings[pos] = Substring().setComponentByName('initial', Initial(filter_node.assertion['initial']))
pos += 1
if filter_node.assertion['any']:
for substring in filter_node.assertion['any']:
substrings[pos] = Substring().setComponentByName('any', Any(substring))
pos += 1
if filter_node.assertion['final']:
substrings[pos] = Substring().setComponentByName('final', Final(filter_node.assertion['final']))
matching_filter['substrings'] = substrings
compiled_filter['substringFilter'] = matching_filter
elif filter_node.tag == MATCH_EQUAL:
matching_filter = EqualityMatch()
matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
matching_filter['assertionValue'] = AssertionValue(filter_node.assertion['value'])
compiled_filter.setComponentByName('equalityMatch', matching_filter)
else:
raise LDAPInvalidFilterError('unknown filter node tag')
return compiled_filter
def build_filter(search_filter, schema):
return compile_filter(parse_filter(search_filter, schema).elements[0])
def build_attribute_selection(attribute_list, schema):
attribute_selection = AttributeSelection()
for index, attribute in enumerate(attribute_list):
if schema:
if not attribute.lower() in schema.attribute_types and attribute not in '+*1.1':
raise LDAPAttributeError('invalid attribute type in attribute list: ' + attribute)
attribute_selection[index] = Selector(attribute)
return attribute_selection
def search_operation(search_base,
search_filter,
search_scope,
dereference_aliases,
attributes,
size_limit,
time_limit,
types_only,
schema=None):
request = SearchRequest()
request['baseObject'] = LDAPDN(search_base)
if search_scope == SEARCH_SCOPE_BASE_OBJECT:
request['scope'] = Scope('baseObject')
elif search_scope == SEARCH_SCOPE_SINGLE_LEVEL:
request['scope'] = Scope('singleLevel')
elif search_scope == SEARCH_SCOPE_WHOLE_SUBTREE:
request['scope'] = Scope('wholeSubtree')
else:
raise LDAPInvalidScopeError('invalid scope type')
if dereference_aliases == SEARCH_NEVER_DEREFERENCE_ALIASES:
request['derefAliases'] = DerefAliases('neverDerefAliases')
elif dereference_aliases == SEARCH_DEREFERENCE_IN_SEARCHING:
request['derefAliases'] = DerefAliases('derefInSearching')
elif dereference_aliases == SEARCH_DEREFERENCE_FINDING_BASE_OBJECT:
request['derefAliases'] = DerefAliases('derefFindingBaseObj')
elif dereference_aliases == SEARCH_DEREFERENCE_ALWAYS:
request['derefAliases'] = DerefAliases('derefAlways')
else:
raise LDAPInvalidDereferenceAliasesError('invalid dereference aliases type')
request['sizeLimit'] = Integer0ToMax(size_limit)
request['timeLimit'] = Integer0ToMax(time_limit)
request['typesOnly'] = TypesOnly(True) if types_only else TypesOnly(False)
request['filter'] = build_filter(search_filter, schema) # parse the searchFilter string and compile it starting from the root node
if not isinstance(attributes, (list, tuple)):
attributes = [NO_ATTRIBUTES]
request['attributes'] = build_attribute_selection(attributes, schema)
return request
def decode_vals(vals):
if vals:
return [str(val) for val in vals if val]
else:
return None
def attributes_to_dict(attribute_list):
attributes = dict()
for attribute in attribute_list:
attributes[str(attribute['type'])] = decode_vals(attribute['vals'])
return attributes
def decode_raw_vals(vals):
return [bytes(val) for val in vals] if vals else None
def raw_attributes_to_dict(attribute_list):
attributes = dict()
for attribute in attribute_list:
attributes[str(attribute['type'])] = decode_raw_vals(attribute['vals'])
return attributes
def matching_rule_assertion_to_string(matching_rule_assertion):
return str(matching_rule_assertion)
def filter_to_string(filter_object):
filter_type = filter_object.getName()
filter_string = '('
if filter_type == 'and':
filter_string += '&'
for f in filter_object['and']:
filter_string += filter_to_string(f)
elif filter_type == 'or':
filter_string += '!'
for f in filter_object['or']:
filter_string += filter_to_string(f)
elif filter_type == 'notFilter':
filter_string += '!' + filter_to_string(filter_object['notFilter']['innerNotFilter'])
elif filter_type == 'equalityMatch':
ava = ava_to_dict(filter_object['equalityMatch'])
filter_string += ava['attribute'] + '=' + ava['value']
elif filter_type == 'substringFilter':
attribute = filter_object['substringFilter']['type']
filter_string += str(attribute) + '='
for substring in filter_object['substringFilter']['substrings']:
if substring['initial']:
filter_string += str(substring['initial']) + '*'
elif substring['any']:
filter_string += str(substring['any']) if filter_string.endswith('*') else '*' + str(substring['any'])
filter_string += '*'
elif substring['final']:
filter_string += '*' + str(substring['final'])
elif filter_type == 'greaterOrEqual':
ava = ava_to_dict(filter_object['greaterOrEqual'])
filter_string += ava['attribute'] + '>=' + ava['value']
elif filter_type == 'lessOrEqual':
ava = ava_to_dict(filter_object['lessOrEqual'])
filter_string += ava['attribute'] + '<=' + ava['value']
elif filter_type == 'present':
filter_string += str(filter_object['present']) + '=*'
elif filter_type == 'approxMatch':
ava = ava_to_dict(filter_object['approxMatch'])
filter_string += ava['attribute'] + '~=' + ava['value']
elif filter_type == 'extensibleMatch':
filter_string += matching_rule_assertion_to_string(filter_object['extensibleMatch'])
else:
raise LDAPInvalidFilterError('error converting filter to string')
filter_string += ')'
return filter_string
def search_request_to_dict(request):
return {'base': str(request['baseObject']), 'scope': int(request['scope']), 'dereferenceAlias': int(request['derefAliases']), 'sizeLimit': int(request['sizeLimit']), 'timeLimit': int(request['timeLimit']), 'typeOnly': bool(request['typesOnly']),
'filter': filter_to_string(request['filter']), 'attributes': attributes_to_list(request['attributes'])}
def search_result_entry_response_to_dict(response):
return {'dn': str(response['object']), 'attributes': attributes_to_dict(response['attributes']), 'raw_attributes': raw_attributes_to_dict(response['attributes'])}
def search_result_done_response_to_dict(response):
return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'message': str(response['diagnosticMessage']), 'dn': str(response['matchedDN']), 'referrals': referrals_to_list(response['referral'])}
def search_result_reference_response_to_dict(response):
return {'uri': search_refs_to_list(response)}
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/unbind.py 0000666 0000000 0000000 00000001666 12355103747 021536 0 ustar 0000000 0000000 """
Created on 2013.09.03
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..protocol.rfc4511 import UnbindRequest
def unbind_operation():
request = UnbindRequest()
return request
python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/__init__.py 0000666 0000000 0000000 00000000000 12355103746 021772 0 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/ 0000777 0000000 0000000 00000000000 12355117540 017531 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/convert.py 0000666 0000000 0000000 00000012673 12355103747 021600 0 ustar 0000000 0000000 """
Created on 2013.07.24
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from ..core.exceptions import LDAPControlsError, LDAPAttributeError, LDAPObjectClassError
from .rfc4511 import Controls, Control
def attribute_to_dict(attribute):
return {'type': str(attribute['type']), 'values': [str(val) for val in attribute['vals']]}
def attributes_to_dict(attributes):
attributes_dict = dict()
for attribute in attributes:
attribute_dict = attribute_to_dict(attribute)
attributes_dict[attribute_dict['type']] = attribute_dict['values']
return attributes_dict
def referrals_to_list(referrals):
return [str(referral) for referral in referrals if referral] if referrals else None
def search_refs_to_list(search_refs):
return [str(search_ref) for search_ref in search_refs if search_ref] if search_refs else None
def sasl_to_dict(sasl):
return {'mechanism': str(sasl['mechanism']), 'credentials': str(sasl['credentials'])}
def authentication_choice_to_dict(authentication_choice):
return {'simple': str(authentication_choice['simple']) if authentication_choice.getName() == 'simple' else None, 'sasl': sasl_to_dict(authentication_choice['sasl']) if authentication_choice.getName() == 'sasl' else None}
def decode_referrals(referrals):
return [str(referral) for referral in referrals if referral] if referrals else None
def partial_attribute_to_dict(modification):
return {'type': str(modification['type']), 'value': [str(value) for value in modification['vals']]}
def change_to_dict(change):
return {'operation': int(change['operation']), 'attribute': partial_attribute_to_dict(change['modification'])}
def changes_to_list(changes):
return [change_to_dict(change) for change in changes]
def attributes_to_list(attributes):
return [str(attribute) for attribute in attributes]
def ava_to_dict(ava):
return {'attribute': str(ava['attributeDesc']), 'value': str(ava['assertionValue'])}
def substring_to_dict(substring):
return {'initial': substring['initial'] if substring['initial'] else '', 'any': [middle for middle in substring['any']] if substring['any'] else '', 'final': substring['final'] if substring['final'] else ''}
def prepare_changes_for_request(changes):
prepared = {}
for change in changes:
prepared[change['attribute']['type']] = (change['operation'], change['attribute']['value'])
return prepared
def build_controls_list(controls):
"""
controls is a list of tuple
each tuple must have 3 elements: the control OID, the criticality, the value
criticality must be a boolean
"""
if not controls:
return None
if not isinstance(controls, (list, tuple)):
raise LDAPControlsError('controls must be a list')
built_controls = Controls()
for idx, control in enumerate(controls):
if len(control) == 3 and isinstance(control[1], bool):
built_control = Control()
built_control['controlType'] = control[0]
built_control['criticality'] = control[1]
built_control['controlValue'] = control[2]
built_controls.setComponentByPosition(idx, built_control)
else:
raise LDAPControlsError('control must be a tuple of 3 elements: controlType, criticality (boolean) and controlValue')
return built_controls
def validate_assertion_value(schema, name, value):
if schema:
if not name.lower() in schema.attribute_types:
raise LDAPAttributeError('invalid attribute type in assertion: ' + name)
if not '\\' in value:
return value.encode('utf-8')
validated_value = bytearray()
pos = 0
while pos < len(value):
if value[pos] == '\\':
byte = value[pos + 1: pos + 3]
if len(byte) == 2:
try:
validated_value.append(int(value[pos + 1: pos + 3], 16))
pos += 3
continue
except ValueError:
pass
validated_value += value[pos].encode('utf-8')
pos += 1
return bytes(validated_value)
def validate_attribute_value(schema, name, value):
if schema:
if not name.lower() in schema.attribute_types:
raise LDAPAttributeError('invalid attribute type in attribute')
if name.lower() == 'objectclass':
if value.lower() not in schema.object_classes:
raise LDAPObjectClassError('invalid class in ObjectClass attribute: ' + value)
if isinstance(value, str):
return validate_assertion_value(None, name, value) # schema already checked, no need to check again
return value
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/novell.py 0000666 0000000 0000000 00000001630 12355106663 021406 0 ustar 0000000 0000000 """
Created on 2014.06.27
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from pyasn1.type.univ import OctetString
class Identity(OctetString):
encoding = 'utf-8' python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/oid.py 0000666 0000000 0000000 00000353045 12355103747 020674 0 ustar 0000000 0000000 """
Created on 2013.08.30
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from collections import namedtuple
from .. import OID_CONTROL, OID_EXTENSION, OID_FEATURE, OID_UNSOLICITED_NOTICE, OID_LDAP_SYNTAX, OID_ATTRIBUTE_TYPE, OID_MATCHING_RULE, OID_NAME_FORM, OID_OBJECT_CLASS, OID_ADMINISTRATIVE_ROLE, OID_DIT_CONTENT_RULE, OID_LDAP_URL_EXTENSION, \
OID_FAMILY
# Holds info about OIDs.
# Each OID info is a named tuple with the following attributes:
# oid - the OID number
# type - type of OID
# name - description of OID
# doc - reference document of OID
# obsolete - boolean to define an historic state of the OID
#
# Source of information is IANA ldap-parameters.txt, oid-registry and products documentation as of 2013.08.21
def constant_to_oid_kind(oid_kind):
if oid_kind == OID_CONTROL:
return 'Control'
elif oid_kind == OID_EXTENSION:
return 'Extension'
elif oid_kind == OID_FEATURE:
return 'Feature'
elif oid_kind == OID_UNSOLICITED_NOTICE:
return 'Unsolicited Notice'
elif oid_kind == OID_ATTRIBUTE_TYPE:
return 'Attribute Type'
elif oid_kind == OID_DIT_CONTENT_RULE:
return 'DIT Content Rule'
elif oid_kind == OID_LDAP_URL_EXTENSION:
return 'LDAP URL Extension'
elif oid_kind == OID_FAMILY:
return 'Family'
elif oid_kind == OID_MATCHING_RULE:
return 'Matching Rule'
elif oid_kind == OID_NAME_FORM:
return 'Name Form'
elif oid_kind == OID_OBJECT_CLASS:
return 'Object Class'
elif oid_kind == OID_ADMINISTRATIVE_ROLE:
return 'Administrative Role'
elif oid_kind == OID_LDAP_SYNTAX:
return 'LDAP Syntax'
else:
return 'Unknown'
def decode_oids(sequence):
if sequence:
return [Oids.get(oid, OidInfo(oid, None, None, None)) for oid in sequence if oid]
return list()
def decode_syntax(syntax):
if not syntax:
return None
syntax = syntax.strip()
pos = 0
for pos, c in enumerate(syntax):
if not c in '0123456789.':
break
return Oids.get(syntax[:pos], None)
class OidInfo(namedtuple('OidInfo', 'oid, kind, name, docs')):
def __str__(self):
r = self.oid + ' - '
if self.name:
r += ((', '.join(self.name)) if isinstance(self.name, (list, tuple)) else self.name) + ' - '
r += constant_to_oid_kind(self.kind) + ' - ' if self.kind is not None else ''
r += self.docs + ' - ' if self.docs else ''
return r[:-3]
def __repr__(self):
return self.__str__()
# noinspection PyPep8
Oids = { # administrative role
'2.5.23.1': OidInfo('2.5.23.1', OID_ADMINISTRATIVE_ROLE, 'autonomousArea', 'RFC3672'), '2.5.23.2': OidInfo('2.5.23.2', OID_ADMINISTRATIVE_ROLE, 'accessControlSpecificArea', 'RFC3672'),
'2.5.23.3': OidInfo('2.5.23.3', OID_ADMINISTRATIVE_ROLE, 'accessControlInnerArea', 'RFC3672'), '2.5.23.4': OidInfo('2.5.23.4', OID_ADMINISTRATIVE_ROLE, 'subschemaAdminSpecificArea', 'RFC3672'),
'2.5.23.5': OidInfo('2.5.23.5', OID_ADMINISTRATIVE_ROLE, 'collectiveAttributeSpecificArea', 'RFC3672'), '2.5.23.6': OidInfo('2.5.23.6', OID_ADMINISTRATIVE_ROLE, 'collectiveAttributeInnerArea', 'RFC3672'),
# attributes type
'0.9.2342.19200300.100.1.1': OidInfo('0.9.2342.19200300.100.1.1', OID_ATTRIBUTE_TYPE, ['uid', 'userId'], 'RFC4519'), '0.9.2342.19200300.100.1.2': OidInfo('0.9.2342.19200300.100.1.2', OID_ATTRIBUTE_TYPE, 'textEncodedORAddress', 'RFC1274'),
'0.9.2342.19200300.100.1.3': OidInfo('0.9.2342.19200300.100.1.3', OID_ATTRIBUTE_TYPE, ['mail', 'RFC822Mailbox'], 'RFC4524'), '0.9.2342.19200300.100.1.4': OidInfo('0.9.2342.19200300.100.1.4', OID_ATTRIBUTE_TYPE, 'info', 'RFC4524'),
'0.9.2342.19200300.100.1.5': OidInfo('0.9.2342.19200300.100.1.5', OID_ATTRIBUTE_TYPE, ['drink', 'favouriteDrink'], 'RFC4524'), '0.9.2342.19200300.100.1.6': OidInfo('0.9.2342.19200300.100.1.6', OID_ATTRIBUTE_TYPE, 'roomNumber', 'RFC4524'),
'0.9.2342.19200300.100.1.7': OidInfo('0.9.2342.19200300.100.1.7', OID_ATTRIBUTE_TYPE, 'photo', 'RFC1274'), '0.9.2342.19200300.100.1.8': OidInfo('0.9.2342.19200300.100.1.8', OID_ATTRIBUTE_TYPE, 'userClass', 'RFC4524'),
'0.9.2342.19200300.100.1.9': OidInfo('0.9.2342.19200300.100.1.9', OID_ATTRIBUTE_TYPE, 'host', 'RFC4524'), '0.9.2342.19200300.100.1.10': OidInfo('0.9.2342.19200300.100.1.10', OID_ATTRIBUTE_TYPE, 'manager', 'RFC4524'),
'0.9.2342.19200300.100.1.11': OidInfo('0.9.2342.19200300.100.1.11', OID_ATTRIBUTE_TYPE, 'documentIdentifier', 'RFC4524'), '0.9.2342.19200300.100.1.12': OidInfo('0.9.2342.19200300.100.1.12', OID_ATTRIBUTE_TYPE, 'documentTitle', 'RFC4524'),
'0.9.2342.19200300.100.1.13': OidInfo('0.9.2342.19200300.100.1.13', OID_ATTRIBUTE_TYPE, 'documentVersion', 'RFC4524'), '0.9.2342.19200300.100.1.14': OidInfo('0.9.2342.19200300.100.1.14', OID_ATTRIBUTE_TYPE, 'documentAuthor', 'RFC4524'),
'0.9.2342.19200300.100.1.15': OidInfo('0.9.2342.19200300.100.1.15', OID_ATTRIBUTE_TYPE, 'documentLocation', 'RFC4524'),
'0.9.2342.19200300.100.1.20': OidInfo('0.9.2342.19200300.100.1.20', OID_ATTRIBUTE_TYPE, ['homePhone', 'homeTelephone'], 'RFC4524'),
'0.9.2342.19200300.100.1.21': OidInfo('0.9.2342.19200300.100.1.21', OID_ATTRIBUTE_TYPE, 'secretary', 'RFC4524'), '0.9.2342.19200300.100.1.22': OidInfo('0.9.2342.19200300.100.1.22', OID_ATTRIBUTE_TYPE, 'otherMailbox', 'RFC1274'),
'0.9.2342.19200300.100.1.23': OidInfo('0.9.2342.19200300.100.1.23', OID_ATTRIBUTE_TYPE, 'lastModifiedTime', 'RFC1274'), '0.9.2342.19200300.100.1.24': OidInfo('0.9.2342.19200300.100.1.24', OID_ATTRIBUTE_TYPE, 'lastModifiedBy', 'RFC1274'),
'0.9.2342.19200300.100.1.25': OidInfo('0.9.2342.19200300.100.1.25', OID_ATTRIBUTE_TYPE, ['DC', 'domainComponent'], 'RFC4519'), '0.9.2342.19200300.100.1.26': OidInfo('0.9.2342.19200300.100.1.26', OID_ATTRIBUTE_TYPE, 'aRecord', 'RFC1274'),
'0.9.2342.19200300.100.1.27': OidInfo('0.9.2342.19200300.100.1.27', OID_ATTRIBUTE_TYPE, 'mDRecord', 'RFC1274'), '0.9.2342.19200300.100.1.28': OidInfo('0.9.2342.19200300.100.1.28', OID_ATTRIBUTE_TYPE, 'mXRecord', 'RFC1274'),
'0.9.2342.19200300.100.1.29': OidInfo('0.9.2342.19200300.100.1.29', OID_ATTRIBUTE_TYPE, 'nSRecord', 'RFC1274'), '0.9.2342.19200300.100.1.30': OidInfo('0.9.2342.19200300.100.1.30', OID_ATTRIBUTE_TYPE, 'sOARecord', 'RFC1274'),
'0.9.2342.19200300.100.1.31': OidInfo('0.9.2342.19200300.100.1.31', OID_ATTRIBUTE_TYPE, 'cNAMERecord', 'RFC1274'), '0.9.2342.19200300.100.1.37': OidInfo('0.9.2342.19200300.100.1.37', OID_ATTRIBUTE_TYPE, 'associatedDomain', 'RFC4524'),
'0.9.2342.19200300.100.1.38': OidInfo('0.9.2342.19200300.100.1.38', OID_ATTRIBUTE_TYPE, 'associatedName', 'RFC4524'), '0.9.2342.19200300.100.1.39': OidInfo('0.9.2342.19200300.100.1.39', OID_ATTRIBUTE_TYPE, 'homePostalAddress', 'RFC4524'),
'0.9.2342.19200300.100.1.40': OidInfo('0.9.2342.19200300.100.1.40', OID_ATTRIBUTE_TYPE, 'personalTitle', 'RFC4524'),
'0.9.2342.19200300.100.1.41': OidInfo('0.9.2342.19200300.100.1.41', OID_ATTRIBUTE_TYPE, ['mobile', 'mobileTelephoneNumber'], 'RFC4524'),
'0.9.2342.19200300.100.1.42': OidInfo('0.9.2342.19200300.100.1.42', OID_ATTRIBUTE_TYPE, ['pager', 'pagerTelephoneNumber'], 'RFC4524'),
'0.9.2342.19200300.100.1.43': OidInfo('0.9.2342.19200300.100.1.43', OID_ATTRIBUTE_TYPE, ['co', 'friendlyCountryName'], 'RFC4524'),
'0.9.2342.19200300.100.1.44': OidInfo('0.9.2342.19200300.100.1.44', OID_ATTRIBUTE_TYPE, 'uniqueIdentifier', 'RFC4524'),
'0.9.2342.19200300.100.1.45': OidInfo('0.9.2342.19200300.100.1.45', OID_ATTRIBUTE_TYPE, 'organizationalStatus', 'RFC4524'), '0.9.2342.19200300.100.1.46': OidInfo('0.9.2342.19200300.100.1.46', OID_ATTRIBUTE_TYPE, 'janetMailbox', 'RFC1274'),
'0.9.2342.19200300.100.1.47': OidInfo('0.9.2342.19200300.100.1.47', OID_ATTRIBUTE_TYPE, 'mailPreferenceOption', 'RFC1274'), '0.9.2342.19200300.100.1.48': OidInfo('0.9.2342.19200300.100.1.48', OID_ATTRIBUTE_TYPE, 'buildingName', 'RFC4524'),
'0.9.2342.19200300.100.1.49': OidInfo('0.9.2342.19200300.100.1.49', OID_ATTRIBUTE_TYPE, 'dSAQuality', 'RFC1274'), '0.9.2342.19200300.100.1.50': OidInfo('0.9.2342.19200300.100.1.50', OID_ATTRIBUTE_TYPE, 'singleLevelQuality', 'RFC4524'),
'0.9.2342.19200300.100.1.51': OidInfo('0.9.2342.19200300.100.1.51', OID_ATTRIBUTE_TYPE, 'subtreeMinimumQuality', 'RFC1274'),
'0.9.2342.19200300.100.1.52': OidInfo('0.9.2342.19200300.100.1.52', OID_ATTRIBUTE_TYPE, 'subtreeMaximumQuality', 'RFC1274'),
'0.9.2342.19200300.100.1.53': OidInfo('0.9.2342.19200300.100.1.53', OID_ATTRIBUTE_TYPE, 'personalSignature', 'RFC1274'), '0.9.2342.19200300.100.1.54': OidInfo('0.9.2342.19200300.100.1.54', OID_ATTRIBUTE_TYPE, 'dITRedirect', 'RFC1274'),
'0.9.2342.19200300.100.1.55': OidInfo('0.9.2342.19200300.100.1.55', OID_ATTRIBUTE_TYPE, 'audio', 'RFC1274'), '0.9.2342.19200300.100.1.56': OidInfo('0.9.2342.19200300.100.1.56', OID_ATTRIBUTE_TYPE, 'documentPublisher', 'RFC4524'),
'0.9.2342.19200300.100.1.60': OidInfo('0.9.2342.19200300.100.1.60', OID_ATTRIBUTE_TYPE, 'jpegPhoto', 'RFC2798'), '1.2.840.113549.1.9.1': OidInfo('1.2.840.113549.1.9.1', OID_ATTRIBUTE_TYPE, ['email', 'emailAddress'], 'RFC3280'),
'1.2.840.113556.1.4.478': OidInfo('1.2.840.113556.1.4.478', OID_ATTRIBUTE_TYPE, 'calCalURI', 'RFC2739'), '1.2.840.113556.1.4.479': OidInfo('1.2.840.113556.1.4.479', OID_ATTRIBUTE_TYPE, 'calFBURL', 'RFC2739'),
'1.2.840.113556.1.4.480': OidInfo('1.2.840.113556.1.4.480', OID_ATTRIBUTE_TYPE, 'calCAPURI', 'RFC2739'), '1.2.840.113556.1.4.481': OidInfo('1.2.840.113556.1.4.481', OID_ATTRIBUTE_TYPE, 'calCalAdrURI', 'RFC2739'),
'1.2.840.113556.1.4.482': OidInfo('1.2.840.113556.1.4.482', OID_ATTRIBUTE_TYPE, 'calOtherCalURIs', 'RFC2739'), '1.2.840.113556.1.4.483': OidInfo('1.2.840.113556.1.4.483', OID_ATTRIBUTE_TYPE, 'calOtherFBURLs', 'RFC2739'),
'1.2.840.113556.1.4.484': OidInfo('1.2.840.113556.1.4.484', OID_ATTRIBUTE_TYPE, 'calOtherCAPURIs', 'RFC2739'), '1.2.840.113556.1.4.485': OidInfo('1.2.840.113556.1.4.485', OID_ATTRIBUTE_TYPE, 'calOtherCalAdrURIs', 'RFC2739'),
'1.3.18.0.2.4.1107': OidInfo('1.3.18.0.2.4.1107', OID_ATTRIBUTE_TYPE, 'printer-xri-supported', 'RFC3712'), '1.3.18.0.2.4.1108': OidInfo('1.3.18.0.2.4.1108', OID_ATTRIBUTE_TYPE, 'printer-aliases', 'RFC3712'),
'1.3.18.0.2.4.1109': OidInfo('1.3.18.0.2.4.1109', OID_ATTRIBUTE_TYPE, 'printer-charset-configured', 'RFC3712'), '1.3.18.0.2.4.1110': OidInfo('1.3.18.0.2.4.1110', OID_ATTRIBUTE_TYPE, 'printer-job-priority-supported', 'RFC3712'),
'1.3.18.0.2.4.1111': OidInfo('1.3.18.0.2.4.1111', OID_ATTRIBUTE_TYPE, 'printer-job-k-octets-supported', 'RFC3712'), '1.3.18.0.2.4.1112': OidInfo('1.3.18.0.2.4.1112', OID_ATTRIBUTE_TYPE, 'printer-current-operator', 'RFC3712'),
'1.3.18.0.2.4.1113': OidInfo('1.3.18.0.2.4.1113', OID_ATTRIBUTE_TYPE, 'printer-service-person', 'RFC3712'), '1.3.18.0.2.4.1114': OidInfo('1.3.18.0.2.4.1114', OID_ATTRIBUTE_TYPE, 'printer-delivery-orientation-supported', 'RFC3712'),
'1.3.18.0.2.4.1115': OidInfo('1.3.18.0.2.4.1115', OID_ATTRIBUTE_TYPE, 'printer-stacking-order-supported', 'RFC3712'), '1.3.18.0.2.4.1116': OidInfo('1.3.18.0.2.4.1116', OID_ATTRIBUTE_TYPE, 'printer-output-features-supported', 'RFC3712'),
'1.3.18.0.2.4.1117': OidInfo('1.3.18.0.2.4.1117', OID_ATTRIBUTE_TYPE, 'printer-media-local-supported', 'RFC3712'), '1.3.18.0.2.4.1118': OidInfo('1.3.18.0.2.4.1118', OID_ATTRIBUTE_TYPE, 'printer-copies-supported', 'RFC3712'),
'1.3.18.0.2.4.1119': OidInfo('1.3.18.0.2.4.1119', OID_ATTRIBUTE_TYPE, 'printer-natural-language-configured', 'RFC3712'), '1.3.18.0.2.4.1120': OidInfo('1.3.18.0.2.4.1120', OID_ATTRIBUTE_TYPE, 'printer-print-quality-supported', 'RFC3712'),
'1.3.18.0.2.4.1121': OidInfo('1.3.18.0.2.4.1121', OID_ATTRIBUTE_TYPE, 'printer-resolution-supported', 'RFC3712'), '1.3.18.0.2.4.1122': OidInfo('1.3.18.0.2.4.1122', OID_ATTRIBUTE_TYPE, 'printer-media-supported', 'RFC3712'),
'1.3.18.0.2.4.1123': OidInfo('1.3.18.0.2.4.1123', OID_ATTRIBUTE_TYPE, 'printer-sides-supported', 'RFC3712'), '1.3.18.0.2.4.1124': OidInfo('1.3.18.0.2.4.1124', OID_ATTRIBUTE_TYPE, 'printer-number-up-supported', 'RFC3712'),
'1.3.18.0.2.4.1125': OidInfo('1.3.18.0.2.4.1125', OID_ATTRIBUTE_TYPE, 'printer-finishings-supported', 'RFC3712'), '1.3.18.0.2.4.1126': OidInfo('1.3.18.0.2.4.1126', OID_ATTRIBUTE_TYPE, 'printer-pages-per-minute-color', 'RFC3712'),
'1.3.18.0.2.4.1127': OidInfo('1.3.18.0.2.4.1127', OID_ATTRIBUTE_TYPE, 'printer-pages-per-minute', 'RFC3712'), '1.3.18.0.2.4.1128': OidInfo('1.3.18.0.2.4.1128', OID_ATTRIBUTE_TYPE, 'printer-compression-supported', 'RFC3712'),
'1.3.18.0.2.4.1129': OidInfo('1.3.18.0.2.4.1129', OID_ATTRIBUTE_TYPE, 'printer-color-supported', 'RFC3712'), '1.3.18.0.2.4.1130': OidInfo('1.3.18.0.2.4.1130', OID_ATTRIBUTE_TYPE, 'printer-document-format-supported', 'RFC3712'),
'1.3.18.0.2.4.1131': OidInfo('1.3.18.0.2.4.1131', OID_ATTRIBUTE_TYPE, 'printer-charset-supported', 'RFC3712'), '1.3.18.0.2.4.1132': OidInfo('1.3.18.0.2.4.1132', OID_ATTRIBUTE_TYPE, 'printer-multiple-document-jobs-supported', 'RFC3712'),
'1.3.18.0.2.4.1133': OidInfo('1.3.18.0.2.4.1133', OID_ATTRIBUTE_TYPE, 'printer-ipp-versions-supported', 'RFC3712'), '1.3.18.0.2.4.1134': OidInfo('1.3.18.0.2.4.1134', OID_ATTRIBUTE_TYPE, 'printer-more-info', 'RFC3712'),
'1.3.18.0.2.4.1135': OidInfo('1.3.18.0.2.4.1135', OID_ATTRIBUTE_TYPE, 'printer-name', 'RFC3712'), '1.3.18.0.2.4.1136': OidInfo('1.3.18.0.2.4.1136', OID_ATTRIBUTE_TYPE, 'printer-location', 'RFC3712'),
'1.3.18.0.2.4.1137': OidInfo('1.3.18.0.2.4.1137', OID_ATTRIBUTE_TYPE, 'printer-generated-natural-language-supported', 'RFC3712'), '1.3.18.0.2.4.1138': OidInfo('1.3.18.0.2.4.1138', OID_ATTRIBUTE_TYPE, 'printer-make-and-model', 'RFC3712'),
'1.3.18.0.2.4.1139': OidInfo('1.3.18.0.2.4.1139', OID_ATTRIBUTE_TYPE, 'printer-info', 'RFC3712'), '1.3.18.0.2.4.1140': OidInfo('1.3.18.0.2.4.1140', OID_ATTRIBUTE_TYPE, 'printer-uri', 'RFC3712'),
'1.3.6.1.1.10.4.1': OidInfo('1.3.6.1.1.10.4.1', OID_ATTRIBUTE_TYPE, 'uddiBusinessKey', 'RFC4403'), '1.3.6.1.1.10.4.2': OidInfo('1.3.6.1.1.10.4.2', OID_ATTRIBUTE_TYPE, 'uddiAuthorizedName', 'RFC4403'),
'1.3.6.1.1.10.4.3': OidInfo('1.3.6.1.1.10.4.3', OID_ATTRIBUTE_TYPE, 'uddiOperator', 'RFC4403'), '1.3.6.1.1.10.4.4': OidInfo('1.3.6.1.1.10.4.4', OID_ATTRIBUTE_TYPE, 'uddiName', 'RFC4403'),
'1.3.6.1.1.10.4.5': OidInfo('1.3.6.1.1.10.4.5', OID_ATTRIBUTE_TYPE, 'uddiDescription', 'RFC4403'), '1.3.6.1.1.10.4.6': OidInfo('1.3.6.1.1.10.4.6', OID_ATTRIBUTE_TYPE, 'uddiDiscoveryURLs', 'RFC4403'),
'1.3.6.1.1.10.4.7': OidInfo('1.3.6.1.1.10.4.7', OID_ATTRIBUTE_TYPE, 'uddiUseType', 'RFC4403'), '1.3.6.1.1.10.4.8': OidInfo('1.3.6.1.1.10.4.8', OID_ATTRIBUTE_TYPE, 'uddiPersonName', 'RFC4403'),
'1.3.6.1.1.10.4.9': OidInfo('1.3.6.1.1.10.4.9', OID_ATTRIBUTE_TYPE, 'uddiPhone', 'RFC4403'), '1.3.6.1.1.10.4.10': OidInfo('1.3.6.1.1.10.4.10', OID_ATTRIBUTE_TYPE, 'uddiEMail', 'RFC4403'),
'1.3.6.1.1.10.4.11': OidInfo('1.3.6.1.1.10.4.11', OID_ATTRIBUTE_TYPE, 'uddiSortCode', 'RFC4403'), '1.3.6.1.1.10.4.12': OidInfo('1.3.6.1.1.10.4.12', OID_ATTRIBUTE_TYPE, 'uddiTModelKey', 'RFC4403'),
'1.3.6.1.1.10.4.13': OidInfo('1.3.6.1.1.10.4.13', OID_ATTRIBUTE_TYPE, 'uddiAddressLine', 'RFC4403'), '1.3.6.1.1.10.4.14': OidInfo('1.3.6.1.1.10.4.14', OID_ATTRIBUTE_TYPE, 'uddiIdentifierBag', 'RFC4403'),
'1.3.6.1.1.10.4.15': OidInfo('1.3.6.1.1.10.4.15', OID_ATTRIBUTE_TYPE, 'uddiCategoryBag', 'RFC4403'), '1.3.6.1.1.10.4.16': OidInfo('1.3.6.1.1.10.4.16', OID_ATTRIBUTE_TYPE, 'uddiKeyedReference', 'RFC4403'),
'1.3.6.1.1.10.4.17': OidInfo('1.3.6.1.1.10.4.17', OID_ATTRIBUTE_TYPE, 'uddiServiceKey', 'RFC4403'), '1.3.6.1.1.10.4.18': OidInfo('1.3.6.1.1.10.4.18', OID_ATTRIBUTE_TYPE, 'uddiBindingKey', 'RFC4403'),
'1.3.6.1.1.10.4.19': OidInfo('1.3.6.1.1.10.4.19', OID_ATTRIBUTE_TYPE, 'uddiAccessPoint', 'RFC4403'), '1.3.6.1.1.10.4.20': OidInfo('1.3.6.1.1.10.4.20', OID_ATTRIBUTE_TYPE, 'uddiHostingRedirector', 'RFC4403'),
'1.3.6.1.1.10.4.21': OidInfo('1.3.6.1.1.10.4.21', OID_ATTRIBUTE_TYPE, 'uddiInstanceDescription', 'RFC4403'), '1.3.6.1.1.10.4.22': OidInfo('1.3.6.1.1.10.4.22', OID_ATTRIBUTE_TYPE, 'uddiInstanceParms', 'RFC4403'),
'1.3.6.1.1.10.4.23': OidInfo('1.3.6.1.1.10.4.23', OID_ATTRIBUTE_TYPE, 'uddiOverviewDescription', 'RFC4403'), '1.3.6.1.1.10.4.24': OidInfo('1.3.6.1.1.10.4.24', OID_ATTRIBUTE_TYPE, 'uddiOverviewURL', 'RFC4403'),
'1.3.6.1.1.10.4.25': OidInfo('1.3.6.1.1.10.4.25', OID_ATTRIBUTE_TYPE, 'uddiFromKey', 'RFC4403'), '1.3.6.1.1.10.4.26': OidInfo('1.3.6.1.1.10.4.26', OID_ATTRIBUTE_TYPE, 'uddiToKey', 'RFC4403'),
'1.3.6.1.1.10.4.27': OidInfo('1.3.6.1.1.10.4.27', OID_ATTRIBUTE_TYPE, 'uddiUUID', 'RFC4403'), '1.3.6.1.1.10.4.28': OidInfo('1.3.6.1.1.10.4.28', OID_ATTRIBUTE_TYPE, 'uddiIsHidden', 'RFC4403'),
'1.3.6.1.1.10.4.29': OidInfo('1.3.6.1.1.10.4.29', OID_ATTRIBUTE_TYPE, 'uddiIsProjection', 'RFC4403'), '1.3.6.1.1.10.4.30': OidInfo('1.3.6.1.1.10.4.30', OID_ATTRIBUTE_TYPE, 'uddiLang', 'RFC4403'),
'1.3.6.1.1.10.4.31': OidInfo('1.3.6.1.1.10.4.31', OID_ATTRIBUTE_TYPE, 'uddiv3BusinessKey', 'RFC4403'), '1.3.6.1.1.10.4.32': OidInfo('1.3.6.1.1.10.4.32', OID_ATTRIBUTE_TYPE, 'uddiv3ServiceKey', 'RFC4403'),
'1.3.6.1.1.10.4.33': OidInfo('1.3.6.1.1.10.4.33', OID_ATTRIBUTE_TYPE, 'uddiv3BindingKey', 'RFC4403'), '1.3.6.1.1.10.4.34': OidInfo('1.3.6.1.1.10.4.34', OID_ATTRIBUTE_TYPE, 'uddiv3TmodelKey', 'RFC4403'),
'1.3.6.1.1.10.4.35': OidInfo('1.3.6.1.1.10.4.35', OID_ATTRIBUTE_TYPE, 'uddiv3DigitalSignature', 'RFC4403'), '1.3.6.1.1.10.4.36': OidInfo('1.3.6.1.1.10.4.36', OID_ATTRIBUTE_TYPE, 'uddiv3NodeId', 'RFC4403'),
'1.3.6.1.1.10.4.37': OidInfo('1.3.6.1.1.10.4.37', OID_ATTRIBUTE_TYPE, 'uddiv3EntityModificationTime', 'RFC4403'), '1.3.6.1.1.10.4.38': OidInfo('1.3.6.1.1.10.4.38', OID_ATTRIBUTE_TYPE, 'uddiv3SubscriptionKey', 'RFC4403'),
'1.3.6.1.1.10.4.39': OidInfo('1.3.6.1.1.10.4.39', OID_ATTRIBUTE_TYPE, 'uddiv3SubscriptionFilter', 'RFC4403'), '1.3.6.1.1.10.4.40': OidInfo('1.3.6.1.1.10.4.40', OID_ATTRIBUTE_TYPE, 'uddiv3NotificationInterval', 'RFC4403'),
'1.3.6.1.1.10.4.41': OidInfo('1.3.6.1.1.10.4.41', OID_ATTRIBUTE_TYPE, 'uddiv3MaxEntities', 'RFC4403'), '1.3.6.1.1.10.4.42': OidInfo('1.3.6.1.1.10.4.42', OID_ATTRIBUTE_TYPE, 'uddiv3ExpiresAfter', 'RFC4403'),
'1.3.6.1.1.10.4.43': OidInfo('1.3.6.1.1.10.4.43', OID_ATTRIBUTE_TYPE, 'uddiv3BriefResponse', 'RFC4403'), '1.3.6.1.1.10.4.44': OidInfo('1.3.6.1.1.10.4.44', OID_ATTRIBUTE_TYPE, 'uddiv3EntityKey', 'RFC4403'),
'1.3.6.1.1.10.4.45': OidInfo('1.3.6.1.1.10.4.45', OID_ATTRIBUTE_TYPE, 'uddiv3EntityCreationTime', 'RFC4403'), '1.3.6.1.1.10.4.46': OidInfo('1.3.6.1.1.10.4.46', OID_ATTRIBUTE_TYPE, 'uddiv3EntityDeletionTime', 'RFC4403'),
'1.3.6.1.1.11.2.1': OidInfo('1.3.6.1.1.11.2.1', OID_ATTRIBUTE_TYPE, 'vPIMTelephoneNumber', 'RFC4237'), '1.3.6.1.1.11.2.2': OidInfo('1.3.6.1.1.11.2.2', OID_ATTRIBUTE_TYPE, 'vPIMRfc822Mailbox', 'RFC4237'),
'1.3.6.1.1.11.2.3': OidInfo('1.3.6.1.1.11.2.3', OID_ATTRIBUTE_TYPE, 'vPIMSpokenName', 'RFC4237'), '1.3.6.1.1.11.2.4': OidInfo('1.3.6.1.1.11.2.4', OID_ATTRIBUTE_TYPE, 'vPIMSupportedUABehaviors', 'RFC4237'),
'1.3.6.1.1.11.2.5': OidInfo('1.3.6.1.1.11.2.5', OID_ATTRIBUTE_TYPE, 'vPIMSupportedAudioMediaTypes', 'RFC4237'), '1.3.6.1.1.11.2.6': OidInfo('1.3.6.1.1.11.2.6', OID_ATTRIBUTE_TYPE, 'vPIMSupportedMessageContext', 'RFC4237'),
'1.3.6.1.1.11.2.7': OidInfo('1.3.6.1.1.11.2.7', OID_ATTRIBUTE_TYPE, 'vPIMTextName', 'RFC4237'), '1.3.6.1.1.11.2.8': OidInfo('1.3.6.1.1.11.2.8', OID_ATTRIBUTE_TYPE, 'vPIMExtendedAbsenceStatus', 'RFC4237'),
'1.3.6.1.1.11.2.9': OidInfo('1.3.6.1.1.11.2.9', OID_ATTRIBUTE_TYPE, 'vPIMMaxMessageSize', 'RFC4237'), '1.3.6.1.1.11.2.10': OidInfo('1.3.6.1.1.11.2.10', OID_ATTRIBUTE_TYPE, 'vPIMSubMailboxes', 'RFC4237'),
'1.3.6.1.1.16.4': OidInfo('1.3.6.1.1.16.4', OID_ATTRIBUTE_TYPE, 'entryUUID', 'RFC4530'), '1.3.6.1.1.20': OidInfo('1.3.6.1.1.20', OID_ATTRIBUTE_TYPE, 'entryDN', 'RFC5020'),
'1.3.6.1.1.6.2.3': OidInfo('1.3.6.1.1.6.2.3', OID_ATTRIBUTE_TYPE, 'pcimKeywords', 'RFC3703'), '1.3.6.1.1.6.2.4': OidInfo('1.3.6.1.1.6.2.4', OID_ATTRIBUTE_TYPE, 'pcimGroupName', 'RFC3703'),
'1.3.6.1.1.6.2.5': OidInfo('1.3.6.1.1.6.2.5', OID_ATTRIBUTE_TYPE, 'pcimRuleName', 'RFC3703'), '1.3.6.1.1.6.2.6': OidInfo('1.3.6.1.1.6.2.6', OID_ATTRIBUTE_TYPE, 'pcimRuleEnabled', 'RFC3703'),
'1.3.6.1.1.6.2.7': OidInfo('1.3.6.1.1.6.2.7', OID_ATTRIBUTE_TYPE, 'pcimRuleConditionListType', 'RFC3703'), '1.3.6.1.1.6.2.8': OidInfo('1.3.6.1.1.6.2.8', OID_ATTRIBUTE_TYPE, 'pcimRuleConditionList', 'RFC3703'),
'1.3.6.1.1.6.2.9': OidInfo('1.3.6.1.1.6.2.9', OID_ATTRIBUTE_TYPE, 'pcimRuleActionList', 'RFC3703'), '1.3.6.1.1.6.2.10': OidInfo('1.3.6.1.1.6.2.10', OID_ATTRIBUTE_TYPE, 'pcimRuleValidityPeriodList', 'RFC3703'),
'1.3.6.1.1.6.2.11': OidInfo('1.3.6.1.1.6.2.11', OID_ATTRIBUTE_TYPE, 'pcimRuleUsage', 'RFC3703'), '1.3.6.1.1.6.2.12': OidInfo('1.3.6.1.1.6.2.12', OID_ATTRIBUTE_TYPE, 'pcimRulePriority', 'RFC3703'),
'1.3.6.1.1.6.2.13': OidInfo('1.3.6.1.1.6.2.13', OID_ATTRIBUTE_TYPE, 'pcimRuleMandatory', 'RFC3703'), '1.3.6.1.1.6.2.14': OidInfo('1.3.6.1.1.6.2.14', OID_ATTRIBUTE_TYPE, 'pcimRuleSequencedActions', 'RFC3703'),
'1.3.6.1.1.6.2.15': OidInfo('1.3.6.1.1.6.2.15', OID_ATTRIBUTE_TYPE, 'pcimRoles', 'RFC3703'), '1.3.6.1.1.6.2.16': OidInfo('1.3.6.1.1.6.2.16', OID_ATTRIBUTE_TYPE, 'pcimConditionGroupNumber', 'RFC3703'),
'1.3.6.1.1.6.2.17': OidInfo('1.3.6.1.1.6.2.17', OID_ATTRIBUTE_TYPE, 'pcimConditionNegated', 'RFC3703'), '1.3.6.1.1.6.2.18': OidInfo('1.3.6.1.1.6.2.18', OID_ATTRIBUTE_TYPE, 'pcimConditionName', 'RFC3703'),
'1.3.6.1.1.6.2.19': OidInfo('1.3.6.1.1.6.2.19', OID_ATTRIBUTE_TYPE, 'pcimConditionDN', 'RFC3703'), '1.3.6.1.1.6.2.20': OidInfo('1.3.6.1.1.6.2.20', OID_ATTRIBUTE_TYPE, 'pcimValidityConditionName', 'RFC3703'),
'1.3.6.1.1.6.2.21': OidInfo('1.3.6.1.1.6.2.21', OID_ATTRIBUTE_TYPE, 'pcimTimePeriodConditionDN', 'RFC3703'), '1.3.6.1.1.6.2.22': OidInfo('1.3.6.1.1.6.2.22', OID_ATTRIBUTE_TYPE, 'pcimActionName', 'RFC3703'),
'1.3.6.1.1.6.2.23': OidInfo('1.3.6.1.1.6.2.23', OID_ATTRIBUTE_TYPE, 'pcimActionOrder', 'RFC3703'), '1.3.6.1.1.6.2.24': OidInfo('1.3.6.1.1.6.2.24', OID_ATTRIBUTE_TYPE, 'pcimActionDN', 'RFC3703'),
'1.3.6.1.1.6.2.25': OidInfo('1.3.6.1.1.6.2.25', OID_ATTRIBUTE_TYPE, 'pcimTPCTime', 'RFC3703'), '1.3.6.1.1.6.2.26': OidInfo('1.3.6.1.1.6.2.26', OID_ATTRIBUTE_TYPE, 'pcimTPCMonthOfYearMask', 'RFC3703'),
'1.3.6.1.1.6.2.27': OidInfo('1.3.6.1.1.6.2.27', OID_ATTRIBUTE_TYPE, 'pcimTPCDayOfMonthMask', 'RFC3703'), '1.3.6.1.1.6.2.28': OidInfo('1.3.6.1.1.6.2.28', OID_ATTRIBUTE_TYPE, 'pcimTPCDayOfWeekMask', 'RFC3703'),
'1.3.6.1.1.6.2.29': OidInfo('1.3.6.1.1.6.2.29', OID_ATTRIBUTE_TYPE, 'pcimTPCTimeOfDayMask', 'RFC3703'), '1.3.6.1.1.6.2.30': OidInfo('1.3.6.1.1.6.2.30', OID_ATTRIBUTE_TYPE, 'pcimTPCLocalOrUtcTime', 'RFC3703'),
'1.3.6.1.1.6.2.31': OidInfo('1.3.6.1.1.6.2.31', OID_ATTRIBUTE_TYPE, 'pcimVendorConstraintData', 'RFC3703'), '1.3.6.1.1.6.2.32': OidInfo('1.3.6.1.1.6.2.32', OID_ATTRIBUTE_TYPE, 'pcimVendorConstraintEncoding', 'RFC3703'),
'1.3.6.1.1.6.2.33': OidInfo('1.3.6.1.1.6.2.33', OID_ATTRIBUTE_TYPE, 'pcimVendorActionData', 'RFC3703'), '1.3.6.1.1.6.2.34': OidInfo('1.3.6.1.1.6.2.34', OID_ATTRIBUTE_TYPE, 'pcimVendorActionEncoding', 'RFC3703'),
'1.3.6.1.1.6.2.35': OidInfo('1.3.6.1.1.6.2.35', OID_ATTRIBUTE_TYPE, 'pcimPolicyInstanceName', 'RFC3703'), '1.3.6.1.1.6.2.36': OidInfo('1.3.6.1.1.6.2.36', OID_ATTRIBUTE_TYPE, 'pcimRepositoryName', 'RFC3703'),
'1.3.6.1.1.6.2.37': OidInfo('1.3.6.1.1.6.2.37', OID_ATTRIBUTE_TYPE, 'pcimSubtreesAuxContainedSet', 'RFC3703'), '1.3.6.1.1.6.2.38': OidInfo('1.3.6.1.1.6.2.38', OID_ATTRIBUTE_TYPE, 'pcimGroupsAuxContainedSet', 'RFC3703'),
'1.3.6.1.1.6.2.39': OidInfo('1.3.6.1.1.6.2.39', OID_ATTRIBUTE_TYPE, 'pcimRulesAuxContainedSet', 'RFC3703'), '1.3.6.1.1.9.2.1': OidInfo('1.3.6.1.1.9.2.1', OID_ATTRIBUTE_TYPE, 'pcelsPolicySetName', 'RFC4104'),
'1.3.6.1.1.9.2.2': OidInfo('1.3.6.1.1.9.2.2', OID_ATTRIBUTE_TYPE, 'pcelsDecisionStrategy', 'RFC4104'), '1.3.6.1.1.9.2.3': OidInfo('1.3.6.1.1.9.2.3', OID_ATTRIBUTE_TYPE, 'pcelsPolicySetList', 'RFC4104'),
'1.3.6.1.1.9.2.4': OidInfo('1.3.6.1.1.9.2.4', OID_ATTRIBUTE_TYPE, 'pcelsPriority', 'RFC4104'), '1.3.6.1.1.9.2.5': OidInfo('1.3.6.1.1.9.2.5', OID_ATTRIBUTE_TYPE, 'pcelsPolicySetDN', 'RFC4104'),
'1.3.6.1.1.9.2.6': OidInfo('1.3.6.1.1.9.2.6', OID_ATTRIBUTE_TYPE, 'pcelsConditionListType', 'RFC4104'), '1.3.6.1.1.9.2.7': OidInfo('1.3.6.1.1.9.2.7', OID_ATTRIBUTE_TYPE, 'pcelsConditionList', 'RFC4104'),
'1.3.6.1.1.9.2.8': OidInfo('1.3.6.1.1.9.2.8', OID_ATTRIBUTE_TYPE, 'pcelsActionList', 'RFC4104'), '1.3.6.1.1.9.2.9': OidInfo('1.3.6.1.1.9.2.9', OID_ATTRIBUTE_TYPE, 'pcelsSequencedActions', 'RFC4104'),
'1.3.6.1.1.9.2.10': OidInfo('1.3.6.1.1.9.2.10', OID_ATTRIBUTE_TYPE, 'pcelsExecutionStrategy', 'RFC4104'), '1.3.6.1.1.9.2.11': OidInfo('1.3.6.1.1.9.2.11', OID_ATTRIBUTE_TYPE, 'pcelsVariableDN', 'RFC4104'),
'1.3.6.1.1.9.2.12': OidInfo('1.3.6.1.1.9.2.12', OID_ATTRIBUTE_TYPE, 'pcelsValueDN', 'RFC4104'), '1.3.6.1.1.9.2.13': OidInfo('1.3.6.1.1.9.2.13', OID_ATTRIBUTE_TYPE, 'pcelsIsMirrored', 'RFC4104'),
'1.3.6.1.1.9.2.14': OidInfo('1.3.6.1.1.9.2.14', OID_ATTRIBUTE_TYPE, 'pcelsVariableName', 'RFC4104'), '1.3.6.1.1.9.2.15': OidInfo('1.3.6.1.1.9.2.15', OID_ATTRIBUTE_TYPE, 'pcelsExpectedValueList', 'RFC4104'),
'1.3.6.1.1.9.2.16': OidInfo('1.3.6.1.1.9.2.16', OID_ATTRIBUTE_TYPE, 'pcelsVariableModelClass', 'RFC4104'), '1.3.6.1.1.9.2.17': OidInfo('1.3.6.1.1.9.2.17', OID_ATTRIBUTE_TYPE, 'pcelsVariableModelProperty', 'RFC4104'),
'1.3.6.1.1.9.2.18': OidInfo('1.3.6.1.1.9.2.18', OID_ATTRIBUTE_TYPE, 'pcelsExpectedValueTypes', 'RFC4104'), '1.3.6.1.1.9.2.19': OidInfo('1.3.6.1.1.9.2.19', OID_ATTRIBUTE_TYPE, 'pcelsValueName', 'RFC4104'),
'1.3.6.1.1.9.2.20': OidInfo('1.3.6.1.1.9.2.20', OID_ATTRIBUTE_TYPE, 'pcelsIPv4AddrList', 'RFC4104'), '1.3.6.1.1.9.2.21': OidInfo('1.3.6.1.1.9.2.21', OID_ATTRIBUTE_TYPE, 'pcelsIPv6AddrList', 'RFC4104'),
'1.3.6.1.1.9.2.22': OidInfo('1.3.6.1.1.9.2.22', OID_ATTRIBUTE_TYPE, 'pcelsMACAddrList', 'RFC4104'), '1.3.6.1.1.9.2.23': OidInfo('1.3.6.1.1.9.2.23', OID_ATTRIBUTE_TYPE, 'pcelsStringList', 'RFC4104'),
'1.3.6.1.1.9.2.24': OidInfo('1.3.6.1.1.9.2.24', OID_ATTRIBUTE_TYPE, 'pcelsBitStringList', 'RFC4104'), '1.3.6.1.1.9.2.25': OidInfo('1.3.6.1.1.9.2.25', OID_ATTRIBUTE_TYPE, 'pcelsIntegerList', 'RFC4104'),
'1.3.6.1.1.9.2.26': OidInfo('1.3.6.1.1.9.2.26', OID_ATTRIBUTE_TYPE, 'pcelsBoolean', 'RFC4104'), '1.3.6.1.1.9.2.27': OidInfo('1.3.6.1.1.9.2.27', OID_ATTRIBUTE_TYPE, 'pcelsReusableContainerName', 'RFC4104'),
'1.3.6.1.1.9.2.28': OidInfo('1.3.6.1.1.9.2.28', OID_ATTRIBUTE_TYPE, 'pcelsReusableContainerList', 'RFC4104'), '1.3.6.1.1.9.2.29': OidInfo('1.3.6.1.1.9.2.29', OID_ATTRIBUTE_TYPE, 'pcelsRole', 'RFC4104'),
'1.3.6.1.1.9.2.30': OidInfo('1.3.6.1.1.9.2.30', OID_ATTRIBUTE_TYPE, 'pcelsRoleCollectionName', 'RFC4104'), '1.3.6.1.1.9.2.31': OidInfo('1.3.6.1.1.9.2.31', OID_ATTRIBUTE_TYPE, 'pcelsElementList', 'RFC4104'),
'1.3.6.1.1.9.2.32': OidInfo('1.3.6.1.1.9.2.32', OID_ATTRIBUTE_TYPE, 'pcelsFilterName', 'RFC4104'), '1.3.6.1.1.9.2.33': OidInfo('1.3.6.1.1.9.2.33', OID_ATTRIBUTE_TYPE, 'pcelsFilterIsNegated', 'RFC4104'),
'1.3.6.1.1.9.2.34': OidInfo('1.3.6.1.1.9.2.34', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrVersion', 'RFC4104'), '1.3.6.1.1.9.2.35': OidInfo('1.3.6.1.1.9.2.35', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourceAddress', 'RFC4104'),
'1.3.6.1.1.9.2.36': OidInfo('1.3.6.1.1.9.2.36', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourceAddressEndOfRange', 'RFC4104'), '1.3.6.1.1.9.2.37': OidInfo('1.3.6.1.1.9.2.37', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourceMask', 'RFC4104'),
'1.3.6.1.1.9.2.38': OidInfo('1.3.6.1.1.9.2.38', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestAddress', 'RFC4104'), '1.3.6.1.1.9.2.39': OidInfo('1.3.6.1.1.9.2.39', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestAddressEndOfRange', 'RFC4104'),
'1.3.6.1.1.9.2.40': OidInfo('1.3.6.1.1.9.2.40', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestMask', 'RFC4104'), '1.3.6.1.1.9.2.41': OidInfo('1.3.6.1.1.9.2.41', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrProtocolID', 'RFC4104'),
'1.3.6.1.1.9.2.42': OidInfo('1.3.6.1.1.9.2.42', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourcePortStart', 'RFC4104'), '1.3.6.1.1.9.2.43': OidInfo('1.3.6.1.1.9.2.43', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourcePortEnd', 'RFC4104'),
'1.3.6.1.1.9.2.44': OidInfo('1.3.6.1.1.9.2.44', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestPortStart', 'RFC4104'), '1.3.6.1.1.9.2.45': OidInfo('1.3.6.1.1.9.2.45', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestPortEnd', 'RFC4104'),
'1.3.6.1.1.9.2.46': OidInfo('1.3.6.1.1.9.2.46', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDSCPList', 'RFC4104'), '1.3.6.1.1.9.2.47': OidInfo('1.3.6.1.1.9.2.47', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrFlowLabel', 'RFC4104'),
'1.3.6.1.1.9.2.48': OidInfo('1.3.6.1.1.9.2.48', OID_ATTRIBUTE_TYPE, 'pcels8021HdrSourceMACAddress', 'RFC4104'), '1.3.6.1.1.9.2.49': OidInfo('1.3.6.1.1.9.2.49', OID_ATTRIBUTE_TYPE, 'pcels8021HdrSourceMACMask', 'RFC4104'),
'1.3.6.1.1.9.2.50': OidInfo('1.3.6.1.1.9.2.50', OID_ATTRIBUTE_TYPE, 'pcels8021HdrDestMACAddress', 'RFC4104'), '1.3.6.1.1.9.2.51': OidInfo('1.3.6.1.1.9.2.51', OID_ATTRIBUTE_TYPE, 'pcels8021HdrDestMACMask', 'RFC4104'),
'1.3.6.1.1.9.2.52': OidInfo('1.3.6.1.1.9.2.52', OID_ATTRIBUTE_TYPE, 'pcels8021HdrProtocolID', 'RFC4104'), '1.3.6.1.1.9.2.53': OidInfo('1.3.6.1.1.9.2.53', OID_ATTRIBUTE_TYPE, 'pcels8021HdrPriority', 'RFC4104'),
'1.3.6.1.1.9.2.54': OidInfo('1.3.6.1.1.9.2.54', OID_ATTRIBUTE_TYPE, 'pcels8021HdrVLANID', 'RFC4104'), '1.3.6.1.1.9.2.55': OidInfo('1.3.6.1.1.9.2.55', OID_ATTRIBUTE_TYPE, 'pcelsFilterListName', 'RFC4104'),
'1.3.6.1.1.9.2.56': OidInfo('1.3.6.1.1.9.2.56', OID_ATTRIBUTE_TYPE, 'pcelsFilterDirection', 'RFC4104'), '1.3.6.1.1.9.2.57': OidInfo('1.3.6.1.1.9.2.57', OID_ATTRIBUTE_TYPE, 'pcelsFilterEntryList', 'RFC4104'),
'1.3.6.1.1.9.2.58': OidInfo('1.3.6.1.1.9.2.58', OID_ATTRIBUTE_TYPE, 'pcelsVendorVariableData', 'RFC4104'), '1.3.6.1.1.9.2.59': OidInfo('1.3.6.1.1.9.2.59', OID_ATTRIBUTE_TYPE, 'pcelsVendorVariableEncoding', 'RFC4104'),
'1.3.6.1.1.9.2.60': OidInfo('1.3.6.1.1.9.2.60', OID_ATTRIBUTE_TYPE, 'pcelsVendorValueData', 'RFC4104'), '1.3.6.1.1.9.2.61': OidInfo('1.3.6.1.1.9.2.61', OID_ATTRIBUTE_TYPE, 'pcelsVendorValueEncoding', 'RFC4104'),
'1.3.6.1.1.9.2.62': OidInfo('1.3.6.1.1.9.2.62', OID_ATTRIBUTE_TYPE, 'pcelsRuleValidityPeriodList', 'RFC4104'), '1.3.6.1.4.1.11.1.3.1.1.0': OidInfo('1.3.6.1.4.1.11.1.3.1.1.0', OID_ATTRIBUTE_TYPE, 'defaultServerList', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.1': OidInfo('1.3.6.1.4.1.11.1.3.1.1.1', OID_ATTRIBUTE_TYPE, 'defaultSearchBase', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.2': OidInfo('1.3.6.1.4.1.11.1.3.1.1.2', OID_ATTRIBUTE_TYPE, 'preferredServerList', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.3': OidInfo('1.3.6.1.4.1.11.1.3.1.1.3', OID_ATTRIBUTE_TYPE, 'search_time_limit', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.4': OidInfo('1.3.6.1.4.1.11.1.3.1.1.4', OID_ATTRIBUTE_TYPE, 'bindTimeLimit', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.5': OidInfo('1.3.6.1.4.1.11.1.3.1.1.5', OID_ATTRIBUTE_TYPE, 'followReferrals', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.6': OidInfo('1.3.6.1.4.1.11.1.3.1.1.6', OID_ATTRIBUTE_TYPE, 'authenticationMethod', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.7': OidInfo('1.3.6.1.4.1.11.1.3.1.1.7', OID_ATTRIBUTE_TYPE, 'profileTTL', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.9': OidInfo('1.3.6.1.4.1.11.1.3.1.1.9', OID_ATTRIBUTE_TYPE, 'attributeMap', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.10': OidInfo('1.3.6.1.4.1.11.1.3.1.1.10', OID_ATTRIBUTE_TYPE, 'credentialLevel', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.11': OidInfo('1.3.6.1.4.1.11.1.3.1.1.11', OID_ATTRIBUTE_TYPE, 'objectclassMap', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.12': OidInfo('1.3.6.1.4.1.11.1.3.1.1.12', OID_ATTRIBUTE_TYPE, 'defaultSearchScope', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.13': OidInfo('1.3.6.1.4.1.11.1.3.1.1.13', OID_ATTRIBUTE_TYPE, 'serviceCredentialLevel', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.14': OidInfo('1.3.6.1.4.1.11.1.3.1.1.14', OID_ATTRIBUTE_TYPE, 'serviceSearchDescriptor', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.15': OidInfo('1.3.6.1.4.1.11.1.3.1.1.15', OID_ATTRIBUTE_TYPE, 'serviceAuthenticationMethod', 'RFC4876'),
'1.3.6.1.4.1.11.1.3.1.1.16': OidInfo('1.3.6.1.4.1.11.1.3.1.1.16', OID_ATTRIBUTE_TYPE, 'dereferenceAliases', 'RFC4876'), '1.3.6.1.4.1.1466.101.119.3': OidInfo('1.3.6.1.4.1.1466.101.119.3', OID_ATTRIBUTE_TYPE, 'entryTtl', 'RFC2589'),
'1.3.6.1.4.1.1466.101.119.4': OidInfo('1.3.6.1.4.1.1466.101.119.4', OID_ATTRIBUTE_TYPE, 'dynamicSubtrees', 'RFC2589'),
'1.3.6.1.4.1.1466.101.120.1': OidInfo('1.3.6.1.4.1.1466.101.120.1', OID_ATTRIBUTE_TYPE, 'administratorsAddress', 'Mark_Wahl'),
'1.3.6.1.4.1.1466.101.120.5': OidInfo('1.3.6.1.4.1.1466.101.120.5', OID_ATTRIBUTE_TYPE, 'namingContexts', 'RFC4512'), '1.3.6.1.4.1.1466.101.120.6': OidInfo('1.3.6.1.4.1.1466.101.120.6', OID_ATTRIBUTE_TYPE, 'altServer', 'RFC4512'),
'1.3.6.1.4.1.1466.101.120.7': OidInfo('1.3.6.1.4.1.1466.101.120.7', OID_ATTRIBUTE_TYPE, 'supportedExtension', 'RFC4512'),
'1.3.6.1.4.1.1466.101.120.13': OidInfo('1.3.6.1.4.1.1466.101.120.13', OID_ATTRIBUTE_TYPE, 'supportedControl', 'RFC4512'),
'1.3.6.1.4.1.1466.101.120.14': OidInfo('1.3.6.1.4.1.1466.101.120.14', OID_ATTRIBUTE_TYPE, 'supportedSASLMechanisms', 'RFC4512'),
'1.3.6.1.4.1.1466.101.120.15': OidInfo('1.3.6.1.4.1.1466.101.120.15', OID_ATTRIBUTE_TYPE, 'supportedLDAPVersion', 'RFC4512'),
'1.3.6.1.4.1.1466.101.120.16': OidInfo('1.3.6.1.4.1.1466.101.120.16', OID_ATTRIBUTE_TYPE, 'ldapSyntaxes', 'RFC4512'), '1.3.6.1.4.1.16572.2.2.1': OidInfo('1.3.6.1.4.1.16572.2.2.1', OID_ATTRIBUTE_TYPE, 'providerCertificateHash', 'RFC6109'),
'1.3.6.1.4.1.16572.2.2.2': OidInfo('1.3.6.1.4.1.16572.2.2.2', OID_ATTRIBUTE_TYPE, 'providerCertificate', 'RFC6109'), '1.3.6.1.4.1.16572.2.2.3': OidInfo('1.3.6.1.4.1.16572.2.2.3', OID_ATTRIBUTE_TYPE, 'providerName', 'RFC6109'),
'1.3.6.1.4.1.16572.2.2.4': OidInfo('1.3.6.1.4.1.16572.2.2.4', OID_ATTRIBUTE_TYPE, 'mailReceipt', 'RFC6109'), '1.3.6.1.4.1.16572.2.2.5': OidInfo('1.3.6.1.4.1.16572.2.2.5', OID_ATTRIBUTE_TYPE, 'managedDomains', 'RFC6109'),
'1.3.6.1.4.1.16572.2.2.6': OidInfo('1.3.6.1.4.1.16572.2.2.6', OID_ATTRIBUTE_TYPE, 'LDIFLocationURL', 'RFC6109'), '1.3.6.1.4.1.16572.2.2.7': OidInfo('1.3.6.1.4.1.16572.2.2.7', OID_ATTRIBUTE_TYPE, 'providerUnit', 'RFC6109'),
'1.3.6.1.4.1.250.1.57': OidInfo('1.3.6.1.4.1.250.1.57', OID_ATTRIBUTE_TYPE, 'labeledURI', 'RFC2079'), '1.3.6.1.4.1.31103.1.1': OidInfo('1.3.6.1.4.1.31103.1.1', OID_ATTRIBUTE_TYPE, 'fedfsUuid', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.2': OidInfo('1.3.6.1.4.1.31103.1.2', OID_ATTRIBUTE_TYPE, 'fedfsNetAddr', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.3': OidInfo('1.3.6.1.4.1.31103.1.3', OID_ATTRIBUTE_TYPE, 'fedfsNetPort', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.4': OidInfo('1.3.6.1.4.1.31103.1.4', OID_ATTRIBUTE_TYPE, 'fedfsFsnUuid', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.5': OidInfo('1.3.6.1.4.1.31103.1.5', OID_ATTRIBUTE_TYPE, 'fedfsNsdbName', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.6': OidInfo('1.3.6.1.4.1.31103.1.6', OID_ATTRIBUTE_TYPE, 'fedfsNsdbPort', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.7': OidInfo('1.3.6.1.4.1.31103.1.7', OID_ATTRIBUTE_TYPE, 'fedfsNcePrefix', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.8': OidInfo('1.3.6.1.4.1.31103.1.8', OID_ATTRIBUTE_TYPE, 'fedfsFslUuid', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.9': OidInfo('1.3.6.1.4.1.31103.1.9', OID_ATTRIBUTE_TYPE, 'fedfsFslHost', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.10': OidInfo('1.3.6.1.4.1.31103.1.10', OID_ATTRIBUTE_TYPE, 'fedfsFslPort', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.11': OidInfo('1.3.6.1.4.1.31103.1.11', OID_ATTRIBUTE_TYPE, 'fedfsFslTTL', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.12': OidInfo('1.3.6.1.4.1.31103.1.12', OID_ATTRIBUTE_TYPE, 'fedfsAnnotation', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.13': OidInfo('1.3.6.1.4.1.31103.1.13', OID_ATTRIBUTE_TYPE, 'fedfsDescr', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.14': OidInfo('1.3.6.1.4.1.31103.1.14', OID_ATTRIBUTE_TYPE, 'fedfsNceDN', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.15': OidInfo('1.3.6.1.4.1.31103.1.15', OID_ATTRIBUTE_TYPE, 'fedfsFsnTTL', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.100': OidInfo('1.3.6.1.4.1.31103.1.100', OID_ATTRIBUTE_TYPE, 'fedfsNfsPath', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.101': OidInfo('1.3.6.1.4.1.31103.1.101', OID_ATTRIBUTE_TYPE, 'fedfsNfsMajorVer', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.102': OidInfo('1.3.6.1.4.1.31103.1.102', OID_ATTRIBUTE_TYPE, 'fedfsNfsMinorVer', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.103': OidInfo('1.3.6.1.4.1.31103.1.103', OID_ATTRIBUTE_TYPE, 'fedfsNfsCurrency', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.104': OidInfo('1.3.6.1.4.1.31103.1.104', OID_ATTRIBUTE_TYPE, 'fedfsNfsGenFlagWritable', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.105': OidInfo('1.3.6.1.4.1.31103.1.105', OID_ATTRIBUTE_TYPE, 'fedfsNfsGenFlagGoing', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.106': OidInfo('1.3.6.1.4.1.31103.1.106', OID_ATTRIBUTE_TYPE, 'fedfsNfsGenFlagSplit', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.107': OidInfo('1.3.6.1.4.1.31103.1.107', OID_ATTRIBUTE_TYPE, 'fedfsNfsTransFlagRdma', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.108': OidInfo('1.3.6.1.4.1.31103.1.108', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassSimul', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.109': OidInfo('1.3.6.1.4.1.31103.1.109', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassHandle', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.110': OidInfo('1.3.6.1.4.1.31103.1.110', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassFileid', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.111': OidInfo('1.3.6.1.4.1.31103.1.111', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassWritever', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.112': OidInfo('1.3.6.1.4.1.31103.1.112', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassChange', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.113': OidInfo('1.3.6.1.4.1.31103.1.113', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassReaddir', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.114': OidInfo('1.3.6.1.4.1.31103.1.114', OID_ATTRIBUTE_TYPE, 'fedfsNfsReadRank', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.115': OidInfo('1.3.6.1.4.1.31103.1.115', OID_ATTRIBUTE_TYPE, 'fedfsNfsReadOrder', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.116': OidInfo('1.3.6.1.4.1.31103.1.116', OID_ATTRIBUTE_TYPE, 'fedfsNfsWriteRank', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.117': OidInfo('1.3.6.1.4.1.31103.1.117', OID_ATTRIBUTE_TYPE, 'fedfsNfsWriteOrder', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.118': OidInfo('1.3.6.1.4.1.31103.1.118', OID_ATTRIBUTE_TYPE, 'fedfsNfsVarSub', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.119': OidInfo('1.3.6.1.4.1.31103.1.119', OID_ATTRIBUTE_TYPE, 'fedfsNfsValidFor', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.120': OidInfo('1.3.6.1.4.1.31103.1.120', OID_ATTRIBUTE_TYPE, 'fedfsNfsURI', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.4203.1.3.5': OidInfo('1.3.6.1.4.1.4203.1.3.5', OID_ATTRIBUTE_TYPE, 'supportedFeatures', 'RFC4512'), '1.3.6.1.4.1.453.7.2.1': OidInfo('1.3.6.1.4.1.453.7.2.1', OID_ATTRIBUTE_TYPE, 'textTableKey', 'RFC2293'),
'1.3.6.1.4.1.453.7.2.2': OidInfo('1.3.6.1.4.1.453.7.2.2', OID_ATTRIBUTE_TYPE, 'textTableValue', 'RFC2293'),
'1.3.6.1.4.1.453.7.2.3': OidInfo('1.3.6.1.4.1.453.7.2.3', OID_ATTRIBUTE_TYPE, ['associatedX400Gateway', 'distinguishedNameTableKey'], 'RFC2164-RFC2293'),
'1.3.6.1.4.1.453.7.2.6': OidInfo('1.3.6.1.4.1.453.7.2.6', OID_ATTRIBUTE_TYPE, 'associatedORAddress', 'RFC2164'), '1.3.6.1.4.1.453.7.2.7': OidInfo('1.3.6.1.4.1.453.7.2.7', OID_ATTRIBUTE_TYPE, 'oRAddressComponentType', 'RFC2164'),
'1.3.6.1.4.1.453.7.2.8': OidInfo('1.3.6.1.4.1.453.7.2.8', OID_ATTRIBUTE_TYPE, 'associatedInternetGateway', 'RFC2164'), '1.3.6.1.4.1.453.7.2.9': OidInfo('1.3.6.1.4.1.453.7.2.9', OID_ATTRIBUTE_TYPE, 'mcgamTables', 'RFC2164'),
'2.16.840.1.113730.3.1.34': OidInfo('2.16.840.1.113730.3.1.34', OID_ATTRIBUTE_TYPE, 'ref', 'RFC3296'), '2.5.18.1': OidInfo('2.5.18.1', OID_ATTRIBUTE_TYPE, 'createTimestamp', 'RFC4512'),
'2.5.18.2': OidInfo('2.5.18.2', OID_ATTRIBUTE_TYPE, 'modifyTimestamp', 'RFC4512'), '2.5.18.3': OidInfo('2.5.18.3', OID_ATTRIBUTE_TYPE, 'creatorsName', 'RFC4512'),
'2.5.18.4': OidInfo('2.5.18.4', OID_ATTRIBUTE_TYPE, 'modifiersName', 'RFC4512'), '2.5.18.5': OidInfo('2.5.18.5', OID_ATTRIBUTE_TYPE, 'administrativeRole', 'RFC3672'),
'2.5.18.6': OidInfo('2.5.18.6', OID_ATTRIBUTE_TYPE, 'subtreeSpecification', 'RFC3672'), '2.5.18.7': OidInfo('2.5.18.7', OID_ATTRIBUTE_TYPE, 'collectiveExclusions', 'RFC3671'),
'2.5.18.10': OidInfo('2.5.18.10', OID_ATTRIBUTE_TYPE, 'subschemaSubentry', 'RFC4512'), '2.5.18.12': OidInfo('2.5.18.12', OID_ATTRIBUTE_TYPE, 'collectiveAttributeSubentries', 'RFC3671'),
'2.5.21.1': OidInfo('2.5.21.1', OID_ATTRIBUTE_TYPE, 'dITStructureRules', 'RFC4512'), '2.5.21.2': OidInfo('2.5.21.2', OID_ATTRIBUTE_TYPE, 'dITContentRules', 'RFC4512'),
'2.5.21.4': OidInfo('2.5.21.4', OID_ATTRIBUTE_TYPE, 'matchingRules', 'RFC4512'), '2.5.21.5': OidInfo('2.5.21.5', OID_ATTRIBUTE_TYPE, 'attributeTypes', 'RFC4512'),
'2.5.21.6': OidInfo('2.5.21.6', OID_ATTRIBUTE_TYPE, 'objectClasses', 'RFC4512'), '2.5.21.7': OidInfo('2.5.21.7', OID_ATTRIBUTE_TYPE, 'nameForms', 'RFC4512'), '2.5.21.8': OidInfo('2.5.21.8', OID_ATTRIBUTE_TYPE, 'matchingRuleUse', 'RFC4512'),
'2.5.21.9': OidInfo('2.5.21.9', OID_ATTRIBUTE_TYPE, 'structuralObjectClass', 'RFC4512'), '2.5.21.10': OidInfo('2.5.21.10', OID_ATTRIBUTE_TYPE, 'governingStructureRule', 'RFC4512'),
'2.5.4.0': OidInfo('2.5.4.0', OID_ATTRIBUTE_TYPE, 'objectClass', 'RFC4512'), '2.5.4.1': OidInfo('2.5.4.1', OID_ATTRIBUTE_TYPE, ['aliasedEntryName', 'aliasedObjectName'], 'X.501-RFC4512'),
'2.5.4.2': OidInfo('2.5.4.2', OID_ATTRIBUTE_TYPE, 'knowledgeInformation', 'RFC2256'), '2.5.4.3': OidInfo('2.5.4.3', OID_ATTRIBUTE_TYPE, ['cn', 'commonName'], 'RFC4519'),
'2.5.4.4': OidInfo('2.5.4.4', OID_ATTRIBUTE_TYPE, ['sn', 'surname'], 'RFC4519'), '2.5.4.5': OidInfo('2.5.4.5', OID_ATTRIBUTE_TYPE, 'serialNumber', 'RFC4519'),
'2.5.4.6': OidInfo('2.5.4.6', OID_ATTRIBUTE_TYPE, ['c', 'countryName'], 'RFC4519'), '2.5.4.7': OidInfo('2.5.4.7', OID_ATTRIBUTE_TYPE, ['L', 'localityName'], 'RFC4519'),
'2.5.4.7.1': OidInfo('2.5.4.7.1', OID_ATTRIBUTE_TYPE, 'c-l', 'RFC3671'), '2.5.4.8': OidInfo('2.5.4.8', OID_ATTRIBUTE_TYPE, ['st', 'stateOrProvinceName'], 'RFC4519-RFC2256'),
'2.5.4.8.1': OidInfo('2.5.4.8.1', OID_ATTRIBUTE_TYPE, 'c-st', 'RFC3671'), '2.5.4.9': OidInfo('2.5.4.9', OID_ATTRIBUTE_TYPE, ['street', 'streetAddress'], 'RFC4519-RFC2256'),
'2.5.4.9.1': OidInfo('2.5.4.9.1', OID_ATTRIBUTE_TYPE, 'c-street', 'RFC3671'), '2.5.4.10': OidInfo('2.5.4.10', OID_ATTRIBUTE_TYPE, 'o, organizationName', 'RFC4519'), '2.5.4.10.1': OidInfo('2.5.4.10.1', OID_ATTRIBUTE_TYPE, 'c-o', 'RFC3671'),
'2.5.4.11': OidInfo('2.5.4.11', OID_ATTRIBUTE_TYPE, ['ou', 'organizationalUnitName'], 'RFC4519'), '2.5.4.11.1': OidInfo('2.5.4.11.1', OID_ATTRIBUTE_TYPE, 'c-ou', 'RFC3671'),
'2.5.4.12': OidInfo('2.5.4.12', OID_ATTRIBUTE_TYPE, 'title', 'RFC4519'), '2.5.4.13': OidInfo('2.5.4.13', OID_ATTRIBUTE_TYPE, 'description', 'RFC4519'), '2.5.4.14': OidInfo('2.5.4.14', OID_ATTRIBUTE_TYPE, 'searchGuide', 'RFC4519'),
'2.5.4.15': OidInfo('2.5.4.15', OID_ATTRIBUTE_TYPE, 'businessCategory', 'RFC4519'), '2.5.4.16': OidInfo('2.5.4.16', OID_ATTRIBUTE_TYPE, 'postalAddress', 'RFC4519'),
'2.5.4.16.1': OidInfo('2.5.4.16.1', OID_ATTRIBUTE_TYPE, 'c-PostalAddress', 'RFC3671'), '2.5.4.17': OidInfo('2.5.4.17', OID_ATTRIBUTE_TYPE, 'postalCode', 'RFC4519'),
'2.5.4.17.1': OidInfo('2.5.4.17.1', OID_ATTRIBUTE_TYPE, 'c-PostalCode', 'RFC3671'), '2.5.4.18': OidInfo('2.5.4.18', OID_ATTRIBUTE_TYPE, 'postOfficeBox', 'RFC4519'),
'2.5.4.18.1': OidInfo('2.5.4.18.1', OID_ATTRIBUTE_TYPE, 'c-PostOfficeBox', 'RFC3671'), '2.5.4.19': OidInfo('2.5.4.19', OID_ATTRIBUTE_TYPE, 'physicalDeliveryOfficeName', 'RFC4519'),
'2.5.4.19.1': OidInfo('2.5.4.19.1', OID_ATTRIBUTE_TYPE, 'c-PhysicalDeliveryOffice', 'RFC3671'), '2.5.4.20': OidInfo('2.5.4.20', OID_ATTRIBUTE_TYPE, 'telephoneNumber', 'RFC4519'),
'2.5.4.20.1': OidInfo('2.5.4.20.1', OID_ATTRIBUTE_TYPE, 'c-TelephoneNumber', 'RFC3671'), '2.5.4.21': OidInfo('2.5.4.21', OID_ATTRIBUTE_TYPE, 'telexNumber', 'RFC4519'),
'2.5.4.21.1': OidInfo('2.5.4.21.1', OID_ATTRIBUTE_TYPE, 'c-TelexNumber', 'RFC3671'), '2.5.4.22': OidInfo('2.5.4.22', OID_ATTRIBUTE_TYPE, 'teletexTerminalIdentifier', 'RFC4519'),
'2.5.4.23': OidInfo('2.5.4.23', OID_ATTRIBUTE_TYPE, 'facsimileTelephoneNumber', 'RFC4519'), '2.5.4.23.1': OidInfo('2.5.4.23.1', OID_ATTRIBUTE_TYPE, 'c-FacsimileTelephoneNumber', 'RFC3671'),
'2.5.4.24': OidInfo('2.5.4.24', OID_ATTRIBUTE_TYPE, 'x121Address', 'RFC4519'), '2.5.4.25': OidInfo('2.5.4.25', OID_ATTRIBUTE_TYPE, 'internationaliSDNNumber', 'RFC4519'),
'2.5.4.25.1': OidInfo('2.5.4.25.1', OID_ATTRIBUTE_TYPE, 'c-InternationalISDNNumber', 'RFC3671'), '2.5.4.26': OidInfo('2.5.4.26', OID_ATTRIBUTE_TYPE, 'registeredAddress', 'RFC4519'),
'2.5.4.27': OidInfo('2.5.4.27', OID_ATTRIBUTE_TYPE, 'destinationIndicator', 'RFC4519'), '2.5.4.28': OidInfo('2.5.4.28', OID_ATTRIBUTE_TYPE, 'preferredDeliveryMethod', 'RFC4519'),
'2.5.4.29': OidInfo('2.5.4.29', OID_ATTRIBUTE_TYPE, 'presentationAddress', 'RFC2256'), '2.5.4.30': OidInfo('2.5.4.30', OID_ATTRIBUTE_TYPE, 'supportedApplicationContext', 'RFC2256'),
'2.5.4.31': OidInfo('2.5.4.31', OID_ATTRIBUTE_TYPE, 'member', 'RFC4519'), '2.5.4.32': OidInfo('2.5.4.32', OID_ATTRIBUTE_TYPE, 'owner', 'RFC4519'), '2.5.4.33': OidInfo('2.5.4.33', OID_ATTRIBUTE_TYPE, 'roleOccupant', 'RFC4519'),
'2.5.4.34': OidInfo('2.5.4.34', OID_ATTRIBUTE_TYPE, 'seeAlso', 'RFC4519'), '2.5.4.35': OidInfo('2.5.4.35', OID_ATTRIBUTE_TYPE, 'userPassword', 'RFC4519'), '2.5.4.36': OidInfo('2.5.4.36', OID_ATTRIBUTE_TYPE, 'userCertificate', 'RFC4523'),
'2.5.4.37': OidInfo('2.5.4.37', OID_ATTRIBUTE_TYPE, 'cACertificate', 'RFC4523'), '2.5.4.38': OidInfo('2.5.4.38', OID_ATTRIBUTE_TYPE, 'authorityRevocationList', 'RFC4523'),
'2.5.4.39': OidInfo('2.5.4.39', OID_ATTRIBUTE_TYPE, 'certificateRevocationList', 'RFC4523'), '2.5.4.40': OidInfo('2.5.4.40', OID_ATTRIBUTE_TYPE, 'crossCertificatePair', 'RFC4523'),
'2.5.4.41': OidInfo('2.5.4.41', OID_ATTRIBUTE_TYPE, 'name', 'RFC4519'), '2.5.4.42': OidInfo('2.5.4.42', OID_ATTRIBUTE_TYPE, 'givenName', 'RFC4519'), '2.5.4.43': OidInfo('2.5.4.43', OID_ATTRIBUTE_TYPE, 'initials', 'RFC4519'),
'2.5.4.44': OidInfo('2.5.4.44', OID_ATTRIBUTE_TYPE, 'generationQualifier', 'RFC4519'), '2.5.4.45': OidInfo('2.5.4.45', OID_ATTRIBUTE_TYPE, 'x500UniqueIdentifier', 'RFC4519'),
'2.5.4.46': OidInfo('2.5.4.46', OID_ATTRIBUTE_TYPE, 'dnQualifier', 'RFC4519'), '2.5.4.47': OidInfo('2.5.4.47', OID_ATTRIBUTE_TYPE, 'enhancedSearchGuide', 'RFC4519'),
'2.5.4.48': OidInfo('2.5.4.48', OID_ATTRIBUTE_TYPE, 'protocolInformation', 'RFC2256'), '2.5.4.49': OidInfo('2.5.4.49', OID_ATTRIBUTE_TYPE, 'distinguishedName', 'RFC4519'),
'2.5.4.50': OidInfo('2.5.4.50', OID_ATTRIBUTE_TYPE, 'uniqueMember', 'RFC4519'), '2.5.4.51': OidInfo('2.5.4.51', OID_ATTRIBUTE_TYPE, 'houseIdentifier', 'RFC4519'),
'2.5.4.52': OidInfo('2.5.4.52', OID_ATTRIBUTE_TYPE, 'supportedAlgorithms', 'RFC4523'), '2.5.4.53': OidInfo('2.5.4.53', OID_ATTRIBUTE_TYPE, 'deltaRevocationList', 'RFC4523'),
'2.5.4.54': OidInfo('2.5.4.54', OID_ATTRIBUTE_TYPE, 'dmdName', 'RFC2256'), '2.5.4.65': OidInfo('2.5.4.65', OID_ATTRIBUTE_TYPE, 'pseudonym', 'RFC3280'),
# controls
'1.2.826.0.1.3344810.2.3': OidInfo('1.2.826.0.1.3344810.2.3', OID_CONTROL, 'Matched Values', 'RFC3876'), '1.2.840.113556.1.4.319': OidInfo('1.2.840.113556.1.4.319', OID_CONTROL, 'LDAP Simple Paged Results', 'RFC2696'),
'1.2.840.113556.1.4.417': OidInfo('1.2.840.113556.1.4.417', OID_CONTROL, 'LDAP server show deleted objects', 'MICROSOFT'), '1.2.840.113556.1.4.473': OidInfo('1.2.840.113556.1.4.473', OID_CONTROL, 'Sort Request', 'RFC2891'),
'1.2.840.113556.1.4.474': OidInfo('1.2.840.113556.1.4.474', OID_CONTROL, 'Sort Response', 'RFC2891'), '1.2.840.113556.1.4.521': OidInfo('1.2.840.113556.1.4.521', OID_CONTROL, 'Cross-domain move', 'MICROSOFT'),
'1.2.840.113556.1.4.528': OidInfo('1.2.840.113556.1.4.528', OID_CONTROL, 'Server search notification', 'MICROSOFT'), '1.2.840.113556.1.4.529': OidInfo('1.2.840.113556.1.4.529', OID_CONTROL, 'Extended DN', 'MICROSOFT'),
'1.2.840.113556.1.4.619': OidInfo('1.2.840.113556.1.4.619', OID_CONTROL, 'Lazy commit', 'MICROSOFT'), '1.2.840.113556.1.4.801': OidInfo('1.2.840.113556.1.4.801', OID_CONTROL, 'Security descriptor flags', 'MICROSOFT'),
'1.2.840.113556.1.4.802': OidInfo('1.2.840.113556.1.4.802', OID_CONTROL, 'Range option', 'MICROSOFT'), '1.2.840.113556.1.4.805': OidInfo('1.2.840.113556.1.4.805', OID_CONTROL, 'Tree delete', 'MICROSOFT'),
'1.2.840.113556.1.4.841': OidInfo('1.2.840.113556.1.4.841', OID_CONTROL, 'Directory synchronization', 'MICROSOFT'), '1.2.840.113556.1.4.970': OidInfo('1.2.840.113556.1.4.970', OID_CONTROL, 'Get stats', 'MICROSOFT'),
'1.2.840.113556.1.4.1338': OidInfo('1.2.840.113556.1.4.1338', OID_CONTROL, 'Verify name', 'MICROSOFT'), '1.2.840.113556.1.4.1339': OidInfo('1.2.840.113556.1.4.1339', OID_CONTROL, 'Domain scope', 'MICROSOFT'),
'1.2.840.113556.1.4.1340': OidInfo('1.2.840.113556.1.4.1340', OID_CONTROL, 'Search options', 'MICROSOFT'), '1.2.840.113556.1.4.1341': OidInfo('1.2.840.113556.1.4.1341', OID_CONTROL, 'RODC DCPROMO', 'MICROSOFT'),
'1.2.840.113556.1.4.1413': OidInfo('1.2.840.113556.1.4.1413', OID_CONTROL, 'Permissive modify', 'MICROSOFT'), '1.2.840.113556.1.4.1504': OidInfo('1.2.840.113556.1.4.1504', OID_CONTROL, 'Attribute scoped query', 'MICROSOFT'),
'1.2.840.113556.1.4.1852': OidInfo('1.2.840.113556.1.4.1852', OID_CONTROL, 'User quota', 'MICROSOFT'), '1.2.840.113556.1.4.1907': OidInfo('1.2.840.113556.1.4.1907', OID_CONTROL, 'Server shutdown notify', 'MICROSOFT'),
'1.2.840.113556.1.4.1948': OidInfo('1.2.840.113556.1.4.1948', OID_CONTROL, 'Range retrieval no error', 'MICROSOFT'), '1.2.840.113556.1.4.1974': OidInfo('1.2.840.113556.1.4.1974', OID_CONTROL, 'Server force update', 'MICROSOFT'),
'1.2.840.113556.1.4.2026': OidInfo('1.2.840.113556.1.4.2026', OID_CONTROL, 'Input DN', 'MICROSOFT'), '1.2.840.113556.1.4.2064': OidInfo('1.2.840.113556.1.4.2064', OID_CONTROL, 'Show recycled', 'MICROSOFT'),
'1.2.840.113556.1.4.2065': OidInfo('1.2.840.113556.1.4.2065', OID_CONTROL, 'Show deactivated link', 'MICROSOFT'), '1.2.840.113556.1.4.2066': OidInfo('1.2.840.113556.1.4.2066', OID_CONTROL, 'Policy hints (deprecated)', 'MICROSOFT'),
'1.2.840.113556.1.4.2090': OidInfo('1.2.840.113556.1.4.2090', OID_CONTROL, 'DirSync EX', 'MICROSOFT'), '1.2.840.113556.1.4.2204': OidInfo('1.2.840.113556.1.4.2204', OID_CONTROL, 'Tree deleted EX', 'MICROSOFT'),
'1.2.840.113556.1.4.2205': OidInfo('1.2.840.113556.1.4.2205', OID_CONTROL, 'Updates stats', 'MICROSOFT'), '1.2.840.113556.1.4.2206': OidInfo('1.2.840.113556.1.4.2206', OID_CONTROL, 'Search hints', 'MICROSOFT'),
'1.2.840.113556.1.4.2211': OidInfo('1.2.840.113556.1.4.2211', OID_CONTROL, 'Expected entry count', 'MICROSOFT'), '1.2.840.113556.1.4.2239': OidInfo('1.2.840.113556.1.4.2239', OID_CONTROL, 'Policy hints', 'MICROSOFT'),
'1.2.840.113556.1.4.2255': OidInfo('1.2.840.113556.1.4.2255', OID_CONTROL, 'Set owner', 'MICROSOFT'), '1.2.840.113556.1.4.2256': OidInfo('1.2.840.113556.1.4.2256', OID_CONTROL, 'Bypass quota', 'MICROSOFT'),
'1.3.6.1.1.7.1': OidInfo('1.3.6.1.1.7.1', OID_CONTROL, 'LCUP Sync Request', 'RFC3928'), '1.3.6.1.1.7.2': OidInfo('1.3.6.1.1.7.2', OID_CONTROL, 'LCUP Sync Update', 'RFC3928'),
'1.3.6.1.1.7.3': OidInfo('1.3.6.1.1.7.3', OID_CONTROL, 'LCUP Sync Done', 'RFC3928'), '1.3.6.1.1.12': OidInfo('1.3.6.1.1.12', OID_CONTROL, 'Assertion', 'RFC4528'),
'1.3.6.1.1.13.1': OidInfo('1.3.6.1.1.13.1', OID_CONTROL, 'LDAP Pre-read', 'RFC4527'), '1.3.6.1.1.13.2': OidInfo('1.3.6.1.1.13.2', OID_CONTROL, 'LDAP Post-read', 'RFC4527'),
'1.3.6.1.1.21.2': OidInfo('1.3.6.1.1.21.2', OID_CONTROL, 'Transaction Specification', 'RFC5805'), '1.3.6.1.1.22': OidInfo('1.3.6.1.1.22', OID_CONTROL, "LDAP Don't Use Copy", 'RFC6171'),
'1.3.6.1.4.1.42.2.27.8.5.1': OidInfo('1.3.6.1.4.1.42.2.27.8.5.1', OID_CONTROL, 'Password policy', 'IETF DRAFT behera-ldap-password-policy'),
'1.3.6.1.4.1.42.2.27.9.5.2': OidInfo('1.3.6.1.4.1.42.2.27.9.5.2', OID_CONTROL, 'Get effective rights', 'IETF DRAFT draft-ietf-ldapext-acl-model'),
'1.3.6.1.4.1.42.2.27.9.5.8': OidInfo('1.3.6.1.4.1.42.2.27.9.5.8', OID_CONTROL, 'Account usability', 'SUN microsystems'),
'1.3.6.1.4.1.4203.1.9.1.1': OidInfo('1.3.6.1.4.1.4203.1.9.1.1', OID_CONTROL, 'LDAP content synchronization', 'RFC4533'), '1.3.6.1.4.1.4203.1.10.1': OidInfo('1.3.6.1.4.1.4203.1.10.1', OID_CONTROL, 'Subentries', 'RFC3672'),
'1.3.6.1.4.1.4203.1.10.2': OidInfo('1.3.6.1.4.1.4203.1.10.2', OID_CONTROL, 'No-Operation', 'IETF DRAFT draft-zeilenga-ldap-noop'),
'1.3.6.1.4.1.7628.5.101.1': OidInfo('1.3.6.1.4.1.7628.5.101.1', OID_CONTROL, 'LDAP subentries', 'IETF DRAFT draft-ietf-ldup-subentry'),
'1.3.6.1.4.1.26027.1.5.2': OidInfo('1.3.6.1.4.1.26027.1.5.2', OID_CONTROL, 'Replication repair', 'OpenDS'), '2.16.840.1.113719.1.27.101.5': OidInfo('2.16.840.1.113719.1.27.101.5', OID_CONTROL, 'Simple password', 'NOVELL'),
'2.16.840.1.113719.1.27.101.6': OidInfo('2.16.840.1.113719.1.27.101.6', OID_CONTROL, 'Forward reference', 'NOVELL'), '2.16.840.1.113719.1.27.103.7': OidInfo('2.16.840.1.113719.1.27.103.7', OID_CONTROL, 'Grouping', 'NOVELL'),
'2.16.840.1.113730.3.4.2': OidInfo('2.16.840.1.113730.3.4.2', OID_CONTROL, 'ManageDsaIT', 'RFC3296'), '2.16.840.1.113730.3.4.3': OidInfo('2.16.840.1.113730.3.4.3', OID_CONTROL, 'Persistent Search', 'IETF'),
'2.16.840.1.113730.3.4.4': OidInfo('2.16.840.1.113730.3.4.4', OID_CONTROL, 'Netscape Password Expired', 'Netscape'), '2.16.840.1.113730.3.4.5': OidInfo('2.16.840.1.113730.3.4.5', OID_CONTROL, 'Netscape Password Expiring', 'Netscape'),
'2.16.840.1.113730.3.4.6': OidInfo('2.16.840.1.113730.3.4.6', OID_CONTROL, 'Netscape NT Synchronization Client', 'Netscape'),
'2.16.840.1.113730.3.4.7': OidInfo('2.16.840.1.113730.3.4.7', OID_CONTROL, 'Entry Change Notification', 'Netscape'), '2.16.840.1.113730.3.4.9': OidInfo('2.16.840.1.113730.3.4.9', OID_CONTROL, 'Virtual List View Request', 'IETF'),
'2.16.840.1.113730.3.4.10': OidInfo('2.16.840.1.113730.3.4.10', OID_CONTROL, 'Virtual List View Response', 'IETF'), '2.16.840.1.113730.3.4.12': OidInfo('2.16.840.1.113730.3.4.12', OID_CONTROL, 'Proxied Authorization (old)', 'Netscape'),
'2.16.840.1.113730.3.4.13': OidInfo('2.16.840.1.113730.3.4.13', OID_CONTROL, 'iPlanet Directory Server Replication Update Information', 'iPlanet'),
'2.16.840.1.113730.3.4.14': OidInfo('2.16.840.1.113730.3.4.14', OID_CONTROL, 'Search on specific database', 'iPlanet'),
'2.16.840.1.113730.3.4.15': OidInfo('2.16.840.1.113730.3.4.15', OID_CONTROL, 'Authorization Identity Response Control', 'RFC3829'),
'2.16.840.1.113730.3.4.16': OidInfo('2.16.840.1.113730.3.4.16', OID_CONTROL, 'Authorization Identity Request Control', 'RFC3829'),
'2.16.840.1.113730.3.4.17': OidInfo('2.16.840.1.113730.3.4.17', OID_CONTROL, 'Real attribute only request', 'iPlanet'), '2.16.840.1.113730.3.4.18': OidInfo('2.16.840.1.113730.3.4.18', OID_CONTROL, 'Proxy Authorization Control', 'RFC6171'),
'2.16.840.1.113730.3.4.19': OidInfo('2.16.840.1.113730.3.4.19', OID_CONTROL, 'Virtual attribute only request', 'iPlanet'),
# dit content rules
# extensions
'1.2.840.113556.1.4.1781': OidInfo('1.2.840.113556.1.4.1781', OID_EXTENSION, 'Fast concurrent bind', 'MICROSOFT'),
'1.2.840.113556.1.4.2212': OidInfo('1.2.840.113556.1.4.2212', OID_EXTENSION, 'Batch request', 'MICROSOFT'),
'1.3.6.1.1.8': OidInfo('1.3.6.1.1.8', OID_EXTENSION, 'Cancel Operation', 'RFC3909'),
'1.3.6.1.1.21.1': OidInfo('1.3.6.1.1.21.1', OID_EXTENSION, 'Start Transaction Extended Request', 'RFC5805'),
'1.3.6.1.1.21.3': OidInfo('1.3.6.1.1.21.3', OID_EXTENSION, 'End Transaction Extended Request', 'RFC5805'),
'1.3.6.1.4.1.1466.101.119.1': OidInfo('1.3.6.1.4.1.1466.101.119.1', OID_EXTENSION, 'Dynamic Refresh', 'RFC2589'),
'1.3.6.1.4.1.1466.20037': OidInfo('1.3.6.1.4.1.1466.20037', OID_EXTENSION, 'StartTLS', 'RFC4511-RFC4513'),
'1.3.6.1.4.1.4203.1.11.1': OidInfo('1.3.6.1.4.1.4203.1.11.1', OID_EXTENSION, 'Modify Password', 'RFC3062'),
'1.3.6.1.4.1.4203.1.11.3': OidInfo('1.3.6.1.4.1.4203.1.11.3', OID_EXTENSION, 'Who am I', 'RFC4532'),
'1.3.6.1.1.17.1': OidInfo('1.3.6.1.1.17.1', OID_EXTENSION, 'StartLBURPRequest LDAP ExtendedRequest message', 'RFC4373'),
'1.3.6.1.1.17.2': OidInfo('1.3.6.1.1.17.2', OID_EXTENSION, 'StartLBURPResponse LDAP ExtendedResponse message', 'RFC4373'),
'1.3.6.1.1.17.3': OidInfo('1.3.6.1.1.17.3', OID_EXTENSION, 'EndLBURPRequest LDAP ExtendedRequest message', 'RFC4373'),
'1.3.6.1.1.17.4': OidInfo('1.3.6.1.1.17.4', OID_EXTENSION, 'EndLBURPResponse LDAP ExtendedResponse message', 'RFC4373'),
'1.3.6.1.1.17.5': OidInfo('1.3.6.1.1.17.5', OID_EXTENSION, 'LBURPUpdateRequest LDAP ExtendedRequest message', 'RFC4373'),
'1.3.6.1.1.17.6': OidInfo('1.3.6.1.1.17.6', OID_EXTENSION, 'LBURPUpdateResponse LDAP ExtendedResponse message', 'RFC4373'),
'1.3.6.1.1.19': OidInfo('1.3.6.1.1.19', OID_EXTENSION, 'LDAP Turn Operation', 'RFC4531'),
'1.3.6.1.4.1.26027.1.6.1': OidInfo('1.3.6.1.4.1.26027.1.6.1', OID_CONTROL, 'Password policy state', 'OpenDS'),
'1.3.6.1.4.1.26027.1.6.2': OidInfo('1.3.6.1.4.1.26027.1.6.2', OID_CONTROL, 'Get connection ID', 'OpenDS'),
'1.3.6.1.4.1.26027.1.6.3': OidInfo('1.3.6.1.4.1.26027.1.6.3', OID_CONTROL, 'Get symmetric key', 'OpenDS'),
'2.16.840.1.113719.1.14.100.1': OidInfo('2.16.840.1.113719.1.14.100.1', OID_EXTENSION, 'getDriverSetRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.2': OidInfo('2.16.840.1.113719.1.14.100.2', OID_EXTENSION, 'getDriverSetResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.3': OidInfo('2.16.840.1.113719.1.14.100.3', OID_EXTENSION, 'setDriverSetRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.4': OidInfo('2.16.840.1.113719.1.14.100.4', OID_EXTENSION, 'setDriverSetResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.5': OidInfo('2.16.840.1.113719.1.14.100.5', OID_EXTENSION, 'clearDriverSetRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.6': OidInfo('2.16.840.1.113719.1.14.100.6', OID_EXTENSION, 'clearDriverSetResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.7': OidInfo('2.16.840.1.113719.1.14.100.7', OID_EXTENSION, 'getDriverStartOptionRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.8': OidInfo('2.16.840.1.113719.1.14.100.8', OID_EXTENSION, 'getDriverStartOptionResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.9': OidInfo('2.16.840.1.113719.1.14.100.9', OID_EXTENSION, 'setDriverStartOptionRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.10': OidInfo('2.16.840.1.113719.1.14.100.10', OID_EXTENSION, 'setDriverStartOptionResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.11': OidInfo('2.16.840.1.113719.1.14.100.11', OID_EXTENSION, 'getVersionRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.12': OidInfo('2.16.840.1.113719.1.14.100.12', OID_EXTENSION, 'getVersionResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.13': OidInfo('2.16.840.1.113719.1.14.100.13', OID_EXTENSION, 'getDriverStateRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.14': OidInfo('2.16.840.1.113719.1.14.100.14', OID_EXTENSION, 'getDriverStateResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.15': OidInfo('2.16.840.1.113719.1.14.100.15', OID_EXTENSION, 'startDriverRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.16': OidInfo('2.16.840.1.113719.1.14.100.16', OID_EXTENSION, 'startDriverResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.17': OidInfo('2.16.840.1.113719.1.14.100.17', OID_EXTENSION, 'stopDriverRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.18': OidInfo('2.16.840.1.113719.1.14.100.18', OID_EXTENSION, 'stopDriverResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.19': OidInfo('2.16.840.1.113719.1.14.100.19', OID_EXTENSION, 'getDriverStatsRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.20': OidInfo('2.16.840.1.113719.1.14.100.20', OID_EXTENSION, 'getDriverStatsResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.21': OidInfo('2.16.840.1.113719.1.14.100.21', OID_EXTENSION, 'driverGetSchemaRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.22': OidInfo('2.16.840.1.113719.1.14.100.22', OID_EXTENSION, 'driverGetSchemaResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.23': OidInfo('2.16.840.1.113719.1.14.100.23', OID_EXTENSION, 'driverResyncRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.24': OidInfo('2.16.840.1.113719.1.14.100.24', OID_EXTENSION, 'driverResyncResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.25': OidInfo('2.16.840.1.113719.1.14.100.25', OID_EXTENSION, 'migrateAppRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.26': OidInfo('2.16.840.1.113719.1.14.100.26', OID_EXTENSION, 'migrateAppResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.27': OidInfo('2.16.840.1.113719.1.14.100.27', OID_EXTENSION, 'queueEventRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.28': OidInfo('2.16.840.1.113719.1.14.100.28', OID_EXTENSION, 'queueEventResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.29': OidInfo('2.16.840.1.113719.1.14.100.29', OID_EXTENSION, 'submitCommandRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.30': OidInfo('2.16.840.1.113719.1.14.100.30', OID_EXTENSION, 'submitCommandResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.31': OidInfo('2.16.840.1.113719.1.14.100.31', OID_EXTENSION, 'submitEventRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.32': OidInfo('2.16.840.1.113719.1.14.100.32', OID_EXTENSION, 'submitEventResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.33': OidInfo('2.16.840.1.113719.1.14.100.33', OID_EXTENSION, 'getChunkedResultRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.34': OidInfo('2.16.840.1.113719.1.14.100.34', OID_EXTENSION, 'getChunkedResultResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.35': OidInfo('2.16.840.1.113719.1.14.100.35', OID_EXTENSION, 'closeChunkedResultRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.36': OidInfo('2.16.840.1.113719.1.14.100.36', OID_EXTENSION, 'closeChunkedResultResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.37': OidInfo('2.16.840.1.113719.1.14.100.37', OID_EXTENSION, 'checkObjectPasswordRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.38': OidInfo('2.16.840.1.113719.1.14.100.38', OID_EXTENSION, 'checkObjectPasswordResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.39': OidInfo('2.16.840.1.113719.1.14.100.39', OID_EXTENSION, 'initDriverObjectRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.40': OidInfo('2.16.840.1.113719.1.14.100.40', OID_EXTENSION, 'initDriverObjectResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.41': OidInfo('2.16.840.1.113719.1.14.100.41', OID_EXTENSION, 'viewCacheEntriesRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.42': OidInfo('2.16.840.1.113719.1.14.100.42', OID_EXTENSION, 'viewCacheEntriesResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.43': OidInfo('2.16.840.1.113719.1.14.100.43', OID_EXTENSION, 'deleteCacheEntriesRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.44': OidInfo('2.16.840.1.113719.1.14.100.44', OID_EXTENSION, 'deleteCacheEntriesResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.45': OidInfo('2.16.840.1.113719.1.14.100.45', OID_EXTENSION, 'getPasswordsStateRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.46': OidInfo('2.16.840.1.113719.1.14.100.46', OID_EXTENSION, 'getPasswordsStateResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.47': OidInfo('2.16.840.1.113719.1.14.100.47', OID_EXTENSION, 'regenerateKeyRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.48': OidInfo('2.16.840.1.113719.1.14.100.48', OID_EXTENSION, 'regenerateKeyResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.49': OidInfo('2.16.840.1.113719.1.14.100.49', OID_EXTENSION, 'getServerCertRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.50': OidInfo('2.16.840.1.113719.1.14.100.50', OID_EXTENSION, 'getServerCertResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.51': OidInfo('2.16.840.1.113719.1.14.100.51', OID_EXTENSION, 'discoverJobsRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.52': OidInfo('2.16.840.1.113719.1.14.100.52', OID_EXTENSION, 'discoverJobsResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.53': OidInfo('2.16.840.1.113719.1.14.100.53', OID_EXTENSION, 'notifyJobUpdateRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.54': OidInfo('2.16.840.1.113719.1.14.100.54', OID_EXTENSION, 'notifyJobUpdateResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.55': OidInfo('2.16.840.1.113719.1.14.100.55', OID_EXTENSION, 'startJobRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.56': OidInfo('2.16.840.1.113719.1.14.100.56', OID_EXTENSION, 'startJobResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.57': OidInfo('2.16.840.1.113719.1.14.100.57', OID_EXTENSION, 'abortJobRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.58': OidInfo('2.16.840.1.113719.1.14.100.58', OID_EXTENSION, 'abortJobresponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.59': OidInfo('2.16.840.1.113719.1.14.100.59', OID_EXTENSION, 'getJobStateRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.60': OidInfo('2.16.840.1.113719.1.14.100.60', OID_EXTENSION, 'getJobStateResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.61': OidInfo('2.16.840.1.113719.1.14.100.61', OID_EXTENSION, 'checkJobConfigRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.62': OidInfo('2.16.840.1.113719.1.14.100.62', OID_EXTENSION, 'checkJobConfigResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.63': OidInfo('2.16.840.1.113719.1.14.100.63', OID_EXTENSION, 'setLogEventsRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.64': OidInfo('2.16.840.1.113719.1.14.100.64', OID_EXTENSION, 'setLogEventsResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.65': OidInfo('2.16.840.1.113719.1.14.100.65', OID_EXTENSION, 'clearLogEventsRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.66': OidInfo('2.16.840.1.113719.1.14.100.66', OID_EXTENSION, 'clearLogEventsResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.67': OidInfo('2.16.840.1.113719.1.14.100.67', OID_EXTENSION, 'setAppPasswordRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.68': OidInfo('2.16.840.1.113719.1.14.100.68', OID_EXTENSION, 'setAppPasswordResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.69': OidInfo('2.16.840.1.113719.1.14.100.69', OID_EXTENSION, 'clearAppPasswordRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.70': OidInfo('2.16.840.1.113719.1.14.100.70', OID_EXTENSION, 'clearAppPasswordResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.71': OidInfo('2.16.840.1.113719.1.14.100.71', OID_EXTENSION, 'setRemoteLoaderPasswordRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.72': OidInfo('2.16.840.1.113719.1.14.100.72', OID_EXTENSION, 'setRemoteLoaderPasswordResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.73': OidInfo('2.16.840.1.113719.1.14.100.73', OID_EXTENSION, 'clearRemoteLoaderPasswordRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.74': OidInfo('2.16.840.1.113719.1.14.100.74', OID_EXTENSION, 'clearRemoteLoaderPasswordResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.75': OidInfo('2.16.840.1.113719.1.14.100.75', OID_EXTENSION, 'setNamedPasswordRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.76': OidInfo('2.16.840.1.113719.1.14.100.76', OID_EXTENSION, 'setNamedPasswordResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.77': OidInfo('2.16.840.1.113719.1.14.100.77', OID_EXTENSION, 'removeNamedPasswordRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.78': OidInfo('2.16.840.1.113719.1.14.100.78', OID_EXTENSION, 'removeNamedPasswordResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.79': OidInfo('2.16.840.1.113719.1.14.100.79', OID_EXTENSION, 'removeAllNamedPasswordsRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.80': OidInfo('2.16.840.1.113719.1.14.100.80', OID_EXTENSION, 'removeAllNamedPasswordsResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.81': OidInfo('2.16.840.1.113719.1.14.100.81', OID_EXTENSION, 'listNamedPasswordsRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.82': OidInfo('2.16.840.1.113719.1.14.100.82', OID_EXTENSION, 'listNamedPasswordsResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.83': OidInfo('2.16.840.1.113719.1.14.100.83', OID_EXTENSION, 'getDefaultReciprocalAttrsMapRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.84': OidInfo('2.16.840.1.113719.1.14.100.84', OID_EXTENSION, 'getDefaultReciprocalAttrsMapResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.85': OidInfo('2.16.840.1.113719.1.14.100.85', OID_EXTENSION, 'resetDriverStatsRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.86': OidInfo('2.16.840.1.113719.1.14.100.86', OID_EXTENSION, 'resetDriverStatsResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.87': OidInfo('2.16.840.1.113719.1.14.100.87', OID_EXTENSION, 'regenerateAllKeysRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.88': OidInfo('2.16.840.1.113719.1.14.100.88', OID_EXTENSION, 'regenerateAllKeysResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.89': OidInfo('2.16.840.1.113719.1.14.100.89', OID_EXTENSION, 'getDriverGCVRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.90': OidInfo('2.16.840.1.113719.1.14.100.90', OID_EXTENSION, 'getDriverGCVResponse', 'NOVELL'),
'2.16.840.1.113719.1.14.100.91': OidInfo('2.16.840.1.113719.1.14.100.91', OID_EXTENSION, 'getNamedPasswordRequest', 'NOVELL'),
'2.16.840.1.113719.1.14.100.92': OidInfo('2.16.840.1.113719.1.14.100.92', OID_EXTENSION, 'getNamedPasswordResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.1': OidInfo('2.16.840.1.113719.1.27.100.1', OID_EXTENSION, 'ndsToLdapResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.2': OidInfo('2.16.840.1.113719.1.27.100.2', OID_EXTENSION, 'ndsToLdapRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.3': OidInfo('2.16.840.1.113719.1.27.100.3', OID_EXTENSION, 'splitPartitionRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.4': OidInfo('2.16.840.1.113719.1.27.100.4', OID_EXTENSION, 'splitPartitionResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.5': OidInfo('2.16.840.1.113719.1.27.100.5', OID_EXTENSION, 'mergePartitionRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.6': OidInfo('2.16.840.1.113719.1.27.100.6', OID_EXTENSION, 'mergePartitionResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.7': OidInfo('2.16.840.1.113719.1.27.100.7', OID_EXTENSION, 'addReplicaRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.8': OidInfo('2.16.840.1.113719.1.27.100.8', OID_EXTENSION, 'addReplicaResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.9': OidInfo('2.16.840.1.113719.1.27.100.9', OID_EXTENSION, 'refreshLDAPServerRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.10': OidInfo('2.16.840.1.113719.1.27.100.10', OID_EXTENSION, 'refreshLDAPServerResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.11': OidInfo('2.16.840.1.113719.1.27.100.11', OID_EXTENSION, 'removeReplicaRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.12': OidInfo('2.16.840.1.113719.1.27.100.12', OID_EXTENSION, 'removeReplicaResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.13': OidInfo('2.16.840.1.113719.1.27.100.13', OID_EXTENSION, 'partitionEntryCountRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.14': OidInfo('2.16.840.1.113719.1.27.100.14', OID_EXTENSION, 'partitionEntryCountResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.15': OidInfo('2.16.840.1.113719.1.27.100.15', OID_EXTENSION, 'changeReplicaTypeRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.16': OidInfo('2.16.840.1.113719.1.27.100.16', OID_EXTENSION, 'changeReplicaTypeResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.17': OidInfo('2.16.840.1.113719.1.27.100.17', OID_EXTENSION, 'getReplicaInfoRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.18': OidInfo('2.16.840.1.113719.1.27.100.18', OID_EXTENSION, 'getReplicaInfoResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.19': OidInfo('2.16.840.1.113719.1.27.100.19', OID_EXTENSION, 'listReplicaRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.20': OidInfo('2.16.840.1.113719.1.27.100.20', OID_EXTENSION, 'listReplicaResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.21': OidInfo('2.16.840.1.113719.1.27.100.21', OID_EXTENSION, 'receiveAllUpdatesRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.22': OidInfo('2.16.840.1.113719.1.27.100.22', OID_EXTENSION, 'receiveAllUpdatesResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.23': OidInfo('2.16.840.1.113719.1.27.100.23', OID_EXTENSION, 'sendAllUpdatesRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.24': OidInfo('2.16.840.1.113719.1.27.100.24', OID_EXTENSION, 'sendAllUpdatesResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.25': OidInfo('2.16.840.1.113719.1.27.100.25', OID_EXTENSION, 'requestPartitionSyncRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.26': OidInfo('2.16.840.1.113719.1.27.100.26', OID_EXTENSION, 'requestPartitionSyncResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.27': OidInfo('2.16.840.1.113719.1.27.100.27', OID_EXTENSION, 'requestSchemaSyncRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.28': OidInfo('2.16.840.1.113719.1.27.100.28', OID_EXTENSION, 'requestSchemaSyncResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.29': OidInfo('2.16.840.1.113719.1.27.100.29', OID_EXTENSION, 'abortPartitionOperationRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.30': OidInfo('2.16.840.1.113719.1.27.100.30', OID_EXTENSION, 'abortPartitionOperationResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.31': OidInfo('2.16.840.1.113719.1.27.100.31', OID_EXTENSION, 'getBindDNRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.32': OidInfo('2.16.840.1.113719.1.27.100.32', OID_EXTENSION, 'getBindDNResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.33': OidInfo('2.16.840.1.113719.1.27.100.33', OID_EXTENSION, 'getEffectivePrivilegesRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.34': OidInfo('2.16.840.1.113719.1.27.100.34', OID_EXTENSION, 'getEffectivePrivilegesResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.35': OidInfo('2.16.840.1.113719.1.27.100.35', OID_EXTENSION, 'setReplicationFilterRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.36': OidInfo('2.16.840.1.113719.1.27.100.36', OID_EXTENSION, 'setReplicationFilterResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.37': OidInfo('2.16.840.1.113719.1.27.100.37', OID_EXTENSION, 'getReplicationFilterRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.38': OidInfo('2.16.840.1.113719.1.27.100.38', OID_EXTENSION, 'getReplicationFilterResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.39': OidInfo('2.16.840.1.113719.1.27.100.39', OID_EXTENSION, 'splitOrphanPartitionRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.40': OidInfo('2.16.840.1.113719.1.27.100.40', OID_EXTENSION, 'splitOrphanPartitionResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.41': OidInfo('2.16.840.1.113719.1.27.100.41', OID_EXTENSION, 'removeOrphanPartitionRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.42': OidInfo('2.16.840.1.113719.1.27.100.42', OID_EXTENSION, 'removeOrphanPartitionResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.43': OidInfo('2.16.840.1.113719.1.27.100.43', OID_EXTENSION, 'triggerBKLinkerRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.44': OidInfo('2.16.840.1.113719.1.27.100.44', OID_EXTENSION, 'triggerBKLinkerResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.45': OidInfo('2.16.840.1.113719.1.27.100.45', OID_EXTENSION, 'triggerDRLProcessRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.46': OidInfo('2.16.840.1.113719.1.27.100.46', OID_EXTENSION, 'triggerDRLProcessResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.47': OidInfo('2.16.840.1.113719.1.27.100.47', OID_EXTENSION, 'triggerJanitorRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.48': OidInfo('2.16.840.1.113719.1.27.100.48', OID_EXTENSION, 'triggerJanitorResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.49': OidInfo('2.16.840.1.113719.1.27.100.49', OID_EXTENSION, 'triggerLimberRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.50': OidInfo('2.16.840.1.113719.1.27.100.50', OID_EXTENSION, 'triggerLimberResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.51': OidInfo('2.16.840.1.113719.1.27.100.51', OID_EXTENSION, 'triggerSkulkerRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.52': OidInfo('2.16.840.1.113719.1.27.100.52', OID_EXTENSION, 'triggerSkulkerResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.53': OidInfo('2.16.840.1.113719.1.27.100.53', OID_EXTENSION, 'triggerSchemaSyncRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.54': OidInfo('2.16.840.1.113719.1.27.100.54', OID_EXTENSION, 'triggerSchemaSyncResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.55': OidInfo('2.16.840.1.113719.1.27.100.55', OID_EXTENSION, 'triggerPartitionPurgeRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.56': OidInfo('2.16.840.1.113719.1.27.100.56', OID_EXTENSION, 'triggerPartitionPurgeResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.79': OidInfo('2.16.840.1.113719.1.27.100.79', OID_EXTENSION, 'eventMonitorRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.80': OidInfo('2.16.840.1.113719.1.27.100.80', OID_EXTENSION, 'eventMonitorResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.81': OidInfo('2.16.840.1.113719.1.27.100.81', OID_EXTENSION, 'nldapEventNotification', 'NOVELL'),
'2.16.840.1.113719.1.27.100.84': OidInfo('2.16.840.1.113719.1.27.100.84', OID_EXTENSION, 'filteredEventMonitorRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.85': OidInfo('2.16.840.1.113719.1.27.100.85', OID_EXTENSION, 'filteredEventMonitorResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.96': OidInfo('2.16.840.1.113719.1.27.100.96', OID_EXTENSION, 'ldapBackupRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.97': OidInfo('2.16.840.1.113719.1.27.100.97', OID_EXTENSION, 'ldapBackupResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.98': OidInfo('2.16.840.1.113719.1.27.100.98', OID_EXTENSION, 'ldapRestoreRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.99': OidInfo('2.16.840.1.113719.1.27.100.99', OID_EXTENSION, 'ldapRestoreResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.101': OidInfo('2.16.840.1.113719.1.27.100.101', OID_EXTENSION, 'LDAPDNStoX500DNRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.102': OidInfo('2.16.840.1.113719.1.27.100.102', OID_EXTENSION, 'LDAPDNStoX500DNResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.100.103': OidInfo('2.16.840.1.113719.1.27.100.103', OID_EXTENSION, 'getPrivilegesListRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.100.104': OidInfo('2.16.840.1.113719.1.27.100.104', OID_EXTENSION, 'getPrivilegesListResponse', 'NOVELL'),
'2.16.840.1.113719.1.27.103.1': OidInfo('2.16.840.1.113719.1.27.103.1', OID_EXTENSION, 'createGroupingRequest', 'NOVELL'),
'2.16.840.1.113719.1.27.103.2': OidInfo('2.16.840.1.113719.1.27.103.2', OID_EXTENSION, 'endGroupingRequest', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.1': OidInfo('2.16.840.1.113719.1.39.42.100.1', OID_EXTENSION, 'NMAS Put Login Configuration', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.3': OidInfo('2.16.840.1.113719.1.39.42.100.3', OID_EXTENSION, 'NMAS Get Login Configuration', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.5': OidInfo('2.16.840.1.113719.1.39.42.100.5', OID_EXTENSION, 'NMAS Delete Login Configuration', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.7': OidInfo('2.16.840.1.113719.1.49.42.100.7', OID_EXTENSION, 'NMAS Put Login Secret', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.9': OidInfo('2.16.840.1.113719.1.39.42.100.9', OID_EXTENSION, 'NMAS Delete Login Secret', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.11': OidInfo('2.16.840.1.113719.1.39.42.100.11', OID_EXTENSION, 'NMAS Set Universal Password', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.13': OidInfo('2.16.840.1.113719.1.39.42.100.13', OID_EXTENSION, 'NMAS Get Universal Password', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.15': OidInfo('2.16.840.1.113719.1.39.42.100.15', OID_EXTENSION, 'NMAS Delete Universal Password', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.17': OidInfo('2.16.840.1.113719.1.39.42.100.17', OID_EXTENSION, 'NMAS Check password against password policy', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.19': OidInfo('2.16.840.1.113719.1.39.42.100.19', OID_EXTENSION, 'NMAS Get password policy information', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.21': OidInfo('2.16.840.1.113719.1.39.42.100.21', OID_EXTENSION, 'NMAS Change Universal Password', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.23': OidInfo('2.16.840.1.113719.1.39.42.100.23', OID_EXTENSION, 'NMAS Graded Authentication management', 'NOVELL'),
'2.16.840.1.113719.1.39.42.100.25': OidInfo('2.16.840.1.113719.1.39.42.100.25', OID_EXTENSION, 'NMAS management (new with NMAS 3.1.0)', 'NOVELL'),
'2.16.840.1.113719.1.142.1.4.1': OidInfo('2.16.840.1.113719.1.142.1.4.1', OID_EXTENSION, 'LBURPIncUpdate', 'NOVELL'),
'2.16.840.1.113719.1.142.1.4.2': OidInfo('2.16.840.1.113719.1.142.1.4.2', OID_EXTENSION, 'LBURPFullUpdate', 'NOVELL'),
'2.16.840.1.113719.1.142.100.1': OidInfo('2.16.840.1.113719.1.142.100.1', OID_EXTENSION, 'LBURPStartReplRequest', 'NOVELL'),
'2.16.840.1.113719.1.142.100.2': OidInfo('2.16.840.1.113719.1.142.100.2', OID_EXTENSION, 'LBURPStartReplResponse', 'NOVELL'),
'2.16.840.1.113719.1.142.100.4': OidInfo('2.16.840.1.113719.1.142.100.4', OID_EXTENSION, 'LBURPEndReplRequest', 'NOVELL'),
'2.16.840.1.113719.1.142.100.5': OidInfo('2.16.840.1.113719.1.142.100.5', OID_EXTENSION, 'LBURPEndReplResponse', 'NOVELL'),
'2.16.840.1.113719.1.142.100.6': OidInfo('2.16.840.1.113719.1.142.100.6', OID_EXTENSION, 'LBURPOperationRequest', 'NOVELL'),
'2.16.840.1.113719.1.142.100.7': OidInfo('2.16.840.1.113719.1.142.100.7', OID_EXTENSION, 'LBURPOperationResponse', 'NOVELL'),
'2.16.840.1.113719.1.148.100.1': OidInfo('2.16.840.1.113719.1.148.100.1', OID_EXTENSION, 'SSLDAP_GET_SERVICE_INFO_REQUEST', 'NOVELL'),
'2.16.840.1.113719.1.148.100.2': OidInfo('2.16.840.1.113719.1.148.100.2', OID_EXTENSION, 'SSLDAP_GET_SERVICE_INFO_REPLY', 'NOVELL'),
'2.16.840.1.113719.1.148.100.3': OidInfo('2.16.840.1.113719.1.148.100.3', OID_EXTENSION, 'SSLDAP_READ_SECRET_REQUEST', 'NOVELL'),
'2.16.840.1.113719.1.148.100.4': OidInfo('2.16.840.1.113719.1.148.100.4', OID_EXTENSION, 'SSLDAP_READ_SECRET_REPLY', 'NOVELL'),
'2.16.840.1.113719.1.148.100.5': OidInfo('2.16.840.1.113719.1.148.100.5', OID_EXTENSION, 'SSLDAP_WRITE_SECRET_REQUEST', 'NOVELL'),
'2.16.840.1.113719.1.148.100.6': OidInfo('2.16.840.1.113719.1.148.100.6', OID_EXTENSION, 'SSLDAP_WRITE_SECRET_REPLY', 'NOVELL'),
'2.16.840.1.113719.1.148.100.7': OidInfo('2.16.840.1.113719.1.148.100.7', OID_EXTENSION, 'SSLDAP_ADD_SECRET_ID_REQUEST', 'NOVELL'),
'2.16.840.1.113719.1.148.100.8': OidInfo('2.16.840.1.113719.1.148.100.8', OID_EXTENSION, 'SSLDAP_ADD_SECRET_ID_REPLY', 'NOVELL'),
'2.16.840.1.113719.1.148.100.9': OidInfo('2.16.840.1.113719.1.148.100.9', OID_EXTENSION, 'SSLDAP_REMOVE_SECRET_REQUEST', 'NOVELL'),
'2.16.840.1.113719.1.148.100.10': OidInfo('2.16.840.1.113719.1.148.100.10', OID_EXTENSION, 'SSLDAP_REMOVE_SECRET_REPLY', 'NOVELL'),
'2.16.840.1.113719.1.148.100.11': OidInfo('2.16.840.1.113719.1.148.100.11', OID_EXTENSION, 'SSLDAP_REMOVE_SECRET_STORE_REQUEST', 'NOVELL'),
'2.16.840.1.113719.1.148.100.12': OidInfo('2.16.840.1.113719.1.148.100.12', OID_EXTENSION, 'SSLDAP_REMOVE_SECRET_STORE_REPLY', 'NOVELL'),
'2.16.840.1.113719.1.148.100.13': OidInfo('2.16.840.1.113719.1.148.100.13', OID_EXTENSION, 'SSLDAP_ENUMERATE_SECRET_IDS_REQUEST', 'NOVELL'),
'2.16.840.1.113719.1.148.100.14': OidInfo('2.16.840.1.113719.1.148.100.14', OID_EXTENSION, 'SSLDAP_ENUMERATE_SECRET_IDS_REPLY', 'NOVELL'),
'2.16.840.1.113719.1.148.100.15': OidInfo('2.16.840.1.113719.1.148.100.15', OID_EXTENSION, 'SSLDAP_UNLOCK_SECRETS_REQUEST', 'NOVELL'),
'2.16.840.1.113719.1.148.100.16': OidInfo('2.16.840.1.113719.1.148.100.16', OID_EXTENSION, 'SSLDAP_UNLOCK_SECRETS_REPLY', 'NOVELL'),
'2.16.840.1.113719.1.148.100.17': OidInfo('2.16.840.1.113719.1.148.100.17', OID_EXTENSION, 'SSLDAP_SET_EP_MASTER_PASSWORD_REQUEST', 'NOVELL'),
'2.16.840.1.113719.1.148.100.18': OidInfo('2.16.840.1.113719.1.148.100.18', OID_EXTENSION, 'SSLDAP_SET_EP_MASTER_PASSWORD_REPLY', 'NOVELL'),
# features (capabilities)
'1.2.840.113556.1.4.800': OidInfo('1.2.840.113556.1.4.800', OID_FEATURE, 'Active directory', 'MICROSOFT'), '1.2.840.113556.1.4.1670': OidInfo('1.2.840.113556.1.4.1670', OID_FEATURE, 'Active directory V51', 'MICROSOFT'),
'1.2.840.113556.1.4.1791': OidInfo('1.2.840.113556.1.4.1791', OID_FEATURE, 'Active directory LDAP Integration', 'MICROSOFT'),
'1.2.840.113556.1.4.1880': OidInfo('1.2.840.113556.1.4.1880', OID_FEATURE, 'Active directory ADAM digest', 'MICROSOFT'), '1.2.840.113556.1.4.1851': OidInfo('1.2.840.113556.1.4.1851', OID_FEATURE, 'Active directory ADAM', 'MICROSOFT'),
'1.2.840.113556.1.4.1920': OidInfo('1.2.840.113556.1.4.1920', OID_FEATURE, 'Active directory partial secrets', 'MICROSOFT'), '1.2.840.113556.1.4.1935': OidInfo('1.2.840.113556.1.4.1935', OID_FEATURE, 'Active directory V60', 'MICROSOFT'),
'1.2.840.113556.1.4.2080': OidInfo('1.2.840.113556.1.4.2080', OID_FEATURE, 'Active directory V61 R2', 'MICROSOFT'), '1.2.840.113556.1.4.2237': OidInfo('1.2.840.113556.1.4.2237', OID_FEATURE, 'Active directory W8', 'MICROSOFT'),
'1.3.6.1.1.14': OidInfo('1.3.6.1.1.14', OID_FEATURE, 'Modify-Increment', 'RFC4525'), '1.3.6.1.1.17.7': OidInfo('1.3.6.1.1.17.7', OID_FEATURE, 'LBURP Incremental Update style OID', 'RFC4373'),
'1.3.6.1.4.1.4203.1.5.1': OidInfo('1.3.6.1.4.1.4203.1.5.1', OID_FEATURE, 'All Op Attrs', 'RFC3673'), '1.3.6.1.4.1.4203.1.5.2': OidInfo('1.3.6.1.4.1.4203.1.5.2', OID_FEATURE, 'OC AD Lists', 'RFC4529'),
'1.3.6.1.4.1.4203.1.5.3': OidInfo('1.3.6.1.4.1.4203.1.5.3', OID_FEATURE, 'True/False filters', 'RFC4526'), '1.3.6.1.4.1.4203.1.5.4': OidInfo('1.3.6.1.4.1.4203.1.5.4', OID_FEATURE, 'Language Tag Options', 'RFC3866'),
'1.3.6.1.4.1.4203.1.5.5': OidInfo('1.3.6.1.4.1.4203.1.5.5', OID_FEATURE, 'language Range Options', 'RFC3866'), '2.16.840.1.113719.1.27.99.1': OidInfo('2.16.840.1.113719.1.27.99.1', OID_FEATURE, 'Superior References', 'NOVELL'),
# ldap syntaxes
'1.3.6.1.1.16.1': OidInfo('1.3.6.1.1.16.1', OID_LDAP_SYNTAX, 'UUID', 'RFC4530'), '1.3.6.1.4.1.1466.115.121.1.3': OidInfo('1.3.6.1.4.1.1466.115.121.1.3', OID_LDAP_SYNTAX, 'Attribute Type Description', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.6': OidInfo('1.3.6.1.4.1.1466.115.121.1.6', OID_LDAP_SYNTAX, 'Bit String', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.7': OidInfo('1.3.6.1.4.1.1466.115.121.1.7', OID_LDAP_SYNTAX, 'Boolean', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.11': OidInfo('1.3.6.1.4.1.1466.115.121.1.11', OID_LDAP_SYNTAX, 'Country String', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.12': OidInfo('1.3.6.1.4.1.1466.115.121.1.12', OID_LDAP_SYNTAX, 'DN', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.14': OidInfo('1.3.6.1.4.1.1466.115.121.1.14', OID_LDAP_SYNTAX, 'Delivery Method', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.15': OidInfo('1.3.6.1.4.1.1466.115.121.1.15', OID_LDAP_SYNTAX, 'Directory String', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.16': OidInfo('1.3.6.1.4.1.1466.115.121.1.16', OID_LDAP_SYNTAX, 'DIT Content Rule Description', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.17': OidInfo('1.3.6.1.4.1.1466.115.121.1.17', OID_LDAP_SYNTAX, 'DIT Structure Rule Description', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.21': OidInfo('1.3.6.1.4.1.1466.115.121.1.21', OID_LDAP_SYNTAX, 'Enhanced Guide', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.22': OidInfo('1.3.6.1.4.1.1466.115.121.1.22', OID_LDAP_SYNTAX, 'Facsimile Telephone Number', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.23': OidInfo('1.3.6.1.4.1.1466.115.121.1.23', OID_LDAP_SYNTAX, 'Fax', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.24': OidInfo('1.3.6.1.4.1.1466.115.121.1.24', OID_LDAP_SYNTAX, 'Generalized Time', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.25': OidInfo('1.3.6.1.4.1.1466.115.121.1.25', OID_LDAP_SYNTAX, 'Guide', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.26': OidInfo('1.3.6.1.4.1.1466.115.121.1.26', OID_LDAP_SYNTAX, 'IA5 String', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.27': OidInfo('1.3.6.1.4.1.1466.115.121.1.27', OID_LDAP_SYNTAX, 'Integer', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.28': OidInfo('1.3.6.1.4.1.1466.115.121.1.28', OID_LDAP_SYNTAX, 'JPEG', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.30': OidInfo('1.3.6.1.4.1.1466.115.121.1.30', OID_LDAP_SYNTAX, 'Matching Rule Description', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.31': OidInfo('1.3.6.1.4.1.1466.115.121.1.31', OID_LDAP_SYNTAX, 'Matching Rule Use Description', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.34': OidInfo('1.3.6.1.4.1.1466.115.121.1.34', OID_LDAP_SYNTAX, 'Name And Optional UID', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.35': OidInfo('1.3.6.1.4.1.1466.115.121.1.35', OID_LDAP_SYNTAX, 'Name Form Description', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.36': OidInfo('1.3.6.1.4.1.1466.115.121.1.36', OID_LDAP_SYNTAX, 'Numeric String', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.37': OidInfo('1.3.6.1.4.1.1466.115.121.1.37', OID_LDAP_SYNTAX, 'Object Class Description', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.38': OidInfo('1.3.6.1.4.1.1466.115.121.1.38', OID_LDAP_SYNTAX, 'OID', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.39': OidInfo('1.3.6.1.4.1.1466.115.121.1.39', OID_LDAP_SYNTAX, 'Other Mailbox', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.40': OidInfo('1.3.6.1.4.1.1466.115.121.1.40', OID_LDAP_SYNTAX, 'Octet String', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.41': OidInfo('1.3.6.1.4.1.1466.115.121.1.41', OID_LDAP_SYNTAX, 'Postal Address', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.44': OidInfo('1.3.6.1.4.1.1466.115.121.1.44', OID_LDAP_SYNTAX, 'Printable String', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.50': OidInfo('1.3.6.1.4.1.1466.115.121.1.50', OID_LDAP_SYNTAX, 'Telephone Number', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.51': OidInfo('1.3.6.1.4.1.1466.115.121.1.52', OID_LDAP_SYNTAX, 'Teletex Terminal Identifier', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.52': OidInfo('1.3.6.1.4.1.1466.115.121.1.52', OID_LDAP_SYNTAX, 'Telex Number', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.53': OidInfo('1.3.6.1.4.1.1466.115.121.1.53', OID_LDAP_SYNTAX, 'UTC Time', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.54': OidInfo('1.3.6.1.4.1.1466.115.121.1.54', OID_LDAP_SYNTAX, 'LDAP Syntax Description', 'RFC4517'),
'1.3.6.1.4.1.1466.115.121.1.58': OidInfo('1.3.6.1.4.1.1466.115.121.1.58', OID_LDAP_SYNTAX, 'Substring Assertion', 'RFC4517'),
# ldap url extensions
# matching rules
'1.2.36.79672281.1.13.2': OidInfo('1.2.36.79672281.1.13.2', OID_MATCHING_RULE, 'componentFilterMatch', 'RFC3687'), '1.2.36.79672281.1.13.3': OidInfo('1.2.36.79672281.1.13.3', OID_MATCHING_RULE, 'rdnMatch', 'RFC3687'),
'1.2.36.79672281.1.13.5': OidInfo('1.2.36.79672281.1.13.5', OID_MATCHING_RULE, 'presentMatch', 'RFC3687'), '1.2.36.79672281.1.13.6': OidInfo('1.2.36.79672281.1.13.6', OID_MATCHING_RULE, 'allComponentsMatch', 'RFC3687'),
'1.2.36.79672281.1.13.7': OidInfo('1.2.36.79672281.1.13.7', OID_MATCHING_RULE, 'directoryComponentsMatch', 'RFC3687'), '1.2.840.113556.1.4.803': OidInfo('1.2.840.113556.1.4.803', OID_MATCHING_RULE, 'Bit AND', 'MICROSOFT'),
'1.2.840.113556.1.4.804': OidInfo('1.2.840.113556.1.4.804', OID_MATCHING_RULE, 'Bit OR', 'MICROSOFT'), '1.2.840.113556.1.4.1941': OidInfo('1.2.840.113556.1.4.1941', OID_MATCHING_RULE, 'Transitive Evaluation', 'MICROSOFT'),
'1.2.840.113556.1.4.2253': OidInfo('1.2.840.113556.1.4.2253', OID_MATCHING_RULE, 'DN with data', 'MICROSOFT'), '1.3.6.1.1.16.2': OidInfo('1.3.6.1.1.16.2', OID_MATCHING_RULE, 'uuidMatch', 'RFC4530'),
'1.3.6.1.1.16.3': OidInfo('1.3.6.1.1.16.3', OID_MATCHING_RULE, 'uuidOrderingMatch', 'RFC4530'), '1.3.6.1.4.1.1466.109.114.1': OidInfo('1.3.6.1.4.1.1466.109.114.1', OID_MATCHING_RULE, 'caseExactIA5Match', 'RFC4517'),
'1.3.6.1.4.1.1466.109.114.2': OidInfo('1.3.6.1.4.1.1466.109.114.2', OID_MATCHING_RULE, 'caseIgnoreIA5Match', 'RFC4517'),
'1.3.6.1.4.1.1466.109.114.3': OidInfo('1.3.6.1.4.1.1466.109.114.3', OID_MATCHING_RULE, 'caseIgnoreIA5SubstringsMatch', 'RFC4517'), '2.5.13.0': OidInfo('2.5.13.0', OID_MATCHING_RULE, 'objectIdentifierMatch', 'RFC4517'),
'2.5.13.1': OidInfo('2.5.13.1', OID_MATCHING_RULE, 'distinguishedNameMatch', 'RFC4517'), '2.5.13.2': OidInfo('2.5.13.2', OID_MATCHING_RULE, 'caseIgnoreMatch', 'RFC4517'),
'2.5.13.3': OidInfo('2.5.13.3', OID_MATCHING_RULE, 'caseIgnoreOrderingMatch', 'RFC4517'), '2.5.13.4': OidInfo('2.5.13.4', OID_MATCHING_RULE, 'caseIgnoreSubstringsMatch', 'RFC4517'),
'2.5.13.5': OidInfo('2.5.13.5', OID_MATCHING_RULE, 'caseExactMatch', 'RFC4517'), '2.5.13.6': OidInfo('2.5.13.6', OID_MATCHING_RULE, 'caseExactOrderingMatch', 'RFC4517'),
'2.5.13.7': OidInfo('2.5.13.7', OID_MATCHING_RULE, 'caseExactSubstringsMatch', 'RFC4517'), '2.5.13.8': OidInfo('2.5.13.8', OID_MATCHING_RULE, 'numericStringMatch', 'RFC4517'),
'2.5.13.9': OidInfo('2.5.13.9', OID_MATCHING_RULE, 'numericStringOrderingMatch', 'RFC4517'), '2.5.13.10': OidInfo('2.5.13.10', OID_MATCHING_RULE, 'numericStringSubstringsMatch', 'RFC4517'),
'2.5.13.11': OidInfo('2.5.13.11', OID_MATCHING_RULE, 'caseIgnoreListMatch', 'RFC4517'), '2.5.13.12': OidInfo('2.5.13.12', OID_MATCHING_RULE, 'caseIgnoreListSubstringsMatch', 'RFC4517'),
'2.5.13.13': OidInfo('2.5.13.13', OID_MATCHING_RULE, 'booleanMatch', 'RFC4517'), '2.5.13.14': OidInfo('2.5.13.14', OID_MATCHING_RULE, 'integerMatch', 'RFC4517'),
'2.5.13.15': OidInfo('2.5.13.15', OID_MATCHING_RULE, 'integerOrderingMatch', 'RFC4517'), '2.5.13.16': OidInfo('2.5.13.16', OID_MATCHING_RULE, 'bitStringMatch', 'RFC4517'),
'2.5.13.17': OidInfo('2.5.13.17', OID_MATCHING_RULE, 'octetStringMatch', 'RFC4517'), '2.5.13.18': OidInfo('2.5.13.18', OID_MATCHING_RULE, 'octetStringOrderingMatch', 'RFC4517'),
'2.5.13.20': OidInfo('2.5.13.20', OID_MATCHING_RULE, 'telephoneNumberMatch', 'RFC4517'), '2.5.13.21': OidInfo('2.5.13.21', OID_MATCHING_RULE, 'telephoneNumberSubstringsMatch', 'RFC4517'),
'2.5.13.22': OidInfo('2.5.13.22', OID_MATCHING_RULE, 'presentationAddressMatch', 'RFC2252'), '2.5.13.23': OidInfo('2.5.13.23', OID_MATCHING_RULE, 'uniqueMemberMatch', 'RFC4517'),
'2.5.13.24': OidInfo('2.5.13.24', OID_MATCHING_RULE, 'protocolInformationMatch', 'RFC2252'), '2.5.13.27': OidInfo('2.5.13.27', OID_MATCHING_RULE, 'generalizedTimeMatch', 'RFC4517'),
'2.5.13.28': OidInfo('2.5.13.28', OID_MATCHING_RULE, 'generalizedTimeOrderingMatch', 'RFC4517'), '2.5.13.29': OidInfo('2.5.13.29', OID_MATCHING_RULE, 'integerFirstComponentMatch', 'RFC4517'),
'2.5.13.30': OidInfo('2.5.13.30', OID_MATCHING_RULE, 'objectIdentifierFirstComponentMatch', 'RFC4517'), '2.5.13.31': OidInfo('2.5.13.31', OID_MATCHING_RULE, 'directoryStringFirstComponentMatch', 'RFC4517'),
'2.5.13.32': OidInfo('2.5.13.32', OID_MATCHING_RULE, 'wordMatch', 'RFC4517'), '2.5.13.33': OidInfo('2.5.13.33', OID_MATCHING_RULE, 'keywordMatch', 'RFC4517'),
'2.5.13.34': OidInfo('2.5.13.34', OID_MATCHING_RULE, 'certificateExactMatch', 'RFC4523'), '2.5.13.35': OidInfo('2.5.13.35', OID_MATCHING_RULE, 'certificateMatch', 'RFC4523'),
'2.5.13.36': OidInfo('2.5.13.36', OID_MATCHING_RULE, 'certificatePairExactMatch', 'RFC4523'), '2.5.13.37': OidInfo('2.5.13.37', OID_MATCHING_RULE, 'certificatePairMatch', 'RFC4523'),
'2.5.13.38': OidInfo('2.5.13.38', OID_MATCHING_RULE, 'certificateListExactMatch', 'RFC4523'), '2.5.13.39': OidInfo('2.5.13.39', OID_MATCHING_RULE, 'certificateListMatch', 'RFC4523'),
'2.5.13.40': OidInfo('2.5.13.40', OID_MATCHING_RULE, 'algorithmIdentifierMatch', 'RFC4523'), '2.5.13.41': OidInfo('2.5.13.41', OID_MATCHING_RULE, 'storedPrefixMatch', 'RFC3698'),
# name forms
'1.3.6.1.1.10.15.1': OidInfo('1.3.6.1.1.10.15.1', OID_NAME_FORM, 'uddiBusinessEntityNameForm', 'RFC4403'), '1.3.6.1.1.10.15.2': OidInfo('1.3.6.1.1.10.15.2', OID_NAME_FORM, 'uddiContactNameForm', 'RFC4403'),
'1.3.6.1.1.10.15.3': OidInfo('1.3.6.1.1.10.15.3', OID_NAME_FORM, 'uddiAddressNameForm', 'RFC4403'), '1.3.6.1.1.10.15.4': OidInfo('1.3.6.1.1.10.15.4', OID_NAME_FORM, 'uddiBusinessServiceNameForm', 'RFC4403'),
'1.3.6.1.1.10.15.5': OidInfo('1.3.6.1.1.10.15.5', OID_NAME_FORM, 'uddiBindingTemplateNameForm', 'RFC4403'), '1.3.6.1.1.10.15.6': OidInfo('1.3.6.1.1.10.15.6', OID_NAME_FORM, 'uddiTModelInstanceInfoNameForm', 'RFC4403'),
'1.3.6.1.1.10.15.7': OidInfo('1.3.6.1.1.10.15.7', OID_NAME_FORM, 'uddiTModelNameForm', 'RFC4403'), '1.3.6.1.1.10.15.8': OidInfo('1.3.6.1.1.10.15.8', OID_NAME_FORM, 'uddiPublisherAssertionNameForm', 'RFC4403'),
'1.3.6.1.1.10.15.9': OidInfo('1.3.6.1.1.10.15.9', OID_NAME_FORM, 'uddiv3SubscriptionNameForm', 'RFC4403'), '1.3.6.1.1.10.15.10': OidInfo('1.3.6.1.1.10.15.10', OID_NAME_FORM, 'uddiv3EntityObituaryNameForm', 'RFC4403'),
'1.3.6.1.4.1.1466.345': OidInfo('1.3.6.1.4.1.1466.345', OID_NAME_FORM, 'domainNameForm', 'RFC2247'),
# object classes
'0.9.2342.19200300.100.4.3': OidInfo('0.9.2342.19200300.100.4.3', OID_OBJECT_CLASS, 'pilotObject', 'RFC1274'), '0.9.2342.19200300.100.4.4': OidInfo('0.9.2342.19200300.100.4.4', OID_OBJECT_CLASS, 'pilotPerson', 'RFC1274'),
'0.9.2342.19200300.100.4.5': OidInfo('0.9.2342.19200300.100.4.5', OID_OBJECT_CLASS, 'account', 'RFC4524'), '0.9.2342.19200300.100.4.6': OidInfo('0.9.2342.19200300.100.4.6', OID_OBJECT_CLASS, 'document', 'RFC4524'),
'0.9.2342.19200300.100.4.7': OidInfo('0.9.2342.19200300.100.4.7', OID_OBJECT_CLASS, 'room', 'RFC4524'), '0.9.2342.19200300.100.4.8': OidInfo('0.9.2342.19200300.100.4.8', OID_OBJECT_CLASS, 'documentSeries', 'RFC4524'),
'0.9.2342.19200300.100.4.13': OidInfo('0.9.2342.19200300.100.4.13', OID_OBJECT_CLASS, 'domain', 'RFC4524'), '0.9.2342.19200300.100.4.14': OidInfo('0.9.2342.19200300.100.4.14', OID_OBJECT_CLASS, 'RFC822LocalPart', 'RFC4524'),
'0.9.2342.19200300.100.4.15': OidInfo('0.9.2342.19200300.100.4.15', OID_OBJECT_CLASS, 'dNSDomain', 'RFC1274'), '0.9.2342.19200300.100.4.17': OidInfo('0.9.2342.19200300.100.4.17', OID_OBJECT_CLASS, 'domainRelatedObject', 'RFC4524'),
'0.9.2342.19200300.100.4.18': OidInfo('0.9.2342.19200300.100.4.18', OID_OBJECT_CLASS, 'friendlyCountry', 'RFC4524'), '0.9.2342.19200300.100.4.19': OidInfo('0.9.2342.19200300.100.4.19', OID_OBJECT_CLASS, 'simpleSecurityObject', 'RFC4524'),
'0.9.2342.19200300.100.4.20': OidInfo('0.9.2342.19200300.100.4.20', OID_OBJECT_CLASS, 'pilotOrganization', 'RFC1274'), '0.9.2342.19200300.100.4.21': OidInfo('0.9.2342.19200300.100.4.21', OID_OBJECT_CLASS, 'pilotDSA', 'RFC1274'),
'0.9.2342.19200300.100.4.22': OidInfo('0.9.2342.19200300.100.4.22', OID_OBJECT_CLASS, 'qualityLabelledData', 'RFC1274'), '1.2.840.113556.1.5.87': OidInfo('1.2.840.113556.1.5.87', OID_OBJECT_CLASS, 'calEntry', 'RFC2739'),
'1.3.18.0.2.6.253': OidInfo('1.3.18.0.2.6.253', OID_OBJECT_CLASS, 'printerLPR', 'RFC3712'), '1.3.18.0.2.6.254': OidInfo('1.3.18.0.2.6.254', OID_OBJECT_CLASS, 'slpServicePrinter', 'RFC3712'),
'1.3.18.0.2.6.255': OidInfo('1.3.18.0.2.6.255', OID_OBJECT_CLASS, 'printerService', 'RFC3712'), '1.3.18.0.2.6.256': OidInfo('1.3.18.0.2.6.256', OID_OBJECT_CLASS, 'printerIPP', 'RFC3712'),
'1.3.18.0.2.6.257': OidInfo('1.3.18.0.2.6.257', OID_OBJECT_CLASS, 'printerServiceAuxClass', 'RFC3712'), '1.3.18.0.2.6.258': OidInfo('1.3.18.0.2.6.258', OID_OBJECT_CLASS, 'printerAbstract', 'RFC3712'),
'1.3.6.1.1.10.6.1': OidInfo('1.3.6.1.1.10.6.1', OID_OBJECT_CLASS, 'uddiBusinessEntity', 'RFC4403'), '1.3.6.1.1.10.6.2': OidInfo('1.3.6.1.1.10.6.2', OID_OBJECT_CLASS, 'uddiContact', 'RFC4403'),
'1.3.6.1.1.10.6.3': OidInfo('1.3.6.1.1.10.6.3', OID_OBJECT_CLASS, 'uddiAddress', 'RFC4403'), '1.3.6.1.1.10.6.4': OidInfo('1.3.6.1.1.10.6.4', OID_OBJECT_CLASS, 'uddiBusinessService', 'RFC4403'),
'1.3.6.1.1.10.6.5': OidInfo('1.3.6.1.1.10.6.5', OID_OBJECT_CLASS, 'uddiBindingTemplate', 'RFC4403'), '1.3.6.1.1.10.6.6': OidInfo('1.3.6.1.1.10.6.6', OID_OBJECT_CLASS, 'uddiTModelInstanceInfo', 'RFC4403'),
'1.3.6.1.1.10.6.7': OidInfo('1.3.6.1.1.10.6.7', OID_OBJECT_CLASS, 'uddiTModel', 'RFC4403'), '1.3.6.1.1.10.6.8': OidInfo('1.3.6.1.1.10.6.8', OID_OBJECT_CLASS, 'uddiPublisherAssertion', 'RFC4403'),
'1.3.6.1.1.10.6.9': OidInfo('1.3.6.1.1.10.6.9', OID_OBJECT_CLASS, 'uddiv3Subscription', 'RFC4403'), '1.3.6.1.1.10.6.10': OidInfo('1.3.6.1.1.10.6.10', OID_OBJECT_CLASS, 'uddiv3EntityObituary', 'RFC4403'),
'1.3.6.1.1.11.1.1': OidInfo('1.3.6.1.1.11.1.1', OID_OBJECT_CLASS, 'vPIMUser', 'RFC4237'), '1.3.6.1.1.3.1': OidInfo('1.3.6.1.1.3.1', OID_OBJECT_CLASS, 'uidObject', 'RFC4519'),
'1.3.6.1.1.6.1.1': OidInfo('1.3.6.1.1.6.1.1', OID_OBJECT_CLASS, 'pcimPolicy', 'RFC3703'), '1.3.6.1.1.6.1.2': OidInfo('1.3.6.1.1.6.1.2', OID_OBJECT_CLASS, 'pcimGroup', 'RFC3703'),
'1.3.6.1.1.6.1.3': OidInfo('1.3.6.1.1.6.1.3', OID_OBJECT_CLASS, 'pcimGroupAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.4': OidInfo('1.3.6.1.1.6.1.4', OID_OBJECT_CLASS, 'pcimGroupInstance', 'RFC3703'),
'1.3.6.1.1.6.1.5': OidInfo('1.3.6.1.1.6.1.5', OID_OBJECT_CLASS, 'pcimRule', 'RFC3703'), '1.3.6.1.1.6.1.6': OidInfo('1.3.6.1.1.6.1.6', OID_OBJECT_CLASS, 'pcimRuleAuxClass', 'RFC3703'),
'1.3.6.1.1.6.1.7': OidInfo('1.3.6.1.1.6.1.7', OID_OBJECT_CLASS, 'pcimRuleInstance', 'RFC3703'), '1.3.6.1.1.6.1.8': OidInfo('1.3.6.1.1.6.1.8', OID_OBJECT_CLASS, 'pcimRuleConditionAssociation', 'RFC3703'),
'1.3.6.1.1.6.1.9': OidInfo('1.3.6.1.1.6.1.9', OID_OBJECT_CLASS, 'pcimRuleValidityAssociation', 'RFC3703'), '1.3.6.1.1.6.1.10': OidInfo('1.3.6.1.1.6.1.10', OID_OBJECT_CLASS, 'pcimRuleActionAssociation', 'RFC3703'),
'1.3.6.1.1.6.1.11': OidInfo('1.3.6.1.1.6.1.11', OID_OBJECT_CLASS, 'pcimConditionAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.12': OidInfo('1.3.6.1.1.6.1.12', OID_OBJECT_CLASS, 'pcimTPCAuxClass', 'RFC3703'),
'1.3.6.1.1.6.1.13': OidInfo('1.3.6.1.1.6.1.13', OID_OBJECT_CLASS, 'pcimConditionVendorAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.14': OidInfo('1.3.6.1.1.6.1.14', OID_OBJECT_CLASS, 'pcimActionAuxClass', 'RFC3703'),
'1.3.6.1.1.6.1.15': OidInfo('1.3.6.1.1.6.1.15', OID_OBJECT_CLASS, 'pcimActionVendorAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.16': OidInfo('1.3.6.1.1.6.1.16', OID_OBJECT_CLASS, 'pcimPolicyInstance', 'RFC3703'),
'1.3.6.1.1.6.1.17': OidInfo('1.3.6.1.1.6.1.17', OID_OBJECT_CLASS, 'pcimElementAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.18': OidInfo('1.3.6.1.1.6.1.18', OID_OBJECT_CLASS, 'pcimRepository', 'RFC3703'),
'1.3.6.1.1.6.1.19': OidInfo('1.3.6.1.1.6.1.19', OID_OBJECT_CLASS, 'pcimRepositoryAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.20': OidInfo('1.3.6.1.1.6.1.20', OID_OBJECT_CLASS, 'pcimRepositoryInstance', 'RFC3703'),
'1.3.6.1.1.6.1.21': OidInfo('1.3.6.1.1.6.1.21', OID_OBJECT_CLASS, 'pcimSubtreesPtrAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.22': OidInfo('1.3.6.1.1.6.1.22', OID_OBJECT_CLASS, 'pcimGroupContainmentAuxClass', 'RFC3703'),
'1.3.6.1.1.6.1.23': OidInfo('1.3.6.1.1.6.1.23', OID_OBJECT_CLASS, 'pcimRuleContainmentAuxClass', 'RFC3703'), '1.3.6.1.1.9.1.1': OidInfo('1.3.6.1.1.9.1.1', OID_OBJECT_CLASS, 'pcelsPolicySet', 'RFC4104'),
'1.3.6.1.1.9.1.2': OidInfo('1.3.6.1.1.9.1.2', OID_OBJECT_CLASS, 'pcelsPolicySetAssociation', 'RFC4104'), '1.3.6.1.1.9.1.3': OidInfo('1.3.6.1.1.9.1.3', OID_OBJECT_CLASS, 'pcelsGroup', 'RFC4104'),
'1.3.6.1.1.9.1.4': OidInfo('1.3.6.1.1.9.1.4', OID_OBJECT_CLASS, 'pcelsGroupAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.5': OidInfo('1.3.6.1.1.9.1.5', OID_OBJECT_CLASS, 'pcelsGroupInstance', 'RFC4104'),
'1.3.6.1.1.9.1.6': OidInfo('1.3.6.1.1.9.1.6', OID_OBJECT_CLASS, 'pcelsRule', 'RFC4104'), '1.3.6.1.1.9.1.7': OidInfo('1.3.6.1.1.9.1.7', OID_OBJECT_CLASS, 'pcelsRuleAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.8': OidInfo('1.3.6.1.1.9.1.8', OID_OBJECT_CLASS, 'pcelsRuleInstance', 'RFC4104'), '1.3.6.1.1.9.1.9': OidInfo('1.3.6.1.1.9.1.9', OID_OBJECT_CLASS, 'pcelsConditionAssociation', 'RFC4104'),
'1.3.6.1.1.9.1.10': OidInfo('1.3.6.1.1.9.1.10', OID_OBJECT_CLASS, 'pcelsActionAssociation', 'RFC4104'), '1.3.6.1.1.9.1.11': OidInfo('1.3.6.1.1.9.1.11', OID_OBJECT_CLASS, 'pcelsSimpleConditionAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.12': OidInfo('1.3.6.1.1.9.1.12', OID_OBJECT_CLASS, 'pcelsCompoundConditionAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.13': OidInfo('1.3.6.1.1.9.1.13', OID_OBJECT_CLASS, 'pcelsCompoundFilterConditionAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.14': OidInfo('1.3.6.1.1.9.1.14', OID_OBJECT_CLASS, 'pcelsSimpleActionAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.15': OidInfo('1.3.6.1.1.9.1.15', OID_OBJECT_CLASS, 'pcelsCompoundActionAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.16': OidInfo('1.3.6.1.1.9.1.16', OID_OBJECT_CLASS, 'pcelsVariable', 'RFC4104'), '1.3.6.1.1.9.1.17': OidInfo('1.3.6.1.1.9.1.17', OID_OBJECT_CLASS, 'pcelsExplicitVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.18': OidInfo('1.3.6.1.1.9.1.18', OID_OBJECT_CLASS, 'pcelsImplicitVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.19': OidInfo('1.3.6.1.1.9.1.19', OID_OBJECT_CLASS, 'pcelsSourceIPv4VariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.20': OidInfo('1.3.6.1.1.9.1.20', OID_OBJECT_CLASS, 'pcelsSourceIPv6VariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.21': OidInfo('1.3.6.1.1.9.1.21', OID_OBJECT_CLASS, 'pcelsDestinationIPv4VariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.22': OidInfo('1.3.6.1.1.9.1.22', OID_OBJECT_CLASS, 'pcelsDestinationIPv6VariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.23': OidInfo('1.3.6.1.1.9.1.23', OID_OBJECT_CLASS, 'pcelsSourcePortVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.24': OidInfo('1.3.6.1.1.9.1.24', OID_OBJECT_CLASS, 'pcelsDestinationPortVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.25': OidInfo('1.3.6.1.1.9.1.25', OID_OBJECT_CLASS, 'pcelsIPProtocolVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.26': OidInfo('1.3.6.1.1.9.1.26', OID_OBJECT_CLASS, 'pcelsIPVersionVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.27': OidInfo('1.3.6.1.1.9.1.27', OID_OBJECT_CLASS, 'pcelsIPToSVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.28': OidInfo('1.3.6.1.1.9.1.28', OID_OBJECT_CLASS, 'pcelsDSCPVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.29': OidInfo('1.3.6.1.1.9.1.29', OID_OBJECT_CLASS, 'pcelsFlowIdVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.30': OidInfo('1.3.6.1.1.9.1.30', OID_OBJECT_CLASS, 'pcelsSourceMACVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.31': OidInfo('1.3.6.1.1.9.1.31', OID_OBJECT_CLASS, 'pcelsDestinationMACVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.32': OidInfo('1.3.6.1.1.9.1.32', OID_OBJECT_CLASS, 'pcelsVLANVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.33': OidInfo('1.3.6.1.1.9.1.33', OID_OBJECT_CLASS, 'pcelsCoSVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.34': OidInfo('1.3.6.1.1.9.1.34', OID_OBJECT_CLASS, 'pcelsEthertypeVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.35': OidInfo('1.3.6.1.1.9.1.35', OID_OBJECT_CLASS, 'pcelsSourceSAPVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.36': OidInfo('1.3.6.1.1.9.1.36', OID_OBJECT_CLASS, 'pcelsDestinationSAPVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.37': OidInfo('1.3.6.1.1.9.1.37', OID_OBJECT_CLASS, 'pcelsSNAPOUIVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.38': OidInfo('1.3.6.1.1.9.1.38', OID_OBJECT_CLASS, 'pcelsSNAPTypeVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.39': OidInfo('1.3.6.1.1.9.1.39', OID_OBJECT_CLASS, 'pcelsFlowDirectionVariableAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.40': OidInfo('1.3.6.1.1.9.1.40', OID_OBJECT_CLASS, 'pcelsValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.41': OidInfo('1.3.6.1.1.9.1.41', OID_OBJECT_CLASS, 'pcelsIPv4AddrValueAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.42': OidInfo('1.3.6.1.1.9.1.42', OID_OBJECT_CLASS, 'pcelsIPv6AddrValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.43': OidInfo('1.3.6.1.1.9.1.43', OID_OBJECT_CLASS, 'pcelsMACAddrValueAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.44': OidInfo('1.3.6.1.1.9.1.44', OID_OBJECT_CLASS, 'pcelsStringValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.45': OidInfo('1.3.6.1.1.9.1.45', OID_OBJECT_CLASS, 'pcelsBitStringValueAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.46': OidInfo('1.3.6.1.1.9.1.46', OID_OBJECT_CLASS, 'pcelsIntegerValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.47': OidInfo('1.3.6.1.1.9.1.47', OID_OBJECT_CLASS, 'pcelsBooleanValueAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.48': OidInfo('1.3.6.1.1.9.1.48', OID_OBJECT_CLASS, 'pcelsReusableContainer', 'RFC4104'), '1.3.6.1.1.9.1.49': OidInfo('1.3.6.1.1.9.1.49', OID_OBJECT_CLASS, 'pcelsReusableContainerAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.50': OidInfo('1.3.6.1.1.9.1.50', OID_OBJECT_CLASS, 'pcelsReusableContainerInstance', 'RFC4104'), '1.3.6.1.1.9.1.51': OidInfo('1.3.6.1.1.9.1.51', OID_OBJECT_CLASS, 'pcelsRoleCollection', 'RFC4104'),
'1.3.6.1.1.9.1.52': OidInfo('1.3.6.1.1.9.1.52', OID_OBJECT_CLASS, 'pcelsFilterEntryBase', 'RFC4104'), '1.3.6.1.1.9.1.53': OidInfo('1.3.6.1.1.9.1.53', OID_OBJECT_CLASS, 'pcelsIPHeadersFilter', 'RFC4104'),
'1.3.6.1.1.9.1.54': OidInfo('1.3.6.1.1.9.1.54', OID_OBJECT_CLASS, 'pcels8021Filter', 'RFC4104'), '1.3.6.1.1.9.1.55': OidInfo('1.3.6.1.1.9.1.55', OID_OBJECT_CLASS, 'pcelsFilterListAuxClass', 'RFC4104'),
'1.3.6.1.1.9.1.56': OidInfo('1.3.6.1.1.9.1.56', OID_OBJECT_CLASS, 'pcelsVendorVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.57': OidInfo('1.3.6.1.1.9.1.57', OID_OBJECT_CLASS, 'pcelsVendorValueAuxClass', 'RFC4104'),
'1.3.6.1.4.1.11.1.3.1.2.5': OidInfo('1.3.6.1.4.1.11.1.3.1.2.5', OID_OBJECT_CLASS, 'DUAConfigProfile', 'RFC4876'), '1.3.6.1.4.1.1466.101.119.2': OidInfo('1.3.6.1.4.1.1466.101.119.2', OID_OBJECT_CLASS, 'dynamicObject', 'RFC2589'),
'1.3.6.1.4.1.1466.101.120.111': OidInfo('1.3.6.1.4.1.1466.101.120.111', OID_OBJECT_CLASS, 'extensibleObject', 'RFC4512'), '1.3.6.1.4.1.1466.344': OidInfo('1.3.6.1.4.1.1466.344', OID_OBJECT_CLASS, 'dcObject', 'RFC4519'),
'1.3.6.1.4.1.16572.2.1.1': OidInfo('1.3.6.1.4.1.16572.2.1.1', OID_OBJECT_CLASS, 'LDIFLocationURLObject', 'RFC6109'), '1.3.6.1.4.1.16572.2.1.2': OidInfo('1.3.6.1.4.1.16572.2.1.2', OID_OBJECT_CLASS, 'provider', 'RFC6109'),
'1.3.6.1.4.1.250.3.15': OidInfo('1.3.6.1.4.1.250.3.15', OID_OBJECT_CLASS, 'labeledURIObject', 'RFC2079'),
'1.3.6.1.4.1.31103.1.1001': OidInfo('1.3.6.1.4.1.31103.1.1001', OID_OBJECT_CLASS, 'fedfsNsdbContainerInfo', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.1002': OidInfo('1.3.6.1.4.1.31103.1.1002', OID_OBJECT_CLASS, 'fedfsFsn', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.1003': OidInfo('1.3.6.1.4.1.31103.1.1003', OID_OBJECT_CLASS, 'fedfsFsl', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.31103.1.1004': OidInfo('1.3.6.1.4.1.31103.1.1004', OID_OBJECT_CLASS, 'fedfsNfsFsl', 'RFC-ietf-nfsv4-federated-fs-protocol-15'),
'1.3.6.1.4.1.453.7.1.1': OidInfo('1.3.6.1.4.1.453.7.1.1', OID_OBJECT_CLASS, ['rFC822ToX400Mapping', 'subtree'], 'RFC2164-RFC2293'),
'1.3.6.1.4.1.453.7.1.2': OidInfo('1.3.6.1.4.1.453.7.1.2', OID_OBJECT_CLASS, ['x400ToRFC822Mapping', 'table'], 'RFC2164-RFC2293'),
'1.3.6.1.4.1.453.7.1.3': OidInfo('1.3.6.1.4.1.453.7.1.3', OID_OBJECT_CLASS, ['omittedORAddressComponent', 'tableEntry'], 'RFC2164-RFC2293'),
'1.3.6.1.4.1.453.7.1.4': OidInfo('1.3.6.1.4.1.453.7.1.4', OID_OBJECT_CLASS, ['mixerGateway', 'textTableEntry'], 'RFC2164-RFC2293'),
'1.3.6.1.4.1.453.7.1.5': OidInfo('1.3.6.1.4.1.453.7.1.5', OID_OBJECT_CLASS, 'distinguishedNameTableEntry', 'RFC2293'), '2.16.840.1.113730.3.2.6': OidInfo('2.16.840.1.113730.3.2.6', OID_OBJECT_CLASS, 'referral', 'RFC3296'),
'2.5.17.0': OidInfo('2.5.17.0', OID_OBJECT_CLASS, 'subentry', 'RFC3672'), '2.5.20.1': OidInfo('2.5.20.1', OID_OBJECT_CLASS, 'subschema', 'RFC4512'),
'2.5.20.2': OidInfo('2.5.20.2', OID_OBJECT_CLASS, 'collectiveAttributeSubentry', 'RFC3671'), '2.5.6.0': OidInfo('2.5.6.0', OID_OBJECT_CLASS, 'top', 'RFC4512'), '2.5.6.1': OidInfo('2.5.6.1', OID_OBJECT_CLASS, 'alias', 'RFC4512'),
'2.5.6.2': OidInfo('2.5.6.2', OID_OBJECT_CLASS, 'country', 'RFC4519'), '2.5.6.3': OidInfo('2.5.6.3', OID_OBJECT_CLASS, 'locality', 'RFC4519'), '2.5.6.4': OidInfo('2.5.6.4', OID_OBJECT_CLASS, 'organization', 'RFC4519'),
'2.5.6.5': OidInfo('2.5.6.5', OID_OBJECT_CLASS, 'organizationalUnit', 'RFC4519'), '2.5.6.6': OidInfo('2.5.6.6', OID_OBJECT_CLASS, 'person', 'RFC4519'), '2.5.6.7': OidInfo('2.5.6.7', OID_OBJECT_CLASS, 'organizationalPerson', 'RFC4519'),
'2.5.6.8': OidInfo('2.5.6.8', OID_OBJECT_CLASS, 'organizationalRole', 'RFC4519'), '2.5.6.9': OidInfo('2.5.6.9', OID_OBJECT_CLASS, 'groupOfNames', 'RFC4519'), '2.5.6.10': OidInfo('2.5.6.10', OID_OBJECT_CLASS, 'residentialPerson', 'RFC4519'),
'2.5.6.11': OidInfo('2.5.6.11', OID_OBJECT_CLASS, 'applicationProcess', 'RFC4519'), '2.5.6.12': OidInfo('2.5.6.12', OID_OBJECT_CLASS, 'applicationEntity', 'RFC2256'), '2.5.6.13': OidInfo('2.5.6.13', OID_OBJECT_CLASS, 'dSA', 'RFC2256'),
'2.5.6.14': OidInfo('2.5.6.14', OID_OBJECT_CLASS, 'device', 'RFC4519'), '2.5.6.15': OidInfo('2.5.6.15', OID_OBJECT_CLASS, 'strongAuthenticationUser', 'RFC4523'),
'2.5.6.16': OidInfo('2.5.6.16', OID_OBJECT_CLASS, 'certificationAuthority', 'RFC4523'), '2.5.6.16.2': OidInfo('2.5.6.16.2', OID_OBJECT_CLASS, 'certificationAuthority-V2', 'RFC4523'),
'2.5.6.17': OidInfo('2.5.6.17', OID_OBJECT_CLASS, 'groupOfUniqueNames', 'RFC4519'), '2.5.6.18': OidInfo('2.5.6.18', OID_OBJECT_CLASS, 'userSecurityInformation', 'RFC4523'),
'2.5.6.19': OidInfo('2.5.6.19', OID_OBJECT_CLASS, 'cRLDistributionPoint', 'RFC4523'), '2.5.6.20': OidInfo('2.5.6.20', OID_OBJECT_CLASS, 'dmd', 'RFC2256'), '2.5.6.21': OidInfo('2.5.6.21', OID_OBJECT_CLASS, 'pkiUser', 'RFC4523'),
'2.5.6.22': OidInfo('2.5.6.22', OID_OBJECT_CLASS, 'pkiCA', 'RFC4523'), '2.5.6.23': OidInfo('2.5.6.23', OID_OBJECT_CLASS, 'deltaCRL', 'RFC4523'),
# unsolicited notices
'1.3.6.1.1.21.4': OidInfo('1.3.6.1.1.21.4', OID_UNSOLICITED_NOTICE, 'Aborted Transaction Notice', 'RFC5805'), '1.3.6.1.4.1.1466.20036': OidInfo('1.3.6.1.4.1.1466.20036', OID_UNSOLICITED_NOTICE, 'Notice of Disconnection', 'RFC4511')}
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc2696.py 0000666 0000000 0000000 00000003574 12355103747 021221 0 ustar 0000000 0000000 """
Created on 2013.10.15
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from pyasn1.type.univ import OctetString, Integer, Sequence
from pyasn1.type.namedtype import NamedTypes, NamedType
from pyasn1.type.constraint import ValueRangeConstraint
# constants
# maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --
MAXINT = Integer(2147483647)
# constraints
rangeInt0ToMaxConstraint = ValueRangeConstraint(0, MAXINT)
class Integer0ToMax(Integer):
subtypeSpec = Integer.subtypeSpec + rangeInt0ToMaxConstraint
class Size(Integer0ToMax):
"""
Size INTEGER (0..maxInt)
"""
pass
class Cookie(OctetString):
"""
cookie OCTET STRING
"""
pass
class RealSearchControlValue(Sequence):
"""
realSearchControlValue ::= SEQUENCE {
size INTEGER (0..maxInt),
-- requested page size from client
-- result set size estimate from server
cookie OCTET STRING
"""
componentType = NamedTypes(NamedType('size', Size()),
NamedType('cookie', Cookie()))
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc2849.py 0000666 0000000 0000000 00000017172 12355103747 021220 0 ustar 0000000 0000000 """
Created on 2013.12.08
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from base64 import b64encode
from .. import LDIF_LINE_LENGTH
from ..core.exceptions import LDAPLDIFError
# LDIF converter RFC 2849 compliant
def safe_ldif_string(bytes_value):
if not bytes_value:
return True
# check SAFE-INIT-CHAR: < 127, not NUL, LF, CR, SPACE, COLON, LESS-THAN
if bytes_value[0] > 127 or bytes_value[0] in [0, 10, 13, 32, 58, 60]:
return False
# check SAFE-CHAR: < 127 not NUL, LF, CR
if 0 in bytes_value or 10 in bytes_value or 13 in bytes_value:
return False
# check last char for SPACE
if bytes_value[-1] == 32:
return False
for byte in bytes_value:
if byte > 127:
return False
return True
def convert_to_ldif(descriptor, value, base64):
if not value:
value = ''
if isinstance(value, str):
value = bytearray(value, encoding='utf-8')
if base64 or not safe_ldif_string(value):
try:
encoded = b64encode(value)
except TypeError:
encoded = b64encode(str(value)) # patch for Python 2.6
if not isinstance(encoded, str): # in Python 3 b64encode returns bytes in Python 2 returns str
encoded = str(encoded, encoding='ascii') # Python 3
line = descriptor + ':: ' + encoded
else:
if not str == bytes: # Python 3
value = str(value, encoding='ascii')
else: # Python 2
value = str(value)
line = descriptor + ': ' + value
return line
def add_controls(controls, all_base64):
lines = []
if controls:
for control in controls:
line = 'control: ' + control[0]
line += ' ' + ('true' if control[1] else 'false')
if control[2]:
lines.append(convert_to_ldif(line, control[2], all_base64))
return lines
def add_attributes(attributes, all_base64):
lines = []
oc_attr = None
# objectclass first, even if this is not specified in the RFC
for attr in attributes:
if attr.lower() == 'objectclass':
for val in attributes[attr]:
lines.append(convert_to_ldif(attr, val, all_base64))
oc_attr = attr
break
# remaining attributes
for attr in attributes:
if attr != oc_attr:
for val in attributes[attr]:
lines.append(convert_to_ldif(attr, val, all_base64))
return lines
def search_response_to_ldif(entries, all_base64):
lines = []
for entry in entries:
if 'dn' in entry:
lines.append(convert_to_ldif('dn', entry['dn'], all_base64))
lines.extend(add_attributes(entry['raw_attributes'], all_base64))
else:
raise LDAPLDIFError('unable to convert to LDIF-CONTENT - missing DN')
lines.append('')
if lines:
lines.append('')
lines.append('# total number of entries: ' + str(len(entries)))
return lines
def add_request_to_ldif(entry, all_base64):
lines = []
if 'entry' in entry:
lines.append(convert_to_ldif('dn', entry['entry'], all_base64))
lines.extend(add_controls(entry['controls'], all_base64))
lines.append('changetype: add')
lines.extend(add_attributes(entry['attributes'], all_base64))
else:
raise LDAPLDIFError('unable to convert to LDIF-CHANGE-ADD - missing DN ')
return lines
def delete_request_to_ldif(entry, all_base64):
lines = []
if 'entry' in entry:
lines.append(convert_to_ldif('dn', entry['entry'], all_base64))
lines.append(add_controls(entry['controls'], all_base64))
lines.append('changetype: delete')
else:
raise LDAPLDIFError('unable to convert to LDIF-CHANGE-DELETE - missing DN ')
return lines
def modify_request_to_ldif(entry, all_base64):
lines = []
if 'entry' in entry:
lines.append(convert_to_ldif('dn', entry['entry'], all_base64))
lines.extend(add_controls(entry['controls'], all_base64))
lines.append('changetype: modify')
if 'changes' in entry:
for change in entry['changes']:
lines.append(['add', 'delete', 'replace', 'increment'][change['operation']] + ': ' + change['attribute']['type'])
for value in change['attribute']['value']:
lines.append(convert_to_ldif(change['attribute']['type'], value, all_base64))
lines.append('-')
return lines
def modify_dn_request_to_ldif(entry, all_base64):
lines = []
if 'entry' in entry:
lines.append(convert_to_ldif('dn', entry['entry'], all_base64))
lines.extend(add_controls(entry['controls'], all_base64))
lines.append('changetype: modrdn') if 'newSuperior' in entry and entry['newSuperior'] else lines.append('changetype: moddn')
lines.append(convert_to_ldif('newrdn', entry['newRdn'], all_base64))
lines.append('deleteoldrdn: ' + ('1' if entry['deleteOldRdn'] else '0'))
if 'newSuperior' in entry and entry['newSuperior']:
lines.append(convert_to_ldif('newsuperior', entry['newSuperior'], all_base64))
else:
raise LDAPLDIFError('unable to convert to LDIF-CHANGE-MODDN - missing DN ')
return lines
def operation_to_ldif(operation_type, entries, all_base64=False, sort_order=None):
if operation_type == 'searchResponse':
lines = search_response_to_ldif(entries, all_base64)
elif operation_type == 'addRequest':
lines = add_request_to_ldif(entries, all_base64)
elif operation_type == 'delRequest':
lines = delete_request_to_ldif(entries, all_base64)
elif operation_type == 'modifyRequest':
lines = modify_request_to_ldif(entries, all_base64)
elif operation_type == 'modDNRequest':
lines = modify_dn_request_to_ldif(entries, all_base64)
else:
lines = []
# sort lines as per custom sort_order
# sort order is a list of descriptors, lines will be sorted following the same sequence
if sort_order:
lines = sorted(lines, key=lambda x: ldif_sort(x, sort_order))
ldif_record = []
# check max line length and split as per note 2 of RFC 2849
for line in lines:
if line:
ldif_record.append(line[0:LDIF_LINE_LENGTH])
ldif_record.extend([' ' + line[i: i + LDIF_LINE_LENGTH - 1] for i in range(LDIF_LINE_LENGTH, len(line), LDIF_LINE_LENGTH - 1)] if len(line) > LDIF_LINE_LENGTH else [])
return ldif_record
def add_ldif_header(ldif_lines):
if ldif_lines:
ldif_lines.insert(0, 'version: 1')
return ldif_lines
def ldif_sort(line, sort_order):
for i, descriptor in enumerate(sort_order):
if line and line.startswith(descriptor):
return i
return len(sort_order) + 1
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc3062.py 0000666 0000000 0000000 00000005570 12355107014 021172 0 ustar 0000000 0000000 """
Created on 2014.04.28
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from pyasn1.type.univ import OctetString, Sequence
from pyasn1.type.namedtype import NamedTypes, OptionalNamedType
from pyasn1.type.tag import Tag, tagClassContext, tagFormatSimple
#Modify password extended operation
#passwdModifyOID OBJECT IDENTIFIER ::= 1.3.6.1.4.1.4203.1.11.1
#PasswdModifyRequestValue ::= SEQUENCE {
# userIdentity [0] OCTET STRING OPTIONAL
# oldPasswd [1] OCTET STRING OPTIONAL
# newPasswd [2] OCTET STRING OPTIONAL }
#
# PasswdModifyResponseValue ::= SEQUENCE {
# genPasswd [0] OCTET STRING OPTIONAL }
class UserIdentity(OctetString):
"""
userIdentity [0] OCTET STRING OPTIONAL
"""
tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
encoding = 'utf-8'
class OldPasswd(OctetString):
"""
oldPasswd [1] OCTET STRING OPTIONAL
"""
tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1))
encoding = 'utf-8'
class NewPasswd(OctetString):
"""
newPasswd [2] OCTET STRING OPTIONAL
"""
tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 2))
encoding = 'utf-8'
class GenPasswd(OctetString):
"""
newPasswd [2] OCTET STRING OPTIONAL
"""
tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
encoding = 'utf-8'
class PasswdModifyRequestValue(Sequence):
"""
PasswdModifyRequestValue ::= SEQUENCE {
userIdentity [0] OCTET STRING OPTIONAL
oldPasswd [1] OCTET STRING OPTIONAL
newPasswd [2] OCTET STRING OPTIONAL }
"""
componentType = NamedTypes(OptionalNamedType('userIdentity', UserIdentity()),
OptionalNamedType('oldPasswd', OldPasswd()),
OptionalNamedType('newPasswd', NewPasswd()))
class PasswdModifyResponseValue(Sequence):
"""
PasswdModifyResponseValue ::= SEQUENCE {
genPasswd [0] OCTET STRING OPTIONAL }
"""
componentType = NamedTypes(OptionalNamedType('genPasswd', GenPasswd()))
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc4511.py 0000666 0000000 0000000 00000120654 12355103747 021204 0 ustar 0000000 0000000 """
Created on 2013.05.15
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
# ldap ASN.1 Definition
# from RFC4511 - Appendix B
# extended with result codes from IANA ldap-parameters as of 2013.08.21
# extended with modify_increment from RFC4525
# Lightweight-Directory-Access-Protocol-V3 {1 3 6 1 1 18}
# -- Copyright (C) The Internet Society (2006). This version of
# -- this ASN.1 module is part of RFC 4511; see the RFC itself
# -- for full legal notices.
# DEFINITIONS
# IMPLICIT TAGS
# EXTENSIBILITY IMPLIED
from pyasn1.type.univ import OctetString, Integer, Sequence, Choice, SequenceOf, Boolean, Null, Enumerated, SetOf
from pyasn1.type.namedtype import NamedTypes, NamedType, OptionalNamedType, DefaultedNamedType
from pyasn1.type.constraint import ValueRangeConstraint, SingleValueConstraint, ValueSizeConstraint
from pyasn1.type.namedval import NamedValues
from pyasn1.type.tag import tagClassApplication, tagFormatConstructed, Tag, tagClassContext, tagFormatSimple
from .. import LDAP_MAX_INT
# constants
# maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --
MAXINT = Integer(LDAP_MAX_INT)
# constraints
rangeInt0ToMaxConstraint = ValueRangeConstraint(0, MAXINT)
rangeInt1To127Constraint = ValueRangeConstraint(1, 127)
size1ToMaxConstraint = ValueSizeConstraint(1, MAXINT)
responseValueConstraint = SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 32, 33, 34, 36, 48, 49, 50, 51, 52, 53, 54, 64, 65, 66, 67, 68, 69, 71, 80, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123,
4096)
# custom constraints
numericOIDConstraint = None # tbd
distinguishedNameConstraint = None # tbd
nameComponentConstraint = None # tbd
attributeDescriptionConstraint = None # tbd
uriConstraint = None # tbd
attributeSelectorConstraint = None # tbd
class Integer0ToMax(Integer):
subtypeSpec = Integer.subtypeSpec + rangeInt0ToMaxConstraint
class LDAPString(OctetString):
"""
LDAPString ::= OCTET STRING -- UTF-8 encoded, -- [ISO10646] characters
"""
encoding = 'utf-8'
class MessageID(Integer0ToMax):
"""
MessageID ::= INTEGER (0 .. maxInt)
"""
pass
class LDAPOID(OctetString):
"""
LDAPOID ::= OCTET STRING -- Constrained to
-- [RFC4512]
"""
# subtypeSpec = numericOIDConstraint
pass
class LDAPDN(LDAPString):
"""
LDAPDN ::= LDAPString -- Constrained to
-- [RFC4514]
"""
# subtypeSpec = distinguishedName
pass
class RelativeLDAPDN(LDAPString):
"""
RelativeLDAPDN ::= LDAPString -- Constrained to
-- [RFC4514]
"""
# subtypeSpec = LDAPString.subtypeSpec + nameComponentConstraint
pass
class AttributeDescription(LDAPString):
"""
AttributeDescription ::= LDAPString -- Constrained to
-- [RFC4512]
"""
# subtypeSpec = LDAPString.subtypeSpec + attributeDescriptionConstraint
pass
class AttributeValue(OctetString):
"""
AttributeValue ::= OCTET STRING
"""
encoding = 'utf-8'
class AssertionValue(OctetString):
"""
AssertionValue ::= OCTET STRING
"""
encoding = 'utf-8'
class AttributeValueAssertion(Sequence):
"""
AttributeValueAssertion ::= SEQUENCE {
attributeDesc AttributeDescription,
assertionValue AssertionValue }
"""
componentType = NamedTypes(NamedType('attributeDesc', AttributeDescription()),
NamedType('assertionValue', AssertionValue()))
class MatchingRuleId(LDAPString):
"""
MatchingRuleId ::= LDAPString
"""
pass
class Vals(SetOf):
"""
vals SET OF value AttributeValue }
"""
componentType = AttributeValue()
class ValsAtLeast1(SetOf):
"""
vals SET OF value AttributeValue }
"""
componentType = AttributeValue()
subtypeSpec = SetOf.subtypeSpec + size1ToMaxConstraint
class PartialAttribute(Sequence):
"""
PartialAttribute ::= SEQUENCE {
type AttributeDescription,
vals SET OF value AttributeValue }
"""
componentType = NamedTypes(NamedType('type', AttributeDescription()),
NamedType('vals', Vals()))
class Attribute(Sequence):
"""
Attribute ::= PartialAttribute(WITH COMPONENTS {
...,
vals (SIZE(1..MAX))})
"""
componentType = NamedTypes(NamedType('type', AttributeDescription()),
NamedType('vals', ValsAtLeast1()))
class AttributeList(SequenceOf):
"""
AttributeList ::= SEQUENCE OF attribute Attribute
"""
componentType = Attribute()
class Simple(OctetString):
"""
simple [0] OCTET STRING,
"""
tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
encoding = 'utf-8'
class Credentials(OctetString):
"""
credentials OCTET STRING
"""
encoding = 'utf-8'
class SaslCredentials(Sequence):
"""
SaslCredentials ::= SEQUENCE {
mechanism LDAPString,
credentials OCTET STRING OPTIONAL }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 3))
componentType = NamedTypes(NamedType('mechanism', LDAPString()),
OptionalNamedType('credentials', Credentials()))
class AuthenticationChoice(Choice):
"""
AuthenticationChoice ::= CHOICE {
simple [0] OCTET STRING,
-- 1 and 2 reserved
sasl [3] SaslCredentials,
... }
"""
componentType = NamedTypes(NamedType('simple', Simple()),
NamedType('sasl', SaslCredentials()))
class Version(Integer):
"""
version INTEGER (1 .. 127),
"""
subtypeSpec = Integer.subtypeSpec + rangeInt1To127Constraint
class ResultCode(Enumerated):
"""
resultCode ENUMERATED {
success (0),
operationsError (1),
protocolError (2),
timeLimitExceeded (3),
sizeLimitExceeded (4),
compareFalse (5),
compareTrue (6),
authMethodNotSupported (7),
strongerAuthRequired (8),
-- 9 reserved --
referral (10),
adminLimitExceeded (11),
unavailableCriticalExtension (12),
confidentialityRequired (13),
saslBindInProgress (14),
noSuchAttribute (16),
undefinedAttributeType (17),
inappropriateMatching (18),
constraintViolation (19),
attributeOrValueExists (20),
invalidAttributeSyntax (21),
-- 22-31 unused --
noSuchObject (32),
aliasProblem (33),
invalidDNSyntax (34),
-- 35 reserved for undefined isLeaf --
aliasDereferencingProblem (36),
-- 37-47 unused --
inappropriateAuthentication (48),
invalidCredentials (49),
insufficientAccessRights (50),
busy (51),
unavailable (52),
unwillingToPerform (53),
loopDetect (54),
-- 55-63 unused --
namingViolation (64),
objectClassViolation (65),
notAllowedOnNonLeaf (66),
notAllowedOnRDN (67),
entryAlreadyExists (68),
objectClassModsProhibited (69),
-- 70 reserved for CLDAP --
affectsMultipleDSAs (71),
-- 72-79 unused --
other (80),
... }
from IANA ldap-parameters:
lcupResourcesExhausted 113 IESG [RFC3928]
lcupSecurityViolation 114 IESG [RFC3928]
lcupInvalidData 115 IESG [RFC3928]
lcupUnsupportedScheme 116 IESG [RFC3928]
lcupReloadRequired 117 IESG [RFC3928]
canceled 118 IESG [RFC3909]
noSuchOperation 119 IESG [RFC3909]
tooLate 120 IESG [RFC3909]
cannotCancel 121 IESG [RFC3909]
assertionFailed 122 IESG [RFC4528]
authorizationDenied 123 WELTMAN [RFC4370]
e-syncRefreshRequired 4096 [Kurt_Zeilenga] [Jong_Hyuk_Choi] [RFC4533]
"""
namedValues = NamedValues(('success', 0),
('operationsError', 1),
('protocolError', 2),
('timeLimitExceeded', 3),
('sizeLimitExceeded', 4),
('compareFalse', 5),
('compareTrue', 6),
('authMethodNotSupported', 7),
('strongerAuthRequired', 8),
('referral', 10),
('adminLimitExceeded', 11),
('unavailableCriticalExtension', 12),
('confidentialityRequired', 13),
('saslBindInProgress', 14),
('noSuchAttribute', 16),
('undefinedAttributeType', 17),
('inappropriateMatching', 18),
('constraintViolation', 19),
('attributeOrValueExists', 20),
('invalidAttributeSyntax', 21),
('noSuchObject', 32),
('aliasProblem', 33),
('invalidDNSyntax', 34),
('aliasDereferencingProblem', 36),
('inappropriateAuthentication', 48),
('invalidCredentials', 49),
('insufficientAccessRights', 50),
('busy', 51),
('unavailable', 52),
('unwillingToPerform', 53),
('loopDetected', 54),
('namingViolation', 64),
('objectClassViolation', 65),
('notAllowedOnNonLeaf', 66),
('notAllowedOnRDN', 67),
('entryAlreadyExists', 68),
('objectClassModsProhibited', 69),
('affectMultipleDSAs', 71),
('other', 80),
('lcupResourcesExhausted', 113),
('lcupSecurityViolation', 114),
('lcupInvalidData', 115),
('lcupUnsupportedScheme', 116),
('lcupReloadRequired', 117),
('canceled', 118),
('noSuchOperation', 119),
('tooLate', 120),
('cannotCancel', 121),
('assertionFailed', 122),
('authorizationDenied', 123),
('e-syncRefreshRequired', 4096))
subTypeSpec = Enumerated.subtypeSpec + responseValueConstraint
class URI(LDAPString):
"""
URI ::= LDAPString -- limited to characters permitted in
-- URIs
"""
# subtypeSpec = LDAPString.subTypeSpec + uriConstrain
pass
class Referral(SequenceOf):
"""
Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI
"""
tagSet = SequenceOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 3))
componentType = URI()
class ServerSaslCreds(OctetString):
"""
serverSaslCreds [7] OCTET STRING OPTIONAL
"""
tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 7))
encoding = 'utf-8'
class LDAPResult(Sequence):
"""
LDAPResult ::= SEQUENCE {
resultCode ENUMERATED {
success (0),
operationsError (1),
protocolError (2),
timeLimitExceeded (3),
sizeLimitExceeded (4),
compareFalse (5),
compareTrue (6),
authMethodNotSupported (7),
strongerAuthRequired (8),
-- 9 reserved --
referral (10),
adminLimitExceeded (11),
unavailableCriticalExtension (12),
confidentialityRequired (13),
saslBindInProgress (14),
noSuchAttribute (16),
undefinedAttributeType (17),
inappropriateMatching (18),
constraintViolation (19),
attributeOrValueExists (20),
invalidAttributeSyntax (21),
-- 22-31 unused --
noSuchObject (32),
aliasProblem (33),
invalidDNSyntax (34),
-- 35 reserved for undefined isLeaf --
aliasDereferencingProblem (36),
-- 37-47 unused --
inappropriateAuthentication (48),
invalidCredentials (49),
insufficientAccessRights (50),
busy (51),
unavailable (52),
unwillingToPerform (53),
loopDetect (54),
-- 55-63 unused --
namingViolation (64),
objectClassViolation (65),
notAllowedOnNonLeaf (66),
notAllowedOnRDN (67),
entryAlreadyExists (68),
objectClassModsProhibited (69),
-- 70 reserved for CLDAP --
affectsMultipleDSAs (71),
-- 72-79 unused --
other (80),
... },
matchedDN LDAPDN,
diagnosticMessage LDAPString,
referral [3] Referral OPTIONAL }
"""
componentType = NamedTypes(NamedType('resultCode', ResultCode()),
NamedType('matchedDN', LDAPDN()),
NamedType('diagnosticMessage', LDAPString()),
OptionalNamedType('referral', Referral()))
class Criticality(Boolean):
"""
criticality BOOLEAN DEFAULT FALSE
"""
defaultValue = False
class ControlValue(OctetString):
"""
controlValue OCTET STRING
"""
encoding = 'utf-8'
class Control(Sequence):
"""
Control ::= SEQUENCE {
controlType LDAPOID,
criticality BOOLEAN DEFAULT FALSE,
controlValue OCTET STRING OPTIONAL }
"""
componentType = NamedTypes(NamedType('controlType', LDAPOID()),
DefaultedNamedType('criticality', Criticality()),
OptionalNamedType('controlValue', ControlValue()))
class Controls(SequenceOf):
"""
Controls ::= SEQUENCE OF control Control
"""
tagSet = SequenceOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 0))
componentType = Control()
class Scope(Enumerated):
"""
scope ENUMERATED {
baseObject (0),
singleLevel (1),
wholeSubtree (2),
"""
namedValues = NamedValues(('baseObject', 0), ('singleLevel', 1), ('wholeSubtree', 2))
class DerefAliases(Enumerated):
"""
derefAliases ENUMERATED {
neverDerefAliases (0),
derefInSearching (1),
derefFindingBaseObj (2),
derefAlways (3) },
"""
namedValues = NamedValues(('neverDerefAliases', 0), ('derefInSearching', 1), ('derefFindingBaseObj', 2), ('derefAlways', 3))
class TypesOnly(Boolean):
"""
typesOnly BOOLEAN
"""
pass
class Selector(LDAPString):
"""
-- The LDAPString is constrained to
-- in Section 4.5.1.8
"""
# subtypeSpec = LDAPString.subtypeSpec + attributeSelectorConstraint
pass
class AttributeSelection(SequenceOf):
"""
AttributeSelection ::= SEQUENCE OF selector LDAPString
-- The LDAPString is constrained to
-- in Section 4.5.1.8
"""
componentType = Selector()
class MatchingRule(MatchingRuleId):
"""
matchingRule [1] MatchingRuleId
"""
tagSet = MatchingRuleId.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1))
class Type(AttributeDescription):
"""
type [2] AttributeDescription
"""
tagSet = AttributeDescription.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 2))
class MatchValue(AssertionValue):
"""
matchValue [3] AssertionValue,
"""
tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 3))
class DnAttributes(Boolean):
"""
dnAttributes [4] BOOLEAN DEFAULT FALSE }
"""
tagSet = Boolean.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 4))
defaultValue = Boolean(False)
class MatchingRuleAssertion(Sequence):
"""
MatchingRuleAssertion ::= SEQUENCE {
matchingRule [1] MatchingRuleId OPTIONAL,
type [2] AttributeDescription OPTIONAL,
matchValue [3] AssertionValue,
dnAttributes [4] BOOLEAN DEFAULT FALSE }
"""
componentType = NamedTypes(OptionalNamedType('matchingRule', MatchingRule()),
OptionalNamedType('type', Type()),
NamedType('matchValue', MatchValue()),
DefaultedNamedType('dnAttributes', DnAttributes()))
class Initial(AssertionValue):
"""
initial [0] AssertionValue, -- can occur at most once
"""
tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
class Any(AssertionValue):
"""
any [1] AssertionValue,
"""
tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1))
class Final(AssertionValue):
"""
final [1] AssertionValue, -- can occur at most once
"""
tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 2))
class Substring(Choice):
"""
substring CHOICE {
initial [0] AssertionValue, -- can occur at most once
any [1] AssertionValue,
final [2] AssertionValue } -- can occur at most once
}
"""
componentType = NamedTypes(NamedType('initial', Initial()),
NamedType('any', Any()),
NamedType('final', Final()))
class Substrings(SequenceOf):
"""
substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
...
}
"""
subtypeSpec = SequenceOf.subtypeSpec + size1ToMaxConstraint
componentType = Substring()
class SubstringFilter(Sequence):
"""
SubstringFilter ::= SEQUENCE {
type AttributeDescription,
substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
initial [0] AssertionValue, -- can occur at most once
any [1] AssertionValue,
final [2] AssertionValue } -- can occur at most once
}
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 4))
componentType = NamedTypes(NamedType('type', AttributeDescription()),
NamedType('substrings', Substrings()))
class And(SetOf):
"""
and [0] SET SIZE (1..MAX) OF filter Filter
"""
tagSet = SetOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 0))
subtypeSpec = SetOf.subtypeSpec + size1ToMaxConstraint
class Or(SetOf):
"""
or [1] SET SIZE (1..MAX) OF filter Filter
"""
tagSet = SetOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 1))
subtypeSpec = SetOf.subtypeSpec + size1ToMaxConstraint
class Not(Choice):
"""
not [2] Filter
"""
pass # defined after Filter definition to allow recursion
class EqualityMatch(AttributeValueAssertion):
"""
equalityMatch [3] AttributeValueAssertion
"""
tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 3))
class GreaterOrEqual(AttributeValueAssertion):
"""
greaterOrEqual [5] AttributeValueAssertion
"""
tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 5))
class LessOrEqual(AttributeValueAssertion):
"""
lessOrEqual [6] AttributeValueAssertion
"""
tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 6))
class Present(AttributeDescription):
"""
present [7] AttributeDescription
"""
tagSet = AttributeDescription.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 7))
class ApproxMatch(AttributeValueAssertion):
"""
approxMatch [8] AttributeValueAssertion
"""
tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 8))
class ExtensibleMatch(MatchingRuleAssertion):
"""
extensibleMatch [9] MatchingRuleAssertion
"""
tagSet = MatchingRuleAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 9))
class Filter(Choice):
"""
Filter ::= CHOICE {
and [0] SET SIZE (1..MAX) OF filter Filter,
or [1] SET SIZE (1..MAX) OF filter Filter,
not [2] Filter,
equalityMatch [3] AttributeValueAssertion,
substrings [4] SubstringFilter,
greaterOrEqual [5] AttributeValueAssertion,
lessOrEqual [6] AttributeValueAssertion,
present [7] AttributeDescription,
approxMatch [8] AttributeValueAssertion,
extensibleMatch [9] MatchingRuleAssertion,
... }
"""
componentType = NamedTypes(NamedType('and', And()),
NamedType('or', Or()),
NamedType('notFilter', Not()),
NamedType('equalityMatch', EqualityMatch()),
NamedType('substringFilter', SubstringFilter()),
NamedType('greaterOrEqual', GreaterOrEqual()),
NamedType('lessOrEqual', LessOrEqual()),
NamedType('present', Present()),
NamedType('approxMatch', ApproxMatch()),
NamedType('extensibleMatch', ExtensibleMatch()))
And.componentType = Filter()
Or.componentType = Filter()
Not.componentType = NamedTypes(NamedType('innerNotFilter', Filter()))
Not.tagSet = Filter.tagSet.tagExplicitly(Tag(tagClassContext, tagFormatConstructed, 2)) # as per RFC4511 page 23
class PartialAttributeList(SequenceOf):
"""
PartialAttributeList ::= SEQUENCE OF
partialAttribute PartialAttribute
"""
componentType = PartialAttribute()
class Operation(Enumerated):
"""
operation ENUMERATED {
add (0),
delete (1),
replace (2),
... }
"""
namedValues = NamedValues(('add', 0), ('delete', 1), ('replace', 2), ('increment', 3))
class Change(Sequence):
"""
change SEQUENCE {
operation ENUMERATED {
add (0),
delete (1),
replace (2),
... },
modification PartialAttribute } }
"""
componentType = NamedTypes(NamedType('operation', Operation()),
NamedType('modification', PartialAttribute()))
class Changes(SequenceOf):
"""
changes SEQUENCE OF change SEQUENCE
"""
componentType = Change()
class DeleteOldRDN(Boolean):
"""
deleteoldrdn BOOLEAN
"""
pass
class NewSuperior(LDAPDN):
"""
newSuperior [0] LDAPDN
"""
tagSet = LDAPDN.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
class RequestName(LDAPOID):
"""
requestName [0] LDAPOID
"""
tagSet = LDAPOID.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
class RequestValue(OctetString):
"""
requestValue [1] OCTET STRING
"""
tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1))
encoding = 'utf-8'
class ResponseName(LDAPOID):
"""
responseName [10] LDAPOID
"""
tagSet = LDAPOID.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 10))
class ResponseValue(OctetString):
"""
responseValue [11] OCTET STRING
"""
tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 11))
encoding = 'utf-8'
class IntermediateResponseName(LDAPOID):
"""
responseName [0] LDAPOID
"""
tagSet = LDAPOID.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0))
class IntermediateResponseValue(OctetString):
"""
responseValue [1] OCTET STRING
"""
tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1))
encoding = 'utf-8'
# operations
class BindRequest(Sequence):
"""
BindRequest ::= [APPLICATION 0] SEQUENCE {
version INTEGER (1 .. 127),
name LDAPDN,
authentication AuthenticationChoice }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 0))
componentType = NamedTypes(NamedType('version', Version()),
NamedType('name', LDAPDN()),
NamedType('authentication', AuthenticationChoice()))
class BindResponse(Sequence):
"""
BindResponse ::= [APPLICATION 1] SEQUENCE {
COMPONENTS OF LDAPResult,
serverSaslCreds [7] OCTET STRING OPTIONAL }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 1))
componentType = NamedTypes(NamedType('resultCode', ResultCode()),
NamedType('matchedDN', LDAPDN()),
NamedType('diagnosticMessage', LDAPString()),
OptionalNamedType('referral', Referral()),
OptionalNamedType('serverSaslCreds', ServerSaslCreds()))
class UnbindRequest(Null):
"""
UnbindRequest ::= [APPLICATION 2] NULL
"""
tagSet = Null.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatSimple, 2))
class SearchRequest(Sequence):
"""
SearchRequest ::= [APPLICATION 3] SEQUENCE {
baseObject LDAPDN,
scope ENUMERATED {
baseObject (0),
singleLevel (1),
wholeSubtree (2),
... },
derefAliases ENUMERATED {
neverDerefAliases (0),
derefInSearching (1),
derefFindingBaseObj (2),
derefAlways (3) },
sizeLimit INTEGER (0 .. maxInt),
timeLimit INTEGER (0 .. maxInt),
typesOnly BOOLEAN,
filter Filter,
attributes AttributeSelection }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 3))
componentType = NamedTypes(NamedType('baseObject', LDAPDN()),
NamedType('scope', Scope()),
NamedType('derefAliases', DerefAliases()),
NamedType('sizeLimit', Integer0ToMax()),
NamedType('timeLimit', Integer0ToMax()),
NamedType('typesOnly', TypesOnly()),
NamedType('filter', Filter()),
NamedType('attributes', AttributeSelection()))
class SearchResultReference(SequenceOf):
"""
SearchResultReference ::= [APPLICATION 19] SEQUENCE
SIZE (1..MAX) OF uri URI
"""
tagSet = SequenceOf.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 19))
subtypeSpec = SequenceOf.subtypeSpec + size1ToMaxConstraint
componentType = URI()
class SearchResultEntry(Sequence):
"""
SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
objectName LDAPDN,
attributes PartialAttributeList }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 4))
componentType = NamedTypes(NamedType('object', LDAPDN()),
NamedType('attributes', PartialAttributeList()))
class SearchResultDone(LDAPResult):
"""
SearchResultDone ::= [APPLICATION 5] LDAPResult
"""
tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 5))
class ModifyRequest(Sequence):
"""
ModifyRequest ::= [APPLICATION 6] SEQUENCE {
object LDAPDN,
changes SEQUENCE OF change SEQUENCE {
operation ENUMERATED {
add (0),
delete (1),
replace (2),
... },
modification PartialAttribute } }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 6))
componentType = NamedTypes(NamedType('object', LDAPDN()),
NamedType('changes', Changes()))
class ModifyResponse(LDAPResult):
"""
ModifyResponse ::= [APPLICATION 7] LDAPResult
"""
tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 7))
class AddRequest(Sequence):
"""
AddRequest ::= [APPLICATION 8] SEQUENCE {
entry LDAPDN,
attributes AttributeList }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 8))
componentType = NamedTypes(NamedType('entry', LDAPDN()),
NamedType('attributes', AttributeList()))
class AddResponse(LDAPResult):
"""
AddResponse ::= [APPLICATION 9] LDAPResult
"""
tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 9))
class DelRequest(LDAPDN):
"""
DelRequest ::= [APPLICATION 10] LDAPDN
"""
tagSet = LDAPDN.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatSimple, 10))
class DelResponse(LDAPResult):
"""
DelResponse ::= [APPLICATION 11] LDAPResult
"""
tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 11))
class ModifyDNRequest(Sequence):
"""
ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
entry LDAPDN,
newrdn RelativeLDAPDN,
deleteoldrdn BOOLEAN,
newSuperior [0] LDAPDN OPTIONAL }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 12))
componentType = NamedTypes(NamedType('entry', LDAPDN()),
NamedType('newrdn', RelativeLDAPDN()),
NamedType('deleteoldrdn', DeleteOldRDN()),
OptionalNamedType('newSuperior', NewSuperior()))
class ModifyDNResponse(LDAPResult):
"""
ModifyDNResponse ::= [APPLICATION 13] LDAPResult
"""
tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 13))
class CompareRequest(Sequence):
"""
CompareRequest ::= [APPLICATION 14] SEQUENCE {
entry LDAPDN,
ava AttributeValueAssertion }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 14))
componentType = NamedTypes(NamedType('entry', LDAPDN()),
NamedType('ava', AttributeValueAssertion()))
class CompareResponse(LDAPResult):
"""
CompareResponse ::= [APPLICATION 15] LDAPResult
"""
tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 15))
class AbandonRequest(MessageID):
"""
AbandonRequest ::= [APPLICATION 16] MessageID
"""
tagSet = MessageID.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatSimple, 16))
class ExtendedRequest(Sequence):
"""
ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
requestName [0] LDAPOID,
requestValue [1] OCTET STRING OPTIONAL }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 23))
componentType = NamedTypes(NamedType('requestName', RequestName()),
OptionalNamedType('requestValue', RequestValue()))
class ExtendedResponse(Sequence):
"""
ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
COMPONENTS OF LDAPResult,
responseName [10] LDAPOID OPTIONAL,
responseValue [11] OCTET STRING OPTIONAL }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 24))
componentType = NamedTypes(NamedType('resultCode', ResultCode()),
NamedType('matchedDN', LDAPDN()),
NamedType('diagnosticMessage', LDAPString()),
OptionalNamedType('referral', Referral()),
OptionalNamedType('responseName', ResponseName()),
OptionalNamedType('responseValue', ResponseValue()))
class IntermediateResponse(Sequence):
"""
IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
responseName [0] LDAPOID OPTIONAL,
responseValue [1] OCTET STRING OPTIONAL }
"""
tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 25))
componentType = NamedTypes(OptionalNamedType('responseName', IntermediateResponseName()),
OptionalNamedType('responseValue', IntermediateResponseValue()))
class ProtocolOp(Choice):
"""
protocolOp CHOICE {
bindRequest BindRequest,
bindResponse BindResponse,
unbindRequest UnbindRequest,
searchRequest SearchRequest,
searchResEntry SearchResultEntry,
searchResDone SearchResultDone,
searchResRef SearchResultReference,
modifyRequest ModifyRequest,
modifyResponse ModifyResponse,
addRequest AddRequest,
addResponse AddResponse,
delRequest DelRequest,
delResponse DelResponse,
modDNRequest ModifyDNRequest,
modDNResponse ModifyDNResponse,
compareRequest CompareRequest,
compareResponse CompareResponse,
abandonRequest AbandonRequest,
extendedReq ExtendedRequest,
extendedResp ExtendedResponse,
...,
intermediateResponse IntermediateResponse }
"""
componentType = NamedTypes(NamedType('bindRequest', BindRequest()),
NamedType('bindResponse', BindResponse()),
NamedType('unbindRequest', UnbindRequest()),
NamedType('searchRequest', SearchRequest()),
NamedType('searchResEntry', SearchResultEntry()),
NamedType('searchResDone', SearchResultDone()),
NamedType('searchResRef', SearchResultReference()),
NamedType('modifyRequest', ModifyRequest()),
NamedType('modifyResponse', ModifyResponse()),
NamedType('addRequest', AddRequest()),
NamedType('addResponse', AddResponse()),
NamedType('delRequest', DelRequest()),
NamedType('delResponse', DelResponse()),
NamedType('modDNRequest', ModifyDNRequest()),
NamedType('modDNResponse', ModifyDNResponse()),
NamedType('compareRequest', CompareRequest()),
NamedType('compareResponse', CompareResponse()),
NamedType('abandonRequest', AbandonRequest()),
NamedType('extendedReq', ExtendedRequest()),
NamedType('extendedResp', ExtendedResponse()),
NamedType('intermediateResponse', IntermediateResponse()))
class LDAPMessage(Sequence):
"""
LDAPMessage ::= SEQUENCE {
messageID MessageID,
protocolOp CHOICE {
bindRequest BindRequest,
bindResponse BindResponse,
unbindRequest UnbindRequest,
searchRequest SearchRequest,
searchResEntry SearchResultEntry,
searchResDone SearchResultDone,
searchResRef SearchResultReference,
modifyRequest ModifyRequest,
modifyResponse ModifyResponse,
addRequest AddRequest,
addResponse AddResponse,
delRequest DelRequest,
delResponse DelResponse,
modDNRequest ModifyDNRequest,
modDNResponse ModifyDNResponse,
compareRequest CompareRequest,
compareResponse CompareResponse,
abandonRequest AbandonRequest,
extendedReq ExtendedRequest,
extendedResp ExtendedResponse,
...,
intermediateResponse IntermediateResponse },
controls [0] Controls OPTIONAL }
"""
componentType = NamedTypes(NamedType('messageID', MessageID()),
NamedType('protocolOp', ProtocolOp()),
OptionalNamedType('controls', Controls()))
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc4512.py 0000666 0000000 0000000 00000065366 12355103747 021215 0 ustar 0000000 0000000 """
Created on 2013.09.11
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from os import linesep
import re
from .. import CLASS_ABSTRACT, CLASS_STRUCTURAL, CLASS_AUXILIARY, ATTRIBUTE_USER_APPLICATION, ATTRIBUTE_DIRECTORY_OPERATION, ATTRIBUTE_DISTRIBUTED_OPERATION, ATTRIBUTE_DSA_OPERATION
from .oid import Oids, decode_oids, decode_syntax
from ..core.exceptions import LDAPSchemaError
def constant_to_class_kind(value):
if value == CLASS_STRUCTURAL:
return 'Structural'
elif value == CLASS_ABSTRACT:
return 'Abstract'
elif value == CLASS_AUXILIARY:
return 'Auxiliary'
else:
return 'unknown'
def constant_to_attribute_usage(value):
if value == ATTRIBUTE_USER_APPLICATION:
return 'User Application'
elif value == ATTRIBUTE_DIRECTORY_OPERATION:
return "Directory operation"
elif value == ATTRIBUTE_DISTRIBUTED_OPERATION:
return 'Distributed operation'
elif value == ATTRIBUTE_DSA_OPERATION:
return 'DSA operation'
else:
return 'unknown'
def attribute_usage_to_constant(value):
if value == 'userApplications':
return ATTRIBUTE_USER_APPLICATION
elif value == 'directoryOperation':
return ATTRIBUTE_DIRECTORY_OPERATION
elif value == 'distributedOperation':
return ATTRIBUTE_DISTRIBUTED_OPERATION
elif value == 'dsaOperation':
return ATTRIBUTE_DSA_OPERATION
else:
return 'unknown'
def quoted_string_to_list(quoted_string):
string = quoted_string.strip()
if string[0] == '(' and string[-1] == ')':
string = string[1:-1]
elements = string.split("'")
return [element.strip("'").strip() for element in elements if element.strip()]
def oids_string_to_list(oid_string):
string = oid_string.strip()
if string[0] == '(' and string[-1] == ')':
string = string[1:-1]
elements = string.split('$')
return [element.strip() for element in elements if element.strip()]
def extension_to_tuple(extension_string):
string = extension_string.strip()
name, _, values = string.partition(' ')
return name, quoted_string_to_list(values)
def list_to_string(list_object):
if not isinstance(list_object, (list, tuple)):
return list_object
r = ''
for element in list_object:
r += (list_to_string(element) if isinstance(element, (list, tuple)) else str(element)) + ', '
return r[:-2] if r else ''
class DsaInfo(object):
"""
This class contains info about the ldap server (DSA) read from DSE
as defined in RFC4512 and RFC3045. Unknown attributes are stored in the "other" dict
"""
def __init__(self, attributes):
self.alt_servers = attributes.pop('altServer', None)
self.naming_contexts = attributes.pop('namingContexts', None)
self.supported_controls = decode_oids(attributes.pop('supportedControl', None))
self.supported_extensions = decode_oids(attributes.pop('supportedExtension', None))
self.supported_features = decode_oids(attributes.pop('supportedFeatures', None)) + decode_oids(attributes.pop('supportedCapabilities', None))
self.supported_ldap_versions = attributes.pop('supportedLDAPVersion', None)
self.supported_sasl_mechanisms = attributes.pop('supportedSASLMechanisms', None)
self.vendor_name = attributes.pop('vendorName', None)
self.vendor_version = attributes.pop('vendorVersion', None)
self.schema_entry = attributes.pop('subschemaSubentry', None)
self.other = attributes
def __str__(self):
return self.__repr__()
def __repr__(self):
r = 'DSA info (from DSE):' + linesep
r += (' Supported LDAP Versions: ' + ', '.join([s for s in self.supported_ldap_versions]) + linesep) if self.supported_ldap_versions else ''
r += (' Naming Contexts:' + linesep + linesep.join([' ' + s for s in self.naming_contexts]) + linesep) if self.naming_contexts else ''
r += (' Alternative Servers:' + linesep + linesep.join([' ' + s for s in self.alt_servers]) + linesep) if self.alt_servers else ''
r += (' Supported Controls:' + linesep + linesep.join([' ' + str(s) for s in self.supported_controls]) + linesep) if self.supported_controls else ''
r += (' Supported Extensions:' + linesep + linesep.join([' ' + str(s) for s in self.supported_extensions]) + linesep) if self.supported_extensions else ''
r += (' Supported Features:' + linesep + linesep.join([' ' + str(s) for s in self.supported_features]) + linesep) if self.supported_features else ''
r += (' Supported SASL Mechanisms:' + linesep + ' ' + ', '.join([s for s in self.supported_sasl_mechanisms]) + linesep) if self.supported_sasl_mechanisms else ''
r += (' Schema Entry:' + linesep + linesep.join([' ' + s for s in self.schema_entry]) + linesep) if self.schema_entry else ''
r += 'Other:' + linesep
for k, v in self.other.items():
r += ' ' + k + ': ' + linesep
if isinstance(v, (list, tuple)):
r += linesep.join([' ' + str(s) for s in v]) + linesep
else:
r += v + linesep
return r
class SchemaInfo(object):
"""
This class contains info about the ldap server schema read from an entry (default entry is DSE)
as defined in RFC4512. Unknown attributes are stored in the "other" dict
"""
def __init__(self, schema_entry, attributes):
self.schema_entry = schema_entry
self.create_time_stamp = attributes.pop('createTimestamp', None)
self.modify_time_stamp = attributes.pop('modifyTimestamp', None)
self.attribute_types = AttributeTypeInfo.from_definition(attributes.pop('attributeTypes', []))
self.object_classes = ObjectClassInfo.from_definition(attributes.pop('objectClasses', []))
self.matching_rules = MatchingRuleInfo.from_definition(attributes.pop('matchingRules', []))
self.matching_rule_uses = MatchingRuleUseInfo.from_definition(attributes.pop('matchingRuleUse', []))
self.dit_content_rules = DitContentRuleInfo.from_definition(attributes.pop('dITContentRules', []))
self.dit_structure_rules = DitStructureRuleInfo.from_definition(attributes.pop('dITStructureRules', []))
self.name_forms = NameFormInfo.from_definition(attributes.pop('nameForms', []))
self.ldap_syntaxes = LdapSyntaxInfo.from_definition(attributes.pop('ldapSyntaxes', []))
self.other = attributes # remaining attributes not in RFC4512
def __str__(self):
return self.__repr__()
def __repr__(self):
r = 'DSA Schema from: ' + self.schema_entry + linesep
r += (' Attribute types:' + linesep + ' ' + ', '.join([str(self.attribute_types[s]) for s in self.attribute_types]) + linesep) if self.attribute_types else ''
r += (' Object classes:' + linesep + ' ' + ', '.join([str(self.object_classes[s]) for s in self.object_classes]) + linesep) if self.object_classes else ''
r += (' Matching rules:' + linesep + ' ' + ', '.join([str(self.matching_rules[s]) for s in self.matching_rules]) + linesep) if self.matching_rules else ''
r += (' Matching rule uses:' + linesep + ' ' + ', '.join([str(self.matching_rule_uses[s]) for s in self.matching_rule_uses]) + linesep) if self.matching_rule_uses else ''
r += (' DIT content rule:' + linesep + ' ' + ', '.join([str(self.dit_content_rules[s]) for s in self.dit_content_rules]) + linesep) if self.dit_content_rules else ''
r += (' DIT structure rule:' + linesep + ' ' + ', '.join([str(self.dit_structure_rules[s]) for s in self.dit_structure_rules]) + linesep) if self.dit_structure_rules else ''
r += (' Name forms:' + linesep + ' ' + ', '.join([str(self.name_forms[s]) for s in self.name_forms]) + linesep) if self.name_forms else ''
r += (' LDAP syntaxes:' + linesep + ' ' + ', '.join([str(self.ldap_syntaxes[s]) for s in self.ldap_syntaxes]) + linesep) if self.ldap_syntaxes else ''
r += 'Other:' + linesep
for k, v in self.other.items():
r += ' ' + k + ': ' + linesep
r += (linesep.join([' ' + str(s) for s in v])) if isinstance(v, (list, tuple)) else v + linesep
return r
class BaseObjectInfo(object):
"""
Base class for objects defined in the schema as per RFC4512
"""
def __init__(self,
oid=None,
name=None,
description=None,
obsolete=False,
extensions=None,
experimental=None,
definition=None):
self.oid = oid
self.name = name
self.description = description
self.obsolete = obsolete
self.extensions = extensions
self.experimental = experimental
self.raw_definition = definition
self._oid_info = None
@property
def oid_info(self):
if self._oid_info is None and self.oid:
self._oid_info = Oids.get(self.oid, '')
return self._oid_info if self._oid_info else None
def __str__(self):
return self.__repr__()
def __repr__(self):
r = ': ' + self.oid
r += ' [OBSOLETE]' if self.obsolete else ''
r += (linesep + ' Short name: ' + list_to_string(self.name)) if self.name else ''
r += (linesep + ' Description: ' + self.description) if self.description else ''
r += '<__desc__>'
r += (linesep + ' Extensions:' + linesep + linesep.join([' ' + s[0] + ': ' + list_to_string(s[1]) for s in self.extensions])) if self.extensions else ''
r += (linesep + ' Experimental:' + linesep + linesep.join([' ' + s[0] + ': ' + list_to_string(s[1]) for s in self.experimental])) if self.experimental else ''
r += (linesep + ' OidInfo: ' + str(self.oid_info)) if self.oid_info else ''
r += linesep
return r
@classmethod
def from_definition(cls, definitions):
if not definitions:
return None
ret_dict = dict()
for object_definition in definitions:
if [object_definition[0] == ')' and object_definition[:-1] == ')']:
if cls is MatchingRuleInfo:
pattern = '| SYNTAX '
elif cls is ObjectClassInfo:
pattern = '| SUP | ABSTRACT| STRUCTURAL| AUXILIARY| MUST | MAY '
elif cls is AttributeTypeInfo:
pattern = '| SUP | EQUALITY | ORDERING | SUBSTR | SYNTAX | SINGLE-VALUE| COLLECTIVE| NO-USER-MODIFICATION| USAGE '
elif cls is MatchingRuleUseInfo:
pattern = '| APPLIES '
elif cls is DitContentRuleInfo:
pattern = '| AUX '
elif cls is LdapSyntaxInfo:
pattern = ''
elif cls is DitContentRuleInfo:
pattern = '| AUX | MUST | MAY | NOT '
elif cls is DitStructureRuleInfo:
pattern = '| FORM | SUP '
elif cls is NameFormInfo:
pattern = '| OC | MUST | MAY '
else:
raise LDAPSchemaError('unknown schema definition class')
splitted = re.split('( NAME | DESC | OBSOLETE| X-| E-' + pattern + ')', object_definition[1:-1])
values = splitted[::2]
separators = splitted[1::2]
separators.insert(0, 'OID')
defs = list(zip(separators, values))
object_def = cls()
for d in defs:
key = d[0].strip()
value = d[1].strip()
if key == 'OID':
object_def.oid = value
elif key == 'NAME':
object_def.name = quoted_string_to_list(value)
elif key == 'DESC':
object_def.description = value.strip("'")
elif key == 'OBSOLETE':
object_def.obsolete = True
elif key == 'SYNTAX':
object_def.syntax = oids_string_to_list(value)
elif key == 'SUP':
object_def.superior = oids_string_to_list(value)
elif key == 'ABSTRACT':
object_def.kind = CLASS_ABSTRACT
elif key == 'STRUCTURAL':
object_def.kind = CLASS_STRUCTURAL
elif key == 'AUXILIARY':
object_def.kind = CLASS_AUXILIARY
elif key == 'MUST':
object_def.must_contain = oids_string_to_list(value)
elif key == 'MAY':
object_def.may_contain = oids_string_to_list(value)
elif key == 'EQUALITY':
object_def.equality = oids_string_to_list(value)
elif key == 'ORDERING':
object_def.ordering = oids_string_to_list(value)
elif key == 'SUBSTR':
object_def.substr = oids_string_to_list(value)
elif key == 'SINGLE-VALUE':
object_def.single_value = True
elif key == 'COLLECTIVE':
object_def.collective = True
elif key == 'NO-USER-MODIFICATION':
object_def.no_user_modification = True
elif key == 'USAGE':
object_def.usage = attribute_usage_to_constant(value)
elif key == 'APPLIES':
object_def.apply_to = oids_string_to_list(value)
elif key == 'AUX':
object_def.auxiliary_classes = oids_string_to_list(value)
elif key == 'FORM':
object_def.name_form = oids_string_to_list(value)
elif key == 'OC':
object_def.object_class = oids_string_to_list(value)
elif key == 'X-':
if not object_def.extensions:
object_def.extensions = []
object_def.extensions.append(extension_to_tuple('X-' + value))
elif key == 'E-':
if not object_def.experimental:
object_def.experimental = []
object_def.experimental.append(extension_to_tuple('E-' + value))
else:
raise LDAPSchemaError('malformed schema definition key:' + key)
object_def.raw_definition = object_definition
if hasattr(object_def, 'syntax') and object_def.syntax and len(object_def.syntax) == 1:
object_def.syntax = object_def.syntax[0]
if hasattr(object_def, 'name') and object_def.name:
for name in object_def.name:
ret_dict[name.lower()] = object_def
else:
ret_dict[object_def.oid] = object_def
else:
raise LDAPSchemaError('malformed schema definition')
return ret_dict
class MatchingRuleInfo(BaseObjectInfo):
"""
As per RFC 4512 (4.1.3)
"""
def __init__(self,
oid=None,
name=None,
description=None,
obsolete=False,
syntax=None,
extensions=None,
experimental=None,
definition=None):
BaseObjectInfo.__init__(self,
oid=oid,
name=name,
description=description,
obsolete=obsolete,
extensions=extensions,
experimental=experimental,
definition=definition)
self.syntax = syntax
def __repr__(self):
r = (linesep + ' Syntax: ' + list_to_string(self.syntax)) if self.syntax else ''
return 'Matching rule' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r)
class MatchingRuleUseInfo(BaseObjectInfo):
"""
As per RFC 4512 (4.1.4)
"""
def __init__(self,
oid=None,
name=None,
description=None,
obsolete=False,
apply_to=None,
extensions=None,
experimental=None,
definition=None):
BaseObjectInfo.__init__(self,
oid=oid,
name=name,
description=description,
obsolete=obsolete,
extensions=extensions,
experimental=experimental,
definition=definition)
self.apply_to = apply_to
def __repr__(self):
r = (linesep + ' Apply to: ' + list_to_string(self.apply_to)) if self.apply_to else ''
return 'Matching rule use' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r)
class ObjectClassInfo(BaseObjectInfo):
"""
As per RFC 4512 (4.1.1)
"""
def __init__(self,
oid=None,
name=None,
description=None,
obsolete=False,
superior=None,
kind=None,
must_contain=None,
may_contain=None,
extensions=None,
experimental=None,
definition=None):
BaseObjectInfo.__init__(self,
oid=oid,
name=name,
description=description,
obsolete=obsolete,
extensions=extensions,
experimental=experimental,
definition=definition)
self.superior = superior
self.kind = kind
self.must_contain = must_contain
self.may_contain = may_contain
def __repr__(self):
r = ''
r += (linesep + ' Type: ' + constant_to_class_kind(self.kind)) if isinstance(self.kind, int) else ''
r += (linesep + ' Must contain attributes: ' + list_to_string(self.must_contain)) if self.must_contain else ''
r += (linesep + ' May contain attributes: ' + list_to_string(self.may_contain)) if self.may_contain else ''
return 'Object Class' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r)
class AttributeTypeInfo(BaseObjectInfo):
"""
As per RFC 4512 (4.1.2)
"""
def __init__(self,
oid=None,
name=None,
description=None,
obsolete=False,
superior=None,
equality=None,
ordering=None,
substring=None,
syntax=None,
single_value=False,
collective=False,
no_user_modification=False,
usage=None,
extensions=None,
experimental=None,
definition=None):
BaseObjectInfo.__init__(self,
oid=oid,
name=name,
description=description,
obsolete=obsolete,
extensions=extensions,
experimental=experimental,
definition=definition)
self.superior = superior
self.equality = equality
self.ordering = ordering
self.substring = substring
self.syntax = syntax
self.single_value = single_value
self.collective = collective
self.no_user_modification = no_user_modification
self.usage = usage
def __repr__(self):
r = ''
r += linesep + ' Single Value: True' if self.single_value else ''
r += linesep + ' Collective: True' if self.collective else ''
r += linesep + ' No user modification: True' if self.no_user_modification else ''
r += (linesep + ' Usage: ' + constant_to_attribute_usage(self.usage)) if self.usage else ''
r += (linesep + ' Equality rule: ' + list_to_string(self.equality)) if self.equality else ''
r += (linesep + ' Ordering rule: ' + list_to_string(self.ordering)) if self.ordering else ''
r += (linesep + ' Substring rule: ' + list_to_string(self.substring)) if self.substring else ''
r += (linesep + ' Syntax: ' + (self.syntax + ' - ' + str(decode_syntax(self.syntax)))) if self.syntax else ''
return 'Attribute type' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r)
class LdapSyntaxInfo(BaseObjectInfo):
"""
As per RFC 4512 (4.1.5)
"""
def __init__(self,
oid=None,
description=None,
extensions=None,
experimental=None,
definition=None):
BaseObjectInfo.__init__(self,
oid=oid, name=None,
description=description,
obsolete=False,
extensions=extensions,
experimental=experimental,
definition=definition)
def __repr__(self):
return 'LDAP syntax' + BaseObjectInfo.__repr__(self).replace('<__desc__>', '')
class DitContentRuleInfo(BaseObjectInfo):
"""
As per RFC 4512 (4.1.6)
"""
def __init__(self,
oid=None,
name=None,
description=None,
obsolete=False,
auxiliary_classes=None,
must_contain=None,
may_contain=None,
not_contains=None,
extensions=None,
experimental=None,
definition=None):
BaseObjectInfo.__init__(self,
oid=oid,
name=name,
description=description,
obsolete=obsolete,
extensions=extensions,
experimental=experimental,
definition=definition)
self.auxiliary_classes = auxiliary_classes
self.must_contain = must_contain
self.may_contain = may_contain
self.not_contains = not_contains
def __repr__(self):
r = (linesep + ' Auxiliary classes: ' + list_to_string(self.auxiliary_classes)) if self.auxiliary_classes else ''
r += (linesep + ' Must contain: ' + list_to_string(self.must_contain)) if self.must_contain else ''
r += (linesep + ' May contain: ' + list_to_string(self.may_contain)) if self.may_contain else ''
r += (linesep + ' Not contains: ' + list_to_string(self.not_contains)) if self.not_contains else ''
return 'DIT content rule' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r)
class DitStructureRuleInfo(BaseObjectInfo):
"""
As per RFC 4512 (4.1.7.1)
"""
def __init__(self,
oid=None,
name=None,
description=None,
obsolete=False,
name_form=None,
superior=None,
extensions=None,
experimental=None,
definition=None):
BaseObjectInfo.__init__(self,
oid=oid,
name=name,
description=description,
obsolete=obsolete,
extensions=extensions,
experimental=experimental,
definition=definition)
self.superior = superior
self.name_form = name_form
def __repr__(self):
r = (linesep + ' Superior rules: ' + list_to_string(self.superior)) if self.superior else ''
r += (linesep + ' Name form: ' + list_to_string(self.name_form)) if self.name_form else ''
return 'DIT content rule' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r)
class NameFormInfo(BaseObjectInfo):
"""
As per RFC 4512 (4.1.7.2)
"""
def __init__(self,
oid=None,
name=None,
description=None,
obsolete=False,
object_class=None,
must_contain=None,
may_contain=None,
extensions=None,
experimental=None,
definition=None):
BaseObjectInfo.__init__(self,
oid=oid,
name=name,
description=description,
obsolete=obsolete,
extensions=extensions,
experimental=experimental,
definition=definition)
self.object_class = object_class
self.must_contain = must_contain
self.may_contain = may_contain
def __repr__(self):
r = (linesep + ' Object class: ' + self.object_class) if self.object_class else ''
r += (linesep + ' Must contain: ' + list_to_string(self.must_contain)) if self.must_contain else ''
r += (linesep + ' May contain: ' + list_to_string(self.may_contain)) if self.may_contain else ''
return 'DIT content rule' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r)
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc4532.py 0000666 0000000 0000000 00000002063 12355106663 021200 0 ustar 0000000 0000000 """
Created on 2014.06.30
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from pyasn1.type.univ import OctetString
from pyasn1.type.tag import Tag, tagFormatSimple, tagClassContext
class AuthzId(OctetString):
tagSet = OctetString.tagSet.tagExplicitly(Tag(tagClassContext, tagFormatSimple, 4))
encoding = 'utf-8' python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/ 0000777 0000000 0000000 00000000000 12355117540 020473 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/digestMd5.py 0000666 0000000 0000000 00000010221 12355103747 022672 0 ustar 0000000 0000000 """
Created on 2014.01.04
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from binascii import hexlify
import hashlib
import hmac
from .sasl import abort_sasl_negotiation, send_sasl_negotiation, random_hex_string
def md5_h(value):
if not isinstance(value, bytes):
value = value.encode()
return hashlib.md5(value).digest()
def md5_kd(k, s):
if not isinstance(k, bytes):
k = k.encode()
if not isinstance(s, bytes):
s = s.encode()
return md5_h(k + b':' + s)
def md5_hex(value):
if not isinstance(value, bytes):
value = value.encode()
return hexlify(value)
def md5_hmac(k, s):
if not isinstance(k, bytes):
k = k.encode()
if not isinstance(s, bytes):
s = s.encode()
return hmac.new(k, s).hexdigest()
def sasl_digest_md5(connection, controls):
# sasl_credential must be a tuple made up of the following elements: (realm, user, password, authorization_id)
# if realm is None will be used the realm received from the server, if available
if not isinstance(connection.sasl_credentials, tuple) or not len(connection.sasl_credentials) == 4:
return None
# step One of RFC2831
result = send_sasl_negotiation(connection, controls, None)
if 'saslCreds' in result and result['saslCreds'] != 'None':
server_directives = dict((attr[0], attr[1].strip('"')) for attr in [line.split('=') for line in result['saslCreds'].split(',')]) # convert directives to dict, unquote values
else:
return None
if 'realm' not in server_directives or 'nonce' not in server_directives or 'algorithm' not in server_directives: # mandatory directives, as per RFC2831
abort_sasl_negotiation(connection, controls)
return None
# step Two of RFC2831
charset = server_directives['charset'] if 'charset' in server_directives and server_directives['charset'].lower() == 'utf-8' else 'iso8859-1'
user = connection.sasl_credentials[1].encode(charset)
realm = (connection.sasl_credentials[0] if connection.sasl_credentials[0] else (server_directives['realm'] if 'realm' in server_directives else '')).encode(charset)
password = connection.sasl_credentials[2].encode(charset)
authz_id = connection.sasl_credentials[3].encode(charset) if connection.sasl_credentials[3] else b''
nonce = server_directives['nonce'].encode(charset)
cnonce = random_hex_string(16).encode(charset)
uri = b'ldap/'
qop = b'auth'
digest_response = b'username="' + user + b'",'
digest_response += b'realm="' + realm + b'",'
digest_response += b'nonce="' + nonce + b'",'
digest_response += b'cnonce="' + cnonce + b'",'
digest_response += b'digest-uri="' + uri + b'",'
digest_response += b'qop=' + qop + b','
digest_response += b'nc=00000001' + b','
if charset == 'utf-8':
digest_response += b'charset="utf-8",'
a0 = md5_h(b':'.join([user, realm, password]))
a1 = b':'.join([a0, nonce, cnonce, authz_id]) if authz_id else b':'.join([a0, nonce, cnonce])
a2 = b'AUTHENTICATE:' + uri + (':00000000000000000000000000000000' if qop in [b'auth-int', b'auth-conf'] else b'')
digest_response += b'response="' + md5_hex(md5_kd(md5_hex(md5_h(a1)), b':'.join([nonce, b'00000001', cnonce, qop, md5_hex(md5_h(a2))]))) + b'"'
result = send_sasl_negotiation(connection, controls, digest_response)
return result
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/external.py 0000666 0000000 0000000 00000001773 12355103747 022703 0 ustar 0000000 0000000 """
Created on 2014.01.04
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from .sasl import send_sasl_negotiation
def sasl_external(connection, controls):
result = send_sasl_negotiation(connection, controls, connection.sasl_credentials)
return result
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/sasl.py 0000666 0000000 0000000 00000016410 12355103747 022015 0 ustar 0000000 0000000 """
Created on 2013.09.11
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
import stringprep
from unicodedata import ucd_3_2_0 as unicode32
from os import urandom
from binascii import hexlify
from ... import AUTH_SASL, RESULT_AUTH_METHOD_NOT_SUPPORTED
from ...core.exceptions import LDAPSASLPrepError, LDAPPasswordIsMandatoryError
def sasl_prep(data):
"""
implement SASLPrep profile as per RFC4013:
it defines the "SASLprep" profile of the "stringprep" algorithm [StringPrep].
The profile is designed for use in Simple Authentication and Security
Layer ([SASL]) mechanisms, such as [PLAIN], [CRAM-MD5], and
[DIGEST-MD5]. It may be applicable where simple user names and
passwords are used. This profile is not intended for use in
preparing identity strings that are not simple user names (e.g.,
email addresses, domain names, distinguished names), or where
identity or password strings that are not character data, or require
different handling (e.g., case folding).
"""
# mapping
prepared_data = ''
for c in data:
if stringprep.in_table_c12(c):
# non-ASCII space characters [StringPrep, C.1.2] that can be mapped to SPACE (U+0020)
prepared_data += ' '
elif stringprep.in_table_b1(c):
# the "commonly mapped to nothing" characters [StringPrep, B.1] that can be mapped to nothing.
pass
else:
prepared_data += c
# normalizing
# This profile specifies using Unicode normalization form KC
# The repertoire is Unicode 3.2 as per RFC 4013 (2)
prepared_data = unicode32.normalize('NFKC', prepared_data)
if not prepared_data:
raise LDAPSASLPrepError('SASLprep error: unable to normalize string')
# prohibit
for c in prepared_data:
if stringprep.in_table_c12(c):
# Non-ASCII space characters [StringPrep, C.1.2]
raise LDAPSASLPrepError('SASLprep error: non-ASCII space character present')
elif stringprep.in_table_c21(c):
# ASCII control characters [StringPrep, C.2.1]
raise LDAPSASLPrepError('SASLprep error: ASCII control character present')
elif stringprep.in_table_c22(c):
# Non-ASCII control characters [StringPrep, C.2.2]
raise LDAPSASLPrepError('SASLprep error: non-ASCII control character present')
elif stringprep.in_table_c3(c):
# Private Use characters [StringPrep, C.3]
raise LDAPSASLPrepError('SASLprep error: private character present')
elif stringprep.in_table_c4(c):
# Non-character code points [StringPrep, C.4]
raise LDAPSASLPrepError('SASLprep error: non-character code point present')
elif stringprep.in_table_c5(c):
# Surrogate code points [StringPrep, C.5]
raise LDAPSASLPrepError('SASLprep error: surrogate code point present')
elif stringprep.in_table_c6(c):
# Inappropriate for plain text characters [StringPrep, C.6]
raise LDAPSASLPrepError('SASLprep error: inappropriate for plain text character present')
elif stringprep.in_table_c7(c):
# Inappropriate for canonical representation characters [StringPrep, C.7]
raise LDAPSASLPrepError('SASLprep error: inappropriate for canonical representation character present')
elif stringprep.in_table_c8(c):
# Change display properties or deprecated characters [StringPrep, C.8]
raise LDAPSASLPrepError('SASLprep error: change display property or deprecated character present')
elif stringprep.in_table_c9(c):
# Tagging characters [StringPrep, C.9]
raise LDAPSASLPrepError('SASLprep error: tagging character present')
# check bidi
# if a string contains any r_and_al_cat character, the string MUST NOT contain any l_cat character.
flag_r_and_al_cat = False
flag_l_cat = False
for c in prepared_data:
if stringprep.in_table_d1(c):
flag_r_and_al_cat = True
elif stringprep.in_table_d2(c):
flag_l_cat = True
if flag_r_and_al_cat and flag_l_cat:
raise LDAPSASLPrepError('SASLprep error: string cannot contain (R or AL) and L bidirectional chars')
# If a string contains any r_and_al_cat character, a r_and_al_cat character MUST be the first character of the string
# and a r_and_al_cat character MUST be the last character of the string.
if flag_r_and_al_cat and not stringprep.in_table_d1(prepared_data[0]) and not stringprep.in_table_d2(prepared_data[-1]):
raise LDAPSASLPrepError('r_and_al_cat character present, must be first and last character of the string')
return prepared_data
def validate_simple_password(password):
"""
validate simple password as per RFC4013 using sasl_prep:
"""
if password == '' or password is None:
raise LDAPPasswordIsMandatoryError("simple password can't be empty")
if not isinstance(password, bytes): # bytes are returned raw, as per RFC (4.2)
password = sasl_prep(password)
return password
# def addSaslCredentialsToBindRequest(request, mechanism, credentials):
# sasl_credentials = SaslCredentials()
# sasl_credentials['mechanism'] = mechanism
# if credentials:
# sasl_credentials['credentials'] = credentials
# request['authentication'] = AuthenticationChoice().setComponentByName('sasl', sasl_credentials)
#
# return request
def abort_sasl_negotiation(connection, controls):
from ...operation.bind import bind_operation
request = bind_operation(connection.version, AUTH_SASL, None, None, '', None)
response = connection.post_send_single_response(connection.send('bindRequest', request, controls))
result = connection.get_response(response)[0][0] if isinstance(response, int) else connection.result
return True if result['result'] == RESULT_AUTH_METHOD_NOT_SUPPORTED else False
def send_sasl_negotiation(connection, controls, payload):
from ...operation.bind import bind_operation
request = bind_operation(connection.version, AUTH_SASL, None, None, connection.sasl_mechanism, payload)
response = connection.post_send_single_response(connection.send('bindRequest', request, controls))
result = connection.get_response(response)[1] if isinstance(response, int) else connection.result
return result
def random_hex_string(size):
return str(hexlify(urandom(size)).decode('ascii')) # str fix for Python 2
python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/__init__.py 0000666 0000000 0000000 00000000000 12355103747 022576 0 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/__init__.py 0000666 0000000 0000000 00000000000 12355103747 021634 0 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/ 0000777 0000000 0000000 00000000000 12355117540 017532 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/asyncThreaded.py 0000666 0000000 0000000 00000020162 12355103747 022667 0 ustar 0000000 0000000 """
Created on 2013.07.15
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from threading import Thread, Lock
from pyasn1.codec.ber import decoder
from .. import RESPONSE_COMPLETE, SOCKET_SIZE, RESULT_REFERRAL
from ..core.exceptions import LDAPSSLConfigurationError, LDAPStartTLSError
from ..strategy.baseStrategy import BaseStrategy
from ..protocol.rfc4511 import LDAPMessage
# noinspection PyProtectedMember
class AsyncThreadedStrategy(BaseStrategy):
"""
This strategy is asynchronous. You send the request and get the messageId of the request sent
Receiving data from socket is managed in a separated thread in a blocking mode
Requests return an int value to indicate the messageId of the requested Operation
You get the response with get_response, it has a timeout to wait for response to appear
Connection.response will contain the whole LDAP response for the messageId requested in a dict form
Connection.request will contain the result LDAP message in a dict form
Response appear in strategy._responses dictionary
"""
# noinspection PyProtectedMember
class ReceiverSocketThread(Thread):
"""
The thread that actually manage the receiver socket
"""
def __init__(self, ldap_connection):
Thread.__init__(self)
self.connection = ldap_connection
def run(self):
"""
Wait for data on socket, compute the length of the message and wait for enough bytes to decode the message
Message are appended to strategy._responses
"""
unprocessed = b''
get_more_data = True
listen = True
data = b''
while listen:
if get_more_data:
try:
data = self.connection.socket.recv(SOCKET_SIZE)
except OSError:
listen = False
if len(data) > 0:
unprocessed += data
data = b''
else:
listen = False
length = BaseStrategy.compute_ldap_message_size(unprocessed)
if length == -1 or len(unprocessed) < length:
get_more_data = True
elif len(unprocessed) >= length: # add message to message list
if self.connection._usage:
self.connection._usage.received_message(length)
ldap_resp = decoder.decode(unprocessed[:length], asn1Spec=LDAPMessage())[0]
message_id = int(ldap_resp['messageID'])
dict_response = BaseStrategy.decode_response(ldap_resp)
if dict_response['type'] == 'extendedResp' and dict_response['responseName'] == '1.3.6.1.4.1.1466.20037':
if dict_response['result'] == 0: # StartTls in progress
if self.connection.server.tls:
self.connection.server.tls._start_tls(self.connection)
else:
self.connection.last_error = 'no Tls defined in Server'
raise LDAPSSLConfigurationError(self.connection.last_error)
else:
self.connection.last_error = 'asynchronous StartTls failed'
raise LDAPStartTLSError(self.connection.last_error)
if message_id != 0: # 0 is reserved for 'Unsolicited Notification' from server as per RFC4511 (paragraph 4.4)
with self.connection.strategy.lock:
if message_id in self.connection.strategy._responses:
self.connection.strategy._responses[message_id].append(dict_response)
else:
self.connection.strategy._responses[message_id] = [dict_response]
if dict_response['type'] not in ['searchResEntry', 'searchResRef', 'intermediateResponse']:
self.connection.strategy._responses[message_id].append(RESPONSE_COMPLETE)
unprocessed = unprocessed[length:]
get_more_data = False if unprocessed else True
listen = True if self.connection.listening or unprocessed else False
else: # Unsolicited Notification
if dict_response['responseName'] == '1.3.6.1.4.1.1466.20036': # Notice of Disconnection as per RFC4511 (paragraph 4.4.1)
listen = False
self.connection.strategy.close()
def __init__(self, ldap_connection):
BaseStrategy.__init__(self, ldap_connection)
self.sync = False
self.no_real_dsa = False
self.pooled = False
self.has_stream_capapbility = False
self._responses = None
self.receiver = None
self.lock = Lock()
def open(self, reset_usage=True):
"""
Open connection and start listen on the socket in a different thread
"""
with self.lock:
BaseStrategy.open(self, reset_usage=True)
self._responses = dict()
self.connection.refresh_dsa_info()
def close(self):
"""
Close connection and stop socket thread
"""
with self.lock:
BaseStrategy.close(self)
def post_send_search(self, message_id):
"""
Clears connection.response and returns messageId
"""
self.connection.response = None
self.connection.result = message_id
return message_id
def post_send_single_response(self, message_id):
"""
Clears connection.response and returns messageId.
"""
self.connection.response = None
self.connection.result = message_id
return message_id
def _start_listen(self):
"""
Start thread in daemon mode
"""
if not self.connection.listening:
self.receiver = AsyncThreadedStrategy.ReceiverSocketThread(self.connection)
self.connection.listening = True
self.receiver.daemon = True
self.receiver.start()
def _get_response(self, message_id):
"""
Performs the capture of LDAP response for this strategy
Checks lock to avoid race condition with receiver thread
"""
with self.lock:
responses = self._responses.pop(message_id) if message_id in self._responses and self._responses[message_id][-1] == RESPONSE_COMPLETE else None
if responses is not None and responses[-2]['result'] == RESULT_REFERRAL:
if self.connection._usage:
self.connection._usage.referrals_followed += 1
if self.connection.auto_referrals:
ref_response, ref_result = self.do_operation_on_referral(self._outstanding[message_id], responses[-2]['referrals'])
if ref_response is not None:
responses = ref_response + [ref_result]
responses.append(RESPONSE_COMPLETE)
elif ref_result is not None:
responses = [ref_result, RESPONSE_COMPLETE]
self._referrals = []
return responses
python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/baseStrategy.py 0000666 0000000 0000000 00000066775 12355107541 022566 0 ustar 0000000 0000000 """
Created on 15/lug/2013
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
import socket
from time import sleep
from random import choice
from pyasn1.codec.ber import encoder, decoder
from .. import SESSION_TERMINATED_BY_SERVER, RESPONSE_SLEEPTIME, RESPONSE_WAITING_TIMEOUT, SEARCH_SCOPE_BASE_OBJECT, SEARCH_SCOPE_WHOLE_SUBTREE, SEARCH_SCOPE_SINGLE_LEVEL, STRATEGY_SYNC, AUTH_ANONYMOUS, DO_NOT_RAISE_EXCEPTIONS
from ..core.exceptions import LDAPOperationResult, LDAPSASLBindInProgressError, LDAPSocketOpenError, LDAPSessionTerminatedByServer, LDAPUnknownResponseError, LDAPUnknownRequestError, LDAPReferralError, communication_exception_factory, \
LDAPSocketSendError, LDAPExceptionError, LDAPSocketCloseError
from ..protocol.rfc4511 import LDAPMessage, ProtocolOp, MessageID
from ..operation.add import add_response_to_dict, add_request_to_dict
from ..operation.modify import modify_request_to_dict, modify_response_to_dict
from ..operation.search import search_result_reference_response_to_dict, search_result_done_response_to_dict, search_result_entry_response_to_dict, search_request_to_dict
from ..operation.bind import bind_response_to_dict, bind_request_to_dict
from ..operation.compare import compare_response_to_dict, compare_request_to_dict
from ..operation.extended import extended_request_to_dict, extended_response_to_dict, intermediate_response_to_dict
from ..core.server import Server
from ..operation.modifyDn import modify_dn_request_to_dict, modify_dn_response_to_dict
from ..operation.delete import delete_response_to_dict, delete_request_to_dict
from ..protocol.convert import prepare_changes_for_request, build_controls_list
from ..operation.abandon import abandon_request_to_dict
from ..core.tls import Tls
from ..protocol.oid import Oids
from ..protocol.rfc2696 import RealSearchControlValue
# noinspection PyProtectedMember
class BaseStrategy(object):
"""
Base class for connection strategy
"""
def __init__(self, ldap_connection):
self.connection = ldap_connection
self._outstanding = dict()
self._referrals = []
self.sync = None # indicates a synchronous connection
self.no_real_dsa = None # indicates a connection to a fake LDAP server
self.pooled = None # Indicates a connection with a connection pool
self.can_stream = False # indicate if a strategy keep a stream of responses (i.e. LDIFProducer can accumulate responses with a single header). Stream must be initilized and closed in _start_listen() and _stop_listen()
def open(self, reset_usage=True):
"""
Open a socket to a server. Choose a server from the server pool if available
"""
if self.connection.lazy and not self.connection._executing_deferred:
self.connection._deferred_open = True
self.connection.closed = False
else:
if not self.connection.closed and not self.connection._executing_deferred: # try to close connection if still open
self.close()
self._outstanding = dict()
if self.connection._usage:
if reset_usage or not self.connection._usage.initial_connection_start_time:
self.connection._usage.start()
if self.connection.server_pool:
new_server = self.connection.server_pool.get_server(self.connection) # get a server from the server_pool if available
if self.connection.server != new_server:
self.connection.server = new_server
if self.connection._usage:
self.connection._usage.servers_from_pool += 1
if not self.no_real_dsa:
self._open_socket(self.connection.server.ssl)
self.connection._deferred_open = False
self._start_listen()
def close(self):
"""
Close connection
"""
if self.connection.lazy and not self.connection._executing_deferred and (self.connection._deferred_bind or self.connection._deferred_open):
self.connection.listening = False
self.connection.closed = True
else:
if not self.connection.closed:
self._stop_listen()
if not self. no_real_dsa:
self._close_socket()
self.connection.bound = False
self.connection.request = None
self.connection.response = None
self.connection.tls_started = False
self._outstanding = dict()
self._referrals = []
if self.connection._usage:
self.connection._usage.stop()
def _open_socket(self, use_ssl=False):
"""
Tries to open and connect a socket to a Server
raise LDAPExceptionError if unable to open or connect socket
"""
exc = None
try:
self.connection.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except Exception as e:
self.connection.last_error = 'socket creation error: ' + str(e)
exc = e
if exc:
raise communication_exception_factory(LDAPSocketOpenError, exc)(self.connection.last_error)
try:
self.connection.socket.connect((self.connection.server.host, self.connection.server.port))
except socket.error as e:
self.connection.last_error = 'socket connection error: ' + str(e)
exc = e
if exc:
raise communication_exception_factory(LDAPSocketOpenError, exc)(self.connection.last_error)
if use_ssl:
try:
self.connection.server.tls.wrap_socket(self.connection, do_handshake=True)
if self.connection._usage:
self.connection._usage.wrapped_sockets += 1
except Exception as e:
self.connection.last_error = 'socket ssl wrapping error: ' + str(e)
exc = e
if exc:
raise communication_exception_factory(LDAPSocketOpenError, exc)(self.connection.last_error)
if self.connection._usage:
self.connection._usage.opened_sockets += 1
self.connection.closed = False
def _close_socket(self):
"""
Try to close a socket
raise LDAPExceptionError if unable to close socket
"""
exc = None
try:
self.connection.socket.shutdown(socket.SHUT_RDWR)
self.connection.socket.close()
except Exception as e:
self.connection.last_error = 'socket closing error' + str(e)
exc = e
if exc:
raise communication_exception_factory(LDAPSocketCloseError, exc)(self.connection.last_error)
self.connection.socket = None
self.connection.closed = True
if self.connection._usage:
self.connection._usage.closed_sockets += 1
def _stop_listen(self):
self.connection.listening = False
def send(self, message_type, request, controls=None):
"""
Send an LDAP message
Returns the message_id
"""
exc = None
self.connection.request = None
if self.connection.listening:
if self.connection.sasl_in_progress and message_type not in ['bindRequest']: # as per RFC4511 (4.2.1)
self.connection.last_error = 'cannot send operation requests while SASL bind is in progress'
raise LDAPSASLBindInProgressError(self.connection.last_error)
message_id = self.connection.server.next_message_id()
ldap_message = LDAPMessage()
ldap_message['messageID'] = MessageID(message_id)
ldap_message['protocolOp'] = ProtocolOp().setComponentByName(message_type, request)
message_controls = build_controls_list(controls)
if message_controls is not None:
ldap_message['controls'] = message_controls
try:
encoded_message = encoder.encode(ldap_message)
self.connection.socket.sendall(encoded_message)
except socket.error as e:
self.connection.last_error = 'socket sending error' + str(e)
encoded_message = None
exc = e
if exc:
raise communication_exception_factory(LDAPSocketSendError, exc)(self.connection.last_error)
self.connection.request = BaseStrategy.decode_request(ldap_message)
self.connection.request['controls'] = controls
self._outstanding[message_id] = self.connection.request
if self.connection._usage:
self.connection._usage.transmitted_message(self.connection.request, len(encoded_message))
else:
self.connection.last_error = 'unable to send message, socket is not open'
raise LDAPSocketOpenError(self.connection.last_error)
return message_id
def get_response(self, message_id, timeout=RESPONSE_WAITING_TIMEOUT):
"""
Get response LDAP messages
Responses are returned by the underlying connection strategy
Check if message_id LDAP message is still outstanding and wait for timeout to see if it appears in _get_response
Result is stored in connection.result
Responses without result is stored in connection.response
A tuple (responses, result) is returned
"""
response = None
result = None
if self._outstanding and message_id in self._outstanding:
while timeout >= 0: # waiting for completed message to appear in responses
responses = self._get_response(message_id)
if responses == SESSION_TERMINATED_BY_SERVER:
try: # try to close the session but don't raise any error if server has already closed the session
self.close()
except (socket.error, LDAPExceptionError):
pass
self.connection.last_error = 'session terminated by server'
raise LDAPSessionTerminatedByServer(self.connection.last_error)
if not responses:
sleep(RESPONSE_SLEEPTIME)
timeout -= RESPONSE_SLEEPTIME
else:
if responses:
self._outstanding.pop(message_id)
result = responses[-2]
response = responses[:-2]
self.connection.result = result
self.connection.response = None
break
if self.connection.raise_exceptions and result and result['result'] not in DO_NOT_RAISE_EXCEPTIONS:
raise LDAPOperationResult(result=result['result'], description=result['description'], dn=result['dn'], message=result['message'], response_type=result['type'], response=response)
return response, result
@classmethod
def compute_ldap_message_size(cls, data):
"""
Compute LDAP Message size according to BER definite length rules
Returns -1 if too few data to compute message length
"""
if isinstance(data, str): # fix for Python 2, data is string not bytes
data = bytearray(data) # Python 2 bytearray is equivalent to Python 3 bytes
ret_value = -1
if len(data) > 2:
if data[1] <= 127: # BER definite length - short form. Highest bit of byte 1 is 0, message length is in the last 7 bits - Value can be up to 127 bytes long
ret_value = data[1] + 2
else: # BER definite length - long form. Highest bit of byte 1 is 1, last 7 bits counts the number of following octets containing the value length
bytes_length = data[1] - 128
if len(data) >= bytes_length + 2:
value_length = 0
cont = bytes_length
for byte in data[2:2 + bytes_length]:
cont -= 1
value_length += byte * (256 ** cont)
ret_value = value_length + 2 + bytes_length
return ret_value
@classmethod
def decode_response(cls, ldap_message):
"""
Convert received LDAPMessage to a dict
"""
message_type = ldap_message.getComponentByName('protocolOp').getName()
component = ldap_message['protocolOp'].getComponent()
controls = ldap_message['controls']
if message_type == 'bindResponse':
result = bind_response_to_dict(component)
elif message_type == 'searchResEntry':
result = search_result_entry_response_to_dict(component)
elif message_type == 'searchResDone':
result = search_result_done_response_to_dict(component)
elif message_type == 'searchResRef':
result = search_result_reference_response_to_dict(component)
elif message_type == 'modifyResponse':
result = modify_response_to_dict(component)
elif message_type == 'addResponse':
result = add_response_to_dict(component)
elif message_type == 'delResponse':
result = delete_response_to_dict(component)
elif message_type == 'modDNResponse':
result = modify_dn_response_to_dict(component)
elif message_type == 'compareResponse':
result = compare_response_to_dict(component)
elif message_type == 'extendedResp':
result = extended_response_to_dict(component)
elif message_type == 'intermediateResponse':
result = intermediate_response_to_dict(component)
else:
raise LDAPUnknownResponseError('unknown response')
result['type'] = message_type
if controls:
result['controls'] = dict()
for control in controls:
decoded_control = cls.decode_control(control)
result['controls'][decoded_control[0]] = decoded_control[1]
return result
@classmethod
def decode_control(cls, control):
"""
decode control, return a 2-element tuple where the first element is the control oid
and the second element is a dictionary with description (from Oids), criticality and decoded control value
"""
control_type = str(control['controlType'])
criticality = bool(control['criticality'])
control_value = bytes(control['controlValue'])
if control_type == '1.2.840.113556.1.4.319': # simple paged search as per RFC2696
control_resp, unprocessed = decoder.decode(control_value, asn1Spec=RealSearchControlValue())
control_value = dict()
control_value['size'] = int(control_resp['size'])
control_value['cookie'] = bytes(control_resp['cookie'])
return control_type, {'description': Oids.get(control_type, ''), 'criticality': criticality, 'value': control_value}
@classmethod
def decode_request(cls, ldap_message):
message_type = ldap_message.getComponentByName('protocolOp').getName()
component = ldap_message['protocolOp'].getComponent()
if message_type == 'bindRequest':
result = bind_request_to_dict(component)
elif message_type == 'unbindRequest':
result = dict()
elif message_type == 'addRequest':
result = add_request_to_dict(component)
elif message_type == 'compareRequest':
result = compare_request_to_dict(component)
elif message_type == 'delRequest':
result = delete_request_to_dict(component)
elif message_type == 'extendedReq':
result = extended_request_to_dict(component)
elif message_type == 'modifyRequest':
result = modify_request_to_dict(component)
elif message_type == 'modDNRequest':
result = modify_dn_request_to_dict(component)
elif message_type == 'searchRequest':
result = search_request_to_dict(component)
elif message_type == 'abandonRequest':
result = abandon_request_to_dict(component)
else:
raise LDAPUnknownRequestError('unknown request')
result['type'] = message_type
return result
def valid_referral_list(self, referrals):
referral_list = []
for referral in referrals:
candidate_referral = BaseStrategy.decode_referral(referral)
if candidate_referral:
for ref_host in self.connection.server.allowed_referral_hosts:
if ref_host[0] == candidate_referral['host'] or ref_host[0] == '*':
if candidate_referral['host'] not in self._referrals:
candidate_referral['anonymousBindOnly'] = not ref_host[1]
referral_list.append(candidate_referral)
break
return referral_list
@classmethod
def decode_referral(cls, uri):
"""
Decode referral URI as specified in RFC 4516 relaxing specifications
permitting 'ldaps' as scheme meaning ssl-ldap
ldapurl = scheme COLON SLASH SLASH [host [COLON port]]
[SLASH dn [QUESTION [attributes]
[QUESTION [scope] [QUESTION [filter]
[QUESTION extensions]]]]]
; and are defined
; in Sections 3.2.2 and 3.2.3
; of [RFC3986].
; is from Section 3 of
; [RFC4515], subject to the
; provisions of the
; "Percent-Encoding" section
; below.
scheme = "ldap" / "ldaps" <== not RFC4516 compliant (original is 'scheme = "ldap"')
dn = distinguishedName ; From Section 3 of [RFC4514],
; subject to the provisions of
; the "Percent-Encoding"
; section below.
attributes = attrdesc *(COMMA attrdesc)
attrdesc = selector *(COMMA selector)
selector = attributeSelector ; From Section 4.5.1 of
; [RFC4511], subject to the
; provisions of the
; "Percent-Encoding" section
; below.
scope = "base" / "one" / "sub"
extensions = extension *(COMMA extension)
extension = [EXCLAMATION] extype [EQUALS exvalue]
extype = oid ; From section 1.4 of [RFC4512].
exvalue = LDAPString ; From section 4.1.2 of
; [RFC4511], subject to the
; provisions of the
; "Percent-Encoding" section
; below.
EXCLAMATION = %x21 ; exclamation mark ("!")
SLASH = %x2F ; forward slash ("/")
COLON = %x3A ; colon (":")
QUESTION = %x3F ; question mark ("?")
"""
referral = dict()
parts = uri.split('?')
scheme, sep, remain = parts[0].partition('://')
if sep != '://' or scheme not in ['ldap', 'ldaps']:
return None
address, _, referral['base'] = remain.partition('/')
referral['ssl'] = True if scheme == 'ldaps' else False
referral['host'], sep, referral['port'] = address.partition(':')
if sep != ':':
referral['port'] = None
else:
if not referral['port'].isdigit() or not (0 < int(referral['port']) < 65536):
return None
else:
referral['port'] = int(referral['port'])
referral['attributes'] = parts[1].split(',') if len(parts) > 1 else None
referral['scope'] = parts[2] if len(parts) > 2 else None
if referral['scope'] == 'base':
referral['scope'] = SEARCH_SCOPE_BASE_OBJECT
elif referral['scope'] == 'sub':
referral['scope'] = SEARCH_SCOPE_WHOLE_SUBTREE
elif referral['scope'] == 'one':
referral['scope'] = SEARCH_SCOPE_SINGLE_LEVEL
elif referral['scope']:
return None
referral['filter'] = parts[3] if len(parts) > 3 else None
referral['extensions'] = parts[3].split(',') if len(parts) > 4 else None
return referral
def do_operation_on_referral(self, request, referrals):
valid_referral_list = self.valid_referral_list(referrals)
if valid_referral_list:
preferred_referral_list = [referral for referral in valid_referral_list if referral['ssl'] == self.connection.server.ssl]
selected_referral = choice(preferred_referral_list) if preferred_referral_list else choice(valid_referral_list)
referral_server = Server(host=selected_referral['host'],
port=selected_referral['port'] or self.connection.server.port,
use_ssl=selected_referral['ssl'],
allowed_referral_hosts=self.connection.server.allowed_referral_hosts,
tls=Tls(local_private_key_file=self.connection.server.tls.private_key_file,
local_certificate_file=self.connection.server.tls.certificate_file,
validate=self.connection.server.tls.validate,
version=self.connection.server.tls.version,
ca_certs_file=self.connection.server.tls.ca_certs_file) if selected_referral['ssl'] else None)
from ..core.connection import Connection
referral_connection = Connection(server=referral_server,
user=self.connection.user if not selected_referral['anonymousBindOnly'] else None,
password=self.connection.password if not selected_referral['anonymousBindOnly'] else None,
version=self.connection.version,
authentication=self.connection.authentication if not selected_referral['anonymousBindOnly'] else AUTH_ANONYMOUS,
client_strategy=STRATEGY_SYNC,
auto_referrals=True,
read_only=self.connection.read_only)
if self.connection._usage:
self.connection._usage.referrals_followed += 1
referral_connection.open()
referral_connection.strategy._referrals = self._referrals
if self.connection.bound:
referral_connection.bind()
if request['type'] == 'searchRequest':
referral_connection.search(selected_referral['base'] or request['base'],
selected_referral['filter'] or request['filter'],
selected_referral['scope'] or request['scope'],
request['dereferenceAlias'],
selected_referral['attributes'] or request['attributes'],
request['sizeLimit'],
request['timeLimit'],
request['typeOnly'],
controls=request['controls'])
elif request['type'] == 'addRequest':
referral_connection.add(selected_referral['base'] or request['entry'],
None,
request['attributes'],
controls=request['controls'])
elif request['type'] == 'compareRequest':
referral_connection.compare(selected_referral['base'] or request['entry'],
request['attribute'],
request['value'],
controls=request['controls'])
elif request['type'] == 'delRequest':
referral_connection.delete(selected_referral['base'] or request['entry'],
controls=request['controls'])
elif request['type'] == 'extendedRequest':
# tbd
raise NotImplementedError()
elif request['type'] == 'modifyRequest':
referral_connection.modify(selected_referral['base'] or request['entry'],
prepare_changes_for_request(request['changes']),
controls=request['controls'])
elif request['type'] == 'modDNRequest':
referral_connection.modify_dn(selected_referral['base'] or request['entry'],
request['newRdn'],
request['deleteOldRdn'],
request['newSuperior'],
controls=request['controls'])
else:
self.connection.last_error = 'referral operation not permitted'
raise LDAPReferralError(self.connection.last_error)
response = referral_connection.response
result = referral_connection.result
referral_connection.unbind()
else:
response = None
result = None
return response, result
def _start_listen(self):
#overridden on strategy class
raise NotImplementedError
def _get_response(self, message_id):
# overridden in strategy class
raise NotImplementedError
def receiving(self):
# overridden in strategy class
raise NotImplementedError
def post_send_single_response(self, message_id):
# overridden in strategy class
raise NotImplementedError
def post_send_search(self, message_id):
# overridden in strategy class
raise NotImplementedError
def get_stream(self):
raise NotImplementedError
def set_stream(self, value):
raise NotImplementedError python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/ldifProducer.py 0000666 0000000 0000000 00000012071 12355103747 022533 0 ustar 0000000 0000000 """
Created on 2013.07.15
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from io import StringIO
from os import linesep
import random
from .. import LDAP_MAX_INT
from ..core.exceptions import LDAPLDIFError
from ..utils.conv import prepare_for_stream
from ..protocol.rfc4511 import LDAPMessage, MessageID, ProtocolOp
from ..protocol.rfc2849 import operation_to_ldif, add_ldif_header
from ..protocol.convert import build_controls_list
from .baseStrategy import BaseStrategy
class LdifProducerStrategy(BaseStrategy):
"""
This strategy is used to create the LDIF stream for the Add, Delete, Modify, ModifyDn operations.
You send the request and get the request in the ldif-change representation of the operation.
NO OPERATION IS SENT TO THE LDAP SERVER!
Connection.request will contain the result LDAP message in a dict form
Connection.response will contain the ldif-change format of the requested operation if available
You don't need a real server to connect to for this strategy
"""
def __init__(self, ldap_connection):
BaseStrategy.__init__(self, ldap_connection)
self.sync = True
self.no_real_dsa = True
self.pooled = False
self.can_stream = True
self.line_separator = linesep
self.all_base64 = False
self.stream = None
self.order = dict()
self._header_added = False
random.seed()
def _start_listen(self):
self.connection.listening = True
self.connection.closed = False
self._header_added = False
if not self.stream or (isinstance(self.stream, StringIO) and self.stream.closed):
self.set_stream(StringIO())
def _stop_listen(self):
self.stream.close()
self.connection.listening = False
self.connection.closed = True
def receiving(self):
return None
def send(self, message_type, request, controls=None):
"""
Build the LDAPMessage without sending to server
"""
message_id = random.randint(0, LDAP_MAX_INT)
ldap_message = LDAPMessage()
ldap_message['messageID'] = MessageID(message_id)
ldap_message['protocolOp'] = ProtocolOp().setComponentByName(message_type, request)
message_controls = build_controls_list(controls)
if message_controls is not None:
ldap_message['controls'] = message_controls
self.connection.request = BaseStrategy.decode_request(ldap_message)
self.connection.request['controls'] = controls
self._outstanding[message_id] = self.connection.request
return message_id
def post_send_single_response(self, message_id):
self.connection.response = None
self.connection.result = None
if self._outstanding and message_id in self._outstanding:
request = self._outstanding.pop(message_id)
ldif_lines = operation_to_ldif(self.connection.request['type'], request, self.all_base64, self.order.get(self.connection.request['type']))
if self.stream and ldif_lines and not self.connection.closed:
self.accumulate_stream(self.line_separator.join(ldif_lines))
ldif_lines = add_ldif_header(ldif_lines)
self.connection.response = self.line_separator.join(ldif_lines)
return self.connection.response
return None
def post_send_search(self, message_id):
raise LDAPLDIFError('LDIF-CONTENT cannot be produced for Search Operations')
def _get_response(self, message_id):
pass
def accumulate_stream(self, fragment):
if not self._header_added and self.stream.tell() == 0:
self._header_added = True
header = add_ldif_header(['-'])[0]
self.stream.write(prepare_for_stream(header + self.line_separator + self.line_separator))
self.stream.write(prepare_for_stream(fragment + self.line_separator + self.line_separator))
def get_stream(self):
return self.stream
def set_stream(self, value):
error = False
try:
if not value.writable():
error = True
except (ValueError, AttributeError):
error = True
if error:
raise LDAPLDIFError('stream must be writable')
self.stream = value
python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/reusableThreaded.py 0000666 0000000 0000000 00000037600 12355117035 023354 0 ustar 0000000 0000000 """
Created on 2014.03.23
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from datetime import datetime
from os import linesep
from threading import Thread, Lock
from time import sleep
from .. import REUSABLE_POOL_SIZE, REUSABLE_CONNECTION_LIFETIME, STRATEGY_SYNC_RESTARTABLE, TERMINATE_REUSABLE, RESPONSE_WAITING_TIMEOUT, LDAP_MAX_INT, RESPONSE_SLEEPTIME
from .baseStrategy import BaseStrategy
from ..core.usage import ConnectionUsage
from ..core.exceptions import LDAPConnectionPoolNameIsMandatoryError, LDAPConnectionPoolNotStartedError
from ..core.exceptions import LDAPOperationResult
from ldap3.core.exceptions import LDAPExceptionError
try:
from queue import Queue
except ImportError: # Python 2
# noinspection PyUnresolvedReferences
from Queue import Queue
# noinspection PyProtectedMember
class ReusableThreadedStrategy(BaseStrategy):
"""
A pool of reusable SyncWaitRestartable connections with lazy behaviour and limited lifetime.
The connection using this strategy presents itself as a normal connection, but internally the strategy has a pool of
connections that can be used as needed. Each connection lives in its own thread and has a busy/available status.
The strategy performs the requested operation on the first available connection.
The pool of connections is instantiated at strategy initialization.
Strategy has two customizable properties, the total number of connections in the pool and the lifetime of each connection.
When lifetime is expired the connection is closed and will be opened again when needed.
"""
pools = dict()
# noinspection PyProtectedMember
class ConnectionPool(object):
def __new__(cls, connection):
if connection.pool_name in ReusableThreadedStrategy.pools: # returns existing connection pool
pool = ReusableThreadedStrategy.pools[connection.pool_name]
if not pool.started: # if pool is not started remove it from the pools singleton and create a new onw
del ReusableThreadedStrategy.pools[connection.pool_name]
return object.__new__(cls)
if connection.pool_lifetime and pool.lifetime != connection.pool_lifetime: # change lifetime
pool.lifetime = connection.pool_lifetime
if connection.pool_size and pool.pool_size != connection.pool_size: # if pool size has changed terminate and recreate the connections
pool.terminate_pool()
pool.pool_size = connection.pool_size
return pool
else:
return object.__new__(cls)
def __init__(self, connection):
if not hasattr(self, 'connections'):
self.name = connection.pool_name
self.original_connection = connection
self.connections = []
self.pool_size = connection.pool_size or REUSABLE_POOL_SIZE
self.lifetime = connection.pool_lifetime or REUSABLE_CONNECTION_LIFETIME
self.request_queue = Queue()
self.open_pool = False
self.bind_pool = False
self.tls_pool = False
self._incoming = dict()
self.counter = 0
self.terminated_usage = ConnectionUsage() if connection._usage else None
self.terminated = False
self.lock = Lock()
ReusableThreadedStrategy.pools[self.name] = self
self.started = False
def __str__(self):
s = str(self.name) + ' - ' + ('started' if self.started else 'terminated') + linesep
s += 'original connection: ' + str(self.original_connection) + linesep
s += 'response pool length: ' + str(len(self._incoming))
s += ' - pool size: ' + str(self.pool_size)
s += ' - lifetime: ' + str(self.lifetime)
s += ' - open: ' + str(self.open_pool)
s += ' - bind: ' + str(self.bind_pool)
s += ' - tls: ' + str(self.tls_pool)
for connection in self.connections:
s += linesep
s += str(connection)
return s
def __repr__(self):
return self.__str__()
def start_pool(self):
if not self.started:
self.create_pool()
for connection in self.connections:
connection.thread.start()
self.started = True
return True
return False
def create_pool(self):
self.connections = [ReusableThreadedStrategy.ReusableConnection(self.original_connection, self.request_queue) for _ in range(self.pool_size)]
def terminate_pool(self):
self.started = False
self.request_queue.join() # wait for all queue pending operations
for _ in range(len([connection for connection in self.connections if connection.thread.is_alive()])): # put a TERMINATE signal on the queue for each active thread
self.request_queue.put((TERMINATE_REUSABLE, None, None, None))
self.request_queue.join() # wait for all queue terminate operations
class PooledConnectionThread(Thread):
def __init__(self, reusable_connection, original_connection):
Thread.__init__(self)
self.daemon = True
self.active_connection = reusable_connection
self.original_connection = original_connection
# noinspection PyProtectedMember
def run(self):
self.active_connection.running = True
terminate = False
pool = self.original_connection.strategy.pool
while not terminate:
counter, message_type, request, controls = pool.request_queue.get()
self.active_connection.busy = True
if counter == TERMINATE_REUSABLE:
terminate = True
if self.active_connection.connection.bound:
try:
self.active_connection.connection.unbind()
except LDAPExceptionError:
pass
else:
if (datetime.now() - self.active_connection.creation_time).seconds >= self.original_connection.strategy.pool.lifetime: # destroy and create a new connection
try:
self.active_connection.connection.unbind()
except LDAPExceptionError:
pass
self.active_connection.new_connection()
if message_type not in ['bindRequest', 'unbindRequest']:
if pool.open_pool and self.active_connection.connection.closed:
self.active_connection.connection.open()
if pool.bind_pool and not self.active_connection.connection.bound:
self.active_connection.connection.bind()
if pool.tls_pool and not self.active_connection.connection.tls_started:
self.active_connection.connection.start_tls()
# noinspection PyProtectedMember
self.active_connection.connection._fire_deferred() # force deferred operations
exc = None
response = None
result = None
try:
if message_type == 'searchRequest':
response = self.active_connection.connection.post_send_search(self.active_connection.connection.send(message_type, request, controls))
else:
response = self.active_connection.connection.post_send_single_response(self.active_connection.connection.send(message_type, request, controls))
result = self.active_connection.connection.result
except LDAPOperationResult as e: # raise_exceptions has raise an exception. It must be redirected to the original connection thread
exc = e
with pool.lock:
if exc:
pool._incoming[counter] = (exc, None)
else:
pool._incoming[counter] = (response, result)
self.original_connection.busy = False
pool.request_queue.task_done()
if self.original_connection.usage:
pool.terminated_usage += self.active_connection.connection.usage
self.active_connection.running = False
class ReusableConnection(object):
"""
Container for the Restartable connection. it includes a thread and a lock to execute the connection in the pool
"""
def __init__(self, connection, request_queue):
self.original_connection = connection
self.request_queue = request_queue
self.running = False
self.busy = False
self.connection = None
self.creation_time = None
self.new_connection()
self.thread = ReusableThreadedStrategy.PooledConnectionThread(self, connection)
def __str__(self):
s = str(self.connection) + linesep
s += 'running ' if self.running else '-halted'
s += ' - ' + ('busy' if self.busy else ' available')
s += ' - ' + ('creation time: ' + self.creation_time.isoformat())
return s
def new_connection(self):
from ..core.connection import Connection
# noinspection PyProtectedMember
self.connection = Connection(server=self.original_connection.server_pool if self.original_connection.server_pool else self.original_connection.server,
user=self.original_connection.user,
password=self.original_connection.password,
version=self.original_connection.version,
authentication=self.original_connection.authentication,
client_strategy=STRATEGY_SYNC_RESTARTABLE,
raise_exceptions=self.original_connection.raise_exceptions,
check_names=self.original_connection.check_names,
auto_referrals=self.original_connection.auto_referrals,
sasl_mechanism=self.original_connection.sasl_mechanism,
sasl_credentials=self.original_connection.sasl_credentials,
collect_usage=True if self.original_connection._usage else False,
read_only=self.original_connection.read_only,
auto_bind=self.original_connection.auto_bind,
lazy=True)
if self.original_connection.server_pool:
self.connection.server_pool = self.original_connection.server_pool
self.connection.server_pool.initialize(self.connection)
self.creation_time = datetime.now()
def __init__(self, ldap_connection):
BaseStrategy.__init__(self, ldap_connection)
self.sync = False
self.no_real_dsa = False
self.pooled = True
self.can_stream = False
if hasattr(ldap_connection, 'pool_name') and ldap_connection.pool_name:
self.pool = ReusableThreadedStrategy.ConnectionPool(ldap_connection)
else:
raise LDAPConnectionPoolNameIsMandatoryError('reusable connection must have a pool_name')
def open(self, reset_usage=True):
self.pool.open_pool = True
self.pool.start_pool()
self.connection.closed = False
if self.connection._usage:
if reset_usage or not self.connection._usage.initial_connection_start_time:
self.connection._usage.start()
def terminate(self):
self.pool.terminate_pool()
self.pool.open_pool = False
self.connection.bound = False
self.connection.closed = True
self.pool.bind_pool = False
self.pool.tls_pool = False
def _close_socket(self):
"""
Doesn't really close the socket
"""
self.connection.closed = True
if self.connection._usage:
self.connection._usage.closed_sockets += 1
def send(self, message_type, request, controls=None):
if self.pool.started:
if message_type == 'bindRequest':
self.pool.bind_pool = True
counter = -1 # -1 stands for bind request
elif message_type == 'unbindRequest':
self.pool.bind_pool = False
counter = -2 # -1 stands for unbind request
elif message_type == 'extendedReq' and self.connection.starting_tls:
self.pool.tls_pool = True
counter = -3 # -1 stands for start_tls extended request
else:
with self.pool.lock:
self.pool.counter += 1
if self.pool.counter > LDAP_MAX_INT:
self.pool.counter = 1
counter = self.pool.counter
self.pool.request_queue.put((counter, message_type, request, controls))
return counter
raise LDAPConnectionPoolNotStartedError('reusable connection pool not started')
def get_response(self, counter, timeout=RESPONSE_WAITING_TIMEOUT):
if counter == -1: # send a bogus bindResponse
return list(), {'description': 'success', 'referrals': None, 'type': 'bindResponse', 'result': 0, 'dn': '', 'message': '', 'saslCreds': 'None'}
elif counter == -2: # bogus unbind
return None
elif counter == -3: # bogus startTls extended request
return list(), {'result': 0, 'referrals': None, 'responseName': '1.3.6.1.4.1.1466.20037', 'type': 'extendedResp', 'description': 'success', 'responseValue': 'None', 'dn': '', 'message': ''}
response = None
result = None
while timeout >= 0: # waiting for completed message to appear in _incoming
try:
with self.connection.strategy.pool.lock:
response, result = self.connection.strategy.pool._incoming.pop(counter)
except KeyError:
sleep(RESPONSE_SLEEPTIME)
timeout -= RESPONSE_SLEEPTIME
continue
break
if isinstance(response, LDAPOperationResult):
raise response # an exception has been raised with raise_connections
return response, result
def post_send_single_response(self, counter):
return counter
def post_send_search(self, counter):
return counter
python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/syncWait.py 0000666 0000000 0000000 00000017441 12355107125 021712 0 ustar 0000000 0000000 """
Created on 2013.07.15
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
import socket
from pyasn1.codec.ber import decoder
from .. import SESSION_TERMINATED_BY_SERVER, RESPONSE_COMPLETE, SOCKET_SIZE, RESULT_REFERRAL
from ..core.exceptions import LDAPSocketReceiveError, communication_exception_factory, LDAPExceptionError
from ..strategy.baseStrategy import BaseStrategy
from ..protocol.rfc4511 import LDAPMessage
# noinspection PyProtectedMember
class SyncWaitStrategy(BaseStrategy):
"""
This strategy is synchronous. You send the request and get the response
Requests return a boolean value to indicate the result of the requested Operation
Connection.response will contain the whole LDAP response for the messageId requested in a dict form
Connection.request will contain the result LDAP message in a dict form
"""
def __init__(self, ldap_connection):
BaseStrategy.__init__(self, ldap_connection)
self.sync = True
self.no_real_dsa = False
self.pooled = False
self.can_stream = False
def open(self, reset_usage=True):
BaseStrategy.open(self, reset_usage)
self.connection.refresh_dsa_info()
def _start_listen(self):
if not self.connection.listening and not self.connection.closed:
self.connection.listening = True
def receiving(self):
"""
Receive data over the socket
Checks if the socket is closed
"""
messages = []
receiving = True
unprocessed = b''
data = b''
get_more_data = True
exc = None
while receiving:
if get_more_data:
try:
data = self.connection.socket.recv(SOCKET_SIZE)
except (OSError, socket.error, AttributeError) as e:
self.connection.last_error = 'error receiving data: ' + str(e)
exc = e
if exc:
try: # try to close the connection before raising exception
self.close()
except (socket.error, LDAPExceptionError):
pass
raise communication_exception_factory(LDAPSocketReceiveError, exc)(self.connection.last_error)
unprocessed += data
if len(data) > 0:
length = BaseStrategy.compute_ldap_message_size(unprocessed)
if length == -1: # too few data to decode message length
get_more_data = True
continue
if len(unprocessed) < length:
get_more_data = True
else:
messages.append(unprocessed[:length])
unprocessed = unprocessed[length:]
get_more_data = False
if len(unprocessed) == 0:
receiving = False
else:
receiving = False
return messages
def post_send_single_response(self, message_id):
"""
Executed after an Operation Request (except Search)
Returns the result message or None
"""
responses, result = self.get_response(message_id)
if result['type'] == 'intermediateResponse': # checks that all responses are intermediates (there should be only one)
for response in responses:
if response['type'] != 'intermediateResponse':
self.connection.last_error = 'multiple messages error'
raise LDAPSocketReceiveError(self.connection.last_error)
responses.append(result)
return responses
def post_send_search(self, message_id):
"""
Executed after a search request
Returns the result message and store in connection.response the objects found
"""
responses, result = self.get_response(message_id)
if isinstance(responses, (list, tuple)):
self.connection.response = responses[:] # copy search result entries without result
return responses
self.connection.last_error = 'error receiving response'
raise LDAPSocketReceiveError(self.connection.last_error)
def _get_response(self, message_id):
"""
Performs the capture of LDAP response for SyncWaitStrategy
"""
ldap_responses = []
response_complete = False
while not response_complete:
responses = self.receiving()
if responses:
for response in responses:
while len(response) > 0:
if self.connection._usage:
self.connection._usage.received_message(len(response))
ldap_resp, unprocessed = decoder.decode(response, asn1Spec=LDAPMessage())
if int(ldap_resp['messageID']) == message_id:
dict_response = BaseStrategy.decode_response(ldap_resp)
ldap_responses.append(dict_response)
if dict_response['type'] not in ['searchResEntry', 'searchResRef', 'intermediateResponse']:
response_complete = True
elif int(ldap_resp['messageID']) == 0: # 0 is reserved for 'Unsolicited Notification' from server as per RFC4511 (paragraph 4.4)
dict_response = BaseStrategy.decode_response(ldap_resp)
if dict_response['responseName'] == '1.3.6.1.4.1.1466.20036': # Notice of Disconnection as per RFC4511 (paragraph 4.4.1)
return SESSION_TERMINATED_BY_SERVER
else:
self.connection.last_error = 'invalid messageId received'
raise LDAPSocketReceiveError(self.connection.last_error)
response = unprocessed
if response: # if this statement is removed unprocessed data will be processed as another message
self.connection.last_error = 'unprocessed substrate error'
raise LDAPSocketReceiveError(self.connection.last_error)
else:
return SESSION_TERMINATED_BY_SERVER
ldap_responses.append(RESPONSE_COMPLETE)
if ldap_responses[-2]['result'] == RESULT_REFERRAL:
if self.connection._usage:
self.connection._usage.referrals_received += 1
if self.connection.auto_referrals:
ref_response, ref_result = self.do_operation_on_referral(self._outstanding[message_id], ldap_responses[-2]['referrals'])
if ref_response is not None:
ldap_responses = ref_response + [ref_result]
ldap_responses.append(RESPONSE_COMPLETE)
elif ref_result is not None:
ldap_responses = [ref_result, RESPONSE_COMPLETE]
self._referrals = []
return ldap_responses
python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/syncWaitRestartable.py 0000666 0000000 0000000 00000023536 12355107541 024107 0 ustar 0000000 0000000 """
Created on 2014.03.04
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from sys import exc_info
from time import sleep
import socket
from datetime import datetime
from .. import RESTARTABLE_SLEEPTIME, RESTARTABLE_TRIES
from .syncWait import SyncWaitStrategy
from ..core.exceptions import LDAPSocketOpenError, LDAPOperationResult, LDAPMaximumRetriesError
# noinspection PyBroadException,PyProtectedMember
class SyncWaitRestartableStrategy(SyncWaitStrategy):
def __init__(self, ldap_connection):
SyncWaitStrategy.__init__(self, ldap_connection)
self.sync = True
self.no_real_dsa = False
self.pooled = False
self.can_stream = False
self.restartable_sleep_time = RESTARTABLE_SLEEPTIME
self.restartable_tries = RESTARTABLE_TRIES
self._restarting = False
self._last_bind_controls = None
self._current_message_type = None
self._current_request = None
self._current_controls = None
self._restart_tls = None
self.exception_history = []
def open(self, reset_usage=False):
SyncWaitStrategy.open(self, reset_usage)
def _open_socket(self, use_ssl=False):
"""
Try to open and connect a socket to a Server
raise LDAPExceptionError if unable to open or connect socket
if connection is restartable tries for the number of restarting requested or forever
"""
try:
SyncWaitStrategy._open_socket(self, use_ssl) # try to open socket using SyncWait
self._reset_exception_history()
return
except Exception: # machinery for restartable connection
self._add_exception_to_history()
if not self._restarting: # if not already performing a restart
self._restarting = True
counter = self.restartable_tries
while counter > 0:
sleep(self.restartable_sleep_time)
if not self.connection.closed:
try: # resetting connection
self.connection.close()
except (socket.error, LDAPSocketOpenError): # don't trace catch socket errors because socket could already be closed
pass
except Exception:
self._add_exception_to_history()
try: # reissuing same operation
if self.connection.server_pool:
new_server = self.connection.server_pool.get_server(self.connection) # get a server from the server_pool if available
if self.connection.server != new_server:
self.connection.server = new_server
if self.connection._usage:
self.connection._usage.servers_from_pool += 1
SyncWaitStrategy._open_socket(self, use_ssl) # calls super (not restartable) _open_socket()
if self.connection._usage:
self.connection._usage.restartable_successes += 1
self.connection.closed = False
self._restarting = False
self._reset_exception_history()
return
except Exception:
self._add_exception_to_history()
if self.connection._usage:
self.connection._usage.restartable_failures += 1
if not isinstance(self.restartable_tries, bool):
counter -= 1
self._restarting = False
self.connection.last_error = 'restartable connection strategy failed while opening socket'
raise LDAPMaximumRetriesError(self.connection.last_error, self.exception_history, self.restartable_tries)
def send(self, message_type, request, controls=None):
self._current_message_type = message_type
self._current_request = request
self._current_controls = controls
if not self._restart_tls: # RFCs doesn't define how to stop tls once started
self._restart_tls = self.connection.tls_started
if message_type == 'bindRequest': # store controls used in bind to be used again when restarting the connection
self._last_bind_controls = controls
try:
message_id = SyncWaitStrategy.send(self, message_type, request, controls) # try to send using SyncWait
self._reset_exception_history()
return message_id
except Exception:
self._add_exception_to_history()
if not self._restarting: # machinery for restartable connection
self._restarting = True
counter = self.restartable_tries
while counter > 0:
sleep(self.restartable_sleep_time)
if not self.connection.closed:
try: # resetting connection
self.connection.close()
except (socket.error, LDAPSocketOpenError): # don't trace socket errrors because socket could already be closed
pass
except Exception:
self._add_exception_to_history()
failure = False
try: # reopening connection
self.connection.open(reset_usage=False)
if self._restart_tls: # restart tls if start_tls was previously used
self.connection.start_tls()
if message_type != 'bindRequest':
self.connection.bind(self._last_bind_controls) # binds with previously used controls unless the request is already a bindRequest
except Exception:
self._add_exception_to_history()
failure = True
if not failure:
try: # reissuing same operation
ret_value = self.connection.send(message_type, request, controls)
if self.connection._usage:
self.connection._usage.restartable_successes += 1
self._restarting = False
self._reset_exception_history()
return ret_value # successful send
except Exception:
self._add_exception_to_history()
failure = True
if failure and self.connection._usage:
self.connection._usage.restartable_failures += 1
if not isinstance(self.restartable_tries, bool):
counter -= 1
self._restarting = False
self.connection.last_error = 'restartable connection failed to send'
raise LDAPMaximumRetriesError(self.connection.last_error, self.exception_history, self.restartable_tries)
def post_send_single_response(self, message_id):
try:
ret_value = SyncWaitStrategy.post_send_single_response(self, message_id)
self._reset_exception_history()
return ret_value
except Exception:
self._add_exception_to_history()
# if an LDAPExceptionError is raised then resend the request
try:
ret_value = SyncWaitStrategy.post_send_single_response(self, self.send(self._current_message_type, self._current_request, self._current_controls))
self._reset_exception_history()
return ret_value
except Exception as e:
self._add_exception_to_history()
exc = e
if exc:
if not isinstance(exc, LDAPOperationResult):
self.connection.last_error = 'restartable connection strategy failed in post_send_single_response'
raise exc
def post_send_search(self, message_id):
try:
ret_value = SyncWaitStrategy.post_send_search(self, message_id)
self._reset_exception_history()
return ret_value
except Exception:
self._add_exception_to_history()
# if an LDAPExceptionError is raised then resend the request
try:
ret_value = SyncWaitStrategy.post_send_search(self, self.connection.send(self._current_message_type, self._current_request, self._current_controls))
self._reset_exception_history()
return ret_value
except Exception as e:
self._add_exception_to_history()
exc = e
if exc:
if not isinstance(exc, LDAPOperationResult):
self.connection.last_error = exc.args
raise exc
def _add_exception_to_history(self):
if not isinstance(self.restartable_tries, bool): # doesn't accumulate when restarting forever
if not isinstance(exc_info()[1], LDAPMaximumRetriesError): # doesn't add the LDAPMaximumRetriesError exception
self.exception_history.append((datetime.now(), exc_info()[0], exc_info()[1]))
def _reset_exception_history(self):
if self.exception_history:
self.exception_history = []
python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/__init__.py 0000666 0000000 0000000 00000000000 12355103747 021635 0 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/utils/ 0000777 0000000 0000000 00000000000 12355117540 017030 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/ldap3/utils/conv.py 0000666 0000000 0000000 00000002670 12355103747 020360 0 ustar 0000000 0000000 """
Created on 2014.04.26
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
def escape_bytes(bytes_value):
if str != bytes: # Python 3
if isinstance(bytes_value, str):
bytes_value = bytearray(bytes_value, encoding='utf-8')
escaped = '\\'.join([('%02x' % int(b)) for b in bytes_value])
else: # Python 2
if isinstance(bytes_value, unicode):
bytes_value = bytes_value.encode('utf-8')
escaped = '\\'.join([('%02x' % ord(b)) for b in bytes_value])
return ('\\' + escaped) if escaped else ''
def prepare_for_stream(value):
if str != bytes: # Python 3
return value
else: # Python 2
return value.decode()
python3-ldap-0.9.4.2/python3-ldap/ldap3/utils/__init__.py 0000666 0000000 0000000 00000001466 12355103747 021154 0 ustar 0000000 0000000 """
Created on 2014.04.26
@author: Giovanni Cannata
Copyright 2014 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
python3-ldap-0.9.4.2/python3-ldap/ldap3/__init__.py 0000666 0000000 0000000 00000020033 12355103746 020002 0 ustar 0000000 0000000 """
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
# authentication
AUTH_ANONYMOUS = 0
AUTH_SIMPLE = 1
AUTH_SASL = 2
SASL_AVAILABLE_MECHANISMS = ['EXTERNAL', 'DIGEST-MD5']
AUTHZ_STATE_CLOSED = 0
AUTHZ_STATE_ANONYMOUS = 1
AUTHZ_STATE_UNAUTHENTICATED = 2
# search scope
SEARCH_SCOPE_BASE_OBJECT = 0
SEARCH_SCOPE_SINGLE_LEVEL = 1
SEARCH_SCOPE_WHOLE_SUBTREE = 2
# search alias
SEARCH_NEVER_DEREFERENCE_ALIASES = 0
SEARCH_DEREFERENCE_IN_SEARCHING = 1
SEARCH_DEREFERENCE_FINDING_BASE_OBJECT = 2
SEARCH_DEREFERENCE_ALWAYS = 3
# search attributes
ALL_ATTRIBUTES = '*'
NO_ATTRIBUTES = '1.1' # as per RFC 4511
ALL_OPERATIONAL_ATTRIBUTES = '+' # as per RFC 3673
# modify type
MODIFY_ADD = 0
MODIFY_DELETE = 1
MODIFY_REPLACE = 2
MODIFY_INCREMENT = 3
# client strategies
STRATEGY_SYNC = 0
STRATEGY_ASYNC_THREADED = 1
STRATEGY_LDIF_PRODUCER = 2
STRATEGY_SYNC_RESTARTABLE = 3
STRATEGY_REUSABLE_THREADED = 4
CLIENT_STRATEGIES = [STRATEGY_SYNC, STRATEGY_ASYNC_THREADED, STRATEGY_LDIF_PRODUCER, STRATEGY_SYNC_RESTARTABLE, STRATEGY_REUSABLE_THREADED]
# communication
SESSION_TERMINATED_BY_SERVER = 0
RESPONSE_COMPLETE = -1
RESPONSE_SLEEPTIME = 0.02 # seconds to wait while waiting for a response in asynchronous strategies
RESPONSE_WAITING_TIMEOUT = 10 # waiting timeout for receiving a response in asynchronous strategies
SOCKET_SIZE = 4096 # socket byte size
# restartable strategy
RESTARTABLE_SLEEPTIME = 2 # time to wait in a restartable strategy before retrying the request
RESTARTABLE_TRIES = 50 # number of times to retry in a restartable strategy before giving up. Set to True for unlimited retries
# reusable strategy
TERMINATE_REUSABLE = -1
REUSABLE_POOL_SIZE = 10
REUSABLE_CONNECTION_LIFETIME = 3600
DEFAULT_POOL_NAME = 'connection_pool'
# LDAP protocol
LDAP_MAX_INT = 2147483647
# LDIF
LDIF_LINE_LENGTH = 78
# result codes
RESULT_SUCCESS = 0
RESULT_OPERATIONS_ERROR = 1
RESULT_PROTOCOL_ERROR = 2
RESULT_TIME_LIMIT_EXCEEDED = 3
RESULT_SIZE_LIMIT_EXCEEDED = 4
RESULT_COMPARE_FALSE = 5
RESULT_COMPARE_TRUE = 6
RESULT_AUTH_METHOD_NOT_SUPPORTED = 7
RESULT_STRONGER_AUTH_REQUIRED = 8
RESULT_REFERRAL = 10
RESULT_ADMIN_LIMIT_EXCEEDED = 11
RESULT_UNAVAILABLE_CRITICAL_EXTENSION = 12
RESULT_CONFIDENTIALITY_REQUIRED = 13
RESULT_SASL_BIND_IN_PROGRESS = 14
RESULT_NO_SUCH_ATTRIBUTE = 16
RESULT_UNDEFINED_ATTRIBUTE_TYPE = 17
RESULT_INAPPROPRIATE_MATCHING = 18
RESULT_CONSTRAINT_VIOLATION = 19
RESULT_ATTRIBUTE_OR_VALUE_EXISTS = 20
RESULT_INVALID_ATTRIBUTE_SYNTAX = 21
RESULT_NO_SUCH_OBJECT = 32
RESULT_ALIAS_PROBLEM = 33
RESULT_INVALID_DN_SYNTAX = 34
RESULT_ALIAS_DEREFERENCING_PROBLEM = 36
RESULT_INAPPROPRIATE_AUTHENTICATION = 48
RESULT_INVALID_CREDENTIALS = 49
RESULT_INSUFFICIENT_ACCESS_RIGHTS = 50
RESULT_BUSY = 51
RESULT_UNAVAILABLE = 52
RESULT_UNWILLING_TO_PERFORM = 53
RESULT_LOOP_DETECTED = 54
RESULT_NAMING_VIOLATION = 64
RESULT_OBJECT_CLASS_VIOLATION = 65
RESULT_NOT_ALLOWED_ON_NON_LEAF = 66
RESULT_NOT_ALLOWED_ON_RDN = 67
RESULT_ENTRY_ALREADY_EXISTS = 68
RESULT_OBJECT_CLASS_MODS_PROHIBITED = 69
RESULT_AFFECT_MULTIPLE_DSAS = 71
RESULT_OTHER = 80
RESULT_LCUP_RESOURCES_EXHAUSTED = 113
RESULT_LCUP_SECURITY_VIOLATION = 114
RESULT_LCUP_INVALID_DATA = 115
RESULT_LCUP_UNSUPPORTED_SCHEME = 116
RESULT_LCUP_RELOAD_REQUIRED = 117
RESULT_CANCELED = 118
RESULT_NO_SUCH_OPERATION = 119
RESULT_TOO_LATE = 120
RESULT_CANNOT_CANCEL = 121
RESULT_ASSERTION_FAILED = 122
RESULT_AUTHORIZATION_DENIED = 123
RESULT_E_SYNC_REFRESH_REQUIRED = 4096
# do not raise exception for (in raise_exceptions connection mode)
DO_NOT_RAISE_EXCEPTIONS = [RESULT_SUCCESS, RESULT_COMPARE_FALSE, RESULT_COMPARE_TRUE, RESULT_REFERRAL]
# get rootDSE info
GET_NO_INFO = 0
GET_DSA_INFO = 1
GET_SCHEMA_INFO = 2
GET_ALL_INFO = 3
# OID database definition
OID_CONTROL = 0
OID_EXTENSION = 1
OID_FEATURE = 2
OID_UNSOLICITED_NOTICE = 3
OID_ATTRIBUTE_TYPE = 4
OID_DIT_CONTENT_RULE = 5
OID_LDAP_URL_EXTENSION = 6
OID_FAMILY = 7
OID_MATCHING_RULE = 8
OID_NAME_FORM = 9
OID_OBJECT_CLASS = 10
OID_ADMINISTRATIVE_ROLE = 11
OID_LDAP_SYNTAX = 12
# class kind
CLASS_STRUCTURAL = 0
CLASS_ABSTRACT = 1
CLASS_AUXILIARY = 2
# attribute kind
ATTRIBUTE_USER_APPLICATION = 0
ATTRIBUTE_DIRECTORY_OPERATION = 1
ATTRIBUTE_DISTRIBUTED_OPERATION = 2
ATTRIBUTE_DSA_OPERATION = 3
# abstraction layer
ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX = 'OP_'
# server pooling
POOLING_STRATEGY_FIRST = 0
POOLING_STRATEGY_ROUND_ROBIN = 1
POOLING_STRATEGY_RANDOM = 2
POOLING_STRATEGIES = [POOLING_STRATEGY_FIRST, POOLING_STRATEGY_ROUND_ROBIN, POOLING_STRATEGY_RANDOM]
from .core.server import Server
from .core.connection import Connection
from .core.tls import Tls
from .core.pooling import ServerPool
from .abstract import ObjectDef, AttrDef, Attribute, Entry, Reader, OperationalAttribute
from .core.exceptions import LDAPException, LDAPExceptionError, LDAPSocketCloseError, LDAPReferralError, LDAPAttributeError, LDAPBindError, LDAPCertificateError, LDAPChangesError, LDAPCommunicationError, LDAPConnectionIsReadOnlyError, \
LDAPConnectionPoolNameIsMandatoryError, LDAPConnectionPoolNotStartedError, LDAPControlsError, LDAPEntryError, LDAPInvalidDereferenceAliasesError, LDAPInvalidFilterError, LDAPInvalidScopeError, LDAPInvalidServerError, LDAPKeyError, LDAPLDIFError, \
LDAPMetricsError, LDAPObjectClassError, LDAPObjectError, LDAPPasswordIsMandatoryError, LDAPReaderError, LDAPSASLBindInProgressError, LDAPSASLMechanismNotSupportedError, LDAPSASLPrepError, LDAPSchemaError, LDAPServerPoolError, \
LDAPServerPoolExhaustedError, LDAPSocketOpenError, LDAPSocketReceiveError, LDAPSocketSendError, LDAPSSLConfigurationError, LDAPSSLNotSupportedError, LDAPStartTLSError, LDAPTypeError, LDAPUnknownAuthenticationMethodError, LDAPUnknownRequestError, \
LDAPUnknownResponseError, LDAPUnknownStrategyError
from .core.exceptions import LDAPAdminLimitExceededResult, LDAPAffectMultipleDSASResult, LDAPAliasDereferencingProblemResult, LDAPAliasProblemResult, LDAPAssertionFailedResult, LDAPAttributeOrValueExistsResult, LDAPAuthMethodNotSupportedResult, \
LDAPAuthorizationDeniedResult, LDAPBusyResult, LDAPCanceledResult, LDAPCannotCancelResult, LDAPConfidentialityRequiredResult, LDAPConstraintViolationResult, LDAPEntryAlreadyExistsResult, LDAPESyncRefreshRequiredResult, \
LDAPInappropriateAuthenticationResult, LDAPInappropriateMatchingResult, LDAPInsufficientAccessRightsResult, LDAPInvalidAttributeSyntaxResult, LDAPInvalidCredentialsResult, LDAPInvalidDNSyntaxResult, LDAPLCUPInvalidDataResult, \
LDAPLCUPReloadRequiredResult, LDAPLCUPResourcesExhaustedResult, LDAPLCUPSecurityViolationResult, LDAPLCUPUnsupportedSchemeResult, LDAPLoopDetectedResult, LDAPNamingViolationResult, LDAPNoSuchAttributeResult, LDAPNoSuchObjectResult, \
LDAPNoSuchOperationResult, LDAPNotAllowedOnNotLeafResult, LDAPNotAllowedOnRDNResult, LDAPObjectClassModsProhibitedResult, LDAPObjectClassViolationResult, LDAPOperationResult, LDAPOperationsErrorResult, LDAPOtherResult, LDAPProtocolErrorResult, \
LDAPReferralResult, LDAPSASLBindInProgressResult, LDAPSizeLimitExceededResult, LDAPStrongerAuthRequiredResult, LDAPTimeLimitExceededResult, LDAPTooLateResult, LDAPUnavailableCriticalExtensionResult, LDAPUnavailableResult, \
LDAPUndefinedAttributeTypeResult, LDAPUnwillingToPerformResult, LDAPMaximumRetriesError, LDAPExtensionError
python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/ 0000777 0000000 0000000 00000000000 12355117540 020763 5 ustar 0000000 0000000 python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/dependency_links.txt 0000666 0000000 0000000 00000000001 12355117540 025031 0 ustar 0000000 0000000
python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/PKG-INFO 0000666 0000000 0000000 00000001754 12355117540 022067 0 ustar 0000000 0000000 Metadata-Version: 1.1
Name: python3-ldap
Version: 0.9.4.2
Summary: A strictly RFC 4511 conforming LDAP V3 pure Python 3 client - Python 2 compatible
Home-page: https://www.assembla.com/spaces/python3-ldap
Author: Giovanni Cannata
Author-email: python3ldap@gmail.com
License: LGPL v3
Description: UNKNOWN
Keywords: python3 python2 ldap
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP
python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/requires.txt 0000666 0000000 0000000 00000000020 12355117540 023353 0 ustar 0000000 0000000 pyasn1 == 0.1.7
python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/SOURCES.txt 0000666 0000000 0000000 00000005036 12355117540 022653 0 ustar 0000000 0000000 COPYING.LESSER.txt
COPYING.txt
LICENSE.txt
MANIFEST.in
README.txt
requirements.txt
setup.cfg
setup.py
python3-ldap/ldap3/__init__.py
python3-ldap/ldap3/abstract/__init__.py
python3-ldap/ldap3/abstract/attrDef.py
python3-ldap/ldap3/abstract/attribute.py
python3-ldap/ldap3/abstract/entry.py
python3-ldap/ldap3/abstract/objectDef.py
python3-ldap/ldap3/abstract/operationalAttribute.py
python3-ldap/ldap3/abstract/reader.py
python3-ldap/ldap3/compat/__init__.py
python3-ldap/ldap3/compat/connection.py
python3-ldap/ldap3/compat/server.py
python3-ldap/ldap3/compat/tls.py
python3-ldap/ldap3/core/__init__.py
python3-ldap/ldap3/core/connection.py
python3-ldap/ldap3/core/exceptions.py
python3-ldap/ldap3/core/pooling.py
python3-ldap/ldap3/core/server.py
python3-ldap/ldap3/core/tls.py
python3-ldap/ldap3/core/usage.py
python3-ldap/ldap3/extend/__init__.py
python3-ldap/ldap3/extend/getBindDn.py
python3-ldap/ldap3/extend/modifyPassword.py
python3-ldap/ldap3/extend/whoAmI.py
python3-ldap/ldap3/operation/__init__.py
python3-ldap/ldap3/operation/abandon.py
python3-ldap/ldap3/operation/add.py
python3-ldap/ldap3/operation/bind.py
python3-ldap/ldap3/operation/compare.py
python3-ldap/ldap3/operation/delete.py
python3-ldap/ldap3/operation/extended.py
python3-ldap/ldap3/operation/modify.py
python3-ldap/ldap3/operation/modifyDn.py
python3-ldap/ldap3/operation/search.py
python3-ldap/ldap3/operation/unbind.py
python3-ldap/ldap3/protocol/__init__.py
python3-ldap/ldap3/protocol/convert.py
python3-ldap/ldap3/protocol/novell.py
python3-ldap/ldap3/protocol/oid.py
python3-ldap/ldap3/protocol/rfc2696.py
python3-ldap/ldap3/protocol/rfc2849.py
python3-ldap/ldap3/protocol/rfc3062.py
python3-ldap/ldap3/protocol/rfc4511.py
python3-ldap/ldap3/protocol/rfc4512.py
python3-ldap/ldap3/protocol/rfc4532.py
python3-ldap/ldap3/protocol/sasl/__init__.py
python3-ldap/ldap3/protocol/sasl/digestMd5.py
python3-ldap/ldap3/protocol/sasl/external.py
python3-ldap/ldap3/protocol/sasl/sasl.py
python3-ldap/ldap3/strategy/__init__.py
python3-ldap/ldap3/strategy/asyncThreaded.py
python3-ldap/ldap3/strategy/baseStrategy.py
python3-ldap/ldap3/strategy/ldifProducer.py
python3-ldap/ldap3/strategy/reusableThreaded.py
python3-ldap/ldap3/strategy/syncWait.py
python3-ldap/ldap3/strategy/syncWaitRestartable.py
python3-ldap/ldap3/utils/__init__.py
python3-ldap/ldap3/utils/conv.py
python3-ldap/python3_ldap.egg-info/PKG-INFO
python3-ldap/python3_ldap.egg-info/SOURCES.txt
python3-ldap/python3_ldap.egg-info/dependency_links.txt
python3-ldap/python3_ldap.egg-info/requires.txt
python3-ldap/python3_ldap.egg-info/top_level.txt python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/top_level.txt 0000666 0000000 0000000 00000000006 12355117540 023511 0 ustar 0000000 0000000 ldap3
python3-ldap-0.9.4.2/README.txt 0000666 0000000 0000000 00000033077 12355112231 014043 0 ustar 0000000 0000000 License
-------
The python3-ldap project is open source and released under the LGPL v3 license.
PEP8 Compliance
---------------
python3-ldap is PEP8 compliance (except for line length) starting from version 0.9.0.
Mailing List
------------
You can join the python3-ldap mailing list at http://mail.python.org/mailman/listinfo/python3-ldap
Home Page
---------
Project home page is https://bitbucket.org/python3ldap/python3-ldap
Documentation
-------------
Documentation is available at http://pythonhosted.org/python3-ldap
Download
--------
Package download is available at https://pypi.python.org/pypi/python3-ldap or via pip
Mercurial (hg) repository
-------------------------
You can download the latest source at https://bitbucket.org/python3ldap/python3-ldap
Support
-------
You can submit support tickets on https://bitbucket.org/python3ldap/python3-ldap/issues
Acknowledgements
----------------
* I wish to thank **Ilya Etingof**, the author of the *pyasn1* package for his excellent work and support.
* I wish to thank **Mark Lutz** for his *Learning Python* and *Programming Python* excellent books series and **John Goerzen** and **Brandon Rhodes** for their book *Foundations of Python Network Programming*. These books are wonderful tools for learning Python and this project owes a lot to them.
* I wish to thank **JetBrains** for donating to this project the Open Source license of *PyCharm 3 Professional*.
* I wish to thank **Atlassian** for providing the *free source repository space and the tools* I use to develop this project.
Contact me
----------
For information and suggestions you can contact me at python3ldap@gmail.com or you can join the python3-ldap mailing list at http://mail.python.org/mailman/listinfo/python3-ldap. You can also open a support ticket on https://www.assembla.com/spaces/python3-ldap/support/tickets
CHANGELOG
=========
* 0.9.4.2 2014.07.03
- Moved to Bitbucket + Mercurial
- Fixed import in core.tls package
- Removed unneeded imports
* 0.9.4.1 2014.07.02
- included missing extend package (thanks to debnet)
* 0.9.4 2014.07.02
- when running in python 3.4 or newer now Tls class uses SSLContext object with default secure setting
- added parameters ca_certs_path, ca_certs_data, local_private_key_password to Tls object creation, valid when using SSLContext
- in python 3.4 or newer the system CA certificates configuration can be used (just leave ca_cert_file, ca_certs_path and ca_certs_data set to None)
- removed TLSv1 as default for Tls connection
- upgraded backported ssl function from python 3.4.1 when using with python 2
- when creating a connection server can now be a string, the name of the server to connect in cleartext on default port 389
- fixed bug in ldap3.util.conv.escape_bytes()
- attributes parameter in search can be a tuple
- check_names parameter in connection now defaults to True (so if schema info is available attribute and class name will be checked when performing LDAP operations)
- remove the connection.close() method - you must use connection.unbind()
- new exception LDAPExtensionError for signaling when the requestValue of extended operation is of unknown ASN1 type
- exiting connection manager doesn't raise exception if unbind is not successful (needed in long operations)
- new extended operation: modify_password (RFC3062)
- new extended operation: who_am_i (RFC4532)
- new extended operation: get_bind_dn (Novell)
- updated setuptools to version 5.3
* 0.9.3.5 2014.06.22
- Exception history in restartable strategy is printed when reached the maximum number of retries
- Fixed conditions on terminated_by_server unsolicited message
- Added python2.6 egg installation package
* 0.9.3.4 2014.06.16
- Exception can now be imported from ldap3 package
- Escape_bytes return '' for empty string instead of None (thanks Brian)
- Added exception history to restartable connection (except than for infinite retries)
- Fixed start_tls retrying in restartable connection (thanks Brian)
- New exception LDAPMaximumRetriesError for signaling when the SyncRestartable Strategy has reached the maximum number of retries while performing an operation
- Inverted deleteoldrdn value in LDIF output (thanks Joseph)
* 0.9.3.3 2014.06.01
- Fixed a bug in LDIFProducer when using context manager for connection
- LDIF header in stream is added only whene there are actua data in the stream
- Now LDIF stream can be added to an existing file - version header will not be written if stream is not empty
* 0.9.3.2 2014.05.30
- Fixed a bug while reading schema
- Add an implicit open() when trying binding on a closed connection
* 0.9.3.1 2014.05.28
- Added stream capability to LDIFProducer strategy
- Customizable line separator for ldif output
- Customizable sorting order in ldif output
- object_class parameter is now optional in connection.add()
- Fixed objectClass attribute case sensitive dependency in add operation
- Added stream capability to response_to_ldif() while searching
* 0.9.3 2014.05.20
- Now the key in server.schema.attribute_type is the attribute name (was the oid)
- Now the key in server.schema.object_classes is the class name (was the oid)
- Added check_names to Connection definition to have the names of attributes and object class checked against the schema
- Updated setuptools to 3.6
- Added wheel installation format
- Added raise_exceptions mode for connection
- Exception hierarchy reworked
- Added locking to Server object (for multithreading)
* 0.9.2.2 2014.04.30
- fixed a bug from 0.9.1 that broke start_tls() (thanks Mark)
* 0.9.2.1 2014.04.28
- fixed a bug in 0.9.2 that allowed only string attributes in add, modify and compare operations (thank Mladen)
* 0.9.2 2014.04.26
- changed return value in get_response from response to (response, result) - helpful for multi threaded connections
- added ReusableStrategy for pooling connections
- refined docstrings (thanks Will)
- result and response attributes don't overlap anymore. Operation result is only in result attribute.
- fixed search for binary values (thanks Marcin)
- added convenience function to convert bytes to LDAP binary value string format for search filter
* 0.9.1 2014.03.30
- added laziness flag to test suite
- changed ServerPool signature to accept active and exhaust parameters
- removed unneeded start_listen parameter
- added 'lazy' parameter to open, to bind and to unbind a connection only when an effective operation is performed
- fixed start_tls in SyncWaitRestartable strategy
- fixed certificate name checking while opening an ssl connection
- fixed syntax error during installation
- socket operations now raises proper exception, not generic LDAPException (thanks Joseph)
- tested against Python 3.4, 3.3, 2.7, 2.6
- updated setuptools to 3.3
* 0.9.0 2014.03.20
- PEP8 compliance
- added ldap3.compat package with older (non PEP8 compliant) signatures
- renamed ldap3.abstraction to ldap3.abstract
- moved connection.py, server.py and tls.py files to ldap3.core
- fixed SyncWaitRestartableStrategy (thanks Christoph)
* 0.8.3 2014.03.08
- added SyncWaitRestartable strategy
- removed useless forceBind parameter
- usage statistics updated with restartable success/failure counters and open/closed/wrapped socket counters
* 0.8.2 2014.03.04
- Added refresh() method to Entry object to read again the attributes from the Reader in the abstraction layer
- Fixed Python 2.6 issues
- Fixed test suite for Python 2.6
* 0.8,1 2014.02.12
- Changed exceptions returned by the library to LDAPException, a subclass of Exception.
- Fixed documentation typos
* 0.8.0 - 2014.02.08
- Added abstraction layer (for searching)
- Added context manager to Connection class
- Added readOnly parameter to Connection class
- Fixed a bug in search with 'less than' parameter
- Remove validation of available SSL protocols because different Python interpreters can use different ssl packages
* 0.7.3 - 2014.01.05
- Added SASL DIGEST-MD5 support
- Moved to intrapackage (relative) imports
* 0.7.2 - 2013.12.30
- Fixed a bug when parentheses are used in search filter as ASCII escaped sequences
* 0.7.1 - 2013.12.21
- Completed support for LDFI as per RFC2849
- Added new LDIF_PRODUCER strategy to generate LDIF-CHANGE stream
- Fixed a bug in the autoReferral feature when controls where used in operation
* 0.7.0 - 2013.12.12
- Added support for LDIF as per RFC2849
- Added LDIF-CONTENT compliant search responses
- Added exception when using autoBind if connection is not successful
* 0.6.7 - 2013.12.03
- Fixed exception when DSA is not willing to return rootDSE and schema info
* 0.6.6 - 2013.11.13
- Added parameters to test suite
* 0.6.5 - 2013.11.05
- Modified rawAttributes decoding, now null (empty) values are returned
* 0.6.4 - 2013.10.16
- Added simple paged search as per RFC2696
- Controls return values are decoded and stored in result attribute of connection
* 0.6.3 - 2013.10.07
- Added Extesible Filter syntax to search filter
- Fixed exception while closing connection in AsyncThreaded strategy
* 0.6.2 - 2013.10.01
- Fix for referrals in searchRefResult
- Disabled schema reading on Active Directory
* 0.6.1 - 2013.09.22
- Experimental support for Python 2 - no unicode
- Added backport of ssl.match_name for Python 2
- Minor fixes for using the client in Python 2
- Fix for getting schema info with AsyncThreaded strategy
* 0.6.0 - 2013.09.16
- Moved to beta!
- Added support site hosted on www.assembla.com
- Added public svn repository on www.assembla.com
- Added getInfo to server object, parameter can be: GET_NO_INFO, GET_DSA_INFO, GET_SCHEMA_INFO, GET_ALL_INFO
- Added method to read the schema from the server. Schema is decoded and returned in different dictionaries of the server.schema object
- Updated connection usage info (elapsed time is now computed when connection is closed)
- Updated OID dictionary with extensions and controls from Active Directory specifications.
* 0.5.3 - 2013.09.03
- Added getOperationalAttributes boolean to Search operation to fetch the operational attributes during search
- Added increment operation to modify operation as per RFC4525
- Added dictionary of OID descriptions (for DSE and schema decoding)
- Added method to get Info from DSE (returned in server.info object)
- Modified exceptions for sending controls in LDAP request
- Added connection usage (in connection.usage if collectUsage=True in connection definition)
- Fixed StartTls in asynchronous client strategy
* 0.5.2 - 2013.08.27
- Added SASLprep profile for validating password
- Fixed RFC4511 asn1 definitions
* 0.5.1 - 2013.08.17
- Refactored package structure
- Project description reformatted with reStructuredText
- Added Windows graphical installation
* 0.5.0 - 2013.08.15
- Added reference to LGPL v3 license
- Added Tls object to hold ssl/tls configuration
- Added StartTLS feature
- Added SASL feature
- Added SASL EXTERNAL mechanism
- Fixed Unbind
- connection.close in now an alias for connection.unbind
* 0.4.4 - 2013.08.01
- Added 'Controls' to all LDAP Requests
- Added Extended Request feature
- Added Intermediate Response feature
- Added namespace 'ldap3'
* 0.4.3 - 2013.07.31
- Test suite refactored
- Fixed single object search response error
- Changed attributes returned in search from tuple to dict
- Added 'raw_attributes' key in search response to hold undecoded (binary) attribute values read from ldap
- Added __repr__ for Server and Connection objects to re-create the object instance
* 0.4.2 - 2013.07.29
- Added autoReferral feature as per RFC4511 (4.1.10)
- Added allowedReferralHosts to conform to Security considerations of RFC4516
* 0.4.1 - 2013.07.20
- Add validation to Abandon operation
- Added connection.request to hold a dictionary of infos about last request
- Added info about outstanding operation in connection.strategy._oustanding
- Implemented RFC4515 for search filter coding and decoding
- Added a parser to build filter string from LdapMessage
* 0.4.0 - 2013.07.15
- Refactoring of the connection and strategy classes
- Added the ldap3.strategy namespace to contain client connection strategies
- Added ssl authentication
- Moved authentication parameters from Server object to Connection object
- Added ssl parameters to Server Object
* 0.3.0 - 2013.07.14
- Fixed AsyncThreaded strategy with _outstanding and _responses attributes to hold the pending requests and the not-yet-read responses
- Added Extended Operation
- Added "Unsolicited Notification" discover logic
- Added managing of "Notice of Disconnection" from server to properly close connection
* 0.2.0 - 2013.07.13
- Update setup with setuptools 0.7
- Docstrings added to class
- Removed ez_setup dependency
- Removed distribute dependency
* 0.1.0 - 2013.07.12
- Initial upload on pypi
- PyASN1 RFC4511 module completed and tested
- Synchronous client working properly
- Asynchronous client working but not fully tested
- Basic authentication working
python3-ldap-0.9.4.2/requirements.txt 0000666 0000000 0000000 00000000017 12355103747 015631 0 ustar 0000000 0000000 pyasn1==0.1.7
python3-ldap-0.9.4.2/setup.cfg 0000666 0000000 0000000 00000000132 12355117540 014160 0 ustar 0000000 0000000 [wheel]
universal = 1
[egg_info]
tag_date = 0
tag_svn_revision = 0
tag_build =
python3-ldap-0.9.4.2/setup.py 0000666 0000000 0000000 00000004542 12355105074 014061 0 ustar 0000000 0000000 """
Created on 2013.07.11
@author: Giovanni Cannata
Copyright 2013 Giovanni Cannata
This file is part of python3-ldap.
python3-ldap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
python3-ldap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with python3-ldap in the COPYING and COPYING.LESSER files.
If not, see .
"""
from setuptools import setup
setup(name='python3-ldap',
version='0.9.4.2',
packages=['ldap3',
'ldap3.core',
'ldap3.abstract',
'ldap3.operation',
'ldap3.protocol',
'ldap3.protocol.sasl',
'ldap3.strategy',
'ldap3.compat',
'ldap3.utils',
'ldap3.extend'
],
package_dir={'': 'python3-ldap'},
install_requires=['pyasn1 == 0.1.7'],
license='LGPL v3',
author='Giovanni Cannata',
author_email='python3ldap@gmail.com',
description='A strictly RFC 4511 conforming LDAP V3 pure Python 3 client - Python 2 compatible',
keywords='python3 python2 ldap',
url='https://www.assembla.com/spaces/python3-ldap',
classifiers=['Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Intended Audience :: System Administrators',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX :: Linux',
'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP']
)