inejge / ldap3

A pure-Rust LDAP library using the Tokio stack
Apache License 2.0
220 stars 38 forks source link

Multilegged bind support (GSS-SPNEGO) with saslBindInProgress response #32

Closed awakecoding closed 4 months ago

awakecoding commented 5 years ago

I am currently trying to add support for the GSS-SPNEGO bind type, which would be very useful to connect to Active Directory. I have sample wireshark captures of NTLM and Kerberos traffic, and I also have a working NTLM implementation that I can integrate.

However, I am facing a blocker: even if I can send the first GSS-SPNEGO bind request and get a proper response from the server (saslBindInProgress with the NTLM "Challenge" message in the response payload), I struggle to find a way to extract the NTLM message from the bind response.

The current code only has support for single request/response bind types, none of the implemented bind types are multilegged (meaning they require more than one request/response to complete). As far as I can see, bind success is currently only based on the LdapResult response code being zero.

I figured out how to interpret the result code differently such that code 14 (saslBindInProgress) is not considered an error, but I cannot figure out how to properly modify the LdapResponse type and parsing code to allow me to fetch something other than a vector of controls. A bind response isn't a search result, so it's not a vector of controls :/

Any guidance or hints on this problem?

inejge commented 5 years ago

BindResponse is fully defined as:

BindResponse ::= [APPLICATION 1] SEQUENCE {
      COMPONENTS OF LDAPResult,
      serverSaslCreds    [7] OCTET STRING OPTIONAL } 

For a challenge-response flow, you need the serverSaslCreds string, and for that, you'd have to parse the Bind response differently, which could be shoehorned into Ldap::simple_bind(), but is perhaps better suited for a separate function. It could be implemented similarly to Extended operations: see impl From<Tag> for LdapResultExt in src/protocol.rs and Ldap::extended() in src/extended.rs.

awakecoding commented 5 years ago

thanks for the tip, I figured out a way to extract serverSaslCreds and feed it into a custom "RawControl" using the SPNEGO OID (1.3.6.1.5.5.2). There is no control structure for it, but that was the quickest way to return the serverSaslCreds without a significant change in program structure. Your idea looks cleaner though, I'll look into it.

At this point, I am struck trying to figure out how to handle futures: I need to pass a spnego authenticator context to my first future, which has to process the response, and return a second future call or an error type. I'm still struggling with futures, and I haven't been able to get the compiler happy with lifetimes, putting aside the struggle of getting matching future types for all if/else arms.

awakecoding commented 5 years ago

I've got it working, I've opened a PR: https://github.com/inejge/ldap3/pull/33