pingidentity / ldapsdk

UnboundID LDAP SDK for Java
Other
327 stars 79 forks source link

Is there way to add user to multiple groups using single ldap request ? #150

Closed gredwhite closed 11 months ago

gredwhite commented 11 months ago

Using this code I can add user to group

val addUser: Modification = Modification(ModificationType.ADD, "member", userDn)
val ldapResult = ldapConnectionPool.modify(groupDn, addUser)

Now I want to add user to multiple groups.

I understand that I can use loop but it will require multiple ldap requests. Is there way to do it using single ldap request ?

Also I have related question:

Is there way to add user to group during creation request ?

  val addRequest = AddRequest(
    dn,
    ...
)
 val addResult: LDAPResult = ldapConnectionPool.add(addRequest)
dirmgr commented 11 months ago

There is no standard LDAP operation for modifying multiple entries in a single request. The Ping Identity Directory Server does offer support for a proprietary multi-update extended operation that allows you to do this (and the UnboundID LDAP SDK for Java supports that operation), but I'm not aware of any other LDAP servers that offer anything similar.

If you're primarily concerned about the round-trip time, and if the modifications you're making are completely independent (meaning that none of the modifications depend on the results of the others), then you could issue the requests in parallel. There are a few ways of doing this, but assuming that you aren't creating connections with LDAPConnectionOptions set to operate in synchronous mode, then the easiest and least disruptive way to do this might be to use the asynchronous API. You could call LDAPConnection.asyncModify to send a modify request without waiting for the response, so that you could immediately send additional requests. You can get the results either by callback (in the form of an AsyncResultListener), or using the Java Future API through the AsyncRequestID object that the asyncModify method returns.

gredwhite commented 11 months ago

There is no standard LDAP operation for modifying multiple entries in a single request. The Ping Identity Directory Server does offer support for a proprietary multi-update extended operation that allows you to do this (and the UnboundID LDAP SDK for Java supports that operation), but I'm not aware of any other LDAP servers that offer anything similar.

Could you please provide code example ?

If you're primarily concerned about the round-trip time, and if the modifications you're making are completely independent (meaning that none of the modifications depend on the results of the others), then you could issue the requests in parallel.

I am worry about performance and I also would like to avoid transactions if it is possible

There are a few ways of doing this, but assuming that you aren't creating connections with LDAPConnectionOptions set to operate in synchronous mode, then the easiest and least disruptive way to do this might be to use the asynchronous API.

What options could I use from LDAPConnectionOptions to solve my problem ?

dirmgr commented 11 months ago

The LDAP SDK's documentation for the multi-update extended operation is available at https://docs.ldap.com/ldap-sdk/docs/javadoc/index.html?com/unboundid/ldap/sdk/unboundidds/extensions/MultiUpdateExtendedRequest.html, and it includes an example that demonstrates its use. I also wrote a post about it on my personal blog, at https://nawilson.com/2019/02/19/the-multi-update-extended-operation-in-the-ping-identity-directory-server/.

I'm not sure what your concern about performance has to do with using asynchronous operations. Assuming that the requests are independent, which sounds like the case, then sending them all off at once and waiting for them to be completed would basically collapse the time to process all of those operations to be just the time required for the slowest of the individual operations. The client could send all the requests one after another, and the server could work on them in parallel and send the results as soon as it finishes with each of them. That has the potential to be substantially faster than issuing all of the requests individually, and potentially even faster than something like the multi-update operation because that operation processes the changes sequentially. You would not only be eliminating much of the round-trip time, but as the number of changes increases, then so would the advantage of the server being able to process them in parallel.

I'm also not so sure about what your concern about transactions is. If you're using Active Directory as indicated by your previous posts, then I don't believe that it has any level of support for transactions whatsoever. So regardless of whether you perform the modify operations back-to-back using regular synchronous requests or in parallel by processing them asynchronously, there's the potential for some of the operations to succeed and some to fail. In the back-to-back approach, it's true that if the first change fails, then you could just not issue any of the subsequent changes, but if the failure comes after at least one of them had succeeded, then the earlier changes would have already been applied. Assuming that you wanted to revert the changes that had succeeded (which may not be the case; it may be better to keep some of them and only report on the failures than to roll back previously successful changes), then you could keep track of the changes that you applied and then attempt the inverse (e.g., a modification that removes a value that you previously added), and that would be the same regardless of whether the requests were sent synchronously or asynchronously. Some directory servers (like the Ping Identity Directory Server, and I believe OpenLDAP) do support standard LDAP transactions where you can have multiple requests processed as a single atomic unit, and the multi-update operation in the Ping Identity Directory Server also supports this, but I don't think that Active Directory offers anything like that.

Further, there aren't really any connection options that would allow you to process changes to multiple entries in a single request. The only connection option I was talking about was the LDAPConnectionOptions.setUseSynchronousMode (https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/LDAPConnectionOptions.html#setUseSynchronousMode(boolean) ) method, which tells the LDAP SDK that you won't be performing any asynchronous processing and allows it to operate in a slightly more efficient manner by not maintaining a separate background thread to read responses from the server, but instead reading responses on the same connection that was used to send the request. But this option can only be used if a connection will never have more than one outstanding request at a time, so it's not an option if you either use the asynchronous API to issue multiple requests concurrently, or if several threads might try to use the same connection at the same time.

gredwhite commented 11 months ago

I am using Samba server(replacement of AD) Could you please explain this phrase ? I can't find any proof but I really want. Will experiment proof it ?

I'm also not so sure about what your concern about transactions is. If you're using Active Directory as indicated by your previous posts, then I don't believe that it has any level of support for transactions whatsoever.
dirmgr commented 11 months ago

By transactions, I mean a way of processing multiple independent changes as a single atomic unit. I'm only aware of a couple of mechanisms for accomplishing something like this in LDAP servers:

I'm even less familiar with Samba than I am with Active Directory, but I highly doubt that it offers any way of making multiple independent changes as a single atomic unit. You should be able to make multiple modifications to the same entry in a single request, but modifications to different entries, or any write operations involving multiple entries, will have to be processed separately. If you're concerned about writes involving multiple entries, and if you want them all to succeed or fail, then the only option is to remember what changes you've made successfully and try to undo them in the event that any other attempts fail. You can't be absolutely guaranteed the undo attempts will succeed, but without support for some kind of server-side transactional mechanism, that's the best option that's available.