skip to content

Access Control (Legacy)

The JVM's legacy code-level sandbox: SecurityManager, permission and policy files, protection domains, and JAR sealing and signing. Deprecated for removal, but it still turns up in legacy systems and in interview questions about how applets were sandboxed.

part ofJavaoverview, primer and where to startread it →
on this pageshow

explore

questions

13

What is a Java Permission, and how does a .policy file grant permissions to code?

level: juniorimportance: should knowfreq 30%

answer

  1. Permission = class + target + actions
  2. grant codeBase "url" { permission ...; };
  3. imply(): broader permission covers narrower request
  4. FilePermission / SocketPermission / RuntimePermission
  5. Deprecated for removal — JEP 411

basics

~20 s

A Permission is an object that names one capability the code is allowed to use, like reading a file or opening a network connection. A .policy text file lists grant blocks that hand those capabilities to code from a given location.

solid answer

~40 s

In the legacy Java security model, a Permission is a typed object describing one specific capability: a class (e.g. FilePermission), a target (what it applies to, like a file path), and often an action (read, write). The runtime checks whether the currently running code holds the needed permission before performing a sensitive operation. Permissions are granted declaratively in a .policy file made of grant blocks: `grant codeBase "..." { permission java.io.FilePermission "/tmp/*", "read"; };`. Each grant ties a set of permissions to a code source (a URL and optionally a signer). At startup the JVM loads the policy, builds a Policy object, and uses it to decide what each piece of code may do. This whole mechanism is part of the SecurityManager era and is now deprecated for removal.

code

java · 14 lines
java
// A FilePermission object built in code:
FilePermission p = new FilePermission("/tmp/-", "read,write");

// p.implies(...) answers "does p cover this narrower request?"
boolean ok = p.implies(new FilePermission("/tmp/logs/app.log", "read")); // true

/* Equivalent grant in an app.policy file:

grant codeBase "file:/opt/app/lib/-" {
    permission java.io.FilePermission "/tmp/-", "read,write";
};

Run with:  java -Djava.security.manager -Djava.security.policy=app.policy MyApp
*/

go deeper

for a junior

Can say a Permission represents one allowed capability and a .policy file's grant blocks hand capabilities to code from a location.

for a middle

Knows the class/target/actions structure, the grant codeBase syntax, the common permission classes, and how -Djava.security.policy wires it in.

for a senior

Explains imply() semantics, codeBase vs signedBy vs Principal scoping, append-vs-replace (= vs ==), and that the whole model is deprecated for removal.

for a principal

Frames it historically — why it existed (untrusted-code sandbox), why it failed in practice, JEP 411 removal, and what replaced the concern (OS/container isolation, no in-JVM sandbox).

## The problem this solves Java was designed so you could run code you did not fully trust — classically, applets downloaded from a web page. The question was: how do you let downloaded code do *some* things (draw on screen) but not *others* (read your hard drive)? The answer was a fine-grained, capability-based access-control system. The **SecurityManager** was the gatekeeper that intercepted sensitive operations, and **Permissions** + **policy files** were how you described who is allowed to do what. ## What a Permission is A **Permission** is an ordinary Java object (subclass of `java.security.Permission`) that represents *one specific capability*. It has up to three parts: - **Class** — the *kind* of capability. Examples: `java.io.FilePermission` (filesystem), `java.net.SocketPermission` (network), `java.lang.RuntimePermission` (JVM-level abilities like exiting the VM or creating a classloader). - **Target (name)** — *what* it applies to. For a file permission this is a path like `/tmp/*`; for a socket permission a host:port like `example.com:443`. - **Actions** — *which operations* are allowed, as a comma-separated string. For `FilePermission`: `read`, `write`, `execute`, `delete`. Some permissions (like many `RuntimePermission`s) have no actions — just the name, e.g. `exitVM`. So `new FilePermission("/tmp/*", "read")` means "may read any file directly inside /tmp". Key behavior: permissions know how to **imply** each other. A permission for `/tmp/-` (the whole subtree, recursively) *implies* `/tmp/a.txt`. "read,write" implies "read". When the system checks an access, it asks the granted permissions "does any of you imply the one I need?". ## What a .policy file is A **policy file** is a plain-text file describing which permissions are granted to which code. Its core construct is the **grant block**: ``` grant codeBase "file:/opt/app/lib/-" { permission java.io.FilePermission "/var/data/*", "read,write"; permission java.net.SocketPermission "db.internal:5432", "connect"; }; ``` Reading it: "Code loaded from the URL `file:/opt/app/lib/-` is granted the right to read/write files in /var/data and to open a connection to db.internal:5432." The `codeBase` is a **URL** identifying where the code came from; a trailing `/-` matches that directory and all subdirectories, `/*` matches just the JARs in that directory. You can also restrict by **`signedBy "alias"`** (code signed by a key whose certificate is in the keystore) and **`Principal`** (the authenticated user, used with JAAS). A grant with **no codeBase** applies to *all* code. ## How it is wired up 1. The default policy file ships in the JDK (`$JAVA_HOME/conf/security/java.policy`); you add your own with `-Djava.security.policy=app.policy` (or `==app.policy` to *replace* rather than *append*). 2. The system `Policy` object parses these files into `Permission` objects. 3. You enable enforcement by installing a SecurityManager (historically `-Djava.security.manager`). 4. When sensitive code runs (e.g. `new FileInputStream`), the library calls `SecurityManager.checkPermission(perm)`, which delegates to `AccessController.checkPermission(perm)`, which walks the call stack and asks the Policy whether every frame is allowed. ## Important historical status The **SecurityManager and this entire permission/policy mechanism are deprecated for removal** (JEP 411, Java 17). They are effectively unmaintained and slated to disappear, because the sandbox-untrusted-code use case (applets, Web Start) is dead and the model was hard to use correctly. You should *recognize* it (legacy systems, interview trivia, understanding old stack traces) but not build new systems on it.

  • What does a trailing /- versus /* mean in a FilePermission target?
    /* matches files directly in that directory (one level); /- matches that directory and everything in all subdirectories recursively. The same convention is used for codeBase URLs.
  • How do you point the JVM at your own policy file?
    -Djava.security.policy=app.policy appends it to the default policy; -Djava.security.policy==app.policy (double equals) replaces the default entirely. A SecurityManager must be installed for it to take effect.

saying these in an interview costs you the question

  • Thinking a policy file controls who can log in / authenticate — it controls what code may do, not user accounts.
  • Believing permissions are still actively used in modern apps — the whole model is deprecated for removal.
  • Confusing actions with targets (e.g. saying the path is the action).

context

open as a page

What does it mean to seal a package in a JAR, and how do you configure it in the manifest?

level: middleimportance: should knowfreq 22%

basics

~20 s

Sealing a package means every class in that package must come from the same JAR file. You turn it on by adding 'Sealed: true' to the JAR's MANIFEST.MF, for one package or the whole archive.

open as a page

Why would you sign a JAR, and what security property does a signature actually give you?

level: middleimportance: should knowfreq 30%

basics

~10 s

Signing a JAR attaches a digital signature so you can prove who published it and that nobody changed its files afterward. It gives integrity and authenticity — not secrecy.

open as a page

Why was the SecurityManager deprecated for removal in JEP 411, and what are the modern replacements?

level: middleimportance: should knowfreq 40%

basics

~20 s

JEP 411 (Java 17) deprecated the SecurityManager for removal because its main job — sandboxing browser applets — no longer exists, it was hard to use correctly, and it slowed down the whole JDK. Today you isolate untrusted code with the operating system or containers, and use the Java module system for encapsulation.

open as a page

What is a ProtectionDomain, and how do the permissions of code on the call stack get combined during an access check?

level: seniorimportance: should knowfreq 22%

basics

~20 s

A ProtectionDomain groups code from the same source with the permissions granted to it. When code is checked, Java looks at every method on the call stack and only allows the action if every one of them has the permission — the most restrictive caller wins.

open as a page

Walk through the practical workflow of signing and verifying a JAR with keytool and jarsigner.

level: seniorimportance: should knowfreq 28%

basics

~20 s

Use keytool to create a keypair/certificate in a keystore, then jarsigner to sign the JAR with that key. To check a JAR, run 'jarsigner -verify' which recomputes hashes and validates the signature against the certificate.

open as a page

Explain the files signing adds under META-INF — the manifest digests, the .SF file, and the .RSA/.DSA/.EC block — and how the runtime uses them to verify.

level: seniorimportance: should knowfreq 24%

basics

~20 s

Signing adds per-file hashes to MANIFEST.MF, a NAME.SF file holding a hash of the manifest, and a NAME.RSA/DSA/EC block containing the actual digital signature plus the certificate. Verification re-hashes entries and checks the signature against the certificate.

open as a page

Why were the SecurityManager, permissions, and policy files deprecated for removal, and what should replace that protection today?

level: principalimportance: should knowfreq 25%

basics

~20 s

The permission/policy sandbox was built to run untrusted in-process code like applets, which no longer exist. It was complex, error-prone, and rarely used correctly, so JEP 411 (Java 17) deprecated it for removal. Today you isolate untrusted code with OS, container, or process boundaries instead.

open as a page

What was the Java SecurityManager, and what problem was it designed to solve?

level: juniorimportance: nice to knowfreq 35%

basics

~20 s

The SecurityManager was a built-in Java component that could block code from doing risky things like reading files, opening network connections, or exiting the program. It was created so untrusted code, especially browser applets, could run safely in a restricted sandbox.

open as a page

Name the common built-in Permission classes and what each protects. How does AllPermission differ from a specific permission?

level: middleimportance: nice to knowfreq 18%

basics

~20 s

FilePermission guards file access, SocketPermission guards network connections, and RuntimePermission guards JVM abilities like exiting the VM. AllPermission is a wildcard that grants everything at once, so it implies any other permission and should almost never be granted.

open as a page

Explain how AccessController.doPrivileged worked together with checkPermission and the call-stack-based permission model.

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

Java checked permissions by looking at every method on the current call stack — the action was only allowed if all callers had the needed permission. doPrivileged let trusted code say "use my permissions here, ignore my untrusted caller," so a library could perform a privileged step on behalf of restricted code.

open as a page

In a modern Java codebase, how do sealed JARs, JAR signing, and JPMS strong encapsulation relate — which would you reach for and why?

level: principalimportance: nice to knowfreq 14%

basics

~20 s

They solve different problems: sealing keeps a package's classes in one JAR, signing proves who published a JAR and that it's unchanged, and JPMS modules strongly hide non-exported packages. Use modules for encapsulation, signing for provenance, sealing only for legacy classpath cases.

open as a page

A teammate says 'the SecurityManager isolated untrusted code from trusted code like a separate process would.' Where does that mental model break down?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

The SecurityManager only blocked certain library calls — it did not give untrusted code its own memory or process. Everything still ran in one JVM sharing the same heap, so bugs or clever attacks could often escape. A real separate process is a much stronger wall.

open as a page