如何按规范顺序对SDDL DACL的ACE进行排序?
问题描述
我用ADSDDL库(依赖为implementation("net.tirasa:adsddl:1.9"))操作SDDL,调用SDDLHelper.userCannotChangePassword(sddl, true)启用「用户不能更改密码」标志后,在Windows ADAC(Active Directory管理中心)里收到提示,说我的ACE未按规范顺序排列,建议重新排序。查看DACL里的ACE后,发现问题出在类似(OA;;WP[16];5805bc62-bdc9-4428-a5e2-856a0f4c185e;;S-1-5-32-561)的片段——OD类型ACE出现在OA类型之后。我想解决通用排序问题并实现排序逻辑,请问哪里能找到完整的排序规则?我找到了微软官方文档,但看不懂Explicit ACEs、Deny ACEs、Regular ACEs、object ACEs这些术语的含义,怎么在代码里识别这些类型?
一、ACE规范排序规则
Windows AD对DACL内的ACE顺序有强制规范,正确排序逻辑优先级从高到低为:
- 显式拒绝ACE(直接给对象添加的拒绝权限)
- 显式允许ACE(直接给对象添加的允许权限)
- 继承的拒绝ACE(从父对象继承的拒绝权限)
- 继承的允许ACE(从父对象继承的允许权限)
同一优先级组内还要细分:
- 先处理常规ACE,再处理对象ACE
- 对象ACE内部,先排对象拒绝(OD),再排对象允许(OA)
二、关键ACE类型含义与代码识别(基于ADSDDL库)
1. 显式/继承ACE(Explicit/Inherited ACEs)
- 显式ACE:直接为目标对象配置的权限,非从父容器继承
- 继承ACE:从父容器继承而来的权限
- 代码识别:调用
ACE类的isInherited()方法,返回false为显式ACE,true为继承ACE
2. 拒绝/允许ACE(Deny/Allow ACEs)
- 拒绝ACE:明确禁止主体的某项操作权限
- 允许ACE:明确授予主体的某项操作权限
- 代码识别:调用
ACE类的getAceType()方法,值为AceType.ACCESS_DENIED_ACE_TYPE或AceType.ACCESS_DENIED_OBJECT_ACE_TYPE即为拒绝ACE;值为AceType.ACCESS_ALLOWED_ACE_TYPE或AceType.ACCESS_ALLOWED_OBJECT_ACE_TYPE即为允许ACE
3. 常规/对象ACE(Regular/Object ACEs)
- 常规ACE:针对对象本身的基础权限(如读取对象基本属性),不涉及特定属性或扩展类
- 对象ACE:针对对象特定属性、扩展属性或对象类的权限(比如你遇到的OA/OD,就是针对密码属性的对象级允许/拒绝权限)
- 代码识别:调用
ACE类的getAceType()方法,枚举值带OBJECT后缀的即为对象ACE,其余为常规ACE
三、基于ADSDDL的ACE排序实现
自定义Comparator实现规范排序:
import net.tirasa.adsddl.ntsd.ACE; import net.tirasa.adsddl.ntsd.AceType; import java.util.Comparator; public class ACEComparator implements Comparator<ACE> { @Override public int compare(ACE ace1, ACE ace2) { // 第一步:按显式/继承+拒绝/允许划分优先级组 int group1 = getPriorityGroup(ace1); int group2 = getPriorityGroup(ace2); if (group1 != group2) { return Integer.compare(group1, group2); } // 第二步:同组内先常规ACE,后对象ACE boolean isObjAce1 = isObjectAce(ace1); boolean isObjAce2 = isObjectAce(ace2); if (isObjAce1 != isObjAce2) { return isObjAce1 ? 1 : -1; } // 第三步:对象ACE内部先拒绝,后允许 if (isObjAce1) { boolean isDeny1 = isDenyAce(ace1); boolean isDeny2 = isDenyAce(ace2); if (isDeny1 != isDeny2) { return isDeny1 ? -1 : 1; } } // 其余情况保持原有相对顺序 return 0; } private int getPriorityGroup(ACE ace) { boolean isInherited = ace.isInherited(); boolean isDeny = isDenyAce(ace); if (!isInherited && isDeny) return 1; // 显式拒绝 if (!isInherited && !isDeny) return 2; // 显式允许 if (isInherited && isDeny) return 3; // 继承拒绝 return 4; // 继承允许 } private boolean isDenyAce(ACE ace) { AceType type = ace.getAceType(); return type == AceType.ACCESS_DENIED_ACE_TYPE || type == AceType.ACCESS_DENIED_OBJECT_ACE_TYPE; } private boolean isObjectAce(ACE ace) { AceType type = ace.getAceType(); return type == AceType.ACCESS_ALLOWED_OBJECT_ACE_TYPE || type == AceType.ACCESS_DENIED_OBJECT_ACE_TYPE; } }
使用示例:
// 假设已获取目标SDDL对象 SDDL sddl = ...; // 取出DACL的ACE列表并排序 List<ACE> aces = new ArrayList<>(sddl.getDacl().getAces()); aces.sort(new ACEComparator()); // 重新设置排序后的ACE并生成新SDDL字符串 sddl.getDacl().setAces(aces); String sortedSddl = sddl.toString();
此逻辑会让OD类型ACE排在OA之前,完全符合ADAC的规范要求。
内容的提问来源于stack exchange,提问作者gstackoverflow
相关产品推荐
相关产品推荐

