pingidentity / ldapsdk

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

How to get group by primaryGroupId ? How to convert primaryGroupId to groupDn? #151

Open gredwhite opened 11 months ago

gredwhite commented 11 months ago

I can read user primaryGroupId: enter image description here val entry = ldapConnectionPool.getEntry(userDn) primaryGroupID = entry.getAttributeValue(PRIMARY_GROUP_ID.ldapFieldName)

it is a string which contains number. In my case it is always 513

As I understand user must have this group and it is setup during creation.

I want to get group DN based on primaryGroupId

I've tried to get primary group from group entry:

ldapConnectionPool.getEntry(groupDn)
val token = entry.getAttributeValue("PrimaryGroupToken")

But it always null

Another option I've found is suffix of objectSid:

enter image description here

But solutions from here don't work for me:

https://stackoverflow.com/questions/7118290/how-to-convert-the-sid-to-string-and-vice-versa-in-java

If I use this answer https://stackoverflow.com/a/21818633/2674303

I get wrong suffix.

enter image description here enter image description here

Any ideas hwo to fix it ?

dirmgr commented 11 months ago

This doesn't really sound like a question about or an issue with the LDAP SDK. Instead, it's more specific to the way that Active Directory handles groups, and that's not something that I'm familiar with.

You mention that an attempt to retrieve the primaryGroupToken attribute is always null. Is it possible that it's an operational attribute? If so, then it needs to be explicitly requested when you're retrieving the entry that is supposed to contain it, like:

ldapConnectionPool.getEntry(groupDN, "*", "primaryGroupToken")

Note that the "*" item indicates that the server should return all user attributes in addition to the primaryGroupToken attribute.

It's also possible that the account you're using doesn't have permission to see that attribute.

But ultimately, this doesn't sound like an issue with the LDAP SDK or standard LDAP behavior, but is related entirely to the proprietary group implementation that Active Directory uses, and that's not something I can help with.

gredwhite commented 11 months ago

This doesn't really sound like a question about or an issue with the LDAP SDK. Instead, it's more specific to the way that Active Directory handles groups, and that's not something that I'm familiar with.

You mention that an attempt to retrieve the primaryGroupToken attribute is always null. Is it possible that it's an operational attribute? If so, then it needs to be explicitly requested when you're retrieving the entry that is supposed to contain it, like:

ldapConnectionPool.getEntry(groupDN, "*", "primaryGroupToken")

Note that the "*" item indicates that the server should return all user attributes in addition to the primaryGroupToken attribute.

It's also possible that the account you're using doesn't have permission to see that attribute.

But ultimately, this doesn't sound like an issue with the LDAP SDK or standard LDAP behavior, but is related entirely to the proprietary group implementation that Active Directory uses, and that's not something I can help with.

Sorry, but sometimes it is hard to understand for me what is LDAP specific and what is AD specific. The community is not very active. So it is the reason why I try to find any ability to get the answer. Thank you for your help.

For now I know how to get primaryGroupToken from group side

val objectSidBytes = getAttributeValueBytes("ObjectSid")
val sid = LdapUtils.convertBinarySidToString(objectSidBytes)  // Spring ldap
val primaryGroupToken = it.objectSid.substring(it.objectSid.lastIndexOf('-') + 1)

But I still can't make request which allow me to return group entry by primaryGroupToken

pdsheehan commented 11 months ago

I'm just another user, but I faced a similar challenge. There may be better ways, but here is how I did this (using groovy):


import com.unboundid.ldap.sdk.SearchScope
import org.springframework.ldap.support.LdapUtils

def getGroupEntryByRid(String groupRid){
   LDAPConnection ldap = new LDAPConnection()

   def rootDn = ldap.rootDSE.getAttributeValue('defaultNamingContext')
   def domainSidBytes = ldap.getEntry(rootDn, 'objectSid').getAttributeValueBytes('objectSid')
   String domainSidString = LdapUtils.convertBinarySidToString(domainSidBytes)
   def groupSidString = domainSidString + '-' + groupRid
   def query = "(objectSid=$groupSidString)"
   return ldap.searchForEntry(rootDn, SearchScope.SUB, query)
}
gredwhite commented 11 months ago

I'm just another user, but I faced a similar challenge. There may be better ways, but here is how I did this (using groovy):

import com.unboundid.ldap.sdk.SearchScope
import org.springframework.ldap.support.LdapUtils

def getGroupEntryByRid(String groupRid){
   LDAPConnection ldap = new LDAPConnection()

   def rootDn = ldap.rootDSE.getAttributeValue('defaultNamingContext')
   def domainSidBytes = ldap.getEntry(rootDn, 'objectSid').getAttributeValueBytes('objectSid')
   String domainSidString = LdapUtils.convertBinarySidToString(domainSidBytes)
   def groupSidString = domainSidString + '-' + groupRid
   def query = "(objectSid=$groupSidString)"
   return ldap.searchForEntry(rootDn, SearchScope.SUB, query)
}

Thank you for sharing your experience.

Based on your answer I've found that I can retrieve entry by SID

ldapConnectionPool.searchForEntry(baseDn, SearchScope.SUB, "objectSid=S-1-5-32-550")

But problem here that most of groups have different prefixes (same prefix have groups in the same folder):

image

image

and query like

ldapConnectionPool.searchForEntry(baseDn, SearchScope.SUB, "*-550")

don't work

And user from folder1 could have reference to primaryGroupId from different folder

gredwhite commented 11 months ago

@dirmgr Could you please open discussions in project settings if you don't like to see questions here instead of actual issues ?

gredwhite commented 11 months ago

@dirmgr

Thank you for

ldapConnectionPool.getEntry(dn, "*", "primaryGroupToken")

It really works. It was not obvious for me based on java doc

dirmgr commented 11 months ago

I think that the Javadoc description of the getEntry method is sufficient. It says that if you don't specifically request any attributes, then all user attributes will be requested. That's also standard LDAP behavior (as per RFC 4511 section 4.5.1.8).

What is perhaps less clear is that the primaryGroupToken attribute is defined as operational and therefore needs to be explicitly requested by name. I have found a couple of different pages where Microsoft seems to provide a definition for the attribute, but that definition is in a proprietary form rather than the standard LDAP form, and there's nothing on that page that makes it clear that it has an operational usage. It is probably something that could have been discovered by retrieving the schema from the server, and it is the kind of thing that logically makes sense to be an operational attribute, but it would be nice if Microsoft made it clearer that it's an operational attribute.

gredwhite commented 11 months ago

I think that the Javadoc description of the getEntry method is sufficient. It says that if you don't specifically request any attributes, then all user attributes will be requested. That's also standard LDAP behavior (as per RFC 4511 section 4.5.1.8).

What is perhaps less clear is that the primaryGroupToken attribute is defined as operational and therefore needs to be explicitly requested by name. I have found a couple of different pages where Microsoft seems to provide a definition for the attribute, but that definition is in a proprietary form rather than the standard LDAP form, and there's nothing on that page that makes it clear that it has an operational usage. It is probably something that could have been discovered by retrieving the schema from the server, and it is the kind of thing that logically makes sense to be an operational attribute, but it would be nice if Microsoft made it clearer that it's an operational attribute.

Thank you but lets return back to issue declared in the title. Now I know how to get primaryGroupToken. There are even 2 ways to achieve it:

  1. val entry = ldapConnectionPool.getEntry(dn, "*", "primaryGroupToken") 
    val primaryGroupToken = entry.getAttributeValue("PrimaryGroupToken")
  2. val entry = ldapConnectionPool.getEntry(groupDn, SearchRequest.ALL_USER_ATTRIBUTES, "PrimaryGroupToken")
    val domainSidBytes = entry.getAttributeValueBytes("objectSid")
    val domainSidString = LdapUtils.convertBinarySidToString(domainSidBytes)
    val primaryGroupToken = domainSidString.substringAfterLast("-")

This comment adresses my question but I am not sure that will work for all cases and shared my concerns in response.

Ideally I would like to have smth like

ldapConnectionPool.searchForEntry(SearchRequest(dn, SearchScope.SUB, "PrimaryGroupToken=$primaryGroupToken"))

or

 ldapConnectionPool.search(baseDn, SearchScope.SUB, "objectSid=*-$primaryGroupToken")

but in both cases I don't receive entry.