Ruby-ldap rebinding?

Can anyone tell me where I'm going wrong here?
I'm trying to write a very simple ldap authenticator, which does

get user and pass
open connection to server
bind anonymously
map the user to a dn
bind as dn and pass <- this goes boom

when I rebind I get an error. Here's a cut down version:

$ irb -r ldap
irb(main):001:0> conn = LDAP::SSLConn.new('ldap.server',389,true)
=> #<LDAP::SSLConn:0x812ec70>
irb(main):002:0> a = conn.bind
=> #<LDAP::SSLConn:0x812ec70>
irb(main):003:0> a.unbind
=> nil
irb(main):004:0> b = conn.bind
LDAP::InvalidDataError: The LDAP handler is already unbind()'ed.
        from (irb):4:in `bind'
        from (irb):4

if I omit the unbind(), I get 'The LDAP handler is already binded'

That's some catch, that catch 22....

···

--
'In the beginning the Universe was created. This has made a lot of people
very angry and been widely regarded as a bad move.'
    -- The Guide
Rasputin :: Jack of All Trades - Master of Nuns

Conn#unbind doesn't just unbind from the server; it also destroys the
connection object when it calls ldap_unbind().

From ldap_unbind(3):

UNBINDING
       The ldap_unbind() call is used to unbind from the directory,
       terminate the current association, and free the resources
       contained in the ld structure. Once it is called, the connection
       to the LDAP server is closed, and the ld structure is
       invalid. The ldap_unbind_s() call is just another name for
       ldap_unbind(); both of these calls are synchronous in
       nature.

So, think of Conn#unbind as being more of a Conn#destroy, in that the
Conn object effectively no longer exists after the unbind.

Cheers,

Ian

···

On Thu 10 Mar 2005 at 20:46:51 +0900, Dick Davies wrote:

Can anyone tell me where I'm going wrong here?
I'm trying to write a very simple ldap authenticator, which does

get user and pass
open connection to server
bind anonymously
map the user to a dn
bind as dn and pass <- this goes boom

when I rebind I get an error. Here's a cut down version:

$ irb -r ldap
irb(main):001:0> conn = LDAP::SSLConn.new('ldap.server',389,true)
=> #<LDAP::SSLConn:0x812ec70>
irb(main):002:0> a = conn.bind
=> #<LDAP::SSLConn:0x812ec70>
irb(main):003:0> a.unbind
=> nil
irb(main):004:0> b = conn.bind
LDAP::InvalidDataError: The LDAP handler is already unbind()'ed.
        from (irb):4:in `bind'
        from (irb):4

if I omit the unbind(), I get 'The LDAP handler is already binded'

--
Ian Macdonald | Time is but the stream I go a-fishing in.
System Administrator | -- Henry David Thoreau
ian@caliban.org |
http://www.caliban.org |
                            >

* Ian Macdonald <ian@caliban.org> [0345 06:45]:

···

On Thu 10 Mar 2005 at 20:46:51 +0900, Dick Davies wrote:
> get user and pass
> open connection to server
> bind anonymously
> map the user to a dn
> bind as dn and pass <- this goes boom
>
> when I rebind I get an error. Here's a cut down version:
>
> $ irb -r ldap
> irb(main):001:0> conn = LDAP::SSLConn.new('ldap.server',389,true)
> => #<LDAP::SSLConn:0x812ec70>
> irb(main):002:0> a = conn.bind
> => #<LDAP::SSLConn:0x812ec70>
> irb(main):003:0> a.unbind
> => nil
> irb(main):004:0> b = conn.bind
> LDAP::InvalidDataError: The LDAP handler is already unbind()'ed.
> from (irb):4:in `bind'
> from (irb):4

> if I omit the unbind(), I get 'The LDAP handler is already binded'

Conn#unbind doesn't just unbind from the server; it also destroys the
connection object when it calls ldap_unbind().

From ldap_unbind(3):

UNBINDING
       The ldap_unbind() call is used to unbind from the directory,

Ok thanks - I've used Perl::LDAP in the past which lets you rebind and
existing connection.

Can I do that with ruby-ldap, or do I need a new connection every time
I check a username/password pair?

--
'Oh, wait you're serious. Let me laugh even harder.'
    -- Bender
Rasputin :: Jack of All Trades - Master of Nuns

Yes, I'm afraid you need a new connection to bind as a different user.
On the other hand, is you only want to check the validity of a username
and password combination, you should be able to pull that information
from the directory as a user with the privileges required to view
passwords.

Ian

···

On Fri 11 Mar 2005 at 20:38:31 +0900, Dick Davies wrote:

* Ian Macdonald <ian@caliban.org> [0345 06:45]:

> Conn#unbind doesn't just unbind from the server; it also destroys the
> connection object when it calls ldap_unbind().
>
> From ldap_unbind(3):
>
> UNBINDING
> The ldap_unbind() call is used to unbind from the directory,

Ok thanks - I've used Perl::LDAP in the past which lets you rebind and
existing connection.

Can I do that with ruby-ldap, or do I need a new connection every time
I check a username/password pair?

--
Ian Macdonald | All this wheeling and dealing around, why,
System Administrator | it isn't for money, it's for fun. Money's
ian@caliban.org | just the way we keep score. -- Henry
http://www.caliban.org | Tyroon
                            >

* Ian Macdonald <ian@caliban.org> [0303 20:03]:

> Ok thanks - I've used Perl::LDAP in the past which lets you rebind and
> existing connection.
>
> Can I do that with ruby-ldap, or do I need a new connection every time
> I check a username/password pair?

Yes, I'm afraid you need a new connection to bind as a different user.
On the other hand, is you only want to check the validity of a username
and password combination, you should be able to pull that information
from the directory as a user with the privileges required to view
passwords.

Yeah, but then I need to code an admin user/pass pair into my script,
and that sort of thing gives me the heeby-jeebies..

I suspect perl-ldap actually drops and reloads the connection in any case,
I'm not sure whether the C API lets you reuse a connection by rebinding
as another user.

Looks like I might have to actually open that LDAP programmers guide I got
on ebay before christmas, rather than just letting it sit on the shelf... :slight_smile:

Thanks for your help anyway!

···

On Fri 11 Mar 2005 at 20:38:31 +0900, Dick Davies wrote:

--
'Robots don't have emotions, and that sometimes makes me feel sad.'
    -- Bender
Rasputin :: Jack of All Trades - Master of Nuns

* Ian Macdonald <ian@caliban.org> [0303 20:03]:
>
> Yes, I'm afraid you need a new connection to bind as a different user.
> On the other hand, is you only want to check the validity of a username
> and password combination, you should be able to pull that information
> from the directory as a user with the privileges required to view
> passwords.

Yeah, but then I need to code an admin user/pass pair into my script,
and that sort of thing gives me the heeby-jeebies..

You could consider using SASL and something like GSSAPI instead, but
that might be a lot of work if you're not already set up for it.

I suspect perl-ldap actually drops and reloads the connection in any case,
I'm not sure whether the C API lets you reuse a connection by rebinding
as another user.

It doesn't.

Perhaps Net::LDAP remembers the details of the connection when it was
opened and silently performs another open when you perform a bind after
an unbind, but at some point, you're still opening a new connection.
It's just a question of whether it's implicit or explicit.

Ruby/LDAP could be made to do this, too, I think. The details passed to
LDAP::Conn.new could be put into instance variables. If the connection
is dead at bind time, these could be read and used to transparently
reestablish the connection before conducting the bind.

I'll look at how hard this would be to ship up in practice.

Ian

···

On Sat 12 Mar 2005 at 05:39:42 +0900, Dick Davies wrote:
--
Ian Macdonald | There's something different about us --
System Administrator | different from people of Europe, Africa,
ian@caliban.org | Asia ... a deep and abiding belief in the
http://www.caliban.org | Easter Bunny. -- G. Gordon Liddy
                            >

This feature is now in Ruby/LDAP's CVS and will be released in 0.9.1.

This allows you to perform an LDAP::Conn#unbind, followed by either an
LDAP::Conn#bind or an LDAP::Conn#simple_bind to reconnect to the server,
using different credentials if you wish.

Ian

···

On Sat 12 Mar 2005 at 08:16:12 +0900, Ian Macdonald wrote:

Perhaps Net::LDAP remembers the details of the connection when it was
opened and silently performs another open when you perform a bind after
an unbind, but at some point, you're still opening a new connection.
It's just a question of whether it's implicit or explicit.

Ruby/LDAP could be made to do this, too, I think. The details passed to
LDAP::Conn.new could be put into instance variables. If the connection
is dead at bind time, these could be read and used to transparently
reestablish the connection before conducting the bind.

I'll look at how hard this would be to ship up in practice.

--
Ian Macdonald | This generation doesn't have emotional
System Administrator | baggage. We have emotional moving vans.
ian@caliban.org | -- Bruce Feirstein
http://www.caliban.org |
                            >

* Ian Macdonald <ian@caliban.org> [0351 09:51]:

···

On Sat 12 Mar 2005 at 08:16:12 +0900, Ian Macdonald wrote:

> Perhaps Net::LDAP remembers the details of the connection when it was
> opened and silently performs another open when you perform a bind after
> an unbind, but at some point, you're still opening a new connection.
> It's just a question of whether it's implicit or explicit.
>
> Ruby/LDAP could be made to do this, too, I think. The details passed to
> LDAP::Conn.new could be put into instance variables. If the connection
> is dead at bind time, these could be read and used to transparently
> reestablish the connection before conducting the bind.
>
> I'll look at how hard this would be to ship up in practice.

This feature is now in Ruby/LDAP's CVS and will be released in 0.9.1.

This allows you to perform an LDAP::Conn#unbind, followed by either an
LDAP::Conn#bind or an LDAP::Conn#simple_bind to reconnect to the server,
using different credentials if you wish.

Brilliant, thanks Ian!

--
'Ugh, it's like there's a party in my mouth and everyone's throwing up.'
    -- Fry
Rasputin :: Jack of All Trades - Master of Nuns

You're welcome.

I quickly realised that LDAP::Conn#sasl_bind should also be able to
rebind in this way and that #bind, #simple_bind and #sasl_bind should
also work on SSLConn objects, not just plain old Conn objects. This work
has now also gone into CVS.

Ian

···

On Sat 12 Mar 2005 at 19:34:32 +0900, Dick Davies wrote:

* Ian Macdonald <ian@caliban.org> [0351 09:51]:
>
> This feature is now in Ruby/LDAP's CVS and will be released in 0.9.1.
>
> This allows you to perform an LDAP::Conn#unbind, followed by either an
> LDAP::Conn#bind or an LDAP::Conn#simple_bind to reconnect to the server,
> using different credentials if you wish.

Brilliant, thanks Ian!

--
Ian Macdonald | A crow perched himself on a telephone wire.
System Administrator | He was going to make a long-distance caw.
ian@caliban.org |
http://www.caliban.org |
                            >

And I spoke too soon, because SSLConn connections are more complicated.
For the time being, you can only rebind regular Conn objects, not
SSLConn objects.

Ian

···

On Sun 13 Mar 2005 at 18:49:01 +0900, Ian Macdonald wrote:

I quickly realised that LDAP::Conn#sasl_bind should also be able to
rebind in this way and that #bind, #simple_bind and #sasl_bind should
also work on SSLConn objects, not just plain old Conn objects. This work
has now also gone into CVS.

--
Ian Macdonald | When the fog came in on little cat feet
System Administrator | last night, it left these little muddy paw
ian@caliban.org | prints on the hood of my car.
http://www.caliban.org |
                            >

This has now been fixed in CVS. SSL connections can now also be rebound.

Ian

···

On Sun 13 Mar 2005 at 20:14:39 +0900, Ian Macdonald wrote:

On Sun 13 Mar 2005 at 18:49:01 +0900, Ian Macdonald wrote:

> I quickly realised that LDAP::Conn#sasl_bind should also be able to
> rebind in this way and that #bind, #simple_bind and #sasl_bind should
> also work on SSLConn objects, not just plain old Conn objects. This work
> has now also gone into CVS.

And I spoke too soon, because SSLConn connections are more complicated.
For the time being, you can only rebind regular Conn objects, not
SSLConn objects.

--
Ian Macdonald | An intellectual is someone whose mind
System Administrator | watches itself. -- Albert Camus
ian@caliban.org |
http://www.caliban.org |
                            >

* Ian Macdonald <ian@caliban.org> [0346 01:46]:

>
> > I quickly realised that LDAP::Conn#sasl_bind should also be able to
> > rebind in this way and that #bind, #simple_bind and #sasl_bind should
> > also work on SSLConn objects, not just plain old Conn objects. This work
> > has now also gone into CVS.
>
> And I spoke too soon, because SSLConn connections are more complicated.
> For the time being, you can only rebind regular Conn objects, not
> SSLConn objects.

This has now been fixed in CVS. SSL connections can now also be rebound.

Lovely, ta. Out of interest, is there a reason you need to unbind before binding?

perl-ldap explicitly unbinds for you if you bind an existing connection
(though by the sound of it that's because you actually make a new connection anyway) -
are there reasons you wouldn't want to to that?

···

On Sun 13 Mar 2005 at 20:14:39 +0900, Ian Macdonald wrote:
> On Sun 13 Mar 2005 at 18:49:01 +0900, Ian Macdonald wrote:

Ian
--
Ian Macdonald | An intellectual is someone whose mind
System Administrator | watches itself. -- Albert Camus
ian@caliban.org |
http://www.caliban.org |
                            >

--
'You were doing well until everyone died'
    -- God
Rasputin :: Jack of All Trades - Master of Nuns

It all depends on how much transparency you want.

Right now, you'll get an LDAP::Error exception and the message "already
bound." if you try to bind an already bound connection. This operates on
the historic assumption that you're accidentally trying to bind twice.

In your case, you just want to rebind, but with different credentials.
In that case, you want it to implicitly unbind and reconnect before
performing your bind.

I'm not sure whether it's better for the default reaction to be to treat
this as an error or to give you exactly what you appear to be asking
for.

Another possibility is to add a Conn#rebind method, whereby you get to
explicitly request that a connection be unbound, reconnected and bound.

What do you think of that idea?

Ian

···

On Tue 15 Mar 2005 at 19:05:00 +0900, Dick Davies wrote:

* Ian Macdonald <ian@caliban.org> [0346 01:46]:
>
> This has now been fixed in CVS. SSL connections can now also be rebound.

Lovely, ta. Out of interest, is there a reason you need to unbind before binding?

perl-ldap explicitly unbinds for you if you bind an existing connection
(though by the sound of it that's because you actually make a new connection anyway) -
are there reasons you wouldn't want to to that?

--
Ian Macdonald | Hell is empty and all the devils are here.
System Administrator | -- Wm. Shakespeare, "The Tempest"
ian@caliban.org |
http://www.caliban.org |
                            >

* Ian Macdonald <ian@caliban.org> [0302 23:02]:

> Lovely, ta. Out of interest, is there a reason you need to unbind before binding?
>
> perl-ldap explicitly unbinds for you if you bind an existing connection
> (though by the sound of it that's because you actually make a new connection anyway) -
> are there reasons you wouldn't want to to that?

It all depends on how much transparency you want.

Right now, you'll get an LDAP::Error exception and the message "already
bound." if you try to bind an already bound connection. This operates on
the historic assumption that you're accidentally trying to bind twice.

I think that's what feels wrong about a bind just clobbering the existing
connection, and why I hesitated to suggest it. There's a possibility that this
would mask coding errors if you accidentally try to use a connection you think
is free.

In your case, you just want to rebind, but with different credentials.
In that case, you want it to implicitly unbind and reconnect before
performing your bind.

I think I'm probably being lazy. It's just the code ends up a little cleaner
that way. Whether it's worth adding the complexity to the library just for that
is up to you...

I'm not sure whether it's better for the default reaction to be to treat
this as an error or to give you exactly what you appear to be asking
for.
Another possibility is to add a Conn#rebind method, whereby you get to
explicitly request that a connection be unbound, reconnected and bound.

I think a rebind method would be better than bind 'magically' throwing away
the old connection. It's self-documenting in many ways, and ticks my box of
keeping it to a single method.

Thanks a lot for being so patient - my reaction in your shoes would probably
be closer to "why don't you marry perl-ldap, you love it so much?" :slight_smile:

···

On Tue 15 Mar 2005 at 19:05:00 +0900, Dick Davies wrote:

--
'What have you done to the cat? It looks half-dead.'
    -- Schroedinger's wife
Rasputin :: Jack of All Trades - Master of Nuns