Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
gredwhite opened this issue Aug 21, 2023 · 8 comments

Comments

@gredwhite
Copy link

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
Copy link
Collaborator

dirmgr commented Aug 21, 2023

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
Copy link
Author

gredwhite commented Aug 21, 2023

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
Copy link

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
Copy link
Author

gredwhite commented Aug 22, 2023

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
Copy link
Author

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

@gredwhite
Copy link
Author

@dirmgr

Thank you for

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

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

@dirmgr
Copy link
Collaborator

dirmgr commented Aug 22, 2023

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
Copy link
Author

gredwhite commented Aug 22, 2023

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:

val entry = ldapConnectionPool.getEntry(dn, "*", "primaryGroupToken") 
val primaryGroupToken = entry.getAttributeValue("PrimaryGroupToken")
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants