Beginner guide to AEM permissions, group inheritance, and ACL evaluation.
Nội dung
- Giải thích nguyên nhân user bị thiếu quyền khi thao tác trên AEM (mở trang, sửa content, upload asset, replicate/publish, ...).
- Hiểu rõ ý nghĩa của wildcard và restriction (
"",*,/*,*/jcr:content*, ...) trongrep:glob. - Cung cấp quy trình từng bước để troubleshooting lỗi phân quyền nhanh chóng.
1. Cơ chế phân quyền JCR & Oak
Trên AEM Author, dữ liệu như Page, Asset, Component, Configuration và User được lưu trữ dưới dạng Node/Property trong JCR Repository, được quản lý bởi Apache Jackrabbit Oak.
Cơ chế kiểm soát truy cập của JCR/Oak dựa trên Access Control List (ACL). Mỗi node có thể có node con rep:policy (type rep:ACL, orderable) chứa các Access Control Entry (ACE) (node type rep:GrantACE / rep:DenyACE). Mỗi ACE gồm rep:principalName, rep:privileges và optional node con rep:restrictions (chứa các restriction như rep:glob, rep:ntNames, ...).

Có thể hình dung quá trình authorization như sau:

Các thuật ngữ cốt lõi
Principal
Principal là identity được Oak sử dụng để đánh giá quyền truy cập, thường là User hoặc Group.
Ví dụ:
Một user có thể là member của nhiều group. Khi Oak đánh giá quyền, các ACE áp dụng cho user và các group mà user thuộc về đều có thể tham gia vào quá trình authorization evaluation.
Privilege
Privilege mô tả một hoặc một nhóm thao tác mà Principal có thể thực hiện trên một JCR item.
Ví dụ:
Privilege có thể là:
- Aggregate privilege: bao gồm nhiều privilege khác.
- Non-aggregate privilege: privilege nguyên thủy.
Ví dụ:
Do đó, jcr:write không phải là một thao tác cụ thể mà là một aggregate privilege bao gồm nhiều quyền thao tác khác. Lưu ý: jcr:write KHÔNG bao gồm jcr:nodeTypeManagement — muốn tạo node với node type mới (vd tạo page/component mới) phải cấp thêm privilege này.
ACE — Access Control Entry
ACE là một entry trong ACL, xác định một Principal được Allow hoặc Deny một hoặc nhiều Privilege tại một JCR path, có thể kèm theo Restriction.
Có thể biểu diễn một ACE như:
Ví dụ:
Có thể hiểu:
content-authorsđược phép đọc các item phù hợp với restrictionpublic/*trong phạm vi của ACE này.
Restriction
Restriction là một điều kiện giới hạn phạm vi áp dụng của ACE.
Restriction không phải là một Privilege và cũng không phải là Allow/Deny. Nó bổ sung điều kiện để xác định ACE áp dụng cho những item nào hoặc trong điều kiện nào.
Một restriction thường gặp trong AEM là:
Ví dụ:
Có thể hiểu ở mức khái niệm:
ACE chỉ áp dụng cho các item/path phù hợp với pattern được chỉ định bởi
rep:glob.
Restriction được lưu dưới dạng property trong node con rep:restrictions của ACE. Ngoài rep:glob, Oak còn hỗ trợ rep:ntNames, rep:prefixes, rep:itemNames, rep:globs (multi-value, Oak 1.44+), rep:subtrees (Oak 1.44+).
Allow / Deny
Allow / Deny xác định ACE đang cho phép hoặc từ chối các Privilege được khai báo.
Ví dụ:
Allow/Deny là effect của ACE, không phải Action.
Permission
Permission nên được hiểu là quyết định authorization cuối cùng của Oak Security: một Principal có được phép thực hiện một thao tác tương ứng với required privilege trên một JCR item/path hay không.
Ví dụ:
Do đó, có thể ghi nhớ:
Permission không phải là một thành phần đơn lẻ của ACE. ACE chứa thông tin về Principal, Privilege, Allow/Deny và Restriction. Permission là kết quả của quá trình Oak Security đánh giá các ACE áp dụng cho một Principal và một JCR item/path để quyết định thao tác có được phép hay không.
Tóm tắt
Có thể nhớ ngắn gọn:
ACE là rule, ACL là tập hợp các rule, còn Permission là kết quả sau khi Oak đánh giá các rule đó.
Quy tắc đánh giá ACL (Oak Access Control Evaluation)
Khi user thao tác trên một JCR item, Oak thu thập các ACE khớp principal set (user + tất cả group của user) dọc theo cây từ target đi lên, sắp xếp chúng theo thứ tự ưu tiên, rồi lấy ACE khớp đầu tiên trong thứ tự đó làm kết quả:
Thứ tự ưu tiên (theo tài liệu chính thức Oak — Default Permission Evaluation):
- Mặc định DENY: Nếu không có ACE nào khớp trên toàn bộ đường đi từ target lên tới root → từ chối. (AEM docs: "If no permissions are defined for a page, then all actions are denied.")
- ACE cụ thể hơn thắng (Most specific path wins): Oak đánh giá từ node đang bị tác động, đi ngược lên các node cha cho tới khi gặp ACE khớp đầu tiên — ACE ở node gần target nhất được xét trước ACE kế thừa từ node cha. Hệ quả quan trọng: Deny ở node cha KHÔNG chặn được Allow ở node con cụ thể hơn. Ví dụ:
deny jcr:readtại/content+allow jcr:readtại/content/public→ subtree/content/publicvẫn đọc được. - ACE của User thắng ACE của Group: ACE gán trực tiếp cho user luôn được đánh giá trước ACE của các group mà user thuộc về, bất kể thứ tự trong danh sách hay độ sâu của node ("user principals always take precedence over group principals"). Ví dụ: user có
allowtại/home/user-atrong khi groupeveryonecódenytại chính path đó → user vẫn có quyền. - Trong cùng principal type + cùng path: ACE ghi SAU thắng (entry order): Các ACE trong một ACL được đánh giá theo thứ tự ngược với thứ tự được ghi vào danh sách — ACE ghi sau cùng có độ ưu tiên cao nhất, và ACE khớp đầu tiên trong thứ tự đánh giá quyết định kết quả. KHÔNG có quy tắc "Deny thắng Allow" trong Oak: một Deny chỉ thắng khi nó được ghi sau Allow cạnh tranh (hoặc là ACE của user).
- Restriction là một phần của điều kiện "khớp" ACE (
rep:glob,rep:ntNames, ...) — nếu restriction không khớp item đang xét, ACE đó bị bỏ qua và Oak tiếp tục tìm ACE khác; restriction không phải một bước đánh giá riêng sau khi đã quyết định allow/deny. - Administrators không bị ràng buộc bởi ACL: các principal admin (vd
admin) luôn có toàn quyền trên toàn bộ repository, kể cả khi tồn tại ACE deny-everyone trên node.
Yếu tố quyết định là thứ tự đánh giá ACE, không phải Allow hay Deny. Quan niệm "Deny luôn thắng Allow" là quy tắc của Jackrabbit 2.x / CRX 2 — Oak đã bỏ quy tắc này. Khi troubleshooting, hãy xem thứ tự thực tế của các ACE trong rep:policy (CRXDE → tab Access Control) hoặc trong file cấu hình Repoinit / Netcentric ACL Tool, đừng chỉ nhìn "có allow hay có deny".
2. Wildcard & Restriction Patterns (rep:glob)
rep:glob là restriction dùng để giới hạn phạm vi tác dụng của ACE xuống một tập item con bên dưới path được gán mà không cần tạo thêm ACE thủ công tại từng node con.
Các ví dụ dưới đây lấy ACE gán tại /content/mysite:
3. Tại sao User bị thiếu quyền? (Root Causes & Hidden Dependencies)
Dev và Support Engineer rất hay gặp tình trạng: User được gán Allow trên path trang nhưng vẫn bị lỗi 403, không sửa được trang, hoặc bấm Replicate/Publish không có tác dụng.
Dưới đây là các nguyên nhân cốt lõi về Dependency của AEM Architecture:
Nguyên nhân 1: Thiếu Read permission trên Path cha (Hierarchy Scope)
Để mở được path /content/mysite/en/page-a, Oak yêu cầu user phải có jcr:read trên node đó và trên các node tổ tiên (để traverse cây JCR). Nếu user bị deny jcr:read ở /content hoặc /content/mysite (và không có allow cụ thể hơn ở dưới), user sẽ không thể đi xuyên cây để tới trang con. (Nhớ quy tắc most-specific-wins: một allow jcr:read tại node con cụ thể hơn sẽ khôi phục quyền đọc ở chính node con đó.)
Nguyên nhân 2: Thiếu Read trên các Path phụ thuộc (Hidden Dependencies)
Trang AEM không đứng một mình. Để render và chỉnh sửa 1 trang trên Author Instance, User bắt buộc phải có jcr:read trên:
/conf/...: Nơi chứa Editable Templates, Content Policies, Page Component Configurations. Nếu thiếu -> Trang báo lỗi "Error loading page" hoặc trắng trang./apps/...&/libs/...: Nơi chứa Client Libraries (JS/CSS), Component Dialogs, Granite UI icons. Nếu thiếu -> Dialog không mở được, UI bị hỏng./content/dam/...: Nơi chứa Hình ảnh, Video, Content Fragments được nhúng vào trang. Nếu thiếu -> Không thấy asset trong Asset Finder hoặc không chọn được Image./content/cq:tags/...: Nơi chứa taxonomy tags. Thiếu quyền -> Không chọn được Tag trong Page Properties.
Nguyên nhân 3: Nhầm lẫn giữa Node Privileges (Modify vs Add/Remove Child)
- Edit Property (VD: Sửa Title, Description): Cần Privilege
jcr:modifyProperties. - Thêm Component mới vào Layout Container: Cần
jcr:addChildNodes+jcr:nodeTypeManagement(để tạo node component mới bên dướijcr:content/root/...với node type riêng —jcr:writekhông bao gồmjcr:nodeTypeManagement). - Xóa / Di chuyển Component: Cần
jcr:removeChildNodes(trên node cha) hoặcjcr:removeNode(trên chính node bị xóa); di chuyển thêmjcr:addChildNodes+jcr:nodeTypeManagementở đích.
Nguyên nhân 4: Tại sao không Replicate / Publish được?
Để một Author bấm nút Quick Publish hoặc Manage Publication thành công:
- User cần privilege
crx:replicatetrên path trang/content/mysite/.... - User cần
crx:replicatetrên cả Assets phụ thuộc/content/dam/...nếu chọn "Publish with referenced assets". - Việc ghi vào queue
/var/replication/...do replication agent (chạy bằng service user / credentials riêng) đảm nhiệm — user tác giả KHÔNG cần quyền trên/var. - Nếu site dùng workflow publish (Manage Publication với tùy chọn "Request for Publish"), user cần thuộc nhóm được phép khởi tạo workflow (vd
workflow-users) để bắt đầu workflow.
4. Ma trận Thao tác Authoring vs JCR Path & Privilege
Bảng tra cứu nhanh dành cho Support Engineers & Developers khi cấp quyền cho Group:
5. Quy trình Troubleshooting dành cho Support Engineer & Dev
Khi nhận được Ticket báo lỗi "User X không thể làm Y (mở trang/sửa trang/publish)", hãy thực hiện 5 bước sau:
Bước 1: Kiểm tra User thuộc những Group nào?
- Vào User Admin (
/libs/granite/security/content/admin.htmlhoặc/security/users.html). - Tra cứu User, xem danh sách
Groupsmà User tham gia. Lưu ý các Group kế thừa (Group lồng Group).
Bước 2: Kiểm tra Phân quyền tại Path chính
- Kiểm tra xem Group của User có được cấp
jcr:readtừ root/contentxuống target path hay chưa (nhớ quy tắc most-specific-wins: deny ở cha có thể bị allow ở con cụ thể hơn ghi đè). - Thao tác Create/Edit/Publish đã có đúng Privilege tương ứng (xem Ma trận ở Section 4) chưa?
Bước 3: Soi các ACE xung đột (Deny vs Allow, thứ tự, rep:glob)
- Liệt kê toàn bộ ACE áp dụng cho user và các group của user trên path đang lỗi (CRXDE → tab Access Control, hoặc đọc trực tiếp node
rep:policy). - Nhớ 3 quy tắc đánh giá: (1) ACE của user thắng ACE của group; (2) ACE cụ thể hơn (node gần target) thắng ACE kế thừa từ cha; (3) cùng principal + cùng path thì ACE ghi sau thắng — không có quy tắc "Deny thắng Allow". Một Deny "có vẻ" không có tác dụng thường do bị Allow ghi sau (hoặc Allow của user) thắng.
- Kiểm tra
rep:glob: glob được nối vào path của node chứa ACE. Ví dụrep:glob = ""chỉ ảnh hưởng đúng node đó (không phải con cháu);rep:glob = "*/jcr:content*"chỉ phủ các nodejcr:contentở mọi cấp — nếu Allow chỉ phủ pattern này thì user sửa được nội dung trong trang nhưng không tạo/đổi tên/xóa đượccq:Page(đúng thiết kế, không phải lỗi phân quyền).
Bước 4: Kiểm tra Path phụ thuộc (Dependencies)
- Nếu User mở trang bị lỗi 403 / 500 hoặc không thấy Template: Kiểm tra quyền
jcr:readtrên/conf/<site-name>. - Nếu không thấy Asset: Kiểm tra quyền
jcr:readtrên/content/dam/<site-name>.
Bước 5: Verify bằng công cụ
- User Impersonation: Trong AEM Author, admin có thể Impersonate thành User đó để tái hiện lỗi trên giao diện UI.
- CRXDE Lite Access Control Tab: Chọn node -> Tab
Access Controlở góc dưới phải để xem danh sách ACE thực tế đang có hiệu lực (kể cả thứ tự ACE). - Repository initialiser (Repoinit) / Netcentric ACL Tool: Đảm bảo file cấu hình ACL trong codebase (Repoinit / YAML) khớp với môi trường đang chạy. Lưu ý thứ tự câu lệnh
allow/denytrong file quyết định thứ tự ghi ACE — do đó quyết định ACE nào thắng khi xung đột.
Tài liệu tham khảo thêm
- ACL and Permission Deep-Dive - Tài liệu nâng cao về Repoinit, Netcentric ACL Tool, Service Users và Programmatic ACLs trong Java/Groovy.
- Oak Restrictions (rep:glob) — Official Documentation
- Oak Default Permission Evaluation — Official Documentation
- AEM Security & Oak Access Control Official Documentation