Active directory 如何使用普通ldap客户端访问nTSecurityDescriptor?
我尝试从一台linux机器上读取Active directory 如何使用普通ldap客户端访问nTSecurityDescriptor?,active-directory,ldap,Active Directory,Ldap,我尝试从一台linux机器上读取nTSecurityDescriptor,该机器使用ldapsearch(或其他东西)作为普通域用户 搜索其他东西是可行的,但我找不到nTSecurityDescriptor 可能是相关的,但作为域管理员运行不是服务的选项 那么我如何阅读这些信息呢?我知道我可以阅读DACL,但问题是如何阅读。看起来,这是不可能的 不幸的是,微软产品使用的底层API(COM API等)不是开源的,所以我甚至不知道如何做到这一点 但是我可以通过windows上的windows API
nTSecurityDescriptor
,该机器使用ldapsearch(或其他东西)作为普通域用户
搜索其他东西是可行的,但我找不到nTSecurityDescriptor
可能是相关的,但作为域管理员运行不是服务的选项
那么我如何阅读这些信息呢?我知道我可以阅读DACL,但问题是如何阅读。看起来,这是不可能的 不幸的是,微软产品使用的底层API(COM API等)不是开源的,所以我甚至不知道如何做到这一点 但是我可以通过windows上的windows API调用获取安全描述符。我为windows ntSecurityDescriptor管理创建了一个新的Java(JNDI)库(Apache2许可证)。开始阅读介绍 请查看库()集成测试以获取任何帮助。 下面的示例将“用户无法更改密码”ACE添加到DACL中
final SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
controls.setReturningAttributes(new String[] { "nTSecurityDescriptor" });
ctx.setRequestControls(new Control[] { new SDFlagsControl(0x00000004) });
NamingEnumeration<SearchResult> results =
ctx.search(baseContext, searchFilter, controls);
SearchResult res = results.next();
final String dn = res.getNameInNamespace();
byte[] orig = (byte[]) res.getAttributes().get("nTSecurityDescriptor").get();
SDDL sddl = new SDDL(orig);
results.close();
final List<ACE> toBeChanged = new ArrayList<>();
for (ACE ace : sddl.getDacl().getAces()) {
if ((ace.getType() == AceType.ACCESS_ALLOWED_OBJECT_ACE_TYPE
|| ace.getType() == AceType.ACCESS_DENIED_OBJECT_ACE_TYPE)
&& ace.getObjectFlags().getFlags().contains(
AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT)) {
if (GUID.getGuidAsString(ace.getObjectType()).equals(
UCP_OBJECT_GUID)) {
final SID sid = ace.getSid();
if (sid.getSubAuthorities().size() == 1
&& ((Arrays.equals(sid.getIdentifierAuthority(),
new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 })
&& Arrays.equals(sid.getSubAuthorities().get(0),
new byte[] { 0x00, 0x00, 0x00, 0x00 }))
|| (Arrays.equals(sid.getIdentifierAuthority(),
new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 })
&& Arrays.equals(sid.getSubAuthorities().get(0),
new byte[] { 0x00, 0x00, 0x00, 0x0a })))) {
toBeChanged.add(ace);
}
}
}
}
if (toBeChanged.isEmpty()) {
// prepare aces
ACE self = ACE.newInstance(AceType.ACCESS_DENIED_OBJECT_ACE_TYPE);
self.setObjectFlags(new AceObjectFlags(
AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT));
self.setObjectType(GUID.getGuidAsByteArray(UCP_OBJECT_GUID));
self.setRights(new AceRights().addOjectRight(AceRights.ObjectRight.CR));
SID sd = SID.newInstance(NumberFacility.getBytes(0x000000000001));
sd.addSubAuthority(NumberFacility.getBytes(0));
self.setSid(sd);
ACE all = ACE.newInstance(AceType.ACCESS_DENIED_OBJECT_ACE_TYPE);
all.setObjectFlags(new AceObjectFlags(
AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT));
all.setObjectType(GUID.getGuidAsByteArray(UCP_OBJECT_GUID));
all.setRights(new AceRights().addOjectRight(AceRights.ObjectRight.CR));
sd = SID.newInstance(NumberFacility.getBytes(0x000000000005));
sd.addSubAuthority(NumberFacility.getBytes(0x0A));
all.setSid(sd);
sddl.getDacl().getAces().add(self);
sddl.getDacl().getAces().add(all);
} else {
for (ACE ace : toBeChanged) {
ace.setType(AceType.ACCESS_DENIED_OBJECT_ACE_TYPE);
}
}
final Attribute ntSecurityDescriptor = new BasicAttribute(
"ntSecurityDescriptor", sddl.toByteArray());
final ModificationItem[] mods = new ModificationItem[1];
mods[0] = new ModificationItem(
DirContext.REPLACE_ATTRIBUTE, ntSecurityDescriptor);
ctx.modifyAttributes(dn, mods);
// .....
final SearchControls=new SearchControls();
控件.setSearchScope(SearchControls.SUBTREE_范围);
SetReturningAttribute(新字符串[]{“nTSecurityDescriptor”});
setRequestControls(新控件[]{new SDFlagsControl(0x00000004)});
NamingEnumeration结果=
ctx.search(baseContext、searchFilter、控件);
SearchResult res=results.next();
最后一个字符串dn=res.getNameInNamespace();
字节[]orig=(字节[])res.getAttributes().get(“nTSecurityDescriptor”).get();
SDDL SDDL=新的SDDL(原始);
结果:关闭();
最终列表toBeChanged=新建ArrayList();
for(ACE:sddl.getDacl().getAces()){
if((ace.getType()==AceType.ACCESS\u允许的对象\u ace\u类型
||ace.getType()==AceType.ACCESS\u拒绝\u对象\u ace\u类型)
&&ace.getObjectFlags().getFlags()包含(
AceObjectFlags.Flag.ACE_对象类型(存在)){
if(GUID.getGuidAsString(ace.getObjectType()).equals(
UCP_对象(GUID)){
final SID=ace.getSid();
如果(sid.getSubAuthorities().size()==1
&&((array.equals(sid.getIdentifierAuthority()),
新字节[]{0x00,0x00,0x00,0x00,0x00,0x01})
&&Arrays.equals(sid.getSubAuthorities().get(0),
新字节[](0x00,0x00,0x00,0x00})
||(Arrays.equals(sid.getIdentifierAuthority(),
新字节[]{0x00,0x00,0x00,0x00,0x00,0x05})
&&Arrays.equals(sid.getSubAuthorities().get(0),
新字节[]{0x00,0x00,0x00,0x0a}))){
tobechange.add(ace);
}
}
}
}
if(toBeChanged.isEmpty()){
//准备A
ACE self=ACE.newInstance(AceType.ACCESS\u DENIED\u OBJECT\u ACE\u TYPE);
self.setObjectFlags(新的AceObjectFlags(
AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT));
self.setObjectType(GUID.getGuidAsByteArray(UCP_对象_GUID));
self.setRights(new AceRights().addObjectRight(AceRights.ObjectRight.CR));
SID sd=SID.newInstance(NumberFacility.getBytes(0x000000000001));
sd.addSubAuthority(NumberFacility.getBytes(0));
self.setSid(sd);
ACE all=ACE.newInstance(AceType.ACCESS\u DENIED\u OBJECT\u ACE\u TYPE);
all.setObjectFlags(新的AceObjectFlags(
AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT));
all.setObjectType(GUID.getGuidAsByteArray(UCP_对象_GUID));
all.setRights(new AceRights().addObjectRight(AceRights.ObjectRight.CR));
sd=SID.newInstance(NumberFacility.getBytes(0x000000000005));
sd.addSubAuthority(NumberFacility.getBytes(0x0A));
所有.设置ID(sd);
sddl.getDacl().getAces().add(self);
sddl.getDacl().getAces().add(全部);
}否则{
for(ACE:toBeChanged){
ace.setType(AceType.ACCESS\u DENIED\u OBJECT\u ace\u TYPE);
}
}
最终属性ntSecurityDescriptor=新基本属性(
“ntSecurityDescriptor”,sddl.toByteArray());
最终修改项[]修改=新修改项[1];
mods[0]=新修改项(
DirContext.REPLACE_属性,ntSecurityDescriptor);
修改属性(dn、mods);
// .....
要将ntSecurityDescriptor
选择为非特权帐户,您需要使用值为7的LDAP\u SERVER\u SD\u FLAGS\u OID服务器控件。这表示您需要安全描述符的所有部分减去SACL。默认值(包括SACL)似乎是导致属性不返回的原因,因为大多数非特权帐户将无法访问SACL,并且由于此AD似乎什么也不返回
有关此问题/答案的更多详细信息:
虽然此链接可以回答问题,但最好在此处包含答案的基本部分,并提供链接供参考。如果链接页面发生更改,仅链接的答案可能会无效。我刚刚介绍了答案的基本部分。ntSecurityDescriptor
的格式作为MS-DTYP开放规范文档的一部分在安全描述符第2.4节及其子节中进行了详细描述。挑战在于将其转换为能够实际解码结构的代码,因为在开源世界中,微软并没有为其提供库。Fabio Martelli创建并在其回答中引用的库对于那些尝试自己实现的人来说是一个很好的参考。问题是我如何获得二进制数据块。我必须向LDAP服务器发送什么?似乎要以非管理员身份检索该值,您需要设置LDAP\u server\u SD\u FLAGS\u OID
服务器控件。有关控件的某些信息,请参见此:。当在管理用户下运行时,似乎假定为控制,但不是在正常帐户下运行。不过,我还没有对此进行测试。@ChadSikorra谢谢,这正是我想要的。如果您感兴趣,我将在中提供更多详细信息。