How Jenkins Implements ACL and Authorization Strategies: Security Model Deep Dive

Jenkins uses a two-layer security model where AuthorizationStrategy supplies the root ACL that evaluates permissions against Authentications, allowing plugins to implement matrix, role-based, or custom access controls without modifying core permission checks.

The Jenkins security model in the jenkinsci/jenkins repository centers on a pluggable architecture that separates policy definition from enforcement. Understanding how Jenkins ACL and authorization strategies interact is essential for securing CI/CD pipelines and developing custom security plugins. This architecture allows administrators to mix authentication realms with authorization strategies while maintaining fine-grained access control over jobs, views, nodes, and configuration.

Core Components of the Jenkins Security Model

Jenkins security relies on two primary abstractions defined in hudson.security: the AuthorizationStrategy and the ACL. According to the jenkinsci/jenkins source code, these classes work together to determine whether a specific user or system process can perform an action.

AuthorizationStrategy as the Policy Provider

The AuthorizationStrategy abstract class, located in core/src/main/java/hudson/security/AuthorizationStrategy.java, serves as the entry point for all access control decisions. It provides the root ACL through the getRootACL() method, which all other ACLs ultimately delegate to.

public abstract class AuthorizationStrategy {
    /** Returns the ultimate ACL that all other ACLs delegate to. */
    public abstract @NonNull ACL getRootACL();
}

ACL as the Permission Enforcer

The ACL class in core/src/main/java/hudson/security/ACL.java implements the actual permission-checking logic. It evaluates Permission objects against Authentication instances and recognizes three special principals: SYSTEM2 (the internal system user), EVERYONE (matches any principal), and ANONYMOUS (the unauthenticated user).

How the Root ACL Controls Access

When Jenkins starts, it initializes a single AuthorizationStrategy implementation—either FullControlOnceLoggedInAuthorizationStrategy or the unsecured AuthorizationStrategy.UNSECURED. The strategy's getRootACL() method returns the ultimate ACL stored in the global Jenkins object.

This root ACL has final authority over every permission request in the system. All other ACLs in the hierarchy ultimately delegate to this root instance, making it the central policy enforcement point for the entire Jenkins security model.

Object-Specific ACLs for Fine-Grained Control

AuthorizationStrategy can override specific getACL(...) methods to supply custom ACLs for particular model objects. By default, these methods return the root ACL, but plugins can override them to implement per-job or per-view permissions.

public @NonNull ACL getACL(@NonNull Job<?, ?> project) { return getRootACL(); }
public @NonNull ACL getACL(final @NonNull View view) { … }

This design enables matrix-based or role-based access control without modifying core permission checks. The AuthorizationStrategy determines which ACL applies to each object, while the ACL itself performs the actual permission evaluation.

Permission Checking Mechanics in ACL

Every permission check flows through the ACL class. The convenience methods checkPermission(Permission), hasPermission(Permission), and checkAnyPermission(...) automatically retrieve the current Authentication via Jenkins.getAuthentication2() and delegate to hasPermission2(Authentication, Permission).

The core check in hasPermission2 is abstract, allowing concrete implementations to define their own logic. The built-in UNSECURED_ACL uses a lambda that always returns true:

private static final ACL UNSECURED_ACL = ACL.lambda2((a, p) -> true);

When checking permissions, the system automatically grants access to SYSTEM2 and evaluates the permission hierarchy through the impliedBy chain:

public final void checkPermission(@NonNull Permission p) {
    Authentication a = Jenkins.getAuthentication2();
    if (a.equals(SYSTEM2)) return;                // system user → full access
    if (!hasPermission2(a, p)) {                  // delegate to concrete ACL
        while (!p.enabled && p.impliedBy != null) p = p.impliedBy;
        throw new AccessDeniedException3(a, p);
    }
}

Impersonation and Context Handling

The ACL class provides utilities for temporary impersonation through the as2(Authentication) method, which creates an ACLContext defined in core/src/main/java/hudson/security/ACLContext.java. This pushes a new Authentication onto the thread-local SecurityContextHolder, allowing plugins to execute code as a different user.

User bob = User.get("bob");
try (ACLContext ctx = ACL.as(bob)) {
    // code executed as bob
    Job<?,?> job = Jenkins.get().getItemByFullName("example", Job.class);
    job.scheduleBuild2(0);   // allowed only if bob has Job/Build permission
}

This pattern is essential when build steps need to trigger other jobs or access resources under the identity of the user who initiated the build, rather than the system user.

Implementing Custom Authorization Strategies

To create a custom security model, extend AuthorizationStrategy and override getRootACL() to return a custom ACL implementation. Register the strategy with @Extension and @Symbol for the Jenkins configuration UI.

@Extension @Symbol("simpleMatrix")
public class SimpleMatrixStrategy extends AuthorizationStrategy {
    private final Map<String, Set<String>> userToRoles = new ConcurrentHashMap<>();

    @Override
    public @NonNull ACL getRootACL() {
        return ACL.lambda2((auth, perm) -> {
            // grant everything to SYSTEM
            if (auth.equals(ACL.SYSTEM2)) return true;

            // look up roles assigned to the user name
            Set<String> roles = userToRoles.getOrDefault(auth.getName(), Set.of());
            // evaluate permission against roles (pseudo‑logic)
            return roles.stream().anyMatch(r -> RoleTable.isAllowed(r, perm));
        });
    }
}

The minimal implementation demonstrates the unsecured strategy pattern:

public static final class Unsecured extends AuthorizationStrategy implements Serializable {
    @Override
    public @NonNull ACL getRootACL() {
        return UNSECURED_ACL;                // always true
    }
    private static final ACL UNSECURED_ACL = ACL.lambda2((a, p) -> true);
}

Summary

  • AuthorizationStrategy supplies the root ACL that determines all permission checks in Jenkins, as defined in core/src/main/java/hudson/security/AuthorizationStrategy.java.
  • ACL implements the actual enforcement logic in core/src/main/java/hudson/security/ACL.java, evaluating permissions against Authentication objects with special handling for SYSTEM2, EVERYONE, and ANONYMOUS.
  • Object-specific ACLs allow fine-grained control via overridden getACL() methods in AuthorizationStrategy, enabling per-job or per-view security policies.
  • Thread-local impersonation uses ACL.as2() and ACLContext to temporarily switch security contexts for operations requiring different user identities.
  • Custom strategies extend AuthorizationStrategy and register via @Extension to integrate with Jenkins' pluggable security architecture without core modifications.

Frequently Asked Questions

What is the difference between AuthorizationStrategy and ACL in Jenkins?

AuthorizationStrategy acts as the policy provider that determines which ACL to use for specific objects, while ACL performs the actual permission evaluation against an Authentication. The strategy's getRootACL() method returns the ultimate decision-maker that all other ACLs delegate to, making it the final authority on every permission request.

How does Jenkins handle permissions for the internal system user?

The ACL class automatically grants all permissions to SYSTEM2 (accessible via ACL.SYSTEM2). In the checkPermission method, if the current authentication equals SYSTEM2, the check returns immediately without evaluating the permission, ensuring the internal Jenkins system has unrestricted access to all objects.

Can plugins implement role-based access control without modifying Jenkins core?

Yes. Plugins can extend AuthorizationStrategy and override getRootACL() or specific getACL(...) methods to return custom ACL implementations. By using ACL.lambda2() or creating custom ACL subclasses, plugins can implement matrix-based, role-based, or external authorization strategies while integrating with the standard permission checking API defined in core/src/main/java/hudson/security/ACL.java.

What files define the core Jenkins security interfaces?

The primary interfaces are defined in core/src/main/java/hudson/security/AuthorizationStrategy.java (strategy definition), core/src/main/java/hudson/security/ACL.java (permission checking), core/src/main/java/hudson/security/ACLContext.java (impersonation context), core/src/main/java/hudson/security/Permission.java (permission definitions and hierarchy), and core/src/main/java/hudson/security/SecurityRealm.java (authentication resolution).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →