LDAP class: Difference between revisions

From m204wiki
Jump to navigation Jump to search
mNo edit summary
m (increase limit from 6144)
 
(19 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<!-- LDAP class -->
<!-- LDAP class -->
The <var>LDAP</var> class simplifies public searches of an organization's LDAP (Lightweight Directory Access Protocol) directory.
The <var>LDAP</var> class simplifies public searches of an organization's LDAP
(Lightweight Directory Access Protocol) directory.
The <var>LDAP</var> class is a high level, object oriented interface to
The <var>LDAP</var> class is a high level, object oriented interface to
client sockets that lets you write a <var class="product">User Language</var> LDAP
client sockets that lets you write a <var class="product">SOUL</var> LDAP
request without knowledge of socket level programming or the format of
request without knowledge of socket level programming or the format of LDAP requests and responses.
LDAP requests and responses.
 
The <var>LDAP</var> class methods allow a <var class="product">SOUL</var> program to act as an LDAP client
The <var>LDAP</var> class methods allow a <var class="product">User Language</var> program to act as an LDAP client
to access and retrieve directory information through an LDAP server.
to access and retrieve directory information through an LDAP server.
The LDAP server may be running on any platform to which
The LDAP server may be running on any platform to which
Line 16: Line 12:
You use <var>JANUS</var> commands (<var>DEFINE</var>, <var>START</var>, <var>NAMESERVER</var>)
You use <var>JANUS</var> commands (<var>DEFINE</var>, <var>START</var>, <var>NAMESERVER</var>)
to define and start a TCP/IP <var>CLSOCK</var> port for the LDAP client to use.
to define and start a TCP/IP <var>CLSOCK</var> port for the LDAP client to use.
<br>'''Note:'''
 
To use <var>LDAP</var> class objects,
<p class="note">'''Note:'''
you must have licensed <var class="product">[[Janus Sockets]]</var> '''and''' <var class="product">[[Janus SOAP]]</var>.
To use <var>LDAP</var> objects under versions of Model 204 earlier than 7.5, you must have licensed <var class="product">[[Janus TCP/IP Base]]</var>, <var class="product">[[Janus Sockets]]</var>, '''and''' <var class="product">[[Janus SOAP]]</var>. Under version 7.5 and later,
The Sirius object-oriented alternative to $functions is designed for
you do not require <var class="product">Janus SOAP</var>. </p>
<var class="product">Janus SOAP</var> applications only, and information about using Sirius objects is
 
provided in [[Janus SOAP User Language Interface|"Janus SOAP User Language Interface"]].
For information about using SOUL objects, see [[Object oriented programming in SOUL]].
For details about the object syntax in this chapter, see
[[Notation conventions for methods|"Notation conventions for methods"]].
   
   
==Feature summary==
==Feature summary==
The <var>LDAP</var> class provides the following capabilities:
The <var>LDAP</var> class provides the following capabilities:
<ul>
<ul>
<li>Read access to X.500 and LDAP v2 directory services.
<li>Read access to X.500 and LDAP v2 directory services. </li>
 
<li>One-step connection and login to an LDAP server
<li>One-step connection and login to an LDAP server
(with user ID and password passing as well as also anonymous logins).
(with user ID and password passing as well as also anonymous logins). </li>
<li>Multiple search filters, each in a separate method.
 
<li>Text-only retrieval: all returned data is automatically
<li>Multiple search filters, each in a separate method. </li>
converted from ASCII to EBCDIC.
 
UTF-8 encoding is not supported.
<li>Text-only retrieval: all returned data is automatically converted from ASCII to EBCDIC. UTF-8 encoding is ''not'' supported. </li>
<li>Automatic deserializing of returned data into XML in an <var>[[XmlDoc class|XmlDoc]]</var> object.
 
<li>A limit of approximately 1300 bytes to the data sent in or returned from
<li>Automatic deserializing of returned data into XML in an <var>[[XmlDoc class|XmlDoc]]</var> object. </li>
a single query of the server.
 
<li>Optional retrieval of only the directory entry attribute names, that is,
<li>A limit of approximately 1300 bytes to the data sent in or returned from a single query of the server. </li>
the names without the corresponding attribute values.
 
<li>Optional SSL (Secure Sockets Layer) data transmission.
<li>Optional retrieval of only the directory entry attribute names, that is, the names without the corresponding attribute values. </li>
 
<li>Optional SSL (Secure Sockets Layer) data transmission. </li>
</ul>
</ul>
   
   
The following LDAP features are '''not''' currently supported by the <var>LDAP</var> class:
The following LDAP features are '''not''' currently supported by the <var>LDAP</var> class:
<ul>
<ul>
<li>Kerberos user logins.
<li>Kerberos user logins. </li>
<li>Modifying, deleting, or adding directory content.
<li>Modifying, deleting, or adding directory content. </li>
<li>Full compliance with LDAP v3 (for example, UTF-8 is not supported)
<li>Full compliance with LDAP v3 (for example, UTF-8 is not supported) </li>
<li>Arbitrary, user-constructed search queries
<li>Arbitrary, user-constructed search queries (RFC 1960 syntax featuring boolean operators is not supported). </li>
(RFC 1960 syntax featuring boolean operators is not supported).
<li>Restart of aborted transfers. </li>
<li>Restart of aborted transfers.
<li>Limiting the quantity of the server data returned or the number of entries returned. </li>
<li>Limiting the quantity of the server data returned or
the number of entries returned.
</ul>
</ul>
==LDAP overview==
==LDAP overview==
A '''directory''' is a repository for the storage and retrieval of
A '''directory''' is a repository for the storage and retrieval of
information, and
information, and LDAP (Lightweight Directory Access Protocol) is a
LDAP (Lightweight Directory Access Protocol) is a
vendor- and platform-independent standard for accessing
vendor- and platform-independent standard for accessing
computerized directories.
computerized directories.
LDAP is a subset of '''X.500''',
LDAP is a subset of '''X.500''', a more complex enterprise directory system.
a more complex enterprise directory system.
LDAP, like X.500, is both an information model (with namespace)
LDAP, like X.500, is both an information model (with namespace)
and a protocol for querying and manipulating directory data.
and a protocol for querying and manipulating directory data.
Unlike X.500, LDAP
Unlike X.500, LDAP is designed to run directly over the TCP/IP stack,
is designed to run directly over the TCP/IP stack,
and it has a smaller set of query and update functions.
and it has a smaller set of query and update functions.
   
   
An LDAP directory '''server''' runs on a host computer on the Internet,
An LDAP directory '''server''' runs on a host computer on the Internet,
and it provides directory access to
and it provides directory access to client programs that understand the LDAP
client programs that understand the LDAP
protocol and can log into the server and look up information.
protocol and can log into the server and look up information.
The information is stored in units known as '''entries'''.
The information is stored in units known as '''entries'''.
For example, all the data for a particular person is typically contained in
For example, all the data for a particular person is typically contained in a single entry.
a single entry.
   
   
Entries are used to store '''attributes''', each of which has
Entries are used to store '''attributes''', each of which has
Line 80: Line 71:
An entry for a person may have a <code>firstname</code> attribute type
An entry for a person may have a <code>firstname</code> attribute type
whose value is <code>Byron</code>, for example.
whose value is <code>Byron</code>, for example.
The type determines the
The type determines the attribute's syntax, which defines what kind of
attribute's syntax, which defines what kind of
information is allowed in the values.
information is allowed in the values.
The entries are arranged in a tree structure.
The entries are arranged in a tree structure.
Line 87: Line 77:
LDAP servers index all the data in their entries, and '''filters'''
LDAP servers index all the data in their entries, and '''filters'''
are used to select a matching entry or group of entries.
are used to select a matching entry or group of entries.
A filter specifies attribute types, assertion values, and matching criteria.
A filter specifies attribute types, assertion values, and matching criteria. The LDAP model also defines operations for
The LDAP model also defines operations for
adding, removing, or changing entries in the directory.
adding, removing, or changing entries in the directory.
   
   
For more information about the LDAP protocol,
For more information about the LDAP protocol, hear are some relevant Internet RFCs:
hear are some relevant Internet RFCs:
<ul>
<ul>
<li>RFC 1777
<li>RFC 1777
<p>
The best place for detailed information about LDAP is
The best place for detailed information about LDAP is
Internet RFC 1777 (http://www.ietf.org/rfc/rfc1777.txt),
Internet RFC 1777 (http://www.ietf.org/rfc/rfc1777.txt),
which specifies the protocol.
which specifies the protocol.
An excerpt follows:
An excerpt follows:</p>
<p>
"The protocol described in this document is designed to provide access
"The protocol described in this document is designed to provide access
to the X.500 Directory while not incurring the resource requirements
to the X.500 Directory while not incurring the resource requirements
of the Directory Access Protocol (DAP).
of the Directory Access Protocol (DAP).
This protocol is specifically
This protocol is specifically targeted at simple management applications and browser applications
targeted at simple management applications and browser applications
that provide simple read/write interactive access to the X.500
that provide simple read/write interactive access to the X.500
Directory, and is intended to be a complement to the DAP itself."
Directory, and is intended to be a complement to the DAP itself."
</p></li>
<li>RFC 2256
<li>RFC 2256
<p>
This RFC (http://www.ietf.org/rfc/rfc2256.txt), provides a
This RFC (http://www.ietf.org/rfc/rfc2256.txt), provides a
summary of the attribute types and object classes defined
summary of the attribute types and object classes defined
for use by LDAP/X.500 directory clients.
for use by LDAP/X.500 directory clients.
Although the attribute types implemented by an LDAP server are
Although the attribute types implemented by an LDAP server are
server-specific, many of the standard types are typically used.
server-specific, many of the standard types are typically used.</p></li>
 
<li>RFC 2849
<li>RFC 2849
<p>
This RFC (http://www.ietf.org/rfc/rfc2849.txt) specifies the
This RFC (http://www.ietf.org/rfc/rfc2849.txt) specifies the
format of a directory entry that is returned by the LDAP server.
format of a directory entry that is returned by the LDAP server.</p>
<p>
The LDAP Data Interchange Format (LDIF)
The LDAP Data Interchange Format (LDIF)
&ldquo;consists of a series of records separated by line separators.
"consists of a series of records separated by line separators.
A record consists of a sequence of lines describing a directory entry,
A record consists of a sequence of lines describing a directory entry,
or a sequence of lines describing a set of changes to a directory
or a sequence of lines describing a set of changes to a directory entry.
entry.
An LDIF file specifies a set of directory entries, or a set
An LDIF file specifies a set of directory entries, or a set
of changes to be applied to directory entries, but not both.&rdquo;
of changes to be applied to directory entries, but not both."</p>
<p>
The <var>LDAP</var> class reformats LDAP server responses in an XML document,
The <var>LDAP</var> class reformats LDAP server responses in an XML document, as described in [[#Working with returned values|Working with returned values]].
as described in [[#Working with returned values|"Working with returned values"]].
This <var class="product">Janus</var> XML formatting does '''not'''
This <var class="product">Janus</var> XML formatting does '''not'''
follow the &ldquo;DSML&rdquo; model described in
follow the "DSML" model described in http://www.worldspot.com/dsmlgw-xml-rpc/DSMLGateway.html.</p></li>
http://www.worldspot.com/dsmlgw-xml-rpc/DSMLGateway.html.
 
<li>RFC 1960
<li>RFC 1960
<p>
This RFC (http://www.ietf.org/rfc/rfc1960.txt)
This RFC (http://www.ietf.org/rfc/rfc1960.txt)
provides a grammar that can be used to do arbitrary
provides a grammar that can be used to do arbitrary LDAP queries.
LDAP queries.
This grammar is '''not''' currently supported by the <var>LDAP</var> class.</p></li>
This grammar is '''not''' currently supported by the <var>LDAP</var> class.
</ul>
</ul>
==Using the LDAP class==
==Using the LDAP class==
The <var>LDAP</var> class makes the information in LDAP directories
The <var>LDAP</var> class makes the information in LDAP directories
more easily accessible by removing LDAP protocol concerns from
more easily accessible by removing LDAP protocol concerns from the programmer.
the programmer.
To retrieve data from an LDAP server, applications must:
To retrieve data from an LDAP server, applications must:
<ol>
<ol>
<li>Define a <var class="product">Janus</var> <var>CLSOCK</var> port.
<li>Define a <var class="product">Janus</var> <var>CLSOCK</var> port.
<ul>
<ul>
<li>Use the <var>[[JANUS DEFINE]]</var> command to
<li>Use the <var>[[JANUS DEFINE]]</var> command to:
 
<ul>
<ul>
<li>Create a TCP/IP port for your <var class="product">Model 204</var> LDAP client application.
<li>Create a TCP/IP port for your <var class="product">Model 204</var> LDAP client application. </li>
<li>Indicate the remote LDAP server identifier and port number
<li>Indicate the remote LDAP server identifier and port number
(or a pattern that allows the specific server to be specified
(or a pattern that allows the specific server to be specified by an <var>LDAP</var> class method). </li>
by an <var>LDAP</var> class method).
<li>Set a timeout value for the LDAP connections. </li>
<li>Set a timeout value for the LDAP connections.
</ul>
<li>Use the
<var>[[JANUS NAMESERVER]]</var> command to let you reference remote hosts by name
rather than IP address.
<li>Use a <var>[[JANUS CLSOCK]]</var> command to specify access rules for your port.
<li>Use the <var>[[JANUS START]]</var> command to start your port.
</ul>
</ul>
<li>Use the <var>[[JANUS NAMESERVER]]</var> command to let you reference remote hosts by name rather than IP address. </li>
<li>Use a <var>[[JANUS CLSOCK]]</var> command to specify access rules for your port. </li>
<li>Use the <var>[[JANUS START]]</var> command to start your port. </li>
</ul></li>
<li>Bind a connection and log in to an LDAP server.
<li>Bind a connection and log in to an LDAP server.
<p>
In your <var class="product">User Language</var> request, a single <var>[[Bind (LDAP function)|Bind]]</var> method statement
In your <var class="product">SOUL</var> request, a single <var>[[Bind (LDAP function)|Bind]]</var> method statement performs these actions.</p></li>
performs these actions.
 
<li>Send a search query to the LDAP server.
<li>Send a search query to the LDAP server.
<p>
Use one of the multiple <var>Find</var> methods, which provide a variety of search filters.
Use one of the multiple <var>Find</var> methods, which provide a variety of search filters. See [[#Using the Find methods|Using the Find methods]].</p></li>
See [[#Using the Find methods|"Using the Find methods"]].
 
<li>Optionally, extract particular data from the returned value.
<li>Optionally, extract particular data from the returned value. See [[#Working with returned values|Working with returned values]]. </li>
See [[#Working with returned values|"Working with returned values"]].
 
<li>End your session when ready.
<li>End your session when ready.
<p>
The <var>[[Unbind (LDAP function)|Unbind]]</var> method
The <var>[[Unbind (LDAP function)|Unbind]]</var> method logs off the LDAP user, and it deactivates the connection.</p></li>
logs off the LDAP user, and it deactivates the connection.
</ol>
</ol>
===Working with returned values===
===Working with returned values===
The directory information returned from an
The directory information returned from an LDAP server in response to a <var class="product">Janus</var> <var>LDAP</var> <var>Find</var> call
LDAP server in response to a <var class="product">Janus</var> <var>LDAP</var> <var>Find</var> call
is stored in an <var>[[XmlDoc class|XmlDoc]]</var> object.
is stored in a <var class="product">Janus</var> system <var>XmlDoc</var> object.
This object contains exactly the data strings sent from the server, in whatever case.
This object
contains exactly the data strings sent from the server,
in whatever case.
   
   
The XML structure of such an <var>XmlDoc</var> is shown in this sample fragment,
The XML structure of such an <var>XmlDoc</var> is shown in this sample fragment, whose features are described after the example:
whose features are described after the example:
<p class="code"><result>
<p class="code">   <result>
  <entry objectName="cn: Sildar, John R, id=X479, c=US">
      <entry objectName="cn: Sildar, John R, id=X479, c=US">
      <cn>
          <cn>
          <value>Sildar, John R</value>
              <value>Sildar, John R</value>
      </cn>
          </cn>
      <sn>
          <sn>
          <value>Sildar</value>
              <value>Sildar</value>
      </sn>
          </sn>
  </entry>
      </entry>
</result>
    </result>
</p>
</p>
<ul>
<ul>
<li>The top element is named <code>result</code>.
<li>The top element is named <code>result</code>.
If no matches were found,
If no matches were found, only an empty result element (<code><result/></code>) is present. </li>
only an empty result element (<code><result/></code>) is present.
 
<li>The <code>result</code> element has zero or more <code>entry</code> children.
<li>The <code>result</code> element has zero or more <code>entry</code> children. </li>
<li>Each <code>entry</code> element has one or more child elements, each named
 
for the LDAP attribute type whose returned data it contains.
<li>Each <code>entry</code> element has one or more child elements, each named for the LDAP attribute type whose returned data it contains
(for example, <code>cn</code>, <code>sn</code>, <code>telephonenumber</code>).
(for example, <code>cn</code>, <code>sn</code>, <code>telephonenumber</code>). </li>
<li>Each attribute-type element has zero or more <code>value</code> child elements
 
that contain that LDAP attribute's value(s).
<li>Each attribute-type element has zero or more <code>value</code> child elements that contain that LDAP attribute's value(s).
If the Find call specified an <code>AttributesOnly=True</code> argument,
If the <var>Find</var> call specified an <code>AttributesOnly=True</code> argument, any <code>value</code> children are not displayed. </li>
any <code>value</code> children are not displayed.
 
<li>The <code>entry</code> element in this example has an (XML) attribute
<li>The <code>entry</code> element in this example has an (XML) attribute
named <code>objectName</code> that contains identifying information for the entry
named <code>objectName</code> that contains identifying information for the entry (this is the LDAP Distinguished Name field for the entry). </li>
(this is the LDAP Distinguished Name field for the entry).
</ul>
</ul>
   
   
Line 221: Line 207:
In the <var>XmlDoc</var> returned from an LDAP query,
In the <var>XmlDoc</var> returned from an LDAP query,
the LDAP attribute names themselves are the <var>XmlDoc</var> element names.
the LDAP attribute names themselves are the <var>XmlDoc</var> element names.
One consequence of this is that you can use <var class="product>Janus SOAP</var> [[XmlDoc API]] method
One consequence of this is that you can use <var class="product">Janus SOAP</var> [[XmlDoc API]] method
calls with relatively simple XPath-expression arguments to extract particular
calls with relatively simple XPath-expression arguments to extract particular "fields" from a returned value.
&ldquo;fields&rdquo; from a returned value.
   
   
For example, to extract the first value of attribute <code>sn</code> in the
For example, to extract the first value of attribute <code>sn</code> in the first found entry in the returned <var>XmlDoc</var> <code>%doc</code>, you can use the
first found entry in the returned <var>XmlDoc</var> <code>%doc</code>, you can use the
<var>[[Value (XmlDoc/XmlNode property)|Value]]</var> property with a straightforward [[XmlDoc API#The XmlNode and XmlNodelist classes, and XPath|XPath]] argument:
<var>[[Value (XmlDoc/XmlNode property)|Value]]</var> property with a straightforward [[XmlDoc API#The XmlNode and XmlNodelist classes, and XPath|XPath]] argument:
<p class="code"> Print %doc:Value('result/entry/sn/value')
<p class="code">Print %doc:Value('result/entry/sn/value')
</p>
</p>
   
   
Or, alternatively:
Or, alternatively:
<p class="code"> %entry = %doc:selectSingleNode('/result/entry')
<p class="code">%entry = %doc:selectSingleNode('/result/entry')
Print %doc:Value('sn')
Print %doc:Value('sn')
</p>
</p>
For more information about selecting nodes from an <var>XmlDoc</var>,
For more information about selecting nodes from an <var>XmlDoc</var>,
Line 240: Line 224:
To return the first value of <code>sn</code> in the second found entry,
To return the first value of <code>sn</code> in the second found entry,
in a case where multiple entries were found, you can use:
in a case where multiple entries were found, you can use:
<p class="code"> Print doc:Value('result/entry[2]/sn/value')
<p class="code">Print doc:Value('result/entry[2]/sn/value')
</p>
</p>
   
   
And to return the first value of <code>sn</code> in the third (or greater)
And to return the first value of <code>sn</code> in the third (or greater)
found entry:
found entry:
<p class="code"> Print doc:Value('result/entry[position()>=3]/sn/value')
<p class="code">Print doc:Value('result/entry[position()>=3]/sn/value')
</p>
 
===Instantiating and discarding LDAP objects===
The <var>LDAP</var> class has no explicit constructor or destructor methods.
To create or discard an <var>LDAP</var> object instance, you
use the system <var>New</var> and <var>Discard</var> methods that are available to all <var class="product">SOUL</var> classes.
The <var>[[New (LDAP constructor)|New]]</var> <var>Constructor</var> allocates and initializes storage for a new <var>LDAP</var> object instance. It takes no arguments.
A separate method (<var>[[Bind (LDAP function)|Bind]]</var>) establishes a connection to an LDAP server.
When an LDAP client no longer wants to query the LDAP server,
the <var>LDAP</var> <var>[[Unbind (LDAP function)|Unbind]]</var> method unauthenticates the LDAP user and severs the connection to the server host.
The <var>LDAP</var> object instance remains available for reuse.
If no further references to it exist, it gets discarded automatically ("implicitly").
You can also use the generic (<var>Object</var> class) <var>[[Object variables#Discarding objects|Discard]]</var> method to discard an <var>LDAP</var> object:
<p class="code">%ldapObject:Discard
</p>
</p>
The <var>Discard</var> method does not set the <var>[[ErrorNumber (LDAP function)|ErrorNumber]]</var>
and <var>[[ErrorText (LDAP function)|ErrorText]]</var> properties.
===Using the Find methods===
In the LDAP Internet RFC 1777, a '''filter'''
"defines the conditions that must be fulfilled
in order for the search to match a given entry."
The RFC specifies the variety of search filters shown below:
<p class="code">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
    }
</p>
The <var>LDAP</var> class implements many of these filters with the
following Find methods:
<ul class="nobul">
<li><var>[[FindEQ (LDAP function)|FindEQ]]</var>
<li><var>[[FindStringInCommonName (LDAP function)|FindStringInCommonName]]</var>
<li><var>[[FindGE (LDAP function)|FindGE]]</var>
<li><var>[[FindLE (LDAP function)|FindLE]]</var>
<li><var>[[FindApprox (LDAP function)|FindApprox]]</var>
</ul>
The LDAP Internet RFC 1960 specifies a syntax for a string representation
of these filters, but SOUL <var>LDAP</var> does '''''not''''' have an implementation of such a syntax.
With one exception, the Janus <var>LDAP</var> Find methods have the same arguments and differ only in how the search strings that they provide are interpreted by the LDAP server.
Many of the individual Find method descriptions in the following sections
therefore avoid repetition by pointing to the representative
and probably most commonly used methods: <var>FindEQ</var> (an equality search of the
attribute type you specify) and <var>FindStringInCommonName</var>
(a search of the <code>cn</code> attribute type for the substring you specify).
The following are true for all the Find methods:
<ul>
<li>The LDAP server's resolution of a search query (its "matching rules")
is implementation-specific, varies with the attribute type,
and is affected by what the directory database uses for
search keys, indices, search algorithms, and so on.
<li>The scope of the search requested by the Janus client is hard-coded
to be "whole subtree," that is, all the levels of attribute=value pairs
(nodes) in the directory tree.
<li>By default, <var class="product">Model 204</var> uppercases the search string characters you specify before it sends them to the LDAP server.
You can use the <var class="product">Model&nbsp;204</var> <var>*LOWER</var> command to turn off the default uppercasing.
<li>It is LDAP server-specific whether you must precede special characters
in your search string with an escape character to locate directory values that
include those special characters, and the character to use as an
escape character is also server-specific.
This said, the asterisk (<tt>*</tt>), left-parenthesis ('''<tt>(</tt>'''),
right-parenthesis ('''<tt>)</tt>'''), and backslash (<tt>\</tt>)
characters often require escaping, and
a backslash is often the escape character.
Escaping the question mark character (<tt>?</tt>)
and other special characters, like equal sign (<tt>=</tt>), angle brackets (<tt>< ></tt>),
tilde (<tt>~</tt>), and quotation marks (<tt>", '</tt>), is often optional.
Whether wildcard characters, typically asterisk (<tt>*</tt>) and question mark (<tt>?</tt>), are respected by a server search engine is server-specific.
A search for the surname <code>?aldo*</code> may return the names Baldock and Baldona, or it may return an empty result.
<li id="limit">You cannot limit the amount of the server data returned nor, say, the
number of entries returned, although LDAP servers will enforce their own limits.
For requests sent to the server, the SOUL <var>LDAP</var> client buffers
allow for several hundred bytes for any particular substring (for example, the text in an attribute value)
and a total of 8184 bytes for any single message. </li>
<li>To limit the length of time of a search, you set the <var>[[TIMEOUT]]</var>
parameter value on the <var>[[JANUS DEFINE]]</var> command for the Janus port used for connections to the LDAP server. </li>
<li>The <var>LDAP</var> Find methods store the found entries in an <var>XmlDoc</var> object output argument,
and they return an optional status value with information about the success of the search. </li>
<li>A search that returns no matches is '''not''' considered an error.
Your returned <var>XmlDoc</var> contains a single empty element: <code><result/></code>. </li>
<li>The <var>LDAP</var> Find methods also have options that let you:
<ul>
<li>Restrict the information reported for each entry to just the attribute
types you list </li>
<li>Retrieve only the names of the entry attribute types themselves </li>
</ul> </li>
</ul>
==LDAP class example==
==LDAP class example==
The procedure below, which exercises many of the <var>LDAP</var> methods,
The procedure below, which exercises many of the <var>LDAP</var> methods,
Line 252: Line 349:
<ol>
<ol>
<li>Defines a <var class="product">Janus</var> port for an LDAP client.
<li>Defines a <var class="product">Janus</var> port for an LDAP client.
<li>Creates an <var>LDAP</var> object, then connects to an LDAP server.
<li>Creates an <var>LDAP</var> object, then connects to an LDAP server.
<li>Performs an equality search using a traditional
 
attribute type (<code>sn</code>)
<li>Performs an equality search using a traditional attribute type (<code>sn</code>)
to return the names of the attribute types implemented by this LDAP server.
to return the names of the attribute types implemented by this LDAP server.
This informs the user for the next step.
This informs the user for the next step.
<li>In a repeating loop, prompts the user for
 
an attribute type and search value, performs an equality search with the
<li>In a repeating loop, prompts the user for an attribute type and search value, performs an equality search with the
user-specified values, then searches the
user-specified values, then searches the
returned <var>XmlDoc</var> for the value of a particular attribute.
returned <var>XmlDoc</var> for the value of a particular attribute.
<li>Disconnects from the LDAP server.
<li>Disconnects from the LDAP server.
</ol>
</ol>
<p class="code"> UTABLE LPDLST 8000
 
*
<p class="code">UTABLE LPDLST 8000
JANUS NAMESERVER 198.142.144.8 43
&#42;
JANUS DRAIN LDSOCK1
JANUS NAMESERVER 198.142.144.8 43
JANUS FORCE LDSOCK1
JANUS DRAIN LDSOCK1
JANUS DELETE LDSOCK1
JANUS FORCE LDSOCK1
JANUS DEFINE LDSOCK1 * CLSOCK 5 TIMEOUT 180 MASTER REMOTE * *
JANUS DELETE LDSOCK1
JANUS START LDSOCK1
JANUS DEFINE LDSOCK1 * CLSOCK 5 TIMEOUT 180 MASTER REMOTE * *
JANUS STATUS
JANUS START LDSOCK1
*
JANUS STATUS
Begin
&#42;
  %ld Object Ldap
Begin
  %doc Object XmlDoc Auto New
  %ld Object Ldap
  %status float
  %doc Object XmlDoc Auto New
  %Attrib string len 255
  %status float
  %SearchString string len 255
  %Attrib string len 255
  %PortNumber float
  %SearchString string len 255
  %val is longstring
  %PortNumber float
***************
  %val is longstring
  %ld = New
&#42;**************
  %status = %ld:Bind(JanusPort='LDSOCK1',      -
  %ld = New
                LDAPServer='ldap.college.edu')
  %status = %ld:Bind(JanusPort='LDSOCK1',      -
  If %status then
              LDAPServer='ldap.college.edu')
      Print 'Bad status from Ldap:Bind: ' %status
  If %status then
      Print '  LDERRNO: ' %ld:ErrorNumber
    Print 'Bad status from Ldap:Bind: ' %status
      Print '  LDERRMS: <' %ld:ErrorText '>'
    Print '  LDERRNO: ' %ld:ErrorNumber
      Stop
    Print '  LDERRMS: <' %ld:ErrorText '>'
  End If
    Stop
***************
  End If
  Print 'AttributesOnly result: '
&#42;**************
  %status = %ld:FindEQ('sn', 'Sildar', %doc,    -
  Print 'AttributesOnly result: '
                        AttributesOnly=True)
  %status = %ld:FindEQ('sn', 'Sildar', %doc,    -
  If %status then
                        AttributesOnly=True)
      Print 'Bad status from Ldap:FindOP: ' %status
  If %status then
      Print '  LDERRNO: ' %ld:ErrorNumber
    Print 'Bad status from Ldap:FindOP: ' %status
      Print '  LDERRMS: <' %ld:ErrorText '>'
    Print '  LDERRNO: ' %ld:ErrorNumber
      Stop
    Print '  LDERRMS: <' %ld:ErrorText '>'
  End If
    Stop
  %doc:Print
  End If
* Must clear XmlDoc
  %doc:Print
  %doc = New
&#42; Must clear XmlDoc
***************
  %doc = New
* Ask user for attrib and value for FindEQ test
&#42;**************
* Either string empty breaks out of the loop
&#42; Ask user for attrib and value for FindEQ test
  Repeat Forever
&#42; Either string empty breaks out of the loop
      %Attrib = $READ ('What attribute for an EQ search?')
  Repeat Forever
      If (%Attrib EQ '') then
    %Attrib = $READ ('What attribute for an EQ search?')
        Loop End
      If (%Attrib EQ <nowiki>''</nowiki>) then
      End If
        Loop End
      %SearchString = $READ ('What value?')
      End If
      If (%SearchString EQ '') then
      %SearchString = $READ ('What value?')
        Loop End
      If (%SearchString EQ <nowiki>''</nowiki>) then
      End If
        Loop End
    Print 'Searching for <' %Attrib ' EQ ' %SearchString '>'
      End If
    %status = %ld:FindEQ(%Attrib, %SearchString, %doc)
    Print 'Searching for <' %Attrib ' EQ ' %SearchString '>'
      If %status then
    %status = %ld:FindEQ(%Attrib, %SearchString, %doc)
          Print 'Bad status from Ldap:FindEQ: ' %status
      If %status then
          Print '  LDERRNO: ' %ld:ErrorNumber
        Print 'Bad status from Ldap:FindEQ: ' %status
          Print '  LDERRMS: <' %ld:ErrorText '>'
        Print '  LDERRNO: ' %ld:ErrorNumber
          Stop
        Print '  LDERRMS: <' %ld:ErrorText '>'
      End If
        Stop
    %doc:Print
      End If
* Print the email address
    %doc:Print
    %val = %doc:Value('result/entry/mail/value')
&#42; Print the email address
    Print 'found value is ' %val
    %val = %doc:Value('result/entry/mail/value')
    %doc = New
    Print 'found value is ' %val
  End Repeat
    %doc = New
***************
  End Repeat
    %status = %ld:Unbind
&#42;**************
      If %status then
    %status = %ld:Unbind
          Print 'Bad status from Ldap:Unbind: ' %status
      If %status then
          Print '  LDERRNO: ' %ld:ErrorNumber
        Print 'Bad status from Ldap:Unbind: ' %status
          Print '  LDERRMS: <' %ld:ErrorText '>'
        Print '  LDERRNO: ' %ld:ErrorNumber
      End If
        Print '  LDERRMS: <' %ld:ErrorText '>'
End
      End If
End
</p>
</p>
===Instantiating and discarding LDAP objects===
 
The <var>LDAP</var> class has no explicit constructor or destructor methods.
==List of LDAP methods==
To create or discard an <var>LDAP</var> object instance, you
The [[List of LDAP methods]] contains a complete list of the class methods.
use the system <var>New</var> and <var>Discard</var> methods that are available to all <var class="product">Janus</var> classes.
 
==See also==
The <var>[[New (LDAP constructor)|New]]</var> <var>Constructor</var> allocates and initializes storage for
<ul>
a new <var>LDAP</var> object instance.
<li>[[Janus Sockets User Language coding considerations]]
It takes no arguments.
<li>[[Sample Janus Sockets programs]]
A separate method (<var>[[Bind (LDAP function)|Bind]]</var>) establishes a connection to an LDAP server.
<li>Socket-level interfaces:
<ul>
When an LDAP client no longer wants to query the LDAP server,
<li>[[Janus Sockets $functions|$functions]]
the <var>LDAP</var> <var>[[Unbind (LDAP function)|Unbind]]</var> method unauthenticates the LDAP user and severs the
<li>[[Socket class]]
connection to the server host.
</ul>
The <var>LDAP</var> object instance remains available for reuse.
<li>Higher-level interfaces:
If no further references to it exist, it gets discarded automatically
<ul>
(&ldquo;implicitly&rdquo;).
<li>[[Email class]]
You can also use
<li>[[HTTP Helper|HTTP Helper classes]]
the generic (<var>Object</var> class) <var>[[Object variables#Discarding objects|Discard]]</var> method to discard an <var>LDAP</var> object:
<li>[[LDAP class]]
<p class="code"> %ldapObject:Discard
<li>[[Janus FTP Server]]
</p>
<li>[[Janus Telnet Server]]
</ul>
The <var>Discard</var> method does not set the
 
<var>[[ErrorNumber (LDAP function)|ErrorNumber]]</var>
[[Category:Janus Sockets]]
and <var>[[ErrorText (LDAP function)|ErrorText]]</var> properties.

Latest revision as of 22:33, 1 September 2016

The LDAP class simplifies public searches of an organization's LDAP (Lightweight Directory Access Protocol) directory. The LDAP class is a high level, object oriented interface to client sockets that lets you write a SOUL LDAP request without knowledge of socket level programming or the format of LDAP requests and responses.

The LDAP class methods allow a SOUL program to act as an LDAP client to access and retrieve directory information through an LDAP server. The LDAP server may be running on any platform to which the LDAP client online can make a TCP/IP connection.

You use JANUS commands (DEFINE, START, NAMESERVER) to define and start a TCP/IP CLSOCK port for the LDAP client to use.

Note: To use LDAP objects under versions of Model 204 earlier than 7.5, you must have licensed Janus TCP/IP Base, Janus Sockets, and Janus SOAP. Under version 7.5 and later, you do not require Janus SOAP.

For information about using SOUL objects, see Object oriented programming in SOUL.

Feature summary

The LDAP class provides the following capabilities:

  • Read access to X.500 and LDAP v2 directory services.
  • One-step connection and login to an LDAP server (with user ID and password passing as well as also anonymous logins).
  • Multiple search filters, each in a separate method.
  • Text-only retrieval: all returned data is automatically converted from ASCII to EBCDIC. UTF-8 encoding is not supported.
  • Automatic deserializing of returned data into XML in an XmlDoc object.
  • A limit of approximately 1300 bytes to the data sent in or returned from a single query of the server.
  • Optional retrieval of only the directory entry attribute names, that is, the names without the corresponding attribute values.
  • Optional SSL (Secure Sockets Layer) data transmission.

The following LDAP features are not currently supported by the LDAP class:

  • Kerberos user logins.
  • Modifying, deleting, or adding directory content.
  • Full compliance with LDAP v3 (for example, UTF-8 is not supported)
  • Arbitrary, user-constructed search queries (RFC 1960 syntax featuring boolean operators is not supported).
  • Restart of aborted transfers.
  • Limiting the quantity of the server data returned or the number of entries returned.

LDAP overview

A directory is a repository for the storage and retrieval of information, and LDAP (Lightweight Directory Access Protocol) is a vendor- and platform-independent standard for accessing computerized directories. LDAP is a subset of X.500, a more complex enterprise directory system. LDAP, like X.500, is both an information model (with namespace) and a protocol for querying and manipulating directory data. Unlike X.500, LDAP is designed to run directly over the TCP/IP stack, and it has a smaller set of query and update functions.

An LDAP directory server runs on a host computer on the Internet, and it provides directory access to client programs that understand the LDAP protocol and can log into the server and look up information. The information is stored in units known as entries. For example, all the data for a particular person is typically contained in a single entry.

Entries are used to store attributes, each of which has an associated type and one or more values. An entry for a person may have a firstname attribute type whose value is Byron, for example. The type determines the attribute's syntax, which defines what kind of information is allowed in the values. The entries are arranged in a tree structure.

LDAP servers index all the data in their entries, and filters are used to select a matching entry or group of entries. A filter specifies attribute types, assertion values, and matching criteria. The LDAP model also defines operations for adding, removing, or changing entries in the directory.

For more information about the LDAP protocol, hear are some relevant Internet RFCs:

  • RFC 1777

    The best place for detailed information about LDAP is Internet RFC 1777 (http://www.ietf.org/rfc/rfc1777.txt), which specifies the protocol. An excerpt follows:

    "The protocol described in this document is designed to provide access to the X.500 Directory while not incurring the resource requirements of the Directory Access Protocol (DAP). This protocol is specifically targeted at simple management applications and browser applications that provide simple read/write interactive access to the X.500 Directory, and is intended to be a complement to the DAP itself."

  • RFC 2256

    This RFC (http://www.ietf.org/rfc/rfc2256.txt), provides a summary of the attribute types and object classes defined for use by LDAP/X.500 directory clients. Although the attribute types implemented by an LDAP server are server-specific, many of the standard types are typically used.

  • RFC 2849

    This RFC (http://www.ietf.org/rfc/rfc2849.txt) specifies the format of a directory entry that is returned by the LDAP server.

    The LDAP Data Interchange Format (LDIF) "consists of a series of records separated by line separators. A record consists of a sequence of lines describing a directory entry, or a sequence of lines describing a set of changes to a directory entry. An LDIF file specifies a set of directory entries, or a set of changes to be applied to directory entries, but not both."

    The LDAP class reformats LDAP server responses in an XML document, as described in Working with returned values. This Janus XML formatting does not follow the "DSML" model described in http://www.worldspot.com/dsmlgw-xml-rpc/DSMLGateway.html.

  • RFC 1960

    This RFC (http://www.ietf.org/rfc/rfc1960.txt) provides a grammar that can be used to do arbitrary LDAP queries. This grammar is not currently supported by the LDAP class.

Using the LDAP class

The LDAP class makes the information in LDAP directories more easily accessible by removing LDAP protocol concerns from the programmer. To retrieve data from an LDAP server, applications must:

  1. Define a Janus CLSOCK port.
    • Use the JANUS DEFINE command to:
      • Create a TCP/IP port for your Model 204 LDAP client application.
      • Indicate the remote LDAP server identifier and port number (or a pattern that allows the specific server to be specified by an LDAP class method).
      • Set a timeout value for the LDAP connections.
    • Use the JANUS NAMESERVER command to let you reference remote hosts by name rather than IP address.
    • Use a JANUS CLSOCK command to specify access rules for your port.
    • Use the JANUS START command to start your port.
  2. Bind a connection and log in to an LDAP server.

    In your SOUL request, a single Bind method statement performs these actions.

  3. Send a search query to the LDAP server.

    Use one of the multiple Find methods, which provide a variety of search filters. See Using the Find methods.

  4. Optionally, extract particular data from the returned value. See Working with returned values.
  5. End your session when ready.

    The Unbind method logs off the LDAP user, and it deactivates the connection.

Working with returned values

The directory information returned from an LDAP server in response to a Janus LDAP Find call is stored in an XmlDoc object. This object contains exactly the data strings sent from the server, in whatever case.

The XML structure of such an XmlDoc is shown in this sample fragment, whose features are described after the example:

<result> <entry objectName="cn: Sildar, John R, id=X479, c=US"> <cn> <value>Sildar, John R</value> </cn> <sn> <value>Sildar</value> </sn> </entry> </result>

  • The top element is named result. If no matches were found, only an empty result element (<result/>) is present.
  • The result element has zero or more entry children.
  • Each entry element has one or more child elements, each named for the LDAP attribute type whose returned data it contains (for example, cn, sn, telephonenumber).
  • Each attribute-type element has zero or more value child elements that contain that LDAP attribute's value(s). If the Find call specified an AttributesOnly=True argument, any value children are not displayed.
  • The entry element in this example has an (XML) attribute named objectName that contains identifying information for the entry (this is the LDAP Distinguished Name field for the entry).


Using XPath to search returned values

In the XmlDoc returned from an LDAP query, the LDAP attribute names themselves are the XmlDoc element names. One consequence of this is that you can use Janus SOAP XmlDoc API method calls with relatively simple XPath-expression arguments to extract particular "fields" from a returned value.

For example, to extract the first value of attribute sn in the first found entry in the returned XmlDoc %doc, you can use the Value property with a straightforward XPath argument:

Print %doc:Value('result/entry/sn/value')

Or, alternatively:

%entry = %doc:selectSingleNode('/result/entry') Print %doc:Value('sn')

For more information about selecting nodes from an XmlDoc, see SelectSingleNode.

To return the first value of sn in the second found entry, in a case where multiple entries were found, you can use:

Print doc:Value('result/entry[2]/sn/value')

And to return the first value of sn in the third (or greater) found entry:

Print doc:Value('result/entry[position()>=3]/sn/value')

Instantiating and discarding LDAP objects

The LDAP class has no explicit constructor or destructor methods. To create or discard an LDAP object instance, you use the system New and Discard methods that are available to all SOUL classes.

The New Constructor allocates and initializes storage for a new LDAP object instance. It takes no arguments. A separate method (Bind) establishes a connection to an LDAP server.

When an LDAP client no longer wants to query the LDAP server, the LDAP Unbind method unauthenticates the LDAP user and severs the connection to the server host. The LDAP object instance remains available for reuse. If no further references to it exist, it gets discarded automatically ("implicitly"). You can also use the generic (Object class) Discard method to discard an LDAP object:

%ldapObject:Discard

The Discard method does not set the ErrorNumber and ErrorText properties.

Using the Find methods

In the LDAP Internet RFC 1777, a filter "defines the conditions that must be fulfilled in order for the search to match a given entry." The RFC specifies the variety of search filters shown below:

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 }

The LDAP class implements many of these filters with the following Find methods:

The LDAP Internet RFC 1960 specifies a syntax for a string representation of these filters, but SOUL LDAP does not have an implementation of such a syntax.

With one exception, the Janus LDAP Find methods have the same arguments and differ only in how the search strings that they provide are interpreted by the LDAP server. Many of the individual Find method descriptions in the following sections therefore avoid repetition by pointing to the representative and probably most commonly used methods: FindEQ (an equality search of the attribute type you specify) and FindStringInCommonName (a search of the cn attribute type for the substring you specify).

The following are true for all the Find methods:

  • The LDAP server's resolution of a search query (its "matching rules") is implementation-specific, varies with the attribute type, and is affected by what the directory database uses for search keys, indices, search algorithms, and so on.
  • The scope of the search requested by the Janus client is hard-coded to be "whole subtree," that is, all the levels of attribute=value pairs (nodes) in the directory tree.
  • By default, Model 204 uppercases the search string characters you specify before it sends them to the LDAP server. You can use the Model 204 *LOWER command to turn off the default uppercasing.
  • It is LDAP server-specific whether you must precede special characters in your search string with an escape character to locate directory values that include those special characters, and the character to use as an escape character is also server-specific. This said, the asterisk (*), left-parenthesis ((), right-parenthesis ()), and backslash (\) characters often require escaping, and a backslash is often the escape character. Escaping the question mark character (?) and other special characters, like equal sign (=), angle brackets (< >), tilde (~), and quotation marks (", '), is often optional. Whether wildcard characters, typically asterisk (*) and question mark (?), are respected by a server search engine is server-specific. A search for the surname ?aldo* may return the names Baldock and Baldona, or it may return an empty result.
  • You cannot limit the amount of the server data returned nor, say, the number of entries returned, although LDAP servers will enforce their own limits. For requests sent to the server, the SOUL LDAP client buffers allow for several hundred bytes for any particular substring (for example, the text in an attribute value) and a total of 8184 bytes for any single message.
  • To limit the length of time of a search, you set the TIMEOUT parameter value on the JANUS DEFINE command for the Janus port used for connections to the LDAP server.
  • The LDAP Find methods store the found entries in an XmlDoc object output argument, and they return an optional status value with information about the success of the search.
  • A search that returns no matches is not considered an error. Your returned XmlDoc contains a single empty element: <result/>.
  • The LDAP Find methods also have options that let you:
    • Restrict the information reported for each entry to just the attribute types you list
    • Retrieve only the names of the entry attribute types themselves

LDAP class example

The procedure below, which exercises many of the LDAP methods, does the following:

  1. Defines a Janus port for an LDAP client.
  2. Creates an LDAP object, then connects to an LDAP server.
  3. Performs an equality search using a traditional attribute type (sn) to return the names of the attribute types implemented by this LDAP server. This informs the user for the next step.
  4. In a repeating loop, prompts the user for an attribute type and search value, performs an equality search with the user-specified values, then searches the returned XmlDoc for the value of a particular attribute.
  5. Disconnects from the LDAP server.

UTABLE LPDLST 8000 * JANUS NAMESERVER 198.142.144.8 43 JANUS DRAIN LDSOCK1 JANUS FORCE LDSOCK1 JANUS DELETE LDSOCK1 JANUS DEFINE LDSOCK1 * CLSOCK 5 TIMEOUT 180 MASTER REMOTE * * JANUS START LDSOCK1 JANUS STATUS * Begin %ld Object Ldap %doc Object XmlDoc Auto New %status float %Attrib string len 255 %SearchString string len 255 %PortNumber float %val is longstring *************** %ld = New %status = %ld:Bind(JanusPort='LDSOCK1', - LDAPServer='ldap.college.edu') If %status then Print 'Bad status from Ldap:Bind: ' %status Print ' LDERRNO: ' %ld:ErrorNumber Print ' LDERRMS: <' %ld:ErrorText '>' Stop End If *************** Print 'AttributesOnly result: ' %status = %ld:FindEQ('sn', 'Sildar', %doc, - AttributesOnly=True) If %status then Print 'Bad status from Ldap:FindOP: ' %status Print ' LDERRNO: ' %ld:ErrorNumber Print ' LDERRMS: <' %ld:ErrorText '>' Stop End If %doc:Print * Must clear XmlDoc %doc = New *************** * Ask user for attrib and value for FindEQ test * Either string empty breaks out of the loop Repeat Forever %Attrib = $READ ('What attribute for an EQ search?') If (%Attrib EQ '') then Loop End End If %SearchString = $READ ('What value?') If (%SearchString EQ '') then Loop End End If Print 'Searching for <' %Attrib ' EQ ' %SearchString '>' %status = %ld:FindEQ(%Attrib, %SearchString, %doc) If %status then Print 'Bad status from Ldap:FindEQ: ' %status Print ' LDERRNO: ' %ld:ErrorNumber Print ' LDERRMS: <' %ld:ErrorText '>' Stop End If %doc:Print * Print the email address %val = %doc:Value('result/entry/mail/value') Print 'found value is ' %val %doc = New End Repeat *************** %status = %ld:Unbind If %status then Print 'Bad status from Ldap:Unbind: ' %status Print ' LDERRNO: ' %ld:ErrorNumber Print ' LDERRMS: <' %ld:ErrorText '>' End If End

List of LDAP methods

The List of LDAP methods contains a complete list of the class methods.

See also