ldap4net icon indicating copy to clipboard operation
ldap4net copied to clipboard

Referral Chasing mode

Open Zubastic opened this issue 4 years ago • 6 comments

Is your feature request related to a problem? Please describe. At enterprise level infrastructure contains multiple domains. You connect to domain via kerberos and couldn't search at another trusted domain. This is fixed at Windows default library with ReferralChasingOptions option. Class LdapSessionOptions.

Settings: LdapOption.LDAP_OPT_REFERRALS LdapOption.LDAP_OPT_REFERRAL_HOP_LIMIT

Also usefull fuction: LdapOption.LDAP_OPT_AUTO_RECONNECT

Describe the solution you'd like Add referral chasing function to code. Example: https://www.php.net/manual/en/function.ldap-set-rebind-proc.php https://linux.die.net/man/5/slapd-meta

https://klikr.org/4bbb0c55d527603667041ed0ce0a.png This is current net framework referral connection example.

Zubastic avatar May 21 '20 16:05 Zubastic

Will this implemented at 2.5 release?

Zubastic avatar May 25 '20 11:05 Zubastic

No. Maybe in next release - 2.6. As workaround you could set properties manually. Also contributions are welcome.

flamencist avatar May 25 '20 12:05 flamencist

Well, I try to release Referral Chase... So at windows it created via register LDAP_OPT_REFERRAL_CALLBACK callback:

    private int ProcessDereferenceConnection(
      IntPtr PrimaryConnection,
      IntPtr ConnectionToDereference)
    {
      if (ConnectionToDereference != (IntPtr) 0 && this.callbackRoutine.DereferenceConnection != null)
      {
        WeakReference weakReference = (WeakReference) null;
        lock (LdapConnection.objectLock)
          weakReference = (WeakReference) LdapConnection.handleTable[(object) ConnectionToDereference];
        LdapConnection ldapConnection;
        if (weakReference == null || !weakReference.IsAlive)
        {
          ldapConnection = new LdapConnection((LdapDirectoryIdentifier) this.connection.Directory, this.connection.GetCredential(), this.connection.AuthType, ConnectionToDereference);
        }
        else
        {
          ldapConnection = (LdapConnection) weakReference.Target;
          LdapSessionOptions.ReleaseLdapHandleRef(ldapConnection);
        }
        this.callbackRoutine.DereferenceConnection(this.connection, ldapConnection);
      }
      return 1;
    }

    private int ProcessQueryConnection(
      IntPtr PrimaryConnection,
      IntPtr ReferralFromConnection,
      IntPtr NewDNPtr,
      string HostName,
      int PortNumber,
      SEC_WINNT_AUTH_IDENTITY_EX SecAuthIdentity,
      Luid CurrentUserToken,
      ref IntPtr ConnectionToUse)
    {
      ConnectionToUse = IntPtr.Zero;
      string newDistinguishedName = (string) null;
      if (this.callbackRoutine.QueryForConnection == null)
        return 1;
      if (NewDNPtr != (IntPtr) 0)
        newDistinguishedName = Marshal.PtrToStringUni(NewDNPtr);
      StringBuilder stringBuilder = new StringBuilder();
      stringBuilder.Append(HostName);
      stringBuilder.Append(":");
      stringBuilder.Append(PortNumber);
      LdapDirectoryIdentifier identifier = new LdapDirectoryIdentifier(stringBuilder.ToString());
      NetworkCredential credential = this.ProcessSecAuthIdentity(SecAuthIdentity);
      LdapConnection referralFromConnection = (LdapConnection) null;
      if (ReferralFromConnection != (IntPtr) 0)
      {
        lock (LdapConnection.objectLock)
        {
          WeakReference weakReference = (WeakReference) LdapConnection.handleTable[(object) ReferralFromConnection];
          if (weakReference != null && weakReference.IsAlive)
          {
            referralFromConnection = (LdapConnection) weakReference.Target;
          }
          else
          {
            if (weakReference != null)
              LdapConnection.handleTable.Remove((object) ReferralFromConnection);
            referralFromConnection = new LdapConnection((LdapDirectoryIdentifier) this.connection.Directory, this.connection.GetCredential(), this.connection.AuthType, ReferralFromConnection);
            LdapConnection.handleTable.Add((object) ReferralFromConnection, (object) new WeakReference((object) referralFromConnection));
          }
        }
      }
      long currentUserToken = (long) (uint) CurrentUserToken.LowPart + ((long) CurrentUserToken.HighPart << 32);
      LdapConnection ldapConnection = this.callbackRoutine.QueryForConnection(this.connection, referralFromConnection, newDistinguishedName, identifier, credential, currentUserToken);
      if (ldapConnection != null && ldapConnection.ldapHandle != null && (!ldapConnection.ldapHandle.IsInvalid && LdapSessionOptions.AddLdapHandleRef(ldapConnection)))
        ConnectionToUse = ldapConnection.ldapHandle.DangerousGetHandle();
      return 0;
    }

Now it released via LdapResultCompleteStatus.Partial. So I think it should be OK to handle it via delegate?

Zubastic avatar Jun 15 '20 10:06 Zubastic

Our library is crossplatform. Unfortunately openldap library (linux and osx implementation based on openldap) does not have option LDAP_OPT_REFERRAL_CALLBACK. So I think we need to use openldap's approach: use boolean option for enable referral's handler.

flamencist avatar Jun 15 '20 12:06 flamencist

So how we could implement it in windows? At novell I handle LdapReferralException and recreate it with new base DN + new connection. I think this is overkill for this situation. Also I research this code:


	/* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
	ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS,
		META_BACK_TGT_CHASE_REFERRALS( mt ) ? LDAP_OPT_ON : LDAP_OPT_OFF );

Zubastic avatar Jun 15 '20 15:06 Zubastic

We could use LDAP_OPT_REFERRALS on windows

flamencist avatar Jun 16 '20 09:06 flamencist