Commit 7c467062 authored by Nicolas Delaby's avatar Nicolas Delaby

Initial import of ZLDAPConnection Product

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@17221 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 7e73db33
ZLDAPConnection CHANGES.txt
1.1.0
Features Added
o A non beta release! Although, this may still be a bit shaky.
o The LDAP Connection object has the ability to be
*non-transactional*, which is currently the preferred way of
using the LDAP Connection object. There is still an outstanding
bug with the way the transactional behavior works when updating
more than one Entry object at a time.
o Entry API is vastly improved, and is not backwards compatible
with ZopeLDAP 1.0. The primary advantage is that now that Python
Scripts are in the core, Entry objects are easier to program
without having to use the 'manage_' methods (although those will
continue to work, and their API has not changed).
o To go along with the Entry API improvement, the Permissions of
Entry objects have been improved as well.
o The LDAP Connection has an Entry Factory which decides whether to
use a Transactional or Non-Transactional Entry object. The usage
to the end user is indistinguishable, except that the
nontransactional entry objects update to the LDAP server
*immediately*.
Bugs Fixed
o The bug in the transaction management behavior of the Connection
object has not been fixed, but the new Non-Transactional ability
should make up for this bug in most situations.
1.0b5
Bugs Fixed
o Entry objects would raise a KeyError on a failed attribute
access, which caused a failure in the Security Machinery
(non-critical - security was not affected, only attribute
access). Now AttributeError is properly raised.
1.0b4
Bugs Fixed
o Entry.manage_newEntry and Entry.manage_newEntryWithAttributes
now return the newly added Entry object.
o Should work properly with Zope 2.2.x, and still work with Zope
2.1.6.
1.0b3
Bugs Fixed
o Fixes an issue with getRawEntry() raising an IndexError
exception in some cases.
o LDAPConnection doesn't keep setting self.openc every time _open()
is called, thus avoiding constant writes to the ZODB.
o Fixed ZLDAPConnection.__init__.py to use the proper product
initialization code (prior versions were using an extremely
outdated mechanism). *This also means registering permissions
which affect Entry objects so that on Folders, permissions to
manage entry objects are settable*.
Features Added
o New module 'LDCAccessors.py' implements getter/setter methods for
all ZLDAPConnection properties. It is mixed into ZLDAPConnection.
1.0b2
o Updated for Zope 2.1.5/2.1.6 new security measures on method-ish
objects.
o Has a settable "Browsable" property on the Connection object.
1.0b1
o This is a pretty major overhaul of the original alpha code,
primarily to include some sort of pseudo-transactional safety (all
done in Zope since LDAP has no concept of transactions).
o Seperated ZLDAPConnection and Entry objects. ZLDAPConnection (the
class) no longer subclasses from an Entry object. (In old code,
it was the Entry object at the root of the connection. In this
version, the root is gotten to by calling the method 'getRoot()'
on the connection).
o Seperated the Entry class into two classes: GenericEntry and
Entry, found in Entry.py. GenericEntry holds all of the Entry
related methods and data for communicating with its Connection
object; Entry has the Zope interface and implements the tree
protocol (tpValues, tpId, tpURL) and the objectXXX protocol
(objectValues, objectItems, objectIds). These calls access the
Entry's sub-entry objects.
o Try to ensure some integrity with Zope transactions. Since LDAP
has no concept of transactions, this is not ideal, but it's a step
up from having no transaction support at all.
This diff is collapsed.
__version__="$Revision: 1.3 $"[11:-2]
class LDAPConnectionAccessors:
""" getters / setters for LDAP Properties """
__ac_permissions__ = (
('Access contents information',
('getId','getTitle','getHost','getPort','getBindAs','getBoundAs',
'getPW','getDN','getOpenConnection','getBrowsable',
'shouldBeOpen','getTransactional',),),
('Manage properties',
('setID','setTitle','setHost','setPort', 'setBindAs','setPW',
'setDN','setOpenConnection','setBrowsable','setBoundAs',
'setTransactional',),),
)
def getId(self):
return self.id
def setId(self, id):
self.id = id
def getTitle(self):
return self.title
def setTitle(self, title):
self.title = title
def getHost(self):
""" returns the host that this connection is connected to """
return self.host
def setHost(self, host):
self.host = host
def getPort(self):
""" returns the port on the host that this connection connects to """
return self.port
def setPort(self, port):
self.port = port
def getBindAs(self):
""" return the DN that this connection is bound as """
return self.bind_as
getBoundAs = getBindAs
def setBindAs(self, bindAs):
self.bind_as = bindAs
setBoundAs = setBindAs
def getPW(self):
""" return the password that this connection is connected with """
return self.pw
def setPW(self, pw):
self.pw = pw
def getDN(self):
return self.dn
def setDN(self, dn):
self.dn = dn
def getOpenConnection(self):
""" self.openc means that the connection is open to Zope. However,
the connection to the LDAP server may or may not be opened. If
this returns false, we shouldn't even try connecting."""
return self.openc
def setOpenConnection(self, openc):
self._v_openc = openc
shouldBeOpen = getOpenConnection
def getBrowsable(self):
""" if true, connection object is set to be browsable through the
management interface """
return getattr(self, '_canBrowse', 0)
def setBrowsable(self, browsable):
self._canBrowse = browsable
def getTransactional(self):
""" If transactional returns TRUE, the TransactionManager stuff
is used. If FALSE, changes are sent to LDAP immediately. """
# Default to '1', to emulate the original behavior
return getattr(self, 'isTransactional', 1)
def setTransactional(self, transactional=1):
self.isTransactional = transactional
self._refreshEntryClass()
# We have a fair amount of transaction-sensitive methods that
# only want to run during a commit, and these are the ones that
# actually send the data to the LDAP server. When in non-transactional
# mode, we want these things to run at any time. In a sense, we're
# always committing.
if not transactional:
self._isCommitting = 1
import Globals
Globals.default__class_init__(LDAPConnectionAccessors)
Programming ZopeLDAP Entry Objects
Author -- "Jeffrey P Shell", mailto:jeffrey@digicool.com
Date -- Dec 18, 2000
Revision -- For ZopeLDAP 1.1.0
1. Getting an Entry Object and its attributes
Using an LDAP Filter object is the best way to get an Entry object.
LDAP Filter objects act like methods\functions and return a sequence
of entry objects (so they can be used with any sort of looping
structure). For example, if you had an LDAP Filter titled
'lookupByEmail' with the parameter 'email' with the content::
mail=<dtml-var name="mail">*
Can be used in DTML like this::
<dtml-in expr="lookupByEmail(email='jef')">
Surname: <dtml-var name="sn"><br />
Common name: <dtml-var name="cn"><br /><br />
</dtml-in>
Or in a Python Script like this::
entries = container.lookupByEmail(email='jef')
for entry in entries:
# do something here...
1.1. Notes about Attributes and Entry Objects
By default, LDAP always returns its attributes as sequences (Python
lists), even if there is only one value. ZopeLDAP Entry objects
use a special class, *AttrWrap*, when returning attributes accessed
through normal __getattr__ (the a.b syntax). AttrWrap behaves and
acts like a normal Python list with the exception that when printed
as a string (ie, with 'dtml-var' or Python 'str()' or '"%s"'), it
printes the results as a comma seperated list. This makes DTML
representations of Entry object significantly easier. When using
the Entry method 'get()', the attribute is returned as a Python
list as returned by PythonLDAP. But if you're wanting to do tests
based on attributes, you have to *remember to qualify the
attribute*, ie::
if entry.sn[0] == 'Shell': # Works
if entry.sn == 'Shell': # Won't work
And also remember that 'getattr' based access returns *AttrWrap*
instances, which means the following::
if entry.get('sn') == ['Shell']: # Works
if entry.sn == ['Shell']: # Won't work
2. Changing attribute values
Changing attributes on Entry objects is protected by the permission
**Manage Entry Information**. This permission can be set anywhere
in Zope, and will work best when set in the folder containing the
LDAP Filter used to access the Entry object. The methods exposed
under this permission are:
**set(key, value)** -- example: 'entry.set("sn", "Shell")',
'entry.set("mail", ["foo@bar.com", "foo@baz.net"])'
**setattrs([kwdict, kw])** -- Takes either a mapping argument or
keyword arguments. Or both. Example:
'entry.setattrs({"sn": "Bazzo"}, mail=["foo@bar.com,
"foo@baz.net"])'
**setAll([kwdict, kw])** -- Same as *setattrs*, except that the
existing data is *replaced* by what's passed in here.
**remove(attr)** -- Deletes the attribute, example:
'entry.remove("comments")'
3. Accessing subentries
Attributes on Entry objects are available through the Python
'getattr' protocol, and subentries are available through the
'getitem' protocol via their Relative Distinguished Name (RDN).
Meaning if you had an Organizational Unit entry for 'Housewares'
and wanted to get the subentry '"Betty Ford"', it would appear like
this (considering 'housewares' is the Entry object)::
betty = housewares["cn=Betty Ford"]
3.1. Adding subentries
Adding subentries to an Entry object is done through the
'addSubentry' method. Adding subentries is protected by the
permission **Create New Entry Objects**.
**addSubentry(rdn, [attrs,kw])** -- Add a new subentry identified by
the rdn. The rdn **MUST** be a string in the form 'attr=value',
such as 'ou=Housewares' or 'cn=Davy Jones'. The rest of the
signature can be a combination of a dictionary of attributes
passed in to 'attrs' or keyword arguments. If no 'objectClass'
attribute is passed in, the default objectClass is 'top'. The
newly created Entry object is returned, wrapped in the acquisition
context of its parent. Some example uses are::
betty = housewares.addSubentry("cn=Betty Ford", {
"objectClass": ["top", "person"],
"sn": "Ford",
})
clinic = betty.addSubentry("sn=Clinic",
objectClass=["top","place"],
description="A good place to go..."
)
3.2. Deleting subentries
Deleting subentries from an Entry object is done through the
'deleteSubentry' method. Deleting subentries is protected by the
permission **Delete Entry Objects**.
**deleteSubentry(entry)** -- You can either delete a subentry by
its 'rdn', or by passing in the subentry object itself. Deletion
is recursive and will delete everything below the specified entry
from the LDAP server as well as the Entry object itself. Some
examples uses are::
betty.deleteSubentry("sn=Clinic") # Delete by rdn (local id)
housewares.deleteSubentry(betty) # Delete by entry itself
4. Other Zope Interfaces supported
Entry objects are a combination of classes: The basic Entry class
(either GenericEntry or TransactionalEntry at present), and one
called Entry, which implements some Zope level Interfaces (of the
programming kind). These include::
- '__bobo_traverse__' -- To traverse to subentries along the URL.
- The Tree Protocol -- Allows Entry objects to be used
automatically with the 'dtml-tree' tag.
- 'objectValues()' -- Returns all of the subentries in a list.
- 'objectIds()' -- returns all of the RDN's of the subentries.
- 'objectItems()' -- returns a list of tuples in the form of
('rdn', 'entry object').
\ No newline at end of file
ZopeLDAP README
ZopeLDAP is based off of work done by Anthony Baxter and also
Maurice Davice and Scott Robertson at CodeIt. It is an attempt to
make LDAP behave more like Zope objects.
It needs David Leonard's ldapmodule, from http://python-ldap.sourceforge.net/
and the compiled module needs to be (naturally) in your PYTHONPATH
(or in ZLDAPConnection/).
It's been tested against the OpenLDAP stable server release, as at
March 14, 1999 and Nov 2, 1999.
IMPORTANT
There is a known bug in the transactional behavior of the LDAP
Connection object, and as of 1.1.0 this feature can be turned off.
The bug could put your ZODB into a nasty state due to a failed
transaction (usually fixed by just restarting Zope), so it is
recommended you run with the Transactional ability turned off. *This
bug only occurs when updating more than one Entry object in a single
transaction space*.
Features
o Ability to browse an LDAP database like you would browse normal
folders.
o In 1.1.0, however, the Transactional behavior may be turned off.
This could speed things up for read-only situations, and is more
stable than the transactional one.
o Entry objects obey the rules of Acquisition.
o In the Zope management interface, LDAPConnections and their
Entries may be browsed.
o LDAP Filters provide another way of accessing Entry
objects. They behave in a similar fashion to ZSQL Methods, but
they are *read-only*. There is no current LDAP Spec for
update/insert type queries. *see Caveats below*
o Improved Entry object API that is Python Script friendly. For
updating\adding\deleting new Entry objects, LDAP Filters (to
retrieve entries) and Python Scripts (to update) go nicely together.
Caveats
o Lack of stunning documentation.
o The only way to strongly protect Entry objects from being written is
to use a connection name/password to the LDAP Server that does not
have any write permissions. Zope security permissions can also be
used.
o It currently only supports simple_bind for connecting to the
server.
o All Entry attributes come back in the form of a list of strings.
This is how the LDAP Module (and presumably LDAP in general) does
this. Attributes accessed through __getattr__ (like dtml-var
accesses) come back as an instance of AttrWrap which subclasses
UserList and whose str() return is a comma seperated list. (This
should prevent needing to do
'(dtml-in mail)(dtml-var sequence-item)(/dtml-in)' on every
attribute, especially where one value is expected.
Known Bugs
o Transactional Behavior breaks when updating more than one Entry
object per LDAP Connection in a single transaction. This behavior
can put the ZODB into a bad state since it fails during the
two-phase commit, however restarting Zope tends to return things to
normal.
Special Thanks
o Jens Vagelpohl (jens@digicool.com) for getting the pointy-hairs to
give me time to make 1.1.0 finally happen.
o Anthony Baxter (anthony@interlink.com.au) for most of the original work
o Scott Robertson (sropertson@codeit.com) and Maurice Davice
(mdavis@codeit.com) for theirs too.
o David Leonard for his LDAP Module and for keeping it pretty much
in alignment with the RFC (rfc1823).
Author:
Jeffrey P Shell (jeffrey@Digicool.com)
Original Authors:
Anthony Baxter (anthony@interlink.com.au)
Maurice Davice (mdavis@codeit.com)
Scott Robertson (srobertson@codeit.com)
This diff is collapsed.
"""LDAP Server Connection Package """
import ZLDAP, Entry
__version__ = ZLDAP.__version__
# use the propert product registration
def initialize(context):
context.registerClass(
ZLDAP.ZLDAPConnection,
constructors = (ZLDAP.manage_addZLDAPConnectionForm,
ZLDAP.manage_addZLDAPConnection),
icon = 'LDAP_conn_icon.gif',
permissions = ('Manage Entry information',
'Create New Entry Objects',
),
)
<html>
<head><title>Add LDAP connection</title></head>
<body bgcolor="#FFFFFF">
<h2>Add LDAP connection</h2>
<form action="manage_addZLDAPConnection" method="POST">
<table cellspacing="2">
<tr>
<th align="LEFT" valign="TOP">Id</th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="id" size="50">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>Title</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="title" size="50">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>LDAP Server (host[:port])</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="hostport" size="50">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>Base DN</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="basedn" size="50">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>Bind As</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="bind_as" size="50">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>Bind Password</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="pw" size="50">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>Open Connection?</em></th>
<td align="LEFT" valign="TOP">
<input type="CHECKBOX" name="openc" CHECKED>
</td>
</tr>
<tr>
<th align="left" valign="top"><em>Transactional?</em></th>
<td align="left" valign="top">
<input type="checkbox" name="transactional:int" value="1" checked>
<input type="hidden" name="transactional:default:int" value="0">
</td>
</tr>
<tr>
<td></td>
<td><br><input type="SUBMIT" value="Add"></td>
</tr>
</table>
</form>
</body>
</html>
<html>
<head>
<title>Attributes for &dtml-dn;</title>
</head>
<body bgcolor="#FFFFFF">
<dtml-var manage_tabs>
<h3>Attributes for <em>&dtml-id;</em></h3>
<table border="1" cellpadding="2" cellspacing="0" rules="rows" frame="void">
<dtml-in attributesMap>
<tr valign="top">
<th align="left">&dtml-sequence-key;</th>
<td><dtml-in sequence-item>&dtml-sequence-item;<br /></dtml-in></td>
</tr>
</dtml-in>
</table>
<hr />
<h3>Subentries</h3>
<dtml-if tpValues>
<dtml-tree>
<a href="&dtml-tree-item-url;/manage_attributes"
title="click to view this entry">&dtml-id;</a>
</dtml-tree>
<dtml-else>
<p><em>No subentries for &dtml-id;</em></p>
</dtml-if>
</body>
</html>
\ No newline at end of file
<html>
<head>
<title>Browse &dtml-title_and_id;</title>
</head>
<body bgcolor="#ffffff">
<dtml-var manage_tabs>
<dtml-if name="canBrowse">
<dtml-with name="getRoot">
<h3>Attributes for <em>&dtml-id;</em></h3>
<table border="1" cellpadding="2" cellspacing="0" rules="rows" frame="void">
<dtml-in name="attributesMap">
<tr valign="top">
<th align="left">&dtml-sequence-key;</th>
<td><dtml-in name="sequence-item">&dtml-sequence-item;<br /></dtml-in></td>
</tr>
</dtml-in>
</table>
</dtml-with>
<hr />
<h3>Subentries</h3>
<dtml-tree name="getRoot">
<a href="&dtml-tree-item-url;/manage_attributes"
title="click to view this entry">&dtml-id;</a>
</dtml-tree>
<dtml-else>
<p><em>Connection to <code>&dtml-host;:&dtml-port;</code> is
<dtml-if name="openc">not browsable<dtml-else>closed</dtml-if>.</em></p>
</dtml-if>
</body>
</html>
<html>
<head>
<title>Connection for &dtml-title_or_id;</title>
<style type="text/css"><!--
.open {color: blue}
.close {color: red}
--></style>
</head>
<body bgcolor="#FFFFFF">
<dtml-var manage_tabs>
<h2>Connection to <code>&dtml-host;:&dtml-port;</code> is
<dtml-if isOpen><span class="open"><em>open</em></span>
<dtml-else><span class="close"><em>closed</em></span>
</dtml-if>.</h2>
<dtml-if isOpen>
<form action="manage_close">
<input type="submit" value="Close Connection" class="close" />
</form>
<dtml-else>
<form action="manage_open">
<input type="submit" value="Open Connection" class="open" />
</form>
</dtml-if>
</body>
</html>
\ No newline at end of file
<HTML>
<HEAD>
<TITLE>Contents</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<!--#var manage_tabs-->
<P>
<FORM ACTION="." METHOD="POST">
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="2">
<!--#in "tpValues()" -->
<TR>
<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="16">
<INPUT TYPE="CHECKBOX" NAME="ids:list" VALUE="<!--#var dn-->">
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<A HREF="<!--#var id fmt=url-quote-->/manage_main">
<IMG SRC="<!--#var SCRIPT_NAME-->/<!--#var icon-->"
ALT="[Entry]" BORDER="0"></A>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<A HREF="<!--#var id fmt=url-quote-->/manage_main"><!--#var id--></A>
</TD>
</TR>
<!--#/in-->
</TABLE>
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING=2>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="16"></TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<!--#if "tpValues()"-->
<INPUT TYPE="SUBMIT" NAME="manage_deleteEntry:method" VALUE="Delete">
<!--#/if-->
</TD>
</TR>
</TABLE>
</FORM>
<a name="addentryform">
<form action="." method="POST">
<p>
To add a new entry, enter an RDN (Relative Distinguished Name) for the entry
to appear under the above DN (Distinguished Name) and click the &quot;Add New Entry&quot;
button. For example enter &quot;uid=spam&quot; for the RDN. An attribute of &quot;uid: spam&quot;
will be automatically added to the entry. Other attributes may be entered by using the attribute management screens.
</p>
<table>
<tr>
<th align="left" valign="top">RDN</th>
<td align="left" valign="top"><input type="text" name="rdn" size="20"></td>
<td align="right" valign="top">
<INPUT TYPE="SUBMIT" NAME="manage_newEntry:method" VALUE="Add New Entry">
</td>
</tr>
</table>
</form>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
</BODY>
</HTML>
<html>
<head><title>Edit LDAP connection</title></head>
<body bgcolor="#FFFFFF">
<dtml-var name="manage_tabs">
<h2>Edit LDAP connection <dtml-var name="title_and_id"></h2>
<form action="manage_edit" method="POST">
<table cellspacing="2">
<tr>
<th align="LEFT" valign="TOP">Id</th>
<td align="LEFT" valign="TOP">
<dtml-var name="getId">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>Title</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="title" size="50" value="&dtml-getTitle;">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>LDAP server (host[:port])</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="hostport" size="50" value="&dtml-getHost;:&dtml-getPort;">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>Base DN</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="basedn" size="50" value="&dtml-getDN;">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>Bind As</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="bind_as" size="50" value="&dtml-getBindAs;">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em>Bind Password</em></th>
<td align="LEFT" valign="TOP">
<input type="TEXT" name="pw" size="50" value="&dtml-getPW;">
</td>
</tr>
<tr>
<th align="LEFT" valign="TOP"><em><label for="cb-openc">Open Connection?</label></em></th>
<td align="LEFT" valign="TOP">
<input type="CHECKBOX" name="openc" <dtml-if name="shouldBeOpen">CHECKED</dtml-if> id="cb-openc" value="1">
</td>
</tr>
<tr>
<th align="left" valign="top"><em><label for="cb-canBrowse">Make connection object browsable?</label></em></th>
<td align="left" valign="top">
<input type="checkbox" name="canBrowse" value="1" <dtml-if name="getBrowsable">checked</dtml-if> id="cb-canBrowse">
</td>
</tr>
<tr>
<th align="left" valign="top"><em>
<label for="cb-transactional">Make connection and entries
transactional?</label></em></th>
<td align="left" valign="top">
<input type="checkbox" name="transactional:int" value="1"
<dtml-if name="getTransactional">checked</dtml-if>
id="cb-transactional">
<input type="hidden" name="transactional:default:int" value="0">
</td>
</tr>
<tr>
<td></td>
<td><br><input type="SUBMIT" value="Change"></td>
</tr>
</table>
</form>
</body>
</html>
<html>
<head><title>help for LDAP connections</title></head>
<body>
<h1>Help for LDAP connections</h1>
<b>Arguments are as follows:</b>
<dl>
<dt>LDAP server<dd>The hostname, and optionally the port, where the LDAP
server is running. The standard port for LDAP is 389 - this will be used
if no port is specified.
<dt>Bind As<dd>Who to bind to the LDAP server as. An example:
"cn=Anthony, o=ekorp.com, c=AU"
<dt>Password<dd>The password (if any) to be used to bind to the server.
</dl>
</body></html>
ZPL 2.1
Zope Public License (ZPL) Version 2.1
A copyright notice accompanies this license document that identifies the copyright holders.
This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF).
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders.
4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders.
5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
Disclaimer
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This diff is collapsed.
Quick README on ZLDAP Filter Methods
Current
ZLDAP Filter Methods are a way of executing LDAP Searches according
to RFC1558 'A String Representation of LDAP Search Filters'. They
can be used like ZSQL Methods and use DTML inside of them. For
example, one could do a Filter of 'uid=<dtml-var foo>'. ZLDAP Filter
Methods return Entry objects.
ZLDIF Filter Methods
ZLDIF Filter Methods are a way to generate ldif document which are parsed to modify LDAP database.
This is a sample of dtml code <dtml-ldifline attr="uidNumber" expr="'03ERRRNN981'" type="string">
for generating valid LDIF message.
"""LDAP Filter Methods Package """
import LM
def initialize(context):
context.registerClass(
LM.LDAPMethod,
constructors = (LM.manage_addZLDAPMethodForm,
LM.manage_addZLDAPMethod),
icon = "LDAP_Method_icon.gif",
legacy = (LM.LDAPConnectionIDs,), #special baby to add to ObjectManagers
)
context.registerClass(
LM.LDIFMethod,
constructors = (LM.manage_addZLDIFMethodForm,
LM.manage_addZLDIFMethod),
icon = "LDAP_Method_icon.gif",
legacy = (LM.LDAPConnectionIDs,), #special baby to add to ObjectManagers
)
\ No newline at end of file
<HTML><HEAD><TITLE>New LDAP Method</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<H2>New LDAP Method</H2>
<dtml-if LDAPConnectionIDs>
<form action="manage_addZLDAPMethod" method="post">
<table>
<tr> <th align='LEFT'>Id</th>
<td align='LEFT'><input name="id" size="40"></td></tr>
<tr> <th align='LEFT'><em>Title<em></th>
<td align='LEFT'><input name="title" size="40"></td></tr>
<tr> <th align='LEFT'>Connection id</th>
<td align='LEFT'><select name="connection_id">
<dtml-in LDAPConnectionIDs>
<option value="&dtml-sequence-item;"
><dtml-var sequence-key></option>
</dtml-in>
</select></td></tr>
<tr> <th align='LEFT'><em>Query Scope</em></th>
<td align='LEFT'><select name="scope">
<dtml-in expr="['SUBTREE', 'ONELEVEL', 'BASE']">
<option value="&dtml-sequence-item;"
><dtml-var sequence-item></option>
</dtml-in>
</select></td></tr>
<tr> <th align='LEFT' valign="top"><em>Base DN</em></th>
<td align='LEFT'><input name="basedn" size="40"><br />
<input type="checkbox" name="getfromconnection:int" value="1" id="gfc">
<em><label for="gfc">Append Connection's Base DN</label></em></td></tr>
<tr> <th align='LEFT'><em>Arguments<em></th>
<td align='LEFT'><input name="arguments" size="40"></td></tr>
<tr> <td colspan=2 align='LEFT'><strong>Query Filter</strong><br>
<textarea name="filters:text" rows=9 cols=50>objectclass=*
</textarea></td></tr>
<tr><td colspan=2>
<input type="hidden" name="key" value="">
<input type="SUBMIT" name="submit" value=" Add ">
<input type="SUBMIT" name="submit" value=" Add and Edit ">
<input type="SUBMIT" name="submit" value=" Add and Test ">
</td></tr>
</table>
</form>
<dtml-else>
<em><strong>Warning:</strong>
There are no LDAP connections. You need
to add a Zope LDAP connection
before you can use a Zope LDAP Method.
</em>
</dtml-if>
</body></html>
<HTML><HEAD><TITLE>New LDIF Method</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<H2>New LDIF Method</H2>
<dtml-if LDAPConnectionIDs>
<form action="manage_addZLDIFMethod" method="post">
<table>
<tr> <th align='LEFT'>Id</th>
<td align='LEFT'><input name="id" size="40"></td></tr>
<tr> <th align='LEFT'><em>Title<em></th>
<td align='LEFT'><input name="title" size="40"></td></tr>
<tr> <th align='LEFT'>Connection id</th>
<td align='LEFT'><select name="connection_id">
<dtml-in LDAPConnectionIDs>
<option value="&dtml-sequence-item;"><dtml-var sequence-key></option>
</dtml-in>
</select></td></tr>
<tr> <th align='LEFT' valign="top"><em>Base DN</em></th>
<td align='LEFT'><input name="basedn" size="40"><br />
<input type="checkbox" name="getfromconnection:int" value="1" id="gfc">
<em><label for="gfc">Append Connection's Base DN</label></em></td></tr>
<tr> <th align='LEFT'><em>Arguments<em></th>
<td align='LEFT'><textarea name="arguments:text" rows="4" cols="40"></textarea></td></tr>
<tr> <td colspan=2 align='LEFT'><strong>ldif</strong><br>
<textarea name="ldif:text" rows=9 cols=70></textarea></td></tr>
<tr><td colspan=2>
<input type="hidden" name="key" value="">
<input type="SUBMIT" name="submit" value=" Add ">
<input type="SUBMIT" name="submit" value=" Add and Edit ">
<input type="SUBMIT" name="submit" value=" Add and Test ">
</td></tr>
</table>
</form>
<dtml-else>
<em><strong>Warning:</strong>
There are no LDAP connections. You need
to add a Zope LDAP connection
before you can use a Zope LDAP Method.
</em>
</dtml-if>
</body></html>
<HTML><HEAD><TITLE>New LDAP Method</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<!--#var manage_tabs-->
<H2>Edit LDAP Method</H2>
<!--#if LDAPConnectionIDs-->
<form action="manage_edit" method="post">
<table>
<tr> <th align='LEFT'>Id</th>
<td align='LEFT'><!--#var id--></td></tr>
<tr> <th align='LEFT'><em>Title<em></th>
<td align='LEFT'><input name="title" size="40" value="<!--#var title-->"></td></tr>
<tr> <th align='LEFT'>Connection id</th>
<td align='LEFT'><select name="connection_id">
<!--#in LDAPConnectionIDs-->
<option value="<!--#var sequence-item-->"
<!--#if expr="connection_id==_vars['sequence-item']"-->
SELECTED<!--#/if-->>
<!--#var sequence-key--></option>
<!--#/in-->
</select></td></tr>
<tr> <th align='LEFT'><em>Query Scope</em></th>
<td align='LEFT'><select name="scope">
<!--#in "['SUBTREE', 'ONELEVEL', 'BASE']"-->
<option value="<!--#var sequence-item-->"
<!--#if expr="scope==_vars['sequence-item']"-->
SELECTED<!--#/if-->><!--#var sequence-item--></option>
<!--#/in-->
</select></td></tr>
<tr> <th align='LEFT'><em>Base DN</em></th>
<td align='LEFT'><input name="basedn" size="40" value="<!--#var basedn fmt=html-quote-->"></td></tr>
<tr> <th align='LEFT'><em>Arguments<em></th>
<td align='LEFT'><input name="arguments" size="40" value="<!--#var arguments-->"></td></tr>
<tr> <td colspan=2 align='LEFT'><strong>Query Filter</strong><br>
<textarea name="filters:text" rows=9 cols=50><!--#var filters--></textarea>
</td></tr>
<tr><td colspan=2>
<input type="SUBMIT" name="submit" value="Change">
</td></tr>
</table>
</form>
<!--#else-->
<em><strong>Warning:</strong>
There are no LDAP connections. You need
to add a Zope LDAP connection
before you can use a Zope LDAP Method.
</em>
<!--#/if-->
</body></html>
<HTML><HEAD><TITLE>Edit LDIF Method</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<!--#var manage_tabs-->
<H2>Edit LDIF Method</H2>
<!--#if LDAPConnectionIDs-->
<form action="manage_edit" method="post">
<table>
<tr> <th align='LEFT'>Id</th>
<td align='LEFT'><!--#var id--></td></tr>
<tr> <th align='LEFT'><em>Title<em></th>
<td align='LEFT'><input name="title" size="40" value="<!--#var title-->"></td></tr>
<tr> <th align='LEFT'>Connection id</th>
<td align='LEFT'><select name="connection_id">
<!--#in LDAPConnectionIDs-->
<option value="<!--#var sequence-item-->"
<!--#if expr="connection_id==_vars['sequence-item']"-->
SELECTED<!--#/if-->>
<!--#var sequence-key--></option>
<!--#/in-->
</select></td></tr>
<tr> <th align='LEFT'><em>Base DN</em></th>
<td align='LEFT'><input name="basedn" size="40" value="<!--#var basedn fmt=html-quote-->"></td></tr>
<tr> <th align='LEFT'><em>Arguments<em></th>
<td align='LEFT'><textarea name="arguments:text" rows="4" cols="50"><!--#var arguments--></textarea></td></tr>
<tr> <td colspan=2 align='LEFT'><strong>ldif</strong><br>
<textarea name="ldif:text" rows=20 cols=100><!--#var ldif--></textarea>
</td></tr>
<tr><td colspan=2>
<input type="SUBMIT" name="submit" value="Change">
</td></tr>
</table>
</form>
<!--#else-->
<em><strong>Warning:</strong>
There are no LDAP connections. You need
to add a Zope LDAP connection
before you can use a Zope LDAP Method.
</em>
<!--#/if-->
</body></html>
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
'''Inserting values with the 'ldifvar' tag
The 'ldifvar' tag is used to type-safely insert values into LDIF
text. The 'ldifvar' tag is similar to the 'var' tag, except that
it replaces text formatting parameters with LDIF type information.
The sqlvar tag has the following attributes:
attr -- The name of the attribute to insert. As with other
DTML tags.
type -- The data type of the value to be inserted. This
attribute is required and may be one of 'string',
'int', 'float', or 'nb'. The 'nb' data type indicates a
string that must have a length that is greater than 0.
optional -- A flag indicating that a value is optional. If a
value is optional and is not provided (or is blank
when a non-blank value is expected), then the string
'null' is inserted.
For example, given the tag::
<dtml-ldifvar x attr=objectClass type=nb optional>
if the value of 'x' is::
inetOrgPerson
then the text inserted is:
objectClass: inetOrgPerson
however, if x is ommitted or an empty string, then the value
inserted is ''.
'''
#__rcs_id__='$Id: sqlvar.py,v 1.14.10.2 2005/09/02 23:02:00 tseaver Exp $'
############################################################################
# Copyright
#
# Copyright 1996 Digital Creations, L.C., 910 Princess Anne
# Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All
# rights reserved.
#
############################################################################
#__version__='$Revision: 1.14.10.2 $'[11:-2]
from DocumentTemplate.DT_Util import ParseError, parse_params, name_param
from string import find, split, join, atoi, atof
import sha
StringType=type('')
str=__builtins__['str']
class LDIFVar:
name='ldifvar'
def __init__(self, args):
args = parse_params(args, name='', expr='', type=None, optional=1)
name,expr=name_param(args,'ldifvar',1)
if expr is None: expr=name
else: expr=expr.eval
self.__name__, self.expr = name, expr
self.args=args
if not args.has_key('type'):
raise ParseError, ('the type attribute is required', 'dtvar')
t=args['type']
if not valid_type(t):
raise ParseError, ('invalid type, %s' % t, 'dtvar')
def render(self, md):
name=self.__name__
args=self.args
t=args['type']
try:
expr=self.expr
if type(expr) is type(''): v=md[expr]
else: v=expr(md)
except:
if args.has_key('optional') and args['optional']:
return
if type(expr) is not type(''):
raise
raise ValueError, 'Missing input variable, <em>%s</em>' % name
if v is None:
return ''
if t=='int':
try:
if type(v) is StringType:
if v[-1:]=='L':
v=v[:-1]
atoi(v)
else: v=str(int(v))
except:
if not v and args.has_key('optional') and args['optional']:
return
raise ValueError, (
'Invalid integer value for <em>%s</em>' % name)
elif t=='float':
try:
if type(v) is StringType:
if v[-1:]=='L':
v=v[:-1]
atof(v)
else: v=str(float(v))
except:
if not v and args.has_key('optional') and args['optional']:
return
raise ValueError, (
'Invalid floating-point value for <em>%s</em>' % name)
else:
if not isinstance(v, (str, unicode)):
v=str(v)
if not v and t=='nb':
if args.has_key('optional') and args['optional']:
return
else:
raise ValueError, (
'Invalid empty string value for <em>%s</em>' % name)
return v
__call__=render
class LDIFLine:
name='ldifline'
def __init__(self, args):
args = parse_params(args, name='', expr='', attr='', type=None, optional=1)
name,expr=name_param(args,'ldifvar',1)
if expr is None: expr=name
else: expr=expr.eval
self.__name__, self.expr = name, expr
self.args=args
if not args.has_key('type'):
raise ParseError, ('the type attribute is required', 'ldifattr')
t=args['type']
if not valid_type(t):
raise ParseError, ('invalid type, %s' % t, 'dtvar')
if not args.has_key('attr'):
raise ParseError, ('the attr attribute is required', 'ldifattr')
a=args['attr']
def render(self, md):
name=self.__name__
args=self.args
t=args['type']
a=args['attr']
default = '%s:' % (a)
try:
expr=self.expr
if type(expr) is type(''): v=md[expr]
else: v=expr(md)
except:
if args.has_key('optional') and args['optional']:
return default
if type(expr) is not type(''):
raise
raise ValueError, 'Missing input variable, <em>%s</em>' % name
if v is None:
if args.has_key('optional') and args['optional']:
return default
else:
raise ValueError, 'Missing input variable, <em>%s</em>' % name
if a in ['',None]:
return default
if t=='int':
try:
if type(v) is StringType:
if v[-1:]=='L':
v=v[:-1]
atoi(v)
else: v=str(int(v))
except:
if not v and args.has_key('optional') and args['optional']:
return default
raise ValueError, (
'Invalid integer value for <em>%s</em>' % name)
elif t=='float':
try:
if type(v) is StringType:
if v[-1:]=='L':
v=v[:-1]
atof(v)
else: v=str(float(v))
except:
if not v and args.has_key('optional') and args['optional']:
return default
raise ValueError, (
'Invalid floating-point value for <em>%s</em>' % name)
else:
if not isinstance(v, (str, unicode)):
v=str(v)
if not v and t=='nb':
if args.has_key('optional') and args['optional']:
return default
else:
raise ValueError, (
'Invalid empty string value for <em>%s</em>' % name)
return '%s: %s' % (a, v)
__call__=render
valid_type={'int':1, 'float':1, 'string':1, 'nb': 1}.has_key
<HTML><HEAD><TITLE>New LDAP Method</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<!--#var manage_tabs-->
<H2>Test LDAP Method <!--#var title_or_id--></H2>
<form action="./manage_test">
<table>
<tr> <th align='LEFT'>Connection id</th>
<td align='LEFT'><!--#var connection_id--></td></tr>
<tr> <th align='LEFT'><em>Query Scope</em></th>
<td align='LEFT'><!--#var scope--></td></tr>
<tr> <th align='LEFT'><em>Base DN</em></th>
<td align='LEFT'><!--#var basedn fmt=html-quote-->
<tr> <th align='LEFT'><em>Arguments<em></th>
<td align='LEFT'><!--#var arguments-->
<tr><td colspan=2>
<input type="SUBMIT" name="submit" value="Test">
</td></tr>
</table>
</form>
</BODY>
</HTML>
<HTML><HEAD><TITLE>New LDAP Method</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<!--#var manage_tabs-->
<H2>Test LDAP Method <!--#var title_or_id--></H2>
<form action="./manage_test">
<table>
<tr> <th align='LEFT'>Connection id</th>
<td align='LEFT'><!--#var connection_id--></td></tr>
<tr> <th align='LEFT'><em>Query Scope</em></th>
<td align='LEFT'><!--#var scope--></td></tr>
<tr> <th align='LEFT'><em>Base DN</em></th>
<td align='LEFT'><!--#var basedn fmt=html-quote-->
<tr> <th align='LEFT'><em>Arguments<em></th>
<td align='LEFT'><!--#var arguments-->
<tr><td colspan=2>
<input type="SUBMIT" name="submit" value="Test">
</td></tr>
</table>
</form>
</BODY>
</HTML>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment