flamencist / ldap4net

OpenLdap port for DotNet Core (Linux\OSX\Windows)
MIT License
215 stars 38 forks source link

Referral Chasing mode #34

Open Zubastic opened 4 years ago

Zubastic commented 4 years ago

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 commented 4 years ago

Will this implemented at 2.5 release?

flamencist commented 4 years ago

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

Zubastic commented 4 years ago

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?

flamencist commented 4 years ago

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.

Zubastic commented 4 years ago

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 );
flamencist commented 4 years ago

We could use LDAP_OPT_REFERRALS on windows