Subject: Re: Java LDAP API issues

From: Rob Weltman <[email-masked]>
Date: Sun, 24 Sep 2000 23:10:43 -0700

I've collected all the issues raised (hope I didn't miss any) and responded in short to each one. Many thanks to Miodrag for helping me evaluate the issues. And to Steve and Steven for raising them :-)

Rob

1.
> Section 4.39.13 LDAPV2.setOption
>
>  This method of the LDAPV2 interface seems a little strange.
>
>   1) It probably does not belong under the interface LDAPV2,
>      but instead under LDAPConnection. This would allow it
>      to support setting client & server controls which it
>      cannot do under LDAPV2.  This functionality is currently
>      missing in the method.
>
>      Setting STRING_FORMAT is also an LDAPV3 setting, as UTF-8
>      is only meaningful under LDAPV3.

  OK, but see 4 below (which renders this issue mute)

>   2) STRING_FORMAT is set only by the setOption method.
>      There should be a way to set or get STRING_FORMAT with
>      LDAPSearchConstraints methods.

  OK, but see 4 below (which renders this issue mute)

>   3) setOption operates only on the LDAPSearchConstraints object
>      that is associated with an LDAPConnection object.  Yet
>      there may also be an LDAPConstraints object associated
>      with the LDAPConnection object.  It may or may not be
>      the same as the LDAPSearchConstraints object.  Should
>      there be a setOption kind of method that operates on
>      the LDAPConstraints object associated with a connection?

  LDAPSearchConstraints extends LDAPConstraints. There is only one such object per connection, and it is an LDAPSearchConstraints. If there was an LDAPConstraints object as well, there would be ambiguity as to which object controlled operations other than search.   Also, see 4 below (which renders this issue mute)

>   4) All functionality of SetOption can be performed by code
>      that references the LDAPSearchConstraints object of a
>      connection - i.e. LDAPConnection.getSearchConstraints.method().
>

  Yes, let's eliminate it.

2.
> If references to LDAPv2 are not removed from the draft,
> then the methods that were previously in LDAPAsynchronous
> Connection which are now in LDAPConnection - these methods
> should also be in one of the LDAPV2 or LDAPV3 interfaces
> to identify where they can be used.

  Let's eliminate the references to LDAPv2; the API will assume LDAPv3.

3.
>
>  In the java-api-11 I-D, an application doing asynchronous search
>  operations is confronted with two different data formats when handling
>  referrals and search continuation references.
>
>  When the application gets a referral status on a search operation,
>  referral URL information is retrieved by LDAPResponse.getReferrals()
>  as an array of String objects.
>
>  When the application gets search continuation references as part of
>  the search data, the continuation references are retrieved by
>  LDAPSearchResultReference.getURLs() as an array of LDAPUrl objects.
>
>  To be consistent, shouldn't both return an array of LDAPUrl objects?

Returning String[] seems more flexible. Steve has recognized that in one of his comments following this one. "...This is because the only way to get the list is via the getURLs() method of the LDAPSearchResultReference.Perhaps it should return the  URLs as a string array, and let the applicationturn them into LDAPUrl objects if desired.  This is backwards to what I said in an earlier e-mail, butnow I see the need for Strings instead of LDAPUrls".

So let's return String[] in both cases.

4.
> An application doing its own referral handling may need to make
>  decisions based on the scheme of URLs returned from search
>  continuation references or referrals.
>
>  Shouldn't the LDAPUrl object provide a method to retrieve
>  the URL scheme, viz. ldap, http, & etc.

This is an LDAP only URL and not a generic URL, so there is no reason to report a URL scheme. However, there is a need to support ldaps with some LDAP servers. To accomodate them, we propose a boolean method isSecure().

5.
> I am puzzled why the draft specifies that automatic referral
>  following is done only for synchronous operations.  While
>  it is simple for an application using async to merge results from
>  multiple listeners or to specify the same listener for multiple
>  requests, it is not so simple to determine when a request
>  and all its child referral requests are complete.  Why put
>  this burden on the application?
>
>  IMO there is no technical reason that automatic referral
>  following mechanisms cannot be used across the board,
>  for both synchronous and asynchronous operations.
>
>  Could you fill me in on the reason for the current design.

When originally implementing the asynchronous interfaces, we looked at this option, but we concluded that implementation would be difficult, and the asynchronous interfaces are intended to allow the client to interact with the protocol at a low level anyway, so it was not unreasonable for the client to manage the interactions. SASL authentication is another feature which is not handled automatically by the API for the asynchronous interfaces, for the same reason.

6.
> Re: referrals as defined in draft-ietf-ldapext-ldap-java-api-11.txt
>
>  The I-D seems silent on what happens if an application has automatic
>  referral handling enabled, and for some reason one or more of the
>  referrals or search continuation references cannot be followed.
>
>  This could happen for at least three reasons:
>  1- The bind fails when explicitly binding using the LDAPBind object
>  2- The bind fails when implicitly binding using anonymous credentials,
>       or when using the LDAPRebind object to obtain credentials
>  3- None of the servers in the referrals list have the scheme ldap://
>     specified and thus are ignored (per the draft) (4.7.10)
>
>  I assume that if automatic referral following succeeds, the
>  application doesn't see any referral URLs, i.e. no LDAPReferralException
>  is thrown when doing LDAPSearchResults.next(), (4.35.4) and
>  LDAPSearchResults.nextElement() (4.35.5) does not return an
>  LDAPReferralException object.
>
>  The draft indicates that LDAPReferralException is only thrown
>  if automatic referral handling has not been enabled.  It doesn't
>  indicate whether the LDAPReferralException object is returned
>  on LDAPSearchResults.getElement(), I assume it is not returned. (4.26)
>
>  So what happens if a referral cannot automatically be followed.
>  I think the application needs to be notified of this error, and the
>  logical way to do that is to return the referral information to
>  the application.
>
>  IMO, LDAPReferralException should be returned / thrown on
>  synchronous operations any time a referral is not followed, not just
>  if automatic referral following is disabled.
>
>  Thus, LDAPReferralException would always be returned / thrown
>  if automatic referal following is not enabled.  If enabled,
>  LDAPReferralException would be thrown / returned when none of
>  the servers in a referral response list can be used to follow the referral
>  and would be treated by the application as an error situation.
>
>  Changing the draft to reflect this will  clear up these issues.

A good point, however there should be more info in the exception, so that the application can clearly differentiate between a referral not being followed and errors during automatic referral following. The actual LDAPException that caused the referral following to fail (cannot connect, auth failed, no such object) could be stored in the LDAPReferralException. The app can then simply check

catch (LDAPReferralException ex) {
    if (ex.getReferralFailureException() == null) {
        // I am supposed to follow referrals
        LDAPUrls[] = ex.getURLs();
        ...
    } else {
        // The SDK could not follow the referral
        System.err.println("Failed to follow referral " + getUrls()[0] + " " +
            ex.getReferralFailureException());
    }

7.
>
>  I would like clarification on how LDAPBind vs LDAPRebind objects
>  are used in the Java API.
>
>  The I-D implies, but never quite says that the two objects don't
>  normally exist in the LDAPConstraints object at the same time.
>  (Implied by Appendix G - LDAPConstraints - they should
>  not be specified on the same constructor)
>
>  They certainly can both be set by using the set methods, but
>  are probably not both used at the same time.
>
>  I surmise from the draft that these objects are used as follows:
>
>  1. Neither object is used unless Referrals are enabled in the
>      LDAPConstraint object (automatic referral following enabled).
>
>  2. An LDAPRebind object is used only if present and if an LDAPBind
>      object is not present in the LDAPConstraint object.
>
>  3. An LDAPBind object is used if present.  If present, the LDAPRebind
>      object is not needed by LDAPConnection as no implicit binding is done.
>      Explicit binding is the responsibility of the LDAPBind object.  Therefore
>      the LDAPRebind object is not used in this case.
>
>  If my guesses are correct, maybe the draft should be clarified as to the
>  usage of these objects.

This is a correct interpretation. An improvement to the I-D would be be to specify a single field in LDAPConstraints - rebindHandler - which would accept either LDAPBind or LDAPRebind. An additional tag interface would need to be declared, somthing like this:

public interface LDAPReferralHandler {  // the tag interface
}

public class LDAPConstraints {
     private LDAPReferralHandler rebindProc;
     ...
}

public interface LDAPBind extends LDAPReferralHandler {
...
}

public interface LDAPRebind extends LDAPReferralHandler {
...
}

8.
> Re: LDAPBind as defined in draft-ietf-ldapext-ldap-java-api-11.txt
>
>  It is unclear from the draft how the LDAPConnection object must be
>  used by an application implementing the LDAPBind interface.
>
>  I am guessing that the LDAPConnection object passed to the bind()
>  method of the LDAPBind implementation is a new LDAPConnection object
>  created by automatic referall following code in the original LDAPConnection
>  object. The object contains the  AuthenticationDN and
>  AuthenticationPassword from the LDAPConnection that the continuation
>  reference was received on. The Host and Port are filled in from the
>  referral/reference host & port. When passed to the bind() method,
>  neither connect nor bind has been performed on this LDAPConnection object.
>
>  In order to make this work, I believe the iimplementation of the
>  LDAPBind.bind() method MUST use the LDAPConnection object, which
>  was passed as a parameter, to perform its connect and bind calls.
>  It then returns success if both operations succeed.  The original
>  LDAPConnection object referral handling code can then use the
>  new LDAPConnection object when it resends the search request,
>  updated with the new search base and possibly search filter.
>
>  The above should be clarified in the draft.

  OK

>  It seems that the LDAPRebind interface would be easier to implement if
>  additional data were provided in the new LDAPConnection object.  Such as:
>
>  1. A reference to the LDAPSocketFactory class from the original LDAPConnection
>      object.  This allows it to connect in the same way as the original connection.
>  2. An LDAPConstraints object containing a reference to the LDAPRebind object
>      from the original LDAPConnection object.  The LDAPBind.bind() method may
>      want to get authentication information using and LDAPRebindAuth object, and
>      this gives it a way to do that.
>  3. The protocol version used in the connect/bind of the original object.  This allows
>      The LDAPBind.bind function to bind with same protocol version used in the
>      original connection.
>  4. The mechanism used when binding.  This could be the mechanism used on the
>      bind in the original LDAPConnection object, or perhaps LDAPRebindAuth could
>      be modified to provide the triplet - UserDN, Password, and Mechanism for the
>      specified host.
>
>  IMO the above changes would give the application, using explicit bind, greater flexibility
>  when dealing with referrals / continuation references during automatic referral
>  following:
>

  It's questionable that this is necessary. Can't you do all that with LDAPBind (rather than LDAPRebind)?

  If it really is required (which duplicates what you can do with LDAPBind), how about the following instead (let the implementation pull whatever it needs from the original connection, as LDAPBind does)?

LDAPConnection bind(String ldapurl, LDAPConnection origConn);

9.  (from Kurt)
> You might consider renaming getSubTypes to getOptions as
> not all options (e.g. ;binary) are subtypes.

  Not worth changing, I don't think.

10.
> The I-D interchanges referrals and search continuation references.
>
>  A referral happens only on an operation and no other results are returned.
>
>  A search continuation reference happens only on a search and is mixed in with
>  returned search entries.
>
>  The I-D refers to continuation references only in section 2.2 and 2.34.
>
>  It sometimes uses referrals where search continuation references should
>  be used, and generally where both apply.
>
>  Line 473 - referred to -> referred-to
>
>  The following should probably refer to both referrals and continuation references
>  Section 1: line 459, 468
>  Section 2.2: LDAPRebind / LDAPBind
>  Section 2.3 - LDAPRebindAuth
>  Section 2.4 - LDAPReferralException
>  Section 4.4 - LDAPBind
>  Section 4.7.x - doReferrals / binder /reauth / hop_limit
>  Section 4.7.x - RebindProc, BindProc, Referrals
>      as well as the methods to get and set the above
>  Section 4.24 - LDAPRebindAuth
>  Section 4.25 - LDAPRebind
>  Section 4.26 - LDAPReferralException
>  Section 4.27 - LDAPResponse
>
>  The following refer to search references
>
>  Section 4.31.1 - LDAPSearchConstraints - doReferrals, reauth binder, hop_limit params
>  Section 4.35.4 - LDAPSearchResults.next()
>  Section 4.35.5 - LDAPSearchResults.nextElement()
>  Section 4.39.13 - SetOption ( search options relating to referrals)
>

Yes. The API makes the distinction transparent to the user of the API. The I-D could state that more explicitly.

11.
> Resend - properly indicating where comments are
>
> Steve Sonntag wrote:
>
> >  Re: LDAPBind as defined in draft-ietf-ldapext-ldap-java-api-11.txt It
> > is unclear from the draft how the LDAPConnection object must beused by
> > an application implementing the LDAPBind interface. I am guessing that
> > the LDAPConnection object passed to the bind()method of the LDAPBind
> > implementation is a new LDAPConnection objectcreated by automatic
> > referall following code in the original LDAPConnectionobject. The
> > object contains the  AuthenticationDN andAuthenticationPassword from
> > the LDAPConnection that the continuationreference was received on. The
> > Host and Port are filled in from thereferral/reference host & port.
> > When passed to the bind() method,neither connect nor bind has been
> > performed on this LDAPConnection object. In order to make this work, I
> > believe the iimplementation of theLDAPBind.bind() method MUST use the
> > LDAPConnection object, whichwas passed as a parameter, to perform its
> > connect and bind calls.It then returns success if both operations
> > succeed.  The originalLDAPConnection object referral handling code can
> > then use thenew LDAPConnection object when it resends the search
> > request,updated with the new search base and possibly search filter.
>
> It is also necessary that the application implementing the
> LDAPBind.bind()
> method use a synchronous bind do bind to the referred-to-server, or
> if using an asyncronous bind, it must wait until the bind operation has
> completed before returning status.

This is the same as #8.

12.
> Re: Referrals on operations as defined
>        in draft-ietf-ldapext-ldap-java-api-11.txt
>
>  When a referral occurs on an asynchronous operation
>     the referral is returned as an LDAPResponse object.
>     The referral info is obtained using the getReferrals() method.
>
>  When a referral occurs on a synchronous operation
>      An LDAPException is thrown.  The exception object is
>      specialized as an LDAPReferralException object and
>      the referral info can be obtained via the getURLs() method
>      with appropriate casting on the object.
>
>  Is this correct?
>
>  Should the doc be clarified?

Yes this is correct. For asynch interfaces exceptions are raised only for connection errors. LDAP result messages are converted into LDAPResponse objects which are to be checked by the app for errors and referrals. Again, asynch interfaces operate at a low level, close to the protocol.

13.
>
>  Section 4.40.3: - LDAPv3.extendedOperation
>     Shouldn't this method have a method that
>     includes LDAPConstraints as an argument.
>    The protocol allows extended operations to
>    support controls.

OK.

>  Section 4.40.2 - LDAPV3.connect
>    This special version of connect is really
>    a connect and a bind combinded.  Should
>    this also have a method with an LDAPConstraints
>    object? - or if the application needs that
>    should they just do the two separate operations
>    and put the LDAPConstraints on the bind?

Let's remove the method from the I-D. It's just a convenience.

14.
>
>  I think the draft should describe more fully the
>  semantics of the implicit bind w/r automatic referral following:
>
>  I will describe what the I-D describes and where
>  I have questions:
>
>  1. Authentication - uses anonomyous credentials unless
>     LDAPRebind specified in LDAPConstraints.

Yes

>  2. Protocol Version ?? - Does it use the same protocol
>      version as the LDAPConnection receiving the referral or is it
>      always V2??  I vote for the having it the same as the originating
>      connection.

Yes.

>  3. AuthenticationMethod: Is it the same as the originating connection,
>      or is it "simple" - I assume simple is used.

Yes. LDAPBind must be used if SASL is desired for the referral connection.

>  4. Does it use the LDAPSocketFactory if specified on the
>      originating connection.  I am not sure what to do here.
>      It seems better to use it if available, then an encrypted
>      connection can be established and thus prevent
>      clear text password transmittion on the wire.  I just
>      talked myself into it - it should be used.

If the referral ldap url specifies ldaps, the referral connection should use ldaps (regardless of the original connection). At least in our implementation :-) - since ldaps is being deprecated in favor of startTLS, we may not want to mention it in this I-D (I just remembered that I owe LDAPEXT an informational RFC draft on ldaps). For startTLS, I guess the referral connection should attempt to use startTLS if the original connection was in startTLS mode. Is there any other way to determine whether or not to use startTLS?

15.
>  When performing a search it is possible for the server
>  to return multiple search continuation references, each
>  with a different search base.
>
>  The I-D states that when retrieving results from a
>  search using LDAPSearchResults.next() that all the
>  results are returned to the application after which
>  on the last call to next() an LDAPReferralException
>  is thrown.
>
>  My question is: how does the application get the
>  rest of the continuation references, as a
>  ReferralException object encapsulates the
>  reference list from one search continuation reply.
>
>  If the application did another next() call would
>  another LDAPReferralException be thrown?
>  How would the application know when to stop?
>  Does it check the enumeration count to see if
>  more items exist in the enumeration, and thus
>  continue to call next() and get an LDAPReferralException
>  each time.  As an alternative, the application
>  could switch to calling nextElement() to get the
>  rest of the search references as LDAPReferralException
>  objects.  How do you envision the application doing this?
>
>  The I-D should make it clear that the application
>  can get more than one search continuation
>  reference, and indicate a mechanism to deal
>  with the situation.
>

The app should continue as long as hasMoreElements() returns true. Calling nextElement() is not a good idea. The following example from the Mozilla implemenation javadocs demonstrates proper handling. Note the "continue" after the exception has been processed.

LDAPSearchResults res = ld.search( MY_SEARCHBASE,
                              LDAPConnection.SCOPE_BASE, MY_FILTER,
                              null, false );
      while ( res.hasMoreElements() ) {
        try {
          LDAPEntry findEntry = res.next();
        } catch ( LDAPReferralException e ) {
          LDAPUrl refUrls[] = e.getURLs();
          for ( int i = 0; i < refUrls.length; i++ ) {
          // Your code for handling referrals
          }
          continue;
        } catch ( LDAPException e ) {
          // Your code for handling errors on limits exceeded
          continue;
        }
        ...
      }

16.
>
>  Since LDAPResponseListener and LDAPSearchListener
>  objects implement exactly the same set of methods,
>  does it seem reasonable that an interface be created
>  named something like LDAPListener that specifies
>  those four methods, and that LDAPSearchListener
>  and LDAPResponseListener implement this interface.
>  This forces those methods to stay the same in both classes.
>

> If an LDAPListener interface were created, then
> the two methods in LDAPv2.abandon
>
>    public void abandon(LDAPSearchListener listener)
>    public void abandon(LDAPResponseListener listener)
>
> Could be combined into one
>
>    public void abandon(LDAPListener listener)

We have responded to this earlier, but here is a brief recap. In the very first asynch draft, LDAPSearchListener extended LDAPResponseListener. Later when we adding abandon(int) method, we investigated removing LDAPSearchListener and leaving only LDAPResponseListener because there were implementation issues (multiplexing, and raising exceptions as a result of a lost connection). Then, in order not to change the draft considerably, we decided to make only minor changes and just resolve the implementation problems. We kept LDAPSearchListener, but it does not extend LDAPResponseListener any more.

17.
>
>  4.6.19 setConstraints
>
>  Sets the constraints that apply to all operations performed
>  through this connection
>
>  Wouldn't it be more clear to state:
>
>  Sets the constraints that apply to all non search operations
>  performed through this connection.
>  - - - - - - - - - - - - - - - - - - - -

The constraints (hop limit, bind handler, referrals, timeout, controls) apply to all operations (including search operations).

>  4.39.13 setOption
>
>  Seems to set only the search constraints options, but
>  the first paragraph has a confusing sentence that
>  talks about LDAPConstraints.
>
>  Was it your intention that the LDAPConstraints be
>  the same object as LDAPSearchConstraints or
>  that they be different objects?
>
>     "These options represent the default search constraints for the
>     current connection. Some of these options are also propagated through
>     the LDAPConstraints, which can be obtained from the connection object
>     with the getSearchConstraints method."
>  The above two sections 4.39.13 & 4.6.19 could be
>  construed to indicate that the LDAPConstraints and the
>  LDAPSearchConstraints objects for a connection are
>  in fact the the same object, however, that fact that
>  each has a separate set & get method seems to indicate
>  they are different objects.
>
>  Could you please clarify this?
>

Yes this is intentional. Originally we had only LDAPSearchConstraints but it did not make a lot of sense to use  "search" constraints for non-search operations. We separated the interfaces such that LDAPSearchConstraints extends LDAPConstraints and all properties set on LDAPConstraints are also visible in LDAPSearchConstraints.

But see 1.4 above.

18.
>
>  4.39.1 LDAPv2.abandon
>
>  The RFC 2251 and the C api draft allow controls to be specified
>  on an abandon operation.  In java it is allowed only using the default
>  constraints object or search constraints object.  Should methods
>  be defined that allow constraints to be specified on abandon?

Strictly speaking this is true, but if we look at the properties in LDAPConstraints, none of them are applicable to abandon(). This change is not required.

>  When calling abandon( int id), it is unclear whether LDAPConstraints
>  or LDAPSearchConstraints should be used for the default
>  constraints.

LDAPSearchConstraints is only for search.

19.

> The JAVA LDAP API (draft-ietf-ldapext-ldap-java-api-11.txt) defines the following method for
> extended operations:
>
>
> "public LDAPExtendedOperation extendedOperation(LDAPExtendedOperation op) throws
> LDAPException"
>
> I would think that you would return an LDAPExtendedResponse object rather than an
> LDAPExtendedOperation object. I agree that one could reuse the LDAPExtendedOperation object
> (as it has the same set of fields) but then why bother defining a LDAPExtendedResponse object
> in the draft?
>

OK.

20.

>  Section 4.7.11 LDAPConstraints.setTimeLimit
>
>  LDAP Constraints applies to all operations, not just search operations.
>
>  The first sentence should probably be changed from:
>
>       Sets the maximum number of milliseconds to wait for any operation
>       under these search constraints.
>  To something like:
>
>       Sets the maximum number of milliseconds the client waits for any operation
>       under these constraints.
>
>  Section 4.7.5 LDAPConstraints.getReferrals
>
>      Change nor to or
>
>      Specifies whether nor not ...
>
>  -Steve
>

OK.

21
LDAPSortKey.

> It is still listed in section 2.2
>
>  >>> Rob Weltman  01-Sep-00 2:59:45 PM >>>
>    Someone pointed out that LDAPSortKey is not used/referenced, so I removed it from the draft.
>
>    In the Netscape implementation, it is used by LDAPSortControl. The current API draft does not cover any particular controls.
>

OK

22.

> Re: LDAP_PARTIAL_RESULTS Result Code defined in
> section 4.16.6 of draft-ietf-ldapext-ldap-java-api-11.txt
>
> Section 4.16.6 instructs the reader to review RFC 2251 for
> a discussion of the meanings of the codes defined in that
> section.
>
> RFC 2251 does not discuss the meaning of the LDAP_PARTIAL_RESULTS
> result code. Should this be defined or referenced in this draft?
>
OK.

23.

> In the Bibliography, [3] refers to RFC 1960.
>
>  Shouldn't it refer to RFC 2254 instead?
>

OK.

24.

>  4.40.1
>
>  In the explaination of bind operations that use mechanisms should the first
>  Paragraph be changed from
>
>     Authenticates to the LDAP server (that the object is currently
>     connected to) using the specified name and of a specified set of
>     mechanisms. If none of the requested SASL mechanisms is available, an
>
>      Authenticates to the LDAP server (that the object is currently
>     connected to) using the specified name and ONE of a specified set of  <----
>     mechanisms. If none of the requested SASL mechanisms is available, an
>

OK.

>  What does it mean -
>
>     if the first version of the method (i.e. the one that specifies no mechanism)
>     is called, the LDAP server will be interrogated for its
>     supportedSaslMechanisms attribute of its root DSE.
>
>  What does it do after the LDAP server is interrogated?  Does it use one
>  of them, and if so how does the application know which one is used
>  and how does it know what kind of credentials to supply?
>

Yes, if no mechanisms are specified, the mechanisms supported by the server are processed until one is mutually agreed on. The callback handler is called to obtain credentials. Are you thinking that the credentials to be returned depend on the mechanism being negotiated? Let me think about that a little...

25.

>  4.40.1 bind specifying a mechanism
>
>  It would seem that if the mechanism is "simple"
>  that the API should specify how the password
>  is to be specified in the Hashtable object props
>  so that it is consistent across implementations.
>  Other mechanisms and associated Hashtable
>  values are the subject of other I-Ds.
>
>
>  My suggestions:
>
>        props.put("password", new String("user-password-value");)
>

  Credentials are obtained from the callback handler.

26.

> Shouldn't the SASL bind mechanisms also support the ability
> for the application to specify an LDAPConstraints
> object so that call specific controls can be specified?
>

OK.

27.

> When using an explicit bind for referrals where sasl mechanisms
> were used on the original LDAPConnection, the LDAPBind.bind()
> method will need access to the Hashtable parameter passed on the
> bind to get the credentials used.  A method needs to be
> supplied in LDAPConnection to get the Hashtable object with
> semantics similar to what is now used for getAuthenticationPassword()
>

  Does it need to be a public method? Can't it be a package scope (implementation-defined) method?

28.

> I am trying to understand the encode/decode functions
>  in the LDAPUrl class.
>
>  I assume that the encode method turns unsafe characters
>  (as defined by RFC1738, RFC 2255, & etc.) into characters
>  of the form %HH and that decode turns those characters
>  back into the raw unencoded characters.
>
>  Question 1: The reference to decoding "+" into " "
>  and encoding " " into "+" .  I could not find any reference
>  to the need for doing this in the RFCs.  Could someone
>  please tell me why someone might expect that this behavior?
>
  " " does not need to be encoded in LDAP URLs.

>  Question 2:  What kind of strings do the constructors of the
>  LDAPUrl class expect.  Do the constructors expect the
>  strings to be already encoded?
>

  Yes.

>  Question 3:  Does the encode method take into account the field
>  in the URL when doing the encoding (e.g. filters vs. base DN) which
>  may have different reserved characters and thus slightly different
>  encoding rules — which boils down to the real question - does
>  the encode function expect a full correctly formatted URL
>  or can one hand it just the base-DN, or just the filter and
>  expect it to be correctly encoded?
>
>  i.e., does the LDAPUrl constructor with individual parts expect
>  encoded strings and will the encode function do it?
>

  LDAPUrl.encode() expects to receive a string to be encoded. For all practical purposes, it should be a DN or a filter string (and not a full LDAP URL). After encoding, the DN and filter can be passed to the LDAPUrl constructor.

29.

> 4.16 LDAPException
>
>  The LDAPException class has a method getMatchedDN() but has no way to set
>  the matched DN in the object.  Shouldn't there be a constructor with MatchedDN
>  as a parameter?
>
> Steve,
>
>  I wouldn't think so.  This is really meant to provide access to what a SERVER responds with, and thus I wouldn't know why a CLIENT would want to
>  "setMatchedDN()".
>
>  Regards,
>  Tim Hahn
>
> I was thinking from the API perspective.  An implementation of the API would need to
>  take the ber encoded packet and extract from it the matched DN, and then
>  generate the exception.  My point is that the API needs to be
>  able to set the matchedDN data in the exception.  Are you suggesting that it
>  should use a package method?  The only problem with a package method
>  is that an extension written in a different package may also need to set
>  matchedDN when generating an exception, but wouldn't have any way
>  to set the value.
>

  Is that realistic - that a class in some other package would create an exception and put in its own matchedDN?

30.

> 4.26 LDAPException
>
>  I am trying to understand where the information in the
>  constructor serverMessage comes from.  I am not
>  aware of any message that is returned by the server with a
>  referral result, except for the actual referral URLs.
>
>  Do you intend that the class gets primed with the
>  referral URLs using the serverMessage parameter
>  and if so how are the referrals delimited - otherwise
>  can you elaborate on the meaning of this parameter
>  and explain how the referral URLs are placed into the
>  class.
>

  That is correct. The server returns the referral URLs in the message field. I don't know if it is necessary to define the representation there (it is a contract between the upper layer of an implementation and the BER decoding layer - which is not defined in the I-D); clients query getURLs() to get the URLs.

31.

> In draft-ietf-ldapext-ldap-c-api-04.txt section 11.6 Searching, it states:
>
> filter       A character string as described in [13], representing the
>              search filter.  The value NULL can be passed to indicate
>              that the filter "(objectclass=*)" which matches all entries
>              is to be used.
>
> It might be helpful to note this behavior in sections 4.38.1 and 4.39.12 of
> draft-ietf-ldapext-ldap-java-api-11.txt. (Which would make those sections
> consistent with 4.38.8 of the same draft which states that (objectclass=*)
> is the default filter.)
>
  OK.

32.

> Also, in the Bibliograpy, [7] should be updated. (To draft-ietf-ldapext-ldap-c-api-04.txt)
>
  OK.

---

From: Steven Sonntag <[email-masked]>
Date: Mon, 25 Sep 2000 15:18:27 -0600

Rob Weltman wrote:

>   LDAPSearchConstraints extends LDAPConstraints. There is only one
> such object per connection, and it is an LDAPSearchConstraints. If
> there was an LDAPConstraints object as well, there would be ambiguity
> as to which object controlled operations other than search.   Also,
> see 4 below (which renders this issue mute)

The thing that is confusing to me is that in the LDAPConnection object
there are the following methods:

getConstraints()
getSearchConstraints()
setConstraints()
setSearchConstraints()

Since, as you say, there is only one object per connection, there is
still confusion.  If the
application calls the setConstraints() method with an LDAPConstraints
object, then
there are no search constraints at all, since the added functionality of
the LDAPSearchConstraints
specialization is not present.  Having the four methods make it seem
like there are two separate objects,
or at least that is the way I read it.  Maybe all that is needed is the
set|getConstraints which takes
an LDAPSearchConstraints object and eliminate the other two methods.

-Steve

---

From: Steven Sonntag <[email-masked]>
Date: Mon, 25 Sep 2000 16:07:20 -0600

> LDAPConnection bind(String ldapurl, LDAPConnection origConn);

Sorry, I was saying Rebind, but meaning LDAPBind.  Your solution is a
good one and resolves my concerns.
Does there need to be a way to get protocol version from the
LDAPConnection for the use of LDAPBind?

-Steve

---

From: Rob Weltman <[email-masked]>
Date: Mon, 25 Sep 2000 21:10:46 -0700

> an LDAPSearchConstraints object and eliminate the other two methods.

  In our implementation, setConstraints() just sets the properties of LDAPConstraints, leaving the search-specific properties untouched. setSearchConstraints() replaces all properties. I haven't heard any reports of confusion from the field.

Rob

---

From: Rob Weltman <[email-masked]>
Date: Mon, 25 Sep 2000 21:18:54 -0700

> LDAPConnection for the use of LDAPBind?

  In our implementation, you can get the bind protocol version with
       LDAPConnection.getOption( LDAPv2.PROTOCOL_VERSION)

  If we eliminate get/setOption, I guess we'll need to move that property to LDAPConstraints.

Rob

---

From: Steven Sonntag <[email-masked]>
Date: Wed, 27 Sep 2000 13:58:25 -0600

>   In our implementation, setConstraints() just sets the properties of LDAPConstraints, leaving the search-specific properties untouched. setSearchConstraints() replaces all properties. I haven't he…

Just to clarify if I understand it correctly

I am/was confused because I was seeing in my minds eye setConstraints implemented
as storing the object somewhere internal to the class, and the same for setSearchConstraints.

You must be seeing an implementation where a single LDAPSearchConstraints objecct
exists internally, and the search constraints fields are copied on setConstraints() to the
internal object, and the search constraints fields are copied on setSearchConstraints().

However getConstraints and getSearchConstraints return a reference to the single internal object.

--
------------------------
Steve Sonntag
Novell, Inc., the leading provider of Net services software

---

From: Steven Sonntag <[email-masked]>
Date: Wed, 27 Sep 2000 14:03:01 -0600

Rob,

Here are my responses to all of the issues except two.  Those I will
address in a separate e-mail.
In the responses below, I have elimated the text except the number and
first sentence of the topic for most
of my "OK" responses.  Those where I had more than an OK comment, are
quoted more fully.

Thanks for your time.

-Steve

Rob Weltman wrote:

>   I've collected all the issues raised (hope I didn't miss any) and
> responded in short to each one. Many thanks to Miodrag for helping me
> evaluate the issues. And to Steve and Steven for raising them :-)
>
> Rob
>
>
> 1.
> > Section 4.39.13 LDAPV2.setOption ...

OK

>
> >   2) STRING_FORMAT is set only by the setOption method. ...

OK

>
> >   3) setOption operates only on the LDAPSearchConstraints object ...

See separate e-mail

>
> >   4) All functionality of SetOption can be performed by code ...

OK

>
> 2.
> > If references to LDAPv2 are not removed from the draft, ...

OK

> Returning String[] seems more flexible. Steve has recognized that in
> one of his comments following this one. "...This is because the only
> way to get the list is via the getURLs() method of the
> LDAPSearchResultReference.Perhaps it should return the  URLs as a
> string array, and let the applicationturn them into LDAPUrl objects if
> desired.  This is backwards to what I said in an earlier e-mail,
> butnow I see the need for Strings instead of LDAPUrls".
>

Should the method names be unified, i.e. use getReferrals() instead of
getUrls() ??

> This is an LDAP only URL and not a generic URL, so there is no reason
> to report a URL scheme. However, there is a need to support ldaps with
> some LDAP servers. To accomodate them, we propose a boolean method
> isSecure().

OK - Don't forget toadd this field to the constructors.

> 5.
> > I am puzzled why the draft specifies that automatic referral ...

OK

OK

> This is a correct interpretation. An improvement to the I-D would be
> be to specify a single field in LDAPConstraints - rebindHandler -
> which would accept either LDAPBind or LDAPRebind. An additional tag
> interface would need to be declared, somthing like this:
>

My only objection to this is that I had it in mind that the application
may want to use
the LDAPRebindProc to provide credentials for the LDAPBind.bind()
method.
It is reasonable to think an application might do this??  Having one
object certainly
makes it simpler for the application writer to understand the behavior.

So, OK, I agree.

OK

> >  additional data were provided in the new LDAPConnection object.

( ... )

>   If it really is required (which duplicates what you can do with
> LDAPBind), how about the following instead (let the implementation
> pull whatever it needs from the original connection, as LDAPBind
> does)?
>

But LDAPBind doesn't - it returns a void.  If you change it to the
above,
i.e. returns LDAPConnection (the new connection) then - OK.

OK

OK

OK

OK

OK

OK

OK

> >  2. Protocol Version ?? - Does it use the same protocol

As long as it is added to the constraints so it can be retrieved.

OK

> If the referral ldap url specifies ldaps, the referral connection
> should use ldaps (regardless of the original connection). At least in
> our implementation :-) - since ldaps is being deprecated in favor of
> startTLS, we may not want to mention it in this I-D (I just remembered
> that I owe LDAPEXT an informational RFC draft on ldaps). For startTLS,
> I guess the referral connection should attempt to use startTLS if the
> original connection was in startTLS mode. Is there any other way to
> determine whether or not to use startTLS?

IMO the application if the connection is in startTLS mode, the new
connections should also be startTLS.  Likewise,
LDAPBind.bind() needs to be able to determine if the connection is in
startTLS mode so it can also do startTLS, thus
the app needs to be able to query if the connection is in startTLS mode.

> 15.
> >  When performing a search it is possible for the server ...

OK - Just fix the wording a little to reflect this.  4.35.4
. the last time it is called ..
seems pretty final, when it really means all referral
exceptions are the last elements of the enumeration.

> We have responded to this earlier, but here is a brief recap. In the
> very first asynch draft, LDAPSearchListener extended
> LDAPResponseListener. Later when we adding abandon(int) method, we
> investigated removing LDAPSearchListener and leaving only
> LDAPResponseListener because there were implementation issues
> (multiplexing, and raising exceptions as a result of a lost
> connection). Then, in order not to change the draft considerably, we
> decided to make only minor changes and just resolve the implementation
> problems. We kept LDAPSearchListener, but it does not extend
> LDAPResponseListener any more.

I get the feeling we are talking about different things.
I wasn't describing LDAPSearchListener extending LDAPResponseListener,
but both
implementing a common interface, viz. LDAPListener, with methods
getMessageIDs(), getResponse(), isResponseReceived(),
and merge().  All four of  the methods of each class have identical
signatures.  Doing this reduces abandon to one call, which
can easily do exactly what it is doing now by using the instanceof
operator.

> >  4.6.19 setConstraints

See separate e-mail, same as 1.3

> Strictly speaking this is true, but if we look at the properties in
> LDAPConstraints, none of them are applicable to abandon(). This change
> is not required.

Suppose an application needed to put a control on an abandon operation.
What then?

OK

OK

OK

OK

OK

OK

> Yes, if no mechanisms are specified, the mechanisms supported by the
> server are processed until one is mutually agreed on. The callback
> handler is called to obtain credentials. Are you thinking that the
> credentials to be returned depend on the mechanism being negotiated?
> Let me think about that a little...

That is what I am thinking.  Is perhaps the ChoiceCallback used in some
way to communicate the negogiated choice, or to
influence the negotiation possibilities the app will accept?  This area
is pretty new to me.

>   Credentials are obtained from the callback handler.

I was thinking of the same semantics as getPasswd() where the original
credentials were
contained in the HashTable.  But as you say, the credentials should be
obtained
from the callbackHandler. If the application is handling multiple
connections each with different characteristics and possibly different
users, it would need
a different callback handler for each connection.  The callback handler
needs to be
available for implicit bind and explicit bind, and needs to be set in
the new connection by
the explicit bind method.  Do we need a mechanism them to get the
callbackHandler?

What is contained in HashTable if not the credentials??

OK

> (implementation-defined) method?

I was thinking it does need to be a public method as the explicit Bind
method may need access to it.

OK

> (...)
>   Is that realistic - that a class in some other package would create
> an exception and put in its own matchedDN?

You are right, I was not thinking straight on this one.

>   That is correct. The server returns the referral URLs in the message
> field. I don't know if it is necessary to define the representation
> there (it is a contract between the upper layer of an implementation
> and the BER decoding layer - which is not defined in the I-D); clients
> query getURLs() to get the URLs.
>

A ldap_result  is made up of errmsg, referral, result, matched-dn.  Were
you thinking of the error message field for ServerMessage?

OK

OK

---

From: Rob Weltman <[email-masked]>
Date: Wed, 27 Sep 2000 18:14:29 -0700

> However getConstraints and getSearchConstraints return a reference to the single internal object.

  That is absolutely correct!

Rob

---

From: Rob Weltman <[email-masked]>
Date: Wed, 27 Sep 2000 18:43:26 -0700

> of my "OK" responses.  Those where I had more than an OK comment, are

  Cool. I'll add a little to the remaining ones.

  OK

> OK - Don't forget toadd this field to the constructors.

  For LDAPUrl? Do we need it there if referrals are only reported as strings?

> i.e. returns LDAPConnection (the new connection) then - OK.

  Let me look into that a little.

  OK

  OK

  OK

> can easily do exactly what it is doing now by using the instanceof

  Sounds reasonable, but let me think about it a little more.

> Suppose an application needed to put a control on an abandon operation.

  True. OK

> influence the negotiation possibilities the app will accept?  This area

  I'm working on that area, too - as spec lead for JSR 28 in the JCP. I think it's a general SASL question, not one specific to the LDAP API. I'll need a little more time to clarify this item.

> the explicit bind method.  Do we need a mechanism them to get the

  I don't think so. It is not persistent in the connection.

> What is contained in HashTable if not the credentials??

  See http://www.ietf.org/internet-drafts/draft-weltman-java-sasl-03.txt, pages 7 - 8.

> method may need access to it.

  I need to think about that some more.

> you thinking of the error message field for ServerMessage?

  That's what is used in our implementation, but I don't think it matters - the client of the API should call getURLs() (or now, getReferrals()) to get the referrals. The client shouldn't need to know how they are stored internally.

Rob

---

From: Steven Sonntag <[email-masked]>
Date: Fri, 29 Sep 2000 15:38:52 -0600

A few remaining comments

>   For LDAPUrl? Do we need it there if referrals are only reported as strings?

Are you thinking to eliminate the LDAPUrl class?
IMO it is certainly very useful when one needs to break apart a URL.
Connection.search( LDAPURL toGet) needs it, which I believe to
be a very useful function. An application doing its own referral
following certainly needs to break referrals apart, and what better
way than with the LDAPUrl class.  It makes a very nice utility class.
I say keep it.

>   Let me look into that a little.

I think bind() just has the wrong return type.

>   Sounds reasonable, but let me think about it a little more.

OK - seems reasonable to me also.

>   I don't think so. It is not persistent in the connection.

I'm just trying to figure out how to solve the problem of multiple connections,
each with different connection characteristics, perhaps different users.
When doing an explicit bind, how does the application get credentials
specifiic to that connection/user.  Would the callback handler being
persistent help solve this, or ??

>   See http://www.ietf.org/internet-drafts/draft-weltman-java-sasl-03.txt, pages 7 - 8.

Thanks, I had missed that one.