Skip to content

RANGER-5627: Support configuration-based super users and super groups in Ranger Admin#1000

Open
ramackri wants to merge 2 commits into
masterfrom
RANGER-5627-patch
Open

RANGER-5627: Support configuration-based super users and super groups in Ranger Admin#1000
ramackri wants to merge 2 commits into
masterfrom
RANGER-5627-patch

Conversation

@ramackri
Copy link
Copy Markdown
Contributor

@ramackri ramackri commented Jun 7, 2026

What changes were proposed in this pull request?

Implements RANGER-5627: configuration-based
Ranger Admin super users and super groups via ranger.admin.super.users and
ranger.admin.super.groups in ranger-admin-site.xml.

Problem addressed: Externally authenticated users (LDAP/Kerberos/OIDC/SAML) could
not be designated as Ranger administrators without Ranger managed DB roles. Deployments
relied on shared local admin accounts, limiting enterprise IdM integration, SSO/K8s
models, and per-user auditability.

Solution: Matching users receive full admin session flags, Spring Security roles,
module permissions, and REST authorization at login without changing
x_portal_user_role. Authentication provider remains independent of the elevation
decision. Backward compatible when both config properties are empty. Re-login
required after config or UserSync group membership changes.

Key changes:

  • New RangerSuperUserConfig; session elevation in SessionMgr / UserSessionBase
  • UserMgr.getAuthenticationRolesByLoginId() and profile overrides; XUserMgr.getSyncedGroupsForUser() for super.groups
  • REST/biz bypass of ROLE_USER-only paths via isSingleRoleUserSession() and RangerBizUtil.isUserRangerAdmin()
  • Jira admin capabilities: services, policies, users/groups, roles, audit, security admin
  • UI: XAUtils.js multi-role check; OpenAPI/Swagger alias fixes for local API testing
  • Unit tests; Docker E2E scripts under dev-support/ranger-docker/scripts/admin/; design docs

What changes were proposed in this pull request?

Implements RANGER-5627.

Configuration & template

  • Add ranger.admin.super.users and ranger.admin.super.groups to
    security-admin/src/main/resources/conf.dist/ranger-admin-site.xml and
    security-admin/scripts/ranger-admin-site-template.xml.

New core class

  • RangerSuperUserConfig — reads config, isEnabled(), isSuperUser(loginId, groups),
    case-insensitive user match, group membership check, helpers to merge config super-user
    roles into authentication and profile role lists.

Session & authentication

  • SessionMgrapplyConfigSuperUserSessionFlags() at login; sets
    userAdmin, keyAdmin, configSuperUser; grants all UI modules via
    resetUserModulePermission() when isEffectiveRangerAdmin() or key admin.
  • UserSessionBaseconfigSuperUser flag; isEffectiveRangerAdmin() =
    userAdmin || configSuperUser; isSingleRoleUserSession() bypasses ROLE_USER-only
    restrictions for config super-users.
  • UserMgrgetAuthenticationRolesByLoginId() for Spring Security;
    applyConfigSuperUserProfileOverrides() on /user/profile.
  • Auth filters & RangerAuthenticationProvider — use
    getAuthenticationRolesByLoginId() instead of DB-only role lookup.

Authorization & REST

  • RangerBizUtilisUserRangerAdmin(), isConfigSuperUser(),
    checkUserAccessible() honor session/config elevation.
  • XUserMgrgetSyncedGroupsForUser() for login-time group resolution (DAO,
    no API masking); getGroupsForUser() restored for API paths; isSingleRoleUserSession()
    bypass in group search.
  • RoleDBStore, RoleREST, ServiceREST, XUserREST, AssetREST
    — skip ROLE_USER-only masking when isSingleRoleUserSession() or config super-user
    checks apply.

UI (minimal)

  • react-webapp/src/utils/XAUtils.jsLoginUser() uses
    roles.includes(role) instead of userRoleList[0] only.

Not changed: RoleForm.jsx, EditPermission.jsx, UserForm.jsx — stock
Add-then-Save UX retained.

Unit tests

  • New: TestRangerSuperUserConfig
  • Updated: TestSessionMgr, TestUserMgr, TestXUserMgr, TestRangerBizUtil,
    TestRoleDBStore, TestAssetREST, TestServiceREST, TestXUserREST,
    TestRangerHeaderPreAuthFilter

OpenAPI / Swagger UI Fix

  • distro/src/main/assembly/admin-web.xml — ship swagger.json as an alias of
    openapi.json in the admin tarball (backward-compatible Swagger UI load path).
  • docs/src/site/resources/index.js — Swagger UI loads openapi.json instead
    of swagger.json (supports OpenAPI parity scripts and local API docs testing).

How was this patch tested?

Prerequisites — minimal Docker stack

Only three components are required to validate config super-users (no Hive, HDFS,
Kafka, or audit tier needed):

Component Purpose
PostgreSQL (ranger-postgres) Ranger Admin DB
Ranger Admin (ranger) UI + REST at http://localhost:6080
Ranger UserSync (ranger-usersync) Syncs users/groups from CSV into x_user, x_group, x_group_users

One-time setup (from repo root):

# Build Ranger and stage tarballs for docker
mvn clean package -DskipTests
cp target/ranger-* dev-support/ranger-docker/dist/
cp target/version dev-support/ranger-docker/dist/

cd dev-support/ranger-docker
chmod +x scripts/**/*.sh
export RANGER_DB_TYPE=postgres
export ENABLE_FILE_SYNC_SOURCE=true

Start minimal stack:

cd dev-support/ranger-docker
export RANGER_DB_TYPE=postgres
export ENABLE_FILE_SYNC_SOURCE=true

# DB + Admin (includes KDC, ZK, Solr — required by docker-compose.ranger.yml)
docker compose -f docker-compose.ranger-db.yml -f docker-compose.ranger.yml up -d

# Wait until login page responds (~2–3 min on first boot)
curl -sf http://localhost:6080/login.jsp

# UserSync — file-based sync from ugsync-file-source.csv
docker compose -f docker-compose.ranger-db.yml -f docker-compose.ranger.yml \
  -f docker-compose.ranger-usersync.yml up -d ranger-usersync

Super-user config (must be present before testing; included in this PR’s
ranger-admin-site.xml template):

<property>
  <name>ranger.admin.super.users</name>
  <value>testuser_2</value>
</property>
<property>
  <name>ranger.admin.super.groups</name>
  <value>testgroup_3A</value>
</property>

After changing config or rebuilding the admin image, recreate the ranger
container and re-login test users.

Default credentials: admin / rangerR0cks! · testuser_* / rangerR0cks!


Dev user/group CSV (ugsync-file-source.csv)

Path: dev-support/ranger-docker/scripts/usersync/ugsync-file-source.csv

This file drives both first-boot bootstrap and ongoing UserSync membership.
It is mounted into the UserSync container and also read by
create-ranger-services.py when the ranger container starts.

Format: one row per user; first column = login id; remaining columns = group names
(comma-separated, no header row).

testuser_1,testgroup_1A,testgroup_1B,testgroup_3A,testgroup_3B,
testuser_2,testgroup_2A,testgroup_2B,testgroup_3A,testgroup_3B,
testuser_3,testgroup_3A,testgroup_3B,testgroup_3A,testgroup_3B,
...
testuser_7,testgroup_7A,testgroup_7B,testgroup_3A,testgroup_3B,
...
testuser_10,testgroup_10A,testgroup_10B,testgroup_3A,testgroup_3B,
CSV field Meaning
Column 1 (testuser_N) Ranger portal login id
Columns 2+ (testgroup_*) Group memberships synced into Ranger DB
testgroup_3A Matches ranger.admin.super.groups in config — required for super.groups E2E
Password Not in CSV; set to rangerR0cks! by create-ranger-services.py bootstrap

Why UserSync matters for super.groups: Config does not query LDAP/files at
login. It reads group names already stored in Ranger DB (x_group_users) by
UserSync. Without UserSync (or bootstrap), testuser_7 would have no
testgroup_3A membership and would not elevate via super.groups.


Ranger UserSync — start and verify

UserSync runs as container ranger-usersync with ENABLE_FILE_SYNC_SOURCE=true
(see dev-support/ranger-docker/.env). The CSV is bind-mounted from
scripts/usersync/ugsync-file-source.csv.

Start (if not already up with the stack):

export ENABLE_FILE_SYNC_SOURCE=true
docker compose -f docker-compose.ranger-db.yml -f docker-compose.ranger.yml \
  -f docker-compose.ranger-usersync.yml up -d ranger-usersync

Wait for first sync cycle (~60–90 seconds), then check logs:

docker ps --filter name=ranger-usersync
docker logs ranger-usersync 2>&1 | tail -40

Verify membership in DB (prerequisite for testuser_7 / super.groups):

docker exec ranger-postgres psql -U rangeradmin -d ranger -c \
  "SELECT u.user_name, g.group_name FROM x_user u
   JOIN x_group_users gu ON u.id=gu.user_id
   JOIN x_group g ON g.id=gu.group_id
   WHERE u.user_name IN ('testuser_2','testuser_7') AND g.group_name='testgroup_3A'
   ORDER BY 1;"

Verify in Admin UI (as admin): Settings → Users/Groups → Users → open
testuser_7Groups tab → confirm testgroup_3A. User roles should
still show ROLE_USER only (config elevation does not change DB roles).

After CSV edits: restart ranger-usersync, wait for sync, confirm membership
in UI/DB, then logout and login as the affected user.


1. Unit tests

Run from repo root:

mvn test -pl security-admin \
  -Dtest=TestRangerSuperUserConfig,TestSessionMgr,TestUserMgr,TestXUserMgr,TestRangerBizUtil,TestRoleDBStore \
  -Dfrontend.skip=true

Result: All targeted unit tests pass.

Test class Coverage
TestRangerSuperUserConfig Config parsing, enable/disable, user/group match
TestSessionMgr Session flags and module permissions at login
TestUserMgr Authentication roles and profile overrides
TestXUserMgr getSyncedGroupsForUser vs getGroupsForUser
TestRangerBizUtil isUserRangerAdmin, access checks
TestRoleDBStore Role list bypass for elevated sessions

2. Manual UI smoke (required for reviewers)

Use form login at http://localhost:6080/login.jsp (JDBC auth — username +
password, not SSO/Kerberos for testuser_*).

Important: Elevation is applied at login. After any config or UserSync
change, log out completely and log in again before checking the UI.

3a. Baseline — confirm UserSync data (as admin)

  1. Log in as admin / rangerR0cks!.
  2. Go to Settings → Users/Groups → Users.
  3. Confirm testuser_2 and testuser_7 exist.
  4. Open testuser_7Groups → confirm testgroup_3A is listed.
  5. Open testuser_2 / testuser_7Roles → confirm DB role is
    ROLE_USER only (not SYS admin). Config super-user does not mutate DB roles.

3b. super.users path — testuser_2

  1. Log out. Log in as testuser_2 / rangerR0cks!.
  2. Profile (top-right user menu → Profile):
    • Expected: Roles include ROLE_SYS_ADMIN and ROLE_KEY_ADMIN.
    • Expected: No “You do not have privilege” or empty-permissions error.
    • Failure sign: Only ROLE_USER shown, or profile page error banner.
  3. Left nav — module tabs:
    • Users/Groups — list loads; no HTTP 403 in browser Network tab.
    • Roles — role list visible (not empty due to ROLE_USER masking).
    • Permissions — permission list visible.
    • Audit — tab present and loads (not hidden by KMS-only repo filter).
    • Key Manager — accessible.
  4. Resource Based Policies — service list visible (same general access as admin
    for read/list operations).

3c. super.groups path — testuser_7

  1. Log out. Log in as testuser_7 / rangerR0cks!.
  2. Repeat the same checks as 3b. This validates the getSyncedGroupsForUser
    fix: elevation via group membership synced by UserSync, not via super.users.
  3. If testuser_7 fails but testuser_2 passes, check UserSync first
    (DB query / Groups tab) before assuming an auth bug.

3d. Create / edit smoke (stock Add-then-Save UX)

Still logged in as testuser_2 or testuser_7:

Area Steps Expected
Group Settings → Users/Groups → Add New Group → enter name → Save Group created; no 403
User Add New User → fill fields → Save User created
Role Access → Roles → Add New Role → fill → Save Role created
Permission Access → Permissions → edit a permission → pick user/group from dropdown → click + (Add)Save Must use Add before Save (stock UI); save succeeds without “does not have privilege”

The permission editor is client-side: selecting a user/group in the dropdown
without clicking Add before Save will show a validation error — that is
expected stock behavior, not a super-user regression.

3e. Negative control — no elevation

  1. Pick a user not in ranger.admin.super.users and not a member of any
    group listed in ranger.admin.super.groups (edit CSV to remove testgroup_3A
    from one user, re-sync UserSync, or verify in UI).
  2. Log in as that user.
  3. Expected: Profile shows ROLE_USER only; Users/Groups, Roles,
    and admin-only modules are restricted or hidden; no SYS/KEY admin roles on profile.
  4. Optional: compare side-by-side with admin (DB admin) to confirm config
    super-user matches admin capability without DB role change.

3f. Optional DevTools check

After login as testuser_2 or testuser_7, open Network
GET /service/users/profile:

  • userRoleList should contain ROLE_SYS_ADMIN and ROLE_KEY_ADMIN.
  • userPermList should include Users/Groups, Key Manager, Audit, etc.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ramackri
Copy link
Copy Markdown
Contributor Author

ramackri commented Jun 7, 2026

Comment thread security-admin/scripts/ranger-admin-site-template.xml Outdated
Comment thread security-admin/scripts/ranger-admin-site-template.xml Outdated
Comment thread security-admin/src/main/java/org/apache/ranger/common/UserSessionBase.java Outdated
Comment thread security-admin/src/main/java/org/apache/ranger/biz/RangerBizUtil.java Outdated
Rename configSuperUser to superUser, simplify role getters via OR with
superUser flag, refactor hasKMSPermissions, and update config descriptions
per PR #1000 review feedback.

Co-authored-by: Cursor <cursoragent@cursor.com>
List<String> permissionList;

if (userSession.isUserAdmin() || userSession.isKeyAdmin()) {
List<XXModuleDef> allModules =
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of retrieving list of XXModuleDef objects, retrieving only attribute module (which is referenced in line 233 below) will be more efficient. Consider adding method XXModuleDefDao.getAllModuleNames() to return only the attribute needed here.

applyConfigSuperUserSessionFlags(userSession);

if (userSession.isSuperUser()) {
strRoleList = RangerSuperUserConfig.mergeConfigSuperUserRoles(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For readability, please unnecessary line splits like this - long gone are the days code was printed in paper, which limited line length to 80 or 132. Please review other updates in this PR.

return;
}

Set<String> userGroups = xUserMgr.getSyncedGroupsForUser(loginId);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider calling getSyncedGroupsForUser() only when necessary.

final boolean isSuperUser;

if (RangerSuperUserConfig.isSuperGroupsConfigured()) {
  isSuperUser = RangerSuperUserConfig.isSuperUser(loginId, xUserMgr.getSyncedGroupsForUser(loginId));
} else {
  isSuperUser = RangerSuperUserConfig.isSuperUser(loginId);
}

if (isSuperUser) {
  userSession.setSuperUser(true);

  logger.info("Granted full admin privileges via config for user {}", loginId);
} else {
  userSession.setSuperUser(false);
}

* entry
*/
public static boolean isEnabled() {
return hasNonEmptyEntry(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider initializing in the constructor and return the value from isEnabled(); this will help avoid unnecessary overheads in each call.

public final class RangerSuperUserConfig {
  private final boolean isEnabled;
  private final boolean isSuperUsersConfigured;
  private final boolean isSuperGroupsConfigured;

  private RangerSuperUserConfig() {
    isSuperUsersConfigured  = hasNonEmptyEntry(PropertiesUtil.getPropertyStringList(RangerConstants.RANGER_ADMIN_SUPER_USERS));
    isSuperGroupsConfigured = hasNonEmptyEntry(PropertiesUtil.getPropertyStringList(RangerConstants.RANGER_ADMIN_SUPER_GROUPS));
    isEnabled               = isSuperUsersConfigured || isSuperGroupsConfigured;
  }

  ...
}

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

Successfully merging this pull request may close these issues.

2 participants