git-svn-id: http://redmine.rubyforge.org/svn/trunk@134 e93f8b46-1217-0410-a6f0-8f06a7374b81pull/351/head
parent
e3becc7c3c
commit
f50544bb15
@ -0,0 +1,272 @@ |
||||
GNU GENERAL PUBLIC LICENSE |
||||
Version 2, June 1991 |
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, |
||||
Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and |
||||
distribute verbatim copies of this license document, but changing it is not |
||||
allowed. |
||||
|
||||
Preamble |
||||
|
||||
The licenses for most software are designed to take away your freedom to |
||||
share and change it. By contrast, the GNU General Public License is |
||||
intended to guarantee your freedom to share and change free software--to |
||||
make sure the software is free for all its users. This General Public |
||||
License applies to most of the Free Software Foundation's software and to |
||||
any other program whose authors commit to using it. (Some other Free |
||||
Software Foundation software is covered by the GNU Lesser General Public |
||||
License instead.) 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 this service 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 make restrictions that forbid anyone to |
||||
deny you these rights or to ask you to surrender the rights. These |
||||
restrictions translate to certain responsibilities for you if you distribute |
||||
copies of the software, or if you modify it. |
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or |
||||
for a fee, you must give the recipients all the rights that you have. 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. |
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and (2) |
||||
offer you this license which gives you legal permission to copy, distribute |
||||
and/or modify the software. |
||||
|
||||
Also, for each author's protection and ours, we want to make certain that |
||||
everyone understands that there is no warranty for this free software. If |
||||
the software is modified by someone else and passed on, we want its |
||||
recipients to know that what they have is not the original, so that any |
||||
problems introduced by others will not reflect on the original authors' |
||||
reputations. |
||||
|
||||
Finally, any free program is threatened constantly by software patents. We |
||||
wish to avoid the danger that redistributors of a free program will |
||||
individually obtain patent licenses, in effect making the program |
||||
proprietary. To prevent this, we have made it clear that any patent must be |
||||
licensed for everyone's free use or not licensed at all. |
||||
|
||||
The precise terms and conditions for copying, distribution and modification |
||||
follow. |
||||
|
||||
GNU GENERAL PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. This License applies to any program or other work which contains a notice |
||||
placed by the copyright holder saying it may be distributed under the |
||||
terms of this General Public License. The "Program", below, refers to |
||||
any such program or work, and a "work based on the Program" means either |
||||
the Program or any derivative work under copyright law: that is to say, a |
||||
work containing the Program or a portion of it, either verbatim or with |
||||
modifications and/or translated into another language. (Hereinafter, |
||||
translation is included without limitation in the term "modification".) |
||||
Each licensee is addressed as "you". |
||||
|
||||
Activities other than copying, distribution and modification are not |
||||
covered by this License; they are outside its scope. The act of running |
||||
the Program is not restricted, and the output from the Program is covered |
||||
only if its contents constitute a work based on the Program (independent |
||||
of having been made by running the Program). Whether that is true depends |
||||
on what the Program does. |
||||
|
||||
1. You may copy and distribute 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 and |
||||
disclaimer of warranty; keep intact all the notices that refer to this |
||||
License and to the absence of any warranty; and give any other recipients |
||||
of the Program a copy of this License along with the Program. |
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and you |
||||
may at your option offer warranty protection in exchange for a fee. |
||||
|
||||
2. You may modify your copy or copies of the Program or any portion of it, |
||||
thus forming a work based on the Program, and copy and distribute such |
||||
modifications or work under the terms of Section 1 above, provided that |
||||
you also meet all of these conditions: |
||||
|
||||
a) You must cause the modified files to carry prominent notices stating |
||||
that you changed the files and the date of any change. |
||||
|
||||
b) You must cause any work that you distribute or publish, that in whole |
||||
or in part contains or is derived from the Program or any part |
||||
thereof, to be licensed as a whole at no charge to all third parties |
||||
under the terms of this License. |
||||
|
||||
c) If the modified program normally reads commands interactively when |
||||
run, you must cause it, when started running for such interactive use |
||||
in the most ordinary way, to print or display an announcement |
||||
including an appropriate copyright notice and a notice that there is |
||||
no warranty (or else, saying that you provide a warranty) and that |
||||
users may redistribute the program under these conditions, and telling |
||||
the user how to view a copy of this License. (Exception: if the |
||||
Program itself is interactive but does not normally print such an |
||||
announcement, your work based on the Program is not required to print |
||||
an announcement.) |
||||
|
||||
These requirements apply to the modified work as a whole. If |
||||
identifiable sections of that work are not derived from the Program, and |
||||
can be reasonably considered independent and separate works in |
||||
themselves, then this License, and its terms, do not apply to those |
||||
sections when you distribute them as separate works. But when you |
||||
distribute the same sections as part of a whole which is a work based on |
||||
the Program, the distribution of the whole must be on the terms of this |
||||
License, whose permissions for other licensees extend to the entire |
||||
whole, and thus to each and every part regardless of who wrote it. |
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest |
||||
your rights to work written entirely by you; rather, the intent is to |
||||
exercise the right to control the distribution of derivative or |
||||
collective works based on the Program. |
||||
|
||||
In addition, mere aggregation of another work not based on the Program |
||||
with the Program (or with a work based on the Program) on a volume of a |
||||
storage or distribution medium does not bring the other work under the |
||||
scope of this License. |
||||
|
||||
3. You may copy and distribute the Program (or a work based on it, under |
||||
Section 2) in object code or executable form under the terms of Sections |
||||
1 and 2 above provided that you also do one of the following: |
||||
|
||||
a) Accompany it with the complete corresponding machine-readable source |
||||
code, which must be distributed under the terms of Sections 1 and 2 |
||||
above on a medium customarily used for software interchange; or, |
||||
|
||||
b) Accompany it with a written offer, valid for at least three years, to |
||||
give any third party, for a charge no more than your cost of |
||||
physically performing source distribution, a complete machine-readable |
||||
copy of the corresponding source code, to be distributed under the |
||||
terms of Sections 1 and 2 above on a medium customarily used for |
||||
software interchange; or, |
||||
|
||||
c) Accompany it with the information you received as to the offer to |
||||
distribute corresponding source code. (This alternative is allowed |
||||
only for noncommercial distribution and only if you received the |
||||
program in object code or executable form with such an offer, in |
||||
accord with Subsection b above.) |
||||
|
||||
The source code for a work means the preferred form of the work for |
||||
making modifications to it. For an executable work, complete source code |
||||
means all the source code for all modules it contains, plus any |
||||
associated interface definition files, plus the scripts used to control |
||||
compilation and installation of the executable. However, as a special |
||||
exception, the source code distributed need not include anything that is |
||||
normally distributed (in either source or binary form) with the major |
||||
components (compiler, kernel, and so on) of the operating system on which |
||||
the executable runs, unless that component itself accompanies the |
||||
executable. |
||||
|
||||
If distribution of executable or object code is made by offering access |
||||
to copy from a designated place, then offering equivalent access to copy |
||||
the source code from the same place counts as distribution of the source |
||||
code, even though third parties are not compelled to copy the source |
||||
along with the object code. |
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program except as |
||||
expressly provided under this License. Any attempt otherwise to copy, |
||||
modify, sublicense or distribute the Program is void, and will |
||||
automatically terminate your rights under this License. However, parties |
||||
who have received copies, or rights, from you under this License will not |
||||
have their licenses terminated so long as such parties remain in full |
||||
compliance. |
||||
|
||||
5. You are not required to accept this License, since you have not signed |
||||
it. However, nothing else grants you permission to modify or distribute |
||||
the Program or its derivative works. These actions are prohibited by law |
||||
if you do not accept this License. Therefore, by modifying or |
||||
distributing the Program (or any work based on the Program), you indicate |
||||
your acceptance of this License to do so, and all its terms and |
||||
conditions for copying, distributing or modifying the Program or works |
||||
based on it. |
||||
|
||||
6. Each time you redistribute the Program (or any work based on the |
||||
Program), the recipient automatically receives a license from the |
||||
original licensor to copy, distribute or modify the Program subject to |
||||
these terms and conditions. You may not impose any further restrictions |
||||
on the recipients' exercise of the rights granted herein. You are not |
||||
responsible for enforcing compliance by third parties to this License. |
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent |
||||
infringement or for any other reason (not limited to patent issues), |
||||
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 distribute |
||||
so as to satisfy simultaneously your obligations under this License and |
||||
any other pertinent obligations, then as a consequence you may not |
||||
distribute the Program at all. For example, if a patent license would |
||||
not permit royalty-free redistribution of the Program by all those who |
||||
receive copies directly or indirectly through you, then the only way you |
||||
could satisfy both it and this License would be to refrain entirely from |
||||
distribution of the Program. |
||||
|
||||
If any portion of this section is held invalid or unenforceable under any |
||||
particular circumstance, the balance of the section is intended to apply |
||||
and the section as a whole is intended to apply in other circumstances. |
||||
|
||||
It is not the purpose of this section to induce you to infringe any |
||||
patents or other property right claims or to contest validity of any such |
||||
claims; this section has the sole purpose of protecting the integrity of |
||||
the free software distribution system, which is implemented by public |
||||
license practices. Many people have made generous contributions to the |
||||
wide range of software distributed through that system in reliance on |
||||
consistent application of that system; it is up to the author/donor to |
||||
decide if he or she is willing to distribute software through any other |
||||
system and a licensee cannot impose that choice. |
||||
|
||||
This section is intended to make thoroughly clear what is believed to be |
||||
a consequence of the rest of this License. |
||||
|
||||
8. If the distribution and/or use of the Program is restricted in certain |
||||
countries either by patents or by copyrighted interfaces, the original |
||||
copyright holder who places the Program under this License may add an |
||||
explicit geographical distribution limitation excluding those countries, |
||||
so that distribution is permitted only in or among countries not thus |
||||
excluded. In such case, this License incorporates the limitation as if |
||||
written in the body of this License. |
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions of |
||||
the 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 a version number of this License which applies to it and "any |
||||
later version", you have the option of following the terms and conditions |
||||
either of that version or of any later version published by the Free |
||||
Software Foundation. If the Program does not specify a version number of |
||||
this License, you may choose any version ever published by the Free |
||||
Software Foundation. |
||||
|
||||
10. If you wish to incorporate parts of the Program into other free programs |
||||
whose distribution conditions are different, write to the author to ask |
||||
for permission. For software which is copyrighted by the Free Software |
||||
Foundation, write to the Free Software Foundation; we sometimes make |
||||
exceptions for this. Our decision will be guided by the two goals of |
||||
preserving the free status of all derivatives of our free software and |
||||
of promoting the sharing and reuse of software generally. |
||||
|
||||
NO WARRANTY |
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. |
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
||||
REDISTRIBUTE 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. |
@ -0,0 +1,58 @@ |
||||
= Net::LDAP Changelog |
||||
|
||||
== Net::LDAP 0.0.4: August 15, 2006 |
||||
* Undeprecated Net::LDAP#modify. Thanks to Justin Forder for |
||||
providing the rationale for this. |
||||
* Added a much-expanded set of special characters to the parser |
||||
for RFC-2254 filters. Thanks to Andre Nathan. |
||||
* Changed Net::LDAP#search so you can pass it a filter in string form. |
||||
The conversion to a Net::LDAP::Filter now happens automatically. |
||||
* Implemented Net::LDAP#bind_as (preliminary and subject to change). |
||||
Thanks for Simon Claret for valuable suggestions and for helping test. |
||||
* Fixed bug in Net::LDAP#open that was preventing #open from being |
||||
called more than one on a given Net::LDAP object. |
||||
|
||||
== Net::LDAP 0.0.3: July 26, 2006 |
||||
* Added simple TLS encryption. |
||||
Thanks to Garett Shulman for suggestions and for helping test. |
||||
|
||||
== Net::LDAP 0.0.2: July 12, 2006 |
||||
* Fixed malformation in distro tarball and gem. |
||||
* Improved documentation. |
||||
* Supported "paged search control." |
||||
* Added a range of API improvements. |
||||
* Thanks to Andre Nathan, andre@digirati.com.br, for valuable |
||||
suggestions. |
||||
* Added support for LE and GE search filters. |
||||
* Added support for Search referrals. |
||||
* Fixed a regression with openldap 2.2.x and higher caused |
||||
by the introduction of RFC-2696 controls. Thanks to Andre |
||||
Nathan for reporting the problem. |
||||
* Added support for RFC-2254 filter syntax. |
||||
|
||||
== Net::LDAP 0.0.1: May 1, 2006 |
||||
* Initial release. |
||||
* Client functionality is near-complete, although the APIs |
||||
are not guaranteed and may change depending on feedback |
||||
from the community. |
||||
* We're internally working on a Ruby-based implementation |
||||
of a full-featured, production-quality LDAP server, |
||||
which will leverage the underlying LDAP and BER functionality |
||||
in Net::LDAP. |
||||
* Please tell us if you would be interested in seeing a public |
||||
release of the LDAP server. |
||||
* Grateful acknowledgement to Austin Ziegler, who reviewed |
||||
this code and provided the release framework, including |
||||
minitar. |
||||
|
||||
#-- |
||||
# Net::LDAP for Ruby. |
||||
# http://rubyforge.org/projects/net-ldap/ |
||||
# Copyright (C) 2006 by Francis Cianfrocca |
||||
# |
||||
# Available under the same terms as Ruby. See LICENCE in the main |
||||
# distribution for full licensing information. |
||||
# |
||||
# $Id: ChangeLog,v 1.17.2.4 2005/09/09 12:36:42 austin Exp $ |
||||
#++ |
||||
# vim: sts=2 sw=2 ts=4 et ai tw=77 |
@ -0,0 +1,55 @@ |
||||
Net::LDAP is copyrighted free software by Francis Cianfrocca |
||||
<garbagecat10@gmail.com>. You can redistribute it and/or modify it under either |
||||
the terms of the GPL (see the file COPYING), or the conditions below: |
||||
|
||||
1. You may make and give away verbatim copies of the source form of the |
||||
software without restriction, provided that you duplicate all of the |
||||
original copyright notices and associated disclaimers. |
||||
|
||||
2. You may modify your copy of the software in any way, provided that you do |
||||
at least ONE of the following: |
||||
|
||||
a) place your modifications in the Public Domain or otherwise make them |
||||
Freely Available, such as by posting said modifications to Usenet or |
||||
an equivalent medium, or by allowing the author to include your |
||||
modifications in the software. |
||||
|
||||
b) use the modified software only within your corporation or |
||||
organization. |
||||
|
||||
c) rename any non-standard executables so the names do not conflict with |
||||
standard executables, which must also be provided. |
||||
|
||||
d) make other distribution arrangements with the author. |
||||
|
||||
3. You may distribute the software in object code or executable form, |
||||
provided that you do at least ONE of the following: |
||||
|
||||
a) distribute the executables and library files of the software, together |
||||
with instructions (in the manual page or equivalent) on where to get |
||||
the original distribution. |
||||
|
||||
b) accompany the distribution with the machine-readable source of the |
||||
software. |
||||
|
||||
c) give non-standard executables non-standard names, with instructions on |
||||
where to get the original software distribution. |
||||
|
||||
d) make other distribution arrangements with the author. |
||||
|
||||
4. You may modify and include the part of the software into any other |
||||
software (possibly commercial). But some files in the distribution are |
||||
not written by the author, so that they are not under this terms. |
||||
|
||||
They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some |
||||
files under the ./missing directory. See each file for the copying |
||||
condition. |
||||
|
||||
5. The scripts and library files supplied as input to or produced as output |
||||
from the software do not automatically fall under the copyright of the |
||||
software, but belong to whomever generated them, and may be sold |
||||
commercially, and may be aggregated with this software. |
||||
|
||||
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
||||
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
@ -0,0 +1,32 @@ |
||||
= Net::LDAP for Ruby |
||||
Net::LDAP is an LDAP support library written in pure Ruby. It supports all |
||||
LDAP client features, and a subset of server features as well. |
||||
|
||||
Homepage:: http://rubyforge.org/projects/net-ldap/ |
||||
Copyright:: (C) 2006 by Francis Cianfrocca |
||||
|
||||
Original developer: Francis Cianfrocca |
||||
Contributions by Austin Ziegler gratefully acknowledged. |
||||
|
||||
== LICENCE NOTES |
||||
Please read the file LICENCE for licensing restrictions on this library. In |
||||
the simplest terms, this library is available under the same terms as Ruby |
||||
itself. |
||||
|
||||
== Requirements |
||||
Net::LDAP requires Ruby 1.8.2 or better. |
||||
|
||||
== Documentation |
||||
See Net::LDAP for documentation and usage samples. |
||||
|
||||
#-- |
||||
# Net::LDAP for Ruby. |
||||
# http://rubyforge.org/projects/net-ldap/ |
||||
# Copyright (C) 2006 by Francis Cianfrocca |
||||
# |
||||
# Available under the same terms as Ruby. See LICENCE in the main |
||||
# distribution for full licensing information. |
||||
# |
||||
# $Id: README 141 2006-07-12 10:37:37Z blackhedd $ |
||||
#++ |
||||
# vim: sts=2 sw=2 ts=4 et ai tw=77 |
@ -0,0 +1,294 @@ |
||||
# $Id: ber.rb 142 2006-07-26 12:20:33Z blackhedd $ |
||||
# |
||||
# NET::BER |
||||
# Mixes ASN.1/BER convenience methods into several standard classes. |
||||
# Also provides BER parsing functionality. |
||||
# |
||||
#---------------------------------------------------------------------------- |
||||
# |
||||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. |
||||
# |
||||
# Gmail: garbagecat10 |
||||
# |
||||
# 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 2 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, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
# |
||||
#--------------------------------------------------------------------------- |
||||
# |
||||
# |
||||
|
||||
|
||||
|
||||
|
||||
module Net |
||||
|
||||
module BER |
||||
|
||||
class BerError < Exception; end |
||||
|
||||
|
||||
# This module is for mixing into IO and IO-like objects. |
||||
module BERParser |
||||
|
||||
# The order of these follows the class-codes in BER. |
||||
# Maybe this should have been a hash. |
||||
TagClasses = [:universal, :application, :context_specific, :private] |
||||
|
||||
BuiltinSyntax = { |
||||
:universal => { |
||||
:primitive => { |
||||
1 => :boolean, |
||||
2 => :integer, |
||||
4 => :string, |
||||
10 => :integer, |
||||
}, |
||||
:constructed => { |
||||
16 => :array, |
||||
17 => :array |
||||
} |
||||
} |
||||
} |
||||
|
||||
# |
||||
# read_ber |
||||
# TODO: clean this up so it works properly with partial |
||||
# packets coming from streams that don't block when |
||||
# we ask for more data (like StringIOs). At it is, |
||||
# this can throw TypeErrors and other nasties. |
||||
# |
||||
def read_ber syntax=nil |
||||
return nil if eof? |
||||
|
||||
id = getc # don't trash this value, we'll use it later |
||||
tag = id & 31 |
||||
tag < 31 or raise BerError.new( "unsupported tag encoding: #{id}" ) |
||||
tagclass = TagClasses[ id >> 6 ] |
||||
encoding = (id & 0x20 != 0) ? :constructed : :primitive |
||||
|
||||
n = getc |
||||
lengthlength,contentlength = if n <= 127 |
||||
[1,n] |
||||
else |
||||
j = (0...(n & 127)).inject(0) {|mem,x| mem = (mem << 8) + getc} |
||||
[1 + (n & 127), j] |
||||
end |
||||
|
||||
newobj = read contentlength |
||||
|
||||
objtype = nil |
||||
[syntax, BuiltinSyntax].each {|syn| |
||||
if syn && (ot = syn[tagclass]) && (ot = ot[encoding]) && ot[tag] |
||||
objtype = ot[tag] |
||||
break |
||||
end |
||||
} |
||||
|
||||
obj = case objtype |
||||
when :boolean |
||||
newobj != "\000" |
||||
when :string |
||||
(newobj || "").dup |
||||
when :integer |
||||
j = 0 |
||||
newobj.each_byte {|b| j = (j << 8) + b} |
||||
j |
||||
when :array |
||||
seq = [] |
||||
sio = StringIO.new( newobj || "" ) |
||||
# Interpret the subobject, but note how the loop |
||||
# is built: nil ends the loop, but false (a valid |
||||
# BER value) does not! |
||||
while (e = sio.read_ber(syntax)) != nil |
||||
seq << e |
||||
end |
||||
seq |
||||
else |
||||
raise BerError.new( "unsupported object type: class=#{tagclass}, encoding=#{encoding}, tag=#{tag}" ) |
||||
end |
||||
|
||||
# Add the identifier bits into the object if it's a String or an Array. |
||||
# We can't add extra stuff to Fixnums and booleans, not that it makes much sense anyway. |
||||
obj and ([String,Array].include? obj.class) and obj.instance_eval "def ber_identifier; #{id}; end" |
||||
obj |
||||
|
||||
end |
||||
|
||||
end # module BERParser |
||||
end # module BER |
||||
|
||||
end # module Net |
||||
|
||||
|
||||
class IO |
||||
include Net::BER::BERParser |
||||
end |
||||
|
||||
require "stringio" |
||||
class StringIO |
||||
include Net::BER::BERParser |
||||
end |
||||
|
||||
begin |
||||
require 'openssl' |
||||
class OpenSSL::SSL::SSLSocket |
||||
include Net::BER::BERParser |
||||
end |
||||
rescue LoadError |
||||
# Ignore LoadError. |
||||
# DON'T ignore NameError, which means the SSLSocket class |
||||
# is somehow unavailable on this implementation of Ruby's openssl. |
||||
# This may be WRONG, however, because we don't yet know how Ruby's |
||||
# openssl behaves on machines with no OpenSSL library. I suppose |
||||
# it's possible they do not fail to require 'openssl' but do not |
||||
# create the classes. So this code is provisional. |
||||
# Also, you might think that OpenSSL::SSL::SSLSocket inherits from |
||||
# IO so we'd pick it up above. But you'd be wrong. |
||||
end |
||||
|
||||
class String |
||||
def read_ber syntax=nil |
||||
StringIO.new(self).read_ber(syntax) |
||||
end |
||||
end |
||||
|
||||
|
||||
|
||||
#---------------------------------------------- |
||||
|
||||
|
||||
class FalseClass |
||||
# |
||||
# to_ber |
||||
# |
||||
def to_ber |
||||
"\001\001\000" |
||||
end |
||||
end |
||||
|
||||
|
||||
class TrueClass |
||||
# |
||||
# to_ber |
||||
# |
||||
def to_ber |
||||
"\001\001\001" |
||||
end |
||||
end |
||||
|
||||
|
||||
|
||||
class Fixnum |
||||
# |
||||
# to_ber |
||||
# |
||||
def to_ber |
||||
i = [self].pack('w') |
||||
[2, i.length].pack("CC") + i |
||||
end |
||||
|
||||
# |
||||
# to_ber_enumerated |
||||
# |
||||
def to_ber_enumerated |
||||
i = [self].pack('w') |
||||
[10, i.length].pack("CC") + i |
||||
end |
||||
|
||||
# |
||||
# to_ber_length_encoding |
||||
# |
||||
def to_ber_length_encoding |
||||
if self <= 127 |
||||
[self].pack('C') |
||||
else |
||||
i = [self].pack('N').sub(/^[\0]+/,"") |
||||
[0x80 + i.length].pack('C') + i |
||||
end |
||||
end |
||||
|
||||
end # class Fixnum |
||||
|
||||
|
||||
class Bignum |
||||
|
||||
def to_ber |
||||
i = [self].pack('w') |
||||
i.length > 126 and raise Net::BER::BerError.new( "range error in bignum" ) |
||||
[2, i.length].pack("CC") + i |
||||
end |
||||
|
||||
end |
||||
|
||||
|
||||
|
||||
class String |
||||
# |
||||
# to_ber |
||||
# A universal octet-string is tag number 4, |
||||
# but others are possible depending on the context, so we |
||||
# let the caller give us one. |
||||
# The preferred way to do this in user code is via to_ber_application_sring |
||||
# and to_ber_contextspecific. |
||||
# |
||||
def to_ber code = 4 |
||||
[code].pack('C') + length.to_ber_length_encoding + self |
||||
end |
||||
|
||||
# |
||||
# to_ber_application_string |
||||
# |
||||
def to_ber_application_string code |
||||
to_ber( 0x40 + code ) |
||||
end |
||||
|
||||
# |
||||
# to_ber_contextspecific |
||||
# |
||||
def to_ber_contextspecific code |
||||
to_ber( 0x80 + code ) |
||||
end |
||||
|
||||
end # class String |
||||
|
||||
|
||||
|
||||
class Array |
||||
# |
||||
# to_ber_appsequence |
||||
# An application-specific sequence usually gets assigned |
||||
# a tag that is meaningful to the particular protocol being used. |
||||
# This is different from the universal sequence, which usually |
||||
# gets a tag value of 16. |
||||
# Now here's an interesting thing: We're adding the X.690 |
||||
# "application constructed" code at the top of the tag byte (0x60), |
||||
# but some clients, notably ldapsearch, send "context-specific |
||||
# constructed" (0xA0). The latter would appear to violate RFC-1777, |
||||
# but what do I know? We may need to change this. |
||||
# |
||||
|
||||
def to_ber id = 0; to_ber_seq_internal( 0x30 + id ); end |
||||
def to_ber_set id = 0; to_ber_seq_internal( 0x31 + id ); end |
||||
def to_ber_sequence id = 0; to_ber_seq_internal( 0x30 + id ); end |
||||
def to_ber_appsequence id = 0; to_ber_seq_internal( 0x60 + id ); end |
||||
def to_ber_contextspecific id = 0; to_ber_seq_internal( 0xA0 + id ); end |
||||
|
||||
private |
||||
def to_ber_seq_internal code |
||||
s = self.to_s |
||||
[code].pack('C') + s.length.to_ber_length_encoding + s |
||||
end |
||||
|
||||
end # class Array |
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,108 @@ |
||||
# $Id: dataset.rb 78 2006-04-26 02:57:34Z blackhedd $ |
||||
# |
||||
# |
||||
#---------------------------------------------------------------------------- |
||||
# |
||||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. |
||||
# |
||||
# Gmail: garbagecat10 |
||||
# |
||||
# 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 2 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, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
# |
||||
#--------------------------------------------------------------------------- |
||||
# |
||||
# |
||||
|
||||
|
||||
|
||||
|
||||
module Net |
||||
class LDAP |
||||
|
||||
class Dataset < Hash |
||||
|
||||
attr_reader :comments |
||||
|
||||
|
||||
def Dataset::read_ldif io |
||||
ds = Dataset.new |
||||
|
||||
line = io.gets && chomp |
||||
dn = nil |
||||
|
||||
while line |
||||
io.gets and chomp |
||||
if $_ =~ /^[\s]+/ |
||||
line << " " << $' |
||||
else |
||||
nextline = $_ |
||||
|
||||
if line =~ /^\#/ |
||||
ds.comments << line |
||||
elsif line =~ /^dn:[\s]*/i |
||||
dn = $' |
||||
ds[dn] = Hash.new {|k,v| k[v] = []} |
||||
elsif line.length == 0 |
||||
dn = nil |
||||
elsif line =~ /^([^:]+):([\:]?)[\s]*/ |
||||
# $1 is the attribute name |
||||
# $2 is a colon iff the attr-value is base-64 encoded |
||||
# $' is the attr-value |
||||
# Avoid the Base64 class because not all Ruby versions have it. |
||||
attrvalue = ($2 == ":") ? $'.unpack('m').shift : $' |
||||
ds[dn][$1.downcase.intern] << attrvalue |
||||
end |
||||
|
||||
line = nextline |
||||
end |
||||
end |
||||
|
||||
ds |
||||
end |
||||
|
||||
|
||||
def initialize |
||||
@comments = [] |
||||
end |
||||
|
||||
|
||||
def to_ldif |
||||
ary = [] |
||||
ary += (@comments || []) |
||||
|
||||
keys.sort.each {|dn| |
||||
ary << "dn: #{dn}" |
||||
|
||||
self[dn].keys.map {|sym| sym.to_s}.sort.each {|attr| |
||||
self[dn][attr.intern].each {|val| |
||||
ary << "#{attr}: #{val}" |
||||
} |
||||
} |
||||
|
||||
ary << "" |
||||
} |
||||
|
||||
block_given? and ary.each {|line| yield line} |
||||
|
||||
ary |
||||
end |
||||
|
||||
|
||||
end # Dataset |
||||
|
||||
end # LDAP |
||||
end # Net |
||||
|
||||
|
@ -0,0 +1,165 @@ |
||||
# $Id: entry.rb 123 2006-05-18 03:52:38Z blackhedd $ |
||||
# |
||||
# LDAP Entry (search-result) support classes |
||||
# |
||||
# |
||||
#---------------------------------------------------------------------------- |
||||
# |
||||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. |
||||
# |
||||
# Gmail: garbagecat10 |
||||
# |
||||
# 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 2 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, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
# |
||||
#--------------------------------------------------------------------------- |
||||
# |
||||
|
||||
|
||||
|
||||
|
||||
module Net |
||||
class LDAP |
||||
|
||||
|
||||
# Objects of this class represent individual entries in an LDAP |
||||
# directory. User code generally does not instantiate this class. |
||||
# Net::LDAP#search provides objects of this class to user code, |
||||
# either as block parameters or as return values. |
||||
# |
||||
# In LDAP-land, an "entry" is a collection of attributes that are |
||||
# uniquely and globally identified by a DN ("Distinguished Name"). |
||||
# Attributes are identified by short, descriptive words or phrases. |
||||
# Although a directory is |
||||
# free to implement any attribute name, most of them follow rigorous |
||||
# standards so that the range of commonly-encountered attribute |
||||
# names is not large. |
||||
# |
||||
# An attribute name is case-insensitive. Most directories also |
||||
# restrict the range of characters allowed in attribute names. |
||||
# To simplify handling attribute names, Net::LDAP::Entry |
||||
# internally converts them to a standard format. Therefore, the |
||||
# methods which take attribute names can take Strings or Symbols, |
||||
# and work correctly regardless of case or capitalization. |
||||
# |
||||
# An attribute consists of zero or more data items called |
||||
# <i>values.</i> An entry is the combination of a unique DN, a set of attribute |
||||
# names, and a (possibly-empty) array of values for each attribute. |
||||
# |
||||
# Class Net::LDAP::Entry provides convenience methods for dealing |
||||
# with LDAP entries. |
||||
# In addition to the methods documented below, you may access individual |
||||
# attributes of an entry simply by giving the attribute name as |
||||
# the name of a method call. For example: |
||||
# ldap.search( ... ) do |entry| |
||||
# puts "Common name: #{entry.cn}" |
||||
# puts "Email addresses:" |
||||
# entry.mail.each {|ma| puts ma} |
||||
# end |
||||
# If you use this technique to access an attribute that is not present |
||||
# in a particular Entry object, a NoMethodError exception will be raised. |
||||
# |
||||
#-- |
||||
# Ugly problem to fix someday: We key off the internal hash with |
||||
# a canonical form of the attribute name: convert to a string, |
||||
# downcase, then take the symbol. Unfortunately we do this in |
||||
# at least three places. Should do it in ONE place. |
||||
class Entry |
||||
|
||||
# This constructor is not generally called by user code. |
||||
def initialize dn = nil # :nodoc: |
||||
@myhash = Hash.new {|k,v| k[v] = [] } |
||||
@myhash[:dn] = [dn] |
||||
end |
||||
|
||||
|
||||
def []= name, value # :nodoc: |
||||
sym = name.to_s.downcase.intern |
||||
@myhash[sym] = value |
||||
end |
||||
|
||||
|
||||
#-- |
||||
# We have to deal with this one as we do with []= |
||||
# because this one and not the other one gets called |
||||
# in formulations like entry["CN"] << cn. |
||||
# |
||||
def [] name # :nodoc: |
||||
name = name.to_s.downcase.intern unless name.is_a?(Symbol) |
||||
@myhash[name] |
||||
end |
||||
|
||||
# Returns the dn of the Entry as a String. |
||||
def dn |
||||
self[:dn][0] |
||||
end |
||||
|
||||
# Returns an array of the attribute names present in the Entry. |
||||
def attribute_names |
||||
@myhash.keys |
||||
end |
||||
|
||||
# Accesses each of the attributes present in the Entry. |
||||
# Calls a user-supplied block with each attribute in turn, |
||||
# passing two arguments to the block: a Symbol giving |
||||
# the name of the attribute, and a (possibly empty) |
||||
# Array of data values. |
||||
# |
||||
def each |
||||
if block_given? |
||||
attribute_names.each {|a| |
||||
attr_name,values = a,self[a] |
||||
yield attr_name, values |
||||
} |
||||
end |
||||
end |
||||
|
||||
alias_method :each_attribute, :each |
||||
|
||||
|
||||
#-- |
||||
# Convenience method to convert unknown method names |
||||
# to attribute references. Of course the method name |
||||
# comes to us as a symbol, so let's save a little time |
||||
# and not bother with the to_s.downcase two-step. |
||||
# Of course that means that a method name like mAIL |
||||
# won't work, but we shouldn't be encouraging that |
||||
# kind of bad behavior in the first place. |
||||
# Maybe we should thow something if the caller sends |
||||
# arguments or a block... |
||||
# |
||||
def method_missing *args, &block # :nodoc: |
||||
s = args[0].to_s.downcase.intern |
||||
if attribute_names.include?(s) |
||||
self[s] |
||||
elsif s.to_s[-1] == 61 and s.to_s.length > 1 |
||||
value = args[1] or raise RuntimeError.new( "unable to set value" ) |
||||
value = [value] unless value.is_a?(Array) |
||||
name = s.to_s[0..-2].intern |
||||
self[name] = value |
||||
else |
||||
raise NoMethodError.new( "undefined method '#{s}'" ) |
||||
end |
||||
end |
||||
|
||||
def write |
||||
end |
||||
|
||||
end # class Entry |
||||
|
||||
|
||||
end # class LDAP |
||||
end # module Net |
||||
|
||||
|
@ -0,0 +1,387 @@ |
||||
# $Id: filter.rb 151 2006-08-15 08:34:53Z blackhedd $ |
||||
# |
||||
# |
||||
#---------------------------------------------------------------------------- |
||||
# |
||||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. |
||||
# |
||||
# Gmail: garbagecat10 |
||||
# |
||||
# 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 2 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, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
# |
||||
#--------------------------------------------------------------------------- |
||||
# |
||||
# |
||||
|
||||
|
||||
module Net |
||||
class LDAP |
||||
|
||||
|
||||
# Class Net::LDAP::Filter is used to constrain |
||||
# LDAP searches. An object of this class is |
||||
# passed to Net::LDAP#search in the parameter :filter. |
||||
# |
||||
# Net::LDAP::Filter supports the complete set of search filters |
||||
# available in LDAP, including conjunction, disjunction and negation |
||||
# (AND, OR, and NOT). This class supplants the (infamous) RFC-2254 |
||||
# standard notation for specifying LDAP search filters. |
||||
# |
||||
# Here's how to code the familiar "objectclass is present" filter: |
||||
# f = Net::LDAP::Filter.pres( "objectclass" ) |
||||
# The object returned by this code can be passed directly to |
||||
# the <tt>:filter</tt> parameter of Net::LDAP#search. |
||||
# |
||||
# See the individual class and instance methods below for more examples. |
||||
# |
||||
class Filter |
||||
|
||||
def initialize op, a, b |
||||
@op = op |
||||
@left = a |
||||
@right = b |
||||
end |
||||
|
||||
# #eq creates a filter object indicating that the value of |
||||
# a paticular attribute must be either <i>present</i> or must |
||||
# match a particular string. |
||||
# |
||||
# To specify that an attribute is "present" means that only |
||||
# directory entries which contain a value for the particular |
||||
# attribute will be selected by the filter. This is useful |
||||
# in case of optional attributes such as <tt>mail.</tt> |
||||
# Presence is indicated by giving the value "*" in the second |
||||
# parameter to #eq. This example selects only entries that have |
||||
# one or more values for <tt>sAMAccountName:</tt> |
||||
# f = Net::LDAP::Filter.eq( "sAMAccountName", "*" ) |
||||
# |
||||
# To match a particular range of values, pass a string as the |
||||
# second parameter to #eq. The string may contain one or more |
||||
# "*" characters as wildcards: these match zero or more occurrences |
||||
# of any character. Full regular-expressions are <i>not</i> supported |
||||
# due to limitations in the underlying LDAP protocol. |
||||
# This example selects any entry with a <tt>mail</tt> value containing |
||||
# the substring "anderson": |
||||
# f = Net::LDAP::Filter.eq( "mail", "*anderson*" ) |
||||
#-- |
||||
# Removed gt and lt. They ain't in the standard! |
||||
# |
||||
def Filter::eq attribute, value; Filter.new :eq, attribute, value; end |
||||
def Filter::ne attribute, value; Filter.new :ne, attribute, value; end |
||||
#def Filter::gt attribute, value; Filter.new :gt, attribute, value; end |
||||
#def Filter::lt attribute, value; Filter.new :lt, attribute, value; end |
||||
def Filter::ge attribute, value; Filter.new :ge, attribute, value; end |
||||
def Filter::le attribute, value; Filter.new :le, attribute, value; end |
||||
|
||||
# #pres( attribute ) is a synonym for #eq( attribute, "*" ) |
||||
# |
||||
def Filter::pres attribute; Filter.eq attribute, "*"; end |
||||
|
||||
# operator & ("AND") is used to conjoin two or more filters. |
||||
# This expression will select only entries that have an <tt>objectclass</tt> |
||||
# attribute AND have a <tt>mail</tt> attribute that begins with "George": |
||||
# f = Net::LDAP::Filter.pres( "objectclass" ) & Net::LDAP::Filter.eq( "mail", "George*" ) |
||||
# |
||||
def & filter; Filter.new :and, self, filter; end |
||||
|
||||
# operator | ("OR") is used to disjoin two or more filters. |
||||
# This expression will select entries that have either an <tt>objectclass</tt> |
||||
# attribute OR a <tt>mail</tt> attribute that begins with "George": |
||||
# f = Net::LDAP::Filter.pres( "objectclass" ) | Net::LDAP::Filter.eq( "mail", "George*" ) |
||||
# |
||||
def | filter; Filter.new :or, self, filter; end |
||||
|
||||
|
||||
# |
||||
# operator ~ ("NOT") is used to negate a filter. |
||||
# This expression will select only entries that <i>do not</i> have an <tt>objectclass</tt> |
||||
# attribute: |
||||
# f = ~ Net::LDAP::Filter.pres( "objectclass" ) |
||||
# |
||||
#-- |
||||
# This operator can't be !, evidently. Try it. |
||||
# Removed GT and LT. They're not in the RFC. |
||||
def ~@; Filter.new :not, self, nil; end |
||||
|
||||
|
||||
def to_s |
||||
case @op |
||||
when :ne |
||||
"(!(#{@left}=#{@right}))" |
||||
when :eq |
||||
"(#{@left}=#{@right})" |
||||
#when :gt |
||||
# "#{@left}>#{@right}" |
||||
#when :lt |
||||
# "#{@left}<#{@right}" |
||||
when :ge |
||||
"#{@left}>=#{@right}" |
||||
when :le |
||||
"#{@left}<=#{@right}" |
||||
when :and |
||||
"(&(#{@left})(#{@right}))" |
||||
when :or |
||||
"(|(#{@left})(#{@right}))" |
||||
when :not |
||||
"(!(#{@left}))" |
||||
else |
||||
raise "invalid or unsupported operator in LDAP Filter" |
||||
end |
||||
end |
||||
|
||||
|
||||
#-- |
||||
# to_ber |
||||
# Filter ::= |
||||
# CHOICE { |
||||
# and [0] SET OF Filter, |
||||
# or [1] SET OF Filter, |
||||
# not [2] Filter, |
||||
# equalityMatch [3] AttributeValueAssertion, |
||||
# substrings [4] SubstringFilter, |
||||
# greaterOrEqual [5] AttributeValueAssertion, |
||||
# lessOrEqual [6] AttributeValueAssertion, |
||||
# present [7] AttributeType, |
||||
# approxMatch [8] AttributeValueAssertion |
||||
# } |
||||
# |
||||
# SubstringFilter |
||||
# SEQUENCE { |
||||
# type AttributeType, |
||||
# SEQUENCE OF CHOICE { |
||||
# initial [0] LDAPString, |
||||
# any [1] LDAPString, |
||||
# final [2] LDAPString |
||||
# } |
||||
# } |
||||
# |
||||
# Parsing substrings is a little tricky. |
||||
# We use the split method to break a string into substrings |
||||
# delimited by the * (star) character. But we also need |
||||
# to know whether there is a star at the head and tail |
||||
# of the string. A Ruby particularity comes into play here: |
||||
# if you split on * and the first character of the string is |
||||
# a star, then split will return an array whose first element |
||||
# is an _empty_ string. But if the _last_ character of the |
||||
# string is star, then split will return an array that does |
||||
# _not_ add an empty string at the end. So we have to deal |
||||
# with all that specifically. |
||||
# |
||||
def to_ber |
||||
case @op |
||||
when :eq |
||||
if @right == "*" # present |
||||
@left.to_s.to_ber_contextspecific 7 |
||||
elsif @right =~ /[\*]/ #substring |
||||
ary = @right.split( /[\*]+/ ) |
||||
final_star = @right =~ /[\*]$/ |
||||
initial_star = ary.first == "" and ary.shift |
||||
|
||||
seq = [] |
||||
unless initial_star |
||||
seq << ary.shift.to_ber_contextspecific(0) |
||||
end |
||||
n_any_strings = ary.length - (final_star ? 0 : 1) |
||||
#p n_any_strings |
||||
n_any_strings.times { |
||||
seq << ary.shift.to_ber_contextspecific(1) |
||||
} |
||||
unless final_star |
||||
seq << ary.shift.to_ber_contextspecific(2) |
||||
end |
||||
[@left.to_s.to_ber, seq.to_ber].to_ber_contextspecific 4 |
||||
else #equality |
||||
[@left.to_s.to_ber, @right.to_ber].to_ber_contextspecific 3 |
||||
end |
||||
when :ge |
||||
[@left.to_s.to_ber, @right.to_ber].to_ber_contextspecific 5 |
||||
when :le |
||||
[@left.to_s.to_ber, @right.to_ber].to_ber_contextspecific 6 |
||||
when :and |
||||
ary = [@left.coalesce(:and), @right.coalesce(:and)].flatten |
||||
ary.map {|a| a.to_ber}.to_ber_contextspecific( 0 ) |
||||
when :or |
||||
ary = [@left.coalesce(:or), @right.coalesce(:or)].flatten |
||||
ary.map {|a| a.to_ber}.to_ber_contextspecific( 1 ) |
||||
when :not |
||||
[@left.to_ber].to_ber_contextspecific 2 |
||||
else |
||||
# ERROR, we'll return objectclass=* to keep things from blowing up, |
||||
# but that ain't a good answer and we need to kick out an error of some kind. |
||||
raise "unimplemented search filter" |
||||
end |
||||
end |
||||
|
||||
#-- |
||||
# coalesce |
||||
# This is a private helper method for dealing with chains of ANDs and ORs |
||||
# that are longer than two. If BOTH of our branches are of the specified |
||||
# type of joining operator, then return both of them as an array (calling |
||||
# coalesce recursively). If they're not, then return an array consisting |
||||
# only of self. |
||||
# |
||||
def coalesce operator |
||||
if @op == operator |
||||
[@left.coalesce( operator ), @right.coalesce( operator )] |
||||
else |
||||
[self] |
||||
end |
||||
end |
||||
|
||||
|
||||
|
||||
#-- |
||||
# We get a Ruby object which comes from parsing an RFC-1777 "Filter" |
||||
# object. Convert it to a Net::LDAP::Filter. |
||||
# TODO, we're hardcoding the RFC-1777 BER-encodings of the various |
||||
# filter types. Could pull them out into a constant. |
||||
# |
||||
def Filter::parse_ldap_filter obj |
||||
case obj.ber_identifier |
||||
when 0x87 # present. context-specific primitive 7. |
||||
Filter.eq( obj.to_s, "*" ) |
||||
when 0xa3 # equalityMatch. context-specific constructed 3. |
||||
Filter.eq( obj[0], obj[1] ) |
||||
else |
||||
raise LdapError.new( "unknown ldap search-filter type: #{obj.ber_identifier}" ) |
||||
end |
||||
end |
||||
|
||||
|
||||
#-- |
||||
# We got a hash of attribute values. |
||||
# Do we match the attributes? |
||||
# Return T/F, and call match recursively as necessary. |
||||
def match entry |
||||
case @op |
||||
when :eq |
||||
if @right == "*" |
||||
l = entry[@left] and l.length > 0 |
||||
else |
||||
l = entry[@left] and l = l.to_a and l.index(@right) |
||||
end |
||||
else |
||||
raise LdapError.new( "unknown filter type in match: #{@op}" ) |
||||
end |
||||
end |
||||
|
||||
# Converts an LDAP filter-string (in the prefix syntax specified in RFC-2254) |
||||
# to a Net::LDAP::Filter. |
||||
def self.construct ldap_filter_string |
||||
FilterParser.new(ldap_filter_string).filter |
||||
end |
||||
|
||||
# Synonym for #construct. |
||||
# to a Net::LDAP::Filter. |
||||
def self.from_rfc2254 ldap_filter_string |
||||
construct ldap_filter_string |
||||
end |
||||
|
||||
end # class Net::LDAP::Filter |
||||
|
||||
|
||||
|
||||
class FilterParser #:nodoc: |
||||
|
||||
attr_reader :filter |
||||
|
||||
def initialize str |
||||
require 'strscan' |
||||
@filter = parse( StringScanner.new( str )) or raise Net::LDAP::LdapError.new( "invalid filter syntax" ) |
||||
end |
||||
|
||||
def parse scanner |
||||
parse_filter_branch(scanner) or parse_paren_expression(scanner) |
||||
end |
||||
|
||||
def parse_paren_expression scanner |
||||
if scanner.scan /\s*\(\s*/ |
||||
b = if scanner.scan /\s*\&\s*/ |
||||
a = nil |
||||
branches = [] |
||||
while br = parse_paren_expression(scanner) |
||||
branches << br |
||||
end |
||||
if branches.length >= 2 |
||||
a = branches.shift |
||||
while branches.length > 0 |
||||
a = a & branches.shift |
||||
end |
||||
a |
||||
end |
||||
elsif scanner.scan /\s*\|\s*/ |
||||
# TODO: DRY! |
||||
a = nil |
||||
branches = [] |
||||
while br = parse_paren_expression(scanner) |
||||
branches << br |
||||
end |
||||
if branches.length >= 2 |
||||
a = branches.shift |
||||
while branches.length > 0 |
||||
a = a | branches.shift |
||||
end |
||||
a |
||||
end |
||||
elsif scanner.scan /\s*\!\s*/ |
||||
br = parse_paren_expression(scanner) |
||||
if br |
||||
~ br |
||||
end |
||||
else |
||||
parse_filter_branch( scanner ) |
||||
end |
||||
|
||||
if b and scanner.scan( /\s*\)\s*/ ) |
||||
b |
||||
end |
||||
end |
||||
end |
||||
|
||||
# Added a greatly-augmented filter contributed by Andre Nathan |
||||
# for detecting special characters in values. (15Aug06) |
||||
def parse_filter_branch scanner |
||||
scanner.scan /\s*/ |
||||
if token = scanner.scan( /[\w\-_]+/ ) |
||||
scanner.scan /\s*/ |
||||
if op = scanner.scan( /\=|\<\=|\<|\>\=|\>|\!\=/ ) |
||||
scanner.scan /\s*/ |
||||
#if value = scanner.scan( /[\w\*\.]+/ ) (ORG) |
||||
if value = scanner.scan( /[\w\*\.\+\-@=#\$%&!]+/ ) |
||||
case op |
||||
when "=" |
||||
Filter.eq( token, value ) |
||||
when "!=" |
||||
Filter.ne( token, value ) |
||||
when "<" |
||||
Filter.lt( token, value ) |
||||
when "<=" |
||||
Filter.le( token, value ) |
||||
when ">" |
||||
Filter.gt( token, value ) |
||||
when ">=" |
||||
Filter.ge( token, value ) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
end # class Net::LDAP::FilterParser |
||||
|
||||
end # class Net::LDAP |
||||
end # module Net |
||||
|
||||
|
@ -0,0 +1,205 @@ |
||||
# $Id: pdu.rb 126 2006-05-31 15:55:16Z blackhedd $ |
||||
# |
||||
# LDAP PDU support classes |
||||
# |
||||
# |
||||
#---------------------------------------------------------------------------- |
||||
# |
||||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. |
||||
# |
||||
# Gmail: garbagecat10 |
||||
# |
||||
# 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 2 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, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
# |
||||
#--------------------------------------------------------------------------- |
||||
# |
||||
|
||||
|
||||
|
||||
module Net |
||||
|
||||
|
||||
class LdapPduError < Exception; end |
||||
|
||||
|
||||
class LdapPdu |
||||
|
||||
BindResult = 1 |
||||
SearchReturnedData = 4 |
||||
SearchResult = 5 |
||||
ModifyResponse = 7 |
||||
AddResponse = 9 |
||||
DeleteResponse = 11 |
||||
ModifyRDNResponse = 13 |
||||
SearchResultReferral = 19 |
||||
|
||||
attr_reader :msg_id, :app_tag |
||||
attr_reader :search_dn, :search_attributes, :search_entry |
||||
attr_reader :search_referrals |
||||
|
||||
# |
||||
# initialize |
||||
# An LDAP PDU always looks like a BerSequence with |
||||
# at least two elements: an integer (message-id number), and |
||||
# an application-specific sequence. |
||||
# Some LDAPv3 packets also include an optional |
||||
# third element, which is a sequence of "controls" |
||||
# (See RFC 2251, section 4.1.12). |
||||
# The application-specific tag in the sequence tells |
||||
# us what kind of packet it is, and each kind has its |
||||
# own format, defined in RFC-1777. |
||||
# Observe that many clients (such as ldapsearch) |
||||
# do not necessarily enforce the expected application |
||||
# tags on received protocol packets. This implementation |
||||
# does interpret the RFC strictly in this regard, and |
||||
# it remains to be seen whether there are servers out |
||||
# there that will not work well with our approach. |
||||
# |
||||
# Added a controls-processor to SearchResult. |
||||
# Didn't add it everywhere because it just _feels_ |
||||
# like it will need to be refactored. |
||||
# |
||||
def initialize ber_object |
||||
begin |
||||
@msg_id = ber_object[0].to_i |
||||
@app_tag = ber_object[1].ber_identifier - 0x60 |
||||
rescue |
||||
# any error becomes a data-format error |
||||
raise LdapPduError.new( "ldap-pdu format error" ) |
||||
end |
||||
|
||||
case @app_tag |
||||
when BindResult |
||||
parse_ldap_result ber_object[1] |
||||
when SearchReturnedData |
||||
parse_search_return ber_object[1] |
||||
when SearchResultReferral |
||||
parse_search_referral ber_object[1] |
||||
when SearchResult |
||||
parse_ldap_result ber_object[1] |
||||
parse_controls(ber_object[2]) if ber_object[2] |
||||
when ModifyResponse |
||||
parse_ldap_result ber_object[1] |
||||
when AddResponse |
||||
parse_ldap_result ber_object[1] |
||||
when DeleteResponse |
||||
parse_ldap_result ber_object[1] |
||||
when ModifyRDNResponse |
||||
parse_ldap_result ber_object[1] |
||||
else |
||||
raise LdapPduError.new( "unknown pdu-type: #{@app_tag}" ) |
||||
end |
||||
end |
||||
|
||||
# |
||||
# result_code |
||||
# This returns an LDAP result code taken from the PDU, |
||||
# but it will be nil if there wasn't a result code. |
||||
# That can easily happen depending on the type of packet. |
||||
# |
||||
def result_code code = :resultCode |
||||
@ldap_result and @ldap_result[code] |
||||
end |
||||
|
||||
# Return RFC-2251 Controls if any. |
||||
# Messy. Does this functionality belong somewhere else? |
||||
def result_controls |
||||
@ldap_controls || [] |
||||
end |
||||
|
||||
|
||||
# |
||||
# parse_ldap_result |
||||
# |
||||
def parse_ldap_result sequence |
||||
sequence.length >= 3 or raise LdapPduError |
||||
@ldap_result = {:resultCode => sequence[0], :matchedDN => sequence[1], :errorMessage => sequence[2]} |
||||
end |
||||
private :parse_ldap_result |
||||
|
||||
# |
||||
# parse_search_return |
||||
# Definition from RFC 1777 (we're handling application-4 here) |
||||
# |
||||
# Search Response ::= |
||||
# CHOICE { |
||||
# entry [APPLICATION 4] SEQUENCE { |
||||
# objectName LDAPDN, |
||||
# attributes SEQUENCE OF SEQUENCE { |
||||
# AttributeType, |
||||
# SET OF AttributeValue |
||||
# } |
||||
# }, |
||||
# resultCode [APPLICATION 5] LDAPResult |
||||
# } |
||||
# |
||||
# We concoct a search response that is a hash of the returned attribute values. |
||||
# NOW OBSERVE CAREFULLY: WE ARE DOWNCASING THE RETURNED ATTRIBUTE NAMES. |
||||
# This is to make them more predictable for user programs, but it |
||||
# may not be a good idea. Maybe this should be configurable. |
||||
# ALTERNATE IMPLEMENTATION: In addition to @search_dn and @search_attributes, |
||||
# we also return @search_entry, which is an LDAP::Entry object. |
||||
# If that works out well, then we'll remove the first two. |
||||
# |
||||
# Provisionally removed obsolete search_attributes and search_dn, 04May06. |
||||
# |
||||
def parse_search_return sequence |
||||
sequence.length >= 2 or raise LdapPduError |
||||
@search_entry = LDAP::Entry.new( sequence[0] ) |
||||
#@search_dn = sequence[0] |
||||
#@search_attributes = {} |
||||
sequence[1].each {|seq| |
||||
@search_entry[seq[0]] = seq[1] |
||||
#@search_attributes[seq[0].downcase.intern] = seq[1] |
||||
} |
||||
end |
||||
|
||||
# |
||||
# A search referral is a sequence of one or more LDAP URIs. |
||||
# Any number of search-referral replies can be returned by the server, interspersed |
||||
# with normal replies in any order. |
||||
# Until I can think of a better way to do this, we'll return the referrals as an array. |
||||
# It'll be up to higher-level handlers to expose something reasonable to the client. |
||||
def parse_search_referral uris |
||||
@search_referrals = uris |
||||
end |
||||
|
||||
|
||||
# Per RFC 2251, an LDAP "control" is a sequence of tuples, each consisting |
||||
# of an OID, a boolean criticality flag defaulting FALSE, and an OPTIONAL |
||||
# Octet String. If only two fields are given, the second one may be |
||||
# either criticality or data, since criticality has a default value. |
||||
# Someday we may want to come back here and add support for some of |
||||
# more-widely used controls. RFC-2696 is a good example. |
||||
# |
||||
def parse_controls sequence |
||||
@ldap_controls = sequence.map do |control| |
||||
o = OpenStruct.new |
||||
o.oid,o.criticality,o.value = control[0],control[1],control[2] |
||||
if o.criticality and o.criticality.is_a?(String) |
||||
o.value = o.criticality |
||||
o.criticality = false |
||||
end |
||||
o |
||||
end |
||||
end |
||||
private :parse_controls |
||||
|
||||
|
||||
end |
||||
|
||||
|
||||
end # module Net |
||||
|
@ -0,0 +1,64 @@ |
||||
# $Id: psw.rb 73 2006-04-24 21:59:35Z blackhedd $ |
||||
# |
||||
# |
||||
#---------------------------------------------------------------------------- |
||||
# |
||||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. |
||||
# |
||||
# Gmail: garbagecat10 |
||||
# |
||||
# 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 2 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, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
# |
||||
#--------------------------------------------------------------------------- |
||||
# |
||||
# |
||||
|
||||
|
||||
module Net |
||||
class LDAP |
||||
|
||||
|
||||
class Password |
||||
class << self |
||||
|
||||
# Generate a password-hash suitable for inclusion in an LDAP attribute. |
||||
# Pass a hash type (currently supported: :md5 and :sha) and a plaintext |
||||
# password. This function will return a hashed representation. |
||||
# STUB: This is here to fulfill the requirements of an RFC, which one? |
||||
# TODO, gotta do salted-sha and (maybe) salted-md5. |
||||
# Should we provide sha1 as a synonym for sha1? I vote no because then |
||||
# should you also provide ssha1 for symmetry? |
||||
def generate( type, str ) |
||||
case type |
||||
when :md5 |
||||
require 'md5' |
||||
"{MD5}#{ [MD5.new( str.to_s ).digest].pack("m").chomp }" |
||||
when :sha |
||||
require 'sha1' |
||||
"{SHA}#{ [SHA1.new( str.to_s ).digest].pack("m").chomp }" |
||||
# when ssha |
||||
else |
||||
raise Net::LDAP::LdapError.new( "unsupported password-hash type (#{type})" ) |
||||
end |
||||
end |
||||
|
||||
end |
||||
end |
||||
|
||||
|
||||
end # class LDAP |
||||
end # module Net |
||||
|
||||
|
@ -0,0 +1,39 @@ |
||||
# $Id: ldif.rb 78 2006-04-26 02:57:34Z blackhedd $ |
||||
# |
||||
# Net::LDIF for Ruby |
||||
# |
||||
# |
||||
# |
||||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. |
||||
# |
||||
# Gmail: garbagecat10 |
||||
# |
||||
# 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 2 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, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
# |
||||
# |
||||
|
||||
# THIS FILE IS A STUB. |
||||
|
||||
module Net |
||||
|
||||
class LDIF |
||||
|
||||
|
||||
end # class LDIF |
||||
|
||||
|
||||
end # module Net |
||||
|
||||
|
@ -0,0 +1,42 @@ |
||||
# $Id: testber.rb 57 2006-04-18 00:18:48Z blackhedd $ |
||||
# |
||||
# |
||||
|
||||
|
||||
$:.unshift "lib" |
||||
|
||||
require 'net/ldap' |
||||
require 'stringio' |
||||
|
||||
|
||||
class TestBer < Test::Unit::TestCase |
||||
|
||||
def setup |
||||
end |
||||
|
||||
# TODO: Add some much bigger numbers |
||||
# 5000000000 is a Bignum, which hits different code. |
||||
def test_ber_integers |
||||
assert_equal( "\002\001\005", 5.to_ber ) |
||||
assert_equal( "\002\002\203t", 500.to_ber ) |
||||
assert_equal( "\002\003\203\206P", 50000.to_ber ) |
||||
assert_equal( "\002\005\222\320\227\344\000", 5000000000.to_ber ) |
||||
end |
||||
|
||||
def test_ber_parsing |
||||
assert_equal( 6, "\002\001\006".read_ber( Net::LDAP::AsnSyntax )) |
||||
assert_equal( "testing", "\004\007testing".read_ber( Net::LDAP::AsnSyntax )) |
||||
end |
||||
|
||||
|
||||
def test_ber_parser_on_ldap_bind_request |
||||
s = StringIO.new "0$\002\001\001`\037\002\001\003\004\rAdministrator\200\vad_is_bogus" |
||||
assert_equal( [1, [3, "Administrator", "ad_is_bogus"]], s.read_ber( Net::LDAP::AsnSyntax )) |
||||
end |
||||
|
||||
|
||||
|
||||
|
||||
end |
||||
|
||||
|
@ -0,0 +1,101 @@ |
||||
# $Id: testdata.ldif 50 2006-04-17 17:57:33Z blackhedd $ |
||||
# |
||||
# This is test-data for an LDAP server in LDIF format. |
||||
# |
||||
dn: dc=bayshorenetworks,dc=com |
||||
objectClass: dcObject |
||||
objectClass: organization |
||||
o: Bayshore Networks LLC |
||||
dc: bayshorenetworks |
||||
|
||||
dn: cn=Manager,dc=bayshorenetworks,dc=com |
||||
objectClass: organizationalrole |
||||
cn: Manager |
||||
|
||||
dn: ou=people,dc=bayshorenetworks,dc=com |
||||
objectClass: organizationalunit |
||||
ou: people |
||||
|
||||
dn: ou=privileges,dc=bayshorenetworks,dc=com |
||||
objectClass: organizationalunit |
||||
ou: privileges |
||||
|
||||
dn: ou=roles,dc=bayshorenetworks,dc=com |
||||
objectClass: organizationalunit |
||||
ou: roles |
||||
|
||||
dn: ou=office,dc=bayshorenetworks,dc=com |
||||
objectClass: organizationalunit |
||||
ou: office |
||||
|
||||
dn: mail=nogoodnik@steamheat.net,ou=people,dc=bayshorenetworks,dc=com |
||||
cn: Bob Fosse |
||||
mail: nogoodnik@steamheat.net |
||||
sn: Fosse |
||||
ou: people |
||||
objectClass: top |
||||
objectClass: inetorgperson |
||||
objectClass: authorizedperson |
||||
hasAccessRole: uniqueIdentifier=engineer,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ldapadmin,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ldapsuperadmin,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ogilvy_elephant_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ogilvy_eagle_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=greenplug_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=brandplace_logging_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=brandplace_report_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=workorder_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=bayshore_eagle_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=bayshore_eagle_superuser,ou=roles |
||||
hasAccessRole: uniqueIdentifier=kledaras_user,ou=roles |
||||
|
||||
dn: mail=elephant@steamheat.net,ou=people,dc=bayshorenetworks,dc=com |
||||
cn: Gwen Verdon |
||||
mail: elephant@steamheat.net |
||||
sn: Verdon |
||||
ou: people |
||||
objectClass: top |
||||
objectClass: inetorgperson |
||||
objectClass: authorizedperson |
||||
hasAccessRole: uniqueIdentifier=brandplace_report_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=engineer,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ogilvy_elephant_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ldapsuperadmin,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ldapadmin,ou=roles |
||||
|
||||
dn: uniqueIdentifier=engineering,ou=privileges,dc=bayshorenetworks,dc=com |
||||
uniqueIdentifier: engineering |
||||
ou: privileges |
||||
objectClass: accessPrivilege |
||||
|
||||
dn: uniqueIdentifier=engineer,ou=roles,dc=bayshorenetworks,dc=com |
||||
uniqueIdentifier: engineer |
||||
ou: roles |
||||
objectClass: accessRole |
||||
hasAccessPrivilege: uniqueIdentifier=engineering,ou=privileges |
||||
|
||||
dn: uniqueIdentifier=ldapadmin,ou=roles,dc=bayshorenetworks,dc=com |
||||
uniqueIdentifier: ldapadmin |
||||
ou: roles |
||||
objectClass: accessRole |
||||
|
||||
dn: uniqueIdentifier=ldapsuperadmin,ou=roles,dc=bayshorenetworks,dc=com |
||||
uniqueIdentifier: ldapsuperadmin |
||||
ou: roles |
||||
objectClass: accessRole |
||||
|
||||
dn: mail=catperson@steamheat.net,ou=people,dc=bayshorenetworks,dc=com |
||||
cn: Sid Sorokin |
||||
mail: catperson@steamheat.net |
||||
sn: Sorokin |
||||
ou: people |
||||
objectClass: top |
||||
objectClass: inetorgperson |
||||
objectClass: authorizedperson |
||||
hasAccessRole: uniqueIdentifier=engineer,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ogilvy_elephant_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ldapsuperadmin,ou=roles |
||||
hasAccessRole: uniqueIdentifier=ogilvy_eagle_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=greenplug_user,ou=roles |
||||
hasAccessRole: uniqueIdentifier=workorder_user,ou=roles |
||||
|
@ -0,0 +1,12 @@ |
||||
# $Id: testem.rb 121 2006-05-15 18:36:24Z blackhedd $ |
||||
# |
||||
# |
||||
|
||||
require 'test/unit' |
||||
require 'tests/testber' |
||||
require 'tests/testldif' |
||||
require 'tests/testldap' |
||||
require 'tests/testpsw' |
||||
require 'tests/testfilter' |
||||
|
||||
|
@ -0,0 +1,37 @@ |
||||
# $Id: testfilter.rb 122 2006-05-15 20:03:56Z blackhedd $ |
||||
# |
||||
# |
||||
|
||||
require 'test/unit' |
||||
|
||||
$:.unshift "lib" |
||||
|
||||
require 'net/ldap' |
||||
|
||||
|
||||
class TestFilter < Test::Unit::TestCase |
||||
|
||||
def setup |
||||
end |
||||
|
||||
|
||||
def teardown |
||||
end |
||||
|
||||
def test_rfc_2254 |
||||
p Net::LDAP::Filter.from_rfc2254( " ( uid=george* ) " ) |
||||
p Net::LDAP::Filter.from_rfc2254( "uid!=george*" ) |
||||
p Net::LDAP::Filter.from_rfc2254( "uid<george*" ) |
||||
p Net::LDAP::Filter.from_rfc2254( "uid <= george*" ) |
||||
p Net::LDAP::Filter.from_rfc2254( "uid>george*" ) |
||||
p Net::LDAP::Filter.from_rfc2254( "uid>=george*" ) |
||||
p Net::LDAP::Filter.from_rfc2254( "uid!=george*" ) |
||||
|
||||
p Net::LDAP::Filter.from_rfc2254( "(& (uid!=george* ) (mail=*))" ) |
||||
p Net::LDAP::Filter.from_rfc2254( "(| (uid!=george* ) (mail=*))" ) |
||||
p Net::LDAP::Filter.from_rfc2254( "(! (mail=*))" ) |
||||
end |
||||
|
||||
|
||||
end |
||||
|
@ -0,0 +1,190 @@ |
||||
# $Id: testldap.rb 65 2006-04-23 01:17:49Z blackhedd $ |
||||
# |
||||
# |
||||
|
||||
|
||||
$:.unshift "lib" |
||||
|
||||
require 'test/unit' |
||||
|
||||
require 'net/ldap' |
||||
require 'stringio' |
||||
|
||||
|
||||
class TestLdapClient < Test::Unit::TestCase |
||||
|
||||
# TODO: these tests crash and burn if the associated |
||||
# LDAP testserver isn't up and running. |
||||
# We rely on being able to read a file with test data |
||||
# in LDIF format. |
||||
# TODO, WARNING: for the moment, this data is in a file |
||||
# whose name and location are HARDCODED into the |
||||
# instance method load_test_data. |
||||
|
||||
def setup |
||||
@host = "127.0.0.1" |
||||
@port = 3890 |
||||
@auth = { |
||||
:method => :simple, |
||||
:username => "cn=bigshot,dc=bayshorenetworks,dc=com", |
||||
:password => "opensesame" |
||||
} |
||||
|
||||
@ldif = load_test_data |
||||
end |
||||
|
||||
|
||||
|
||||
# Get some test data which will be used to validate |
||||
# the responses from the test LDAP server we will |
||||
# connect to. |
||||
# TODO, Bogus: we are HARDCODING the location of the file for now. |
||||
# |
||||
def load_test_data |
||||
ary = File.readlines( "tests/testdata.ldif" ) |
||||
hash = {} |
||||
while line = ary.shift and line.chomp! |
||||
if line =~ /^dn:[\s]*/i |
||||
dn = $' |
||||
hash[dn] = {} |
||||
while attr = ary.shift and attr.chomp! and attr =~ /^([\w]+)[\s]*:[\s]*/ |
||||
hash[dn][$1.downcase.intern] ||= [] |
||||
hash[dn][$1.downcase.intern] << $' |
||||
end |
||||
end |
||||
end |
||||
hash |
||||
end |
||||
|
||||
|
||||
|
||||
# Binding tests. |
||||
# Need tests for all kinds of network failures and incorrect auth. |
||||
# TODO: Implement a class-level timeout for operations like bind. |
||||
# Search has a timeout defined at the protocol level, other ops do not. |
||||
# TODO, use constants for the LDAP result codes, rather than hardcoding them. |
||||
def test_bind |
||||
ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth |
||||
assert_equal( true, ldap.bind ) |
||||
assert_equal( 0, ldap.get_operation_result.code ) |
||||
assert_equal( "Success", ldap.get_operation_result.message ) |
||||
|
||||
bad_username = @auth.merge( {:username => "cn=badguy,dc=imposters,dc=com"} ) |
||||
ldap = Net::LDAP.new :host => @host, :port => @port, :auth => bad_username |
||||
assert_equal( false, ldap.bind ) |
||||
assert_equal( 48, ldap.get_operation_result.code ) |
||||
assert_equal( "Inappropriate Authentication", ldap.get_operation_result.message ) |
||||
|
||||
bad_password = @auth.merge( {:password => "cornhusk"} ) |
||||
ldap = Net::LDAP.new :host => @host, :port => @port, :auth => bad_password |
||||
assert_equal( false, ldap.bind ) |
||||
assert_equal( 49, ldap.get_operation_result.code ) |
||||
assert_equal( "Invalid Credentials", ldap.get_operation_result.message ) |
||||
end |
||||
|
||||
|
||||
|
||||
def test_search |
||||
ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth |
||||
|
||||
search = {:base => "dc=smalldomain,dc=com"} |
||||
assert_equal( false, ldap.search( search )) |
||||
assert_equal( 32, ldap.get_operation_result.code ) |
||||
|
||||
search = {:base => "dc=bayshorenetworks,dc=com"} |
||||
assert_equal( true, ldap.search( search )) |
||||
assert_equal( 0, ldap.get_operation_result.code ) |
||||
|
||||
ldap.search( search ) {|res| |
||||
assert_equal( res, @ldif ) |
||||
} |
||||
end |
||||
|
||||
|
||||
|
||||
|
||||
# This is a helper routine for test_search_attributes. |
||||
def internal_test_search_attributes attrs_to_search |
||||
ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth |
||||
assert( ldap.bind ) |
||||
|
||||
search = { |
||||
:base => "dc=bayshorenetworks,dc=com", |
||||
:attributes => attrs_to_search |
||||
} |
||||
|
||||
ldif = @ldif |
||||
ldif.each {|dn,entry| |
||||
entry.delete_if {|attr,value| |
||||
! attrs_to_search.include?(attr) |
||||
} |
||||
} |
||||
|
||||
assert_equal( true, ldap.search( search )) |
||||
ldap.search( search ) {|res| |
||||
res_keys = res.keys.sort |
||||
ldif_keys = ldif.keys.sort |
||||
assert( res_keys, ldif_keys ) |
||||
res.keys.each {|rk| |
||||
assert( res[rk], ldif[rk] ) |
||||
} |
||||
} |
||||
end |
||||
|
||||
|
||||
def test_search_attributes |
||||
internal_test_search_attributes [:mail] |
||||
internal_test_search_attributes [:cn] |
||||
internal_test_search_attributes [:ou] |
||||
internal_test_search_attributes [:hasaccessprivilege] |
||||
internal_test_search_attributes ["mail"] |
||||
internal_test_search_attributes ["cn"] |
||||
internal_test_search_attributes ["ou"] |
||||
internal_test_search_attributes ["hasaccessrole"] |
||||
|
||||
internal_test_search_attributes [:mail, :cn, :ou, :hasaccessrole] |
||||
internal_test_search_attributes [:mail, "cn", :ou, "hasaccessrole"] |
||||
end |
||||
|
||||
|
||||
def test_search_filters |
||||
ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth |
||||
search = { |
||||
:base => "dc=bayshorenetworks,dc=com", |
||||
:filter => Net::LDAP::Filter.eq( "sn", "Fosse" ) |
||||
} |
||||
|
||||
ldap.search( search ) {|res| |
||||
p res |
||||
} |
||||
end |
||||
|
||||
|
||||
|
||||
def test_open |
||||
ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth |
||||
ldap.open {|ldap| |
||||
10.times { |
||||
rc = ldap.search( :base => "dc=bayshorenetworks,dc=com" ) |
||||
assert_equal( true, rc ) |
||||
} |
||||
} |
||||
end |
||||
|
||||
|
||||
def test_ldap_open |
||||
Net::LDAP.open( :host => @host, :port => @port, :auth => @auth ) {|ldap| |
||||
10.times { |
||||
rc = ldap.search( :base => "dc=bayshorenetworks,dc=com" ) |
||||
assert_equal( true, rc ) |
||||
} |
||||
} |
||||
end |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end |
||||
|
||||
|
@ -0,0 +1,69 @@ |
||||
# $Id: testldif.rb 61 2006-04-18 20:55:55Z blackhedd $ |
||||
# |
||||
# |
||||
|
||||
|
||||
$:.unshift "lib" |
||||
|
||||
require 'test/unit' |
||||
|
||||
require 'net/ldap' |
||||
require 'net/ldif' |
||||
|
||||
require 'sha1' |
||||
require 'base64' |
||||
|
||||
class TestLdif < Test::Unit::TestCase |
||||
|
||||
TestLdifFilename = "tests/testdata.ldif" |
||||
|
||||
def test_empty_ldif |
||||
ds = Net::LDAP::Dataset::read_ldif( StringIO.new ) |
||||
assert_equal( true, ds.empty? ) |
||||
end |
||||
|
||||
def test_ldif_with_comments |
||||
str = ["# Hello from LDIF-land", "# This is an unterminated comment"] |
||||
io = StringIO.new( str[0] + "\r\n" + str[1] ) |
||||
ds = Net::LDAP::Dataset::read_ldif( io ) |
||||
assert_equal( str, ds.comments ) |
||||
end |
||||
|
||||
def test_ldif_with_password |
||||
psw = "goldbricks" |
||||
hashed_psw = "{SHA}" + Base64::encode64( SHA1.new(psw).digest ).chomp |
||||
|
||||
ldif_encoded = Base64::encode64( hashed_psw ).chomp |
||||
ds = Net::LDAP::Dataset::read_ldif( StringIO.new( "dn: Goldbrick\r\nuserPassword:: #{ldif_encoded}\r\n\r\n" )) |
||||
recovered_psw = ds["Goldbrick"][:userpassword].shift |
||||
assert_equal( hashed_psw, recovered_psw ) |
||||
end |
||||
|
||||
def test_ldif_with_continuation_lines |
||||
ds = Net::LDAP::Dataset::read_ldif( StringIO.new( "dn: abcdefg\r\n hijklmn\r\n\r\n" )) |
||||
assert_equal( true, ds.has_key?( "abcdefg hijklmn" )) |
||||
end |
||||
|
||||
# TODO, INADEQUATE. We need some more tests |
||||
# to verify the content. |
||||
def test_ldif |
||||
File.open( TestLdifFilename, "r" ) {|f| |
||||
ds = Net::LDAP::Dataset::read_ldif( f ) |
||||
assert_equal( 13, ds.length ) |
||||
} |
||||
end |
||||
|
||||
# TODO, need some tests. |
||||
# Must test folded lines and base64-encoded lines as well as normal ones. |
||||
def test_to_ldif |
||||
File.open( TestLdifFilename, "r" ) {|f| |
||||
ds = Net::LDAP::Dataset::read_ldif( f ) |
||||
ds.to_ldif |
||||
assert_equal( true, false ) # REMOVE WHEN WE HAVE SOME TESTS HERE. |
||||
} |
||||
end |
||||
|
||||
|
||||
end |
||||
|
||||
|
@ -0,0 +1,28 @@ |
||||
# $Id: testpsw.rb 72 2006-04-24 21:58:14Z blackhedd $ |
||||
# |
||||
# |
||||
|
||||
|
||||
$:.unshift "lib" |
||||
|
||||
require 'net/ldap' |
||||
require 'stringio' |
||||
|
||||
|
||||
class TestPassword < Test::Unit::TestCase |
||||
|
||||
def setup |
||||
end |
||||
|
||||
|
||||
def test_psw |
||||
assert_equal( "{MD5}xq8jwrcfibi0sZdZYNkSng==", Net::LDAP::Password.generate( :md5, "cashflow" )) |
||||
assert_equal( "{SHA}YE4eGkN4BvwNN1f5R7CZz0kFn14=", Net::LDAP::Password.generate( :sha, "cashflow" )) |
||||
end |
||||
|
||||
|
||||
|
||||
|
||||
end |
||||
|
||||
|
Loading…
Reference in new issue