Supplemental Material: doPrivileged()

Privileged access was added to the Security objective for Oracle’s Java 11 1Z0-819 Exam, but was not part of the objectives for the now retired 1Z0-816 Exam. We created this Supplemental Material and are releasing it free of charge for all those readers who purchased one of our Java 11 Study Guides. You should read this section carefully before taking the 1Z0-819 Exam. See other changes on The 1Z0-819 Exam page.

Overview

Some Java programs run in an environment where the user does not have full control over the program. In other words, the program runs a privileged action on behalf of the user. The idea for the developer is straight-forward:

  • I have a privileged action I need run for a user
  • I need to verify the user has the proper permission before running the action
  • I need to make sure they are limited in what actions they can run
  • I need to make sure they don’t using caching or other tricks to skip the permission check

Java performs a privileged action using the AccessController.doPrivileged() method found in the java.security package. While using this method is not commonly used by most Java developers, it is required knowledge for the 1Z0-819 Exam.

1. The doPrivileged() method

A common example Oracle likes to use is reading a system property. The idea is that the programmer is only allowed to read a specific predefined system property.

import java.security.*;
public class MySecretReader {
   private static final String KEY = "secret.option";
   public String getSecret() {
      return AccessController.doPrivileged(
         new PrivilegedAction<String>() {
            public String run() {
               return System.getProperty(KEY);
            }
         });
   }
}

Here KEY is a constant that cannot be changed by the user. The idea here is that a user’s privilege is temporarily elevated so they can read the secret.option value within the system.

2. Ensure Principle of Least Privilege

When executing a privileged action, it is important to ensure that only the minimum access is granted. This is known as the principle of least privilege. Can you spot what’s wrong with the following example?

import java.security.*;
public class MySecretReader {
   public String getSecret(String magicWord) {
      return AccessController.doPrivileged(
         new PrivilegedAction<String>() {
            public String run() {
               return System.getProperty(magicWord);  // DON'T DO THIS!
            }
         });
   }
}

In this example, the caller is able to specify which value they want to read. This is considered a poor practice as it allows them to read any property within the system. Oracle refers this as a tainted input. Put simply, don’t trust anything the user provides when dealing with security. Also use a constant or predefined list to confirm they are accessing only what the original developer intended.

For the exam, be wary of any code that allows the user to access data that they specify, rather than the original programmer.

3. Don’t Expose Sensitive Information

Another important aspect of using doPrivileged() is ensuring sensitive data is protected. For example, can you spot the security risk in this code?

import java.security.*;
import java.util.*;
public class MySecretReader {
   private final List<Integer> codes = ...
   public List<Integer> getSecret() {
      return AccessController.doPrivileged(
         new PrivilegedAction<List<Integer>>() {
            public List<Integer> run() {
               return codes;  // DON'T DO THIS!
            }
         });
   }
}

Even though codes is marked final, the content can still be modified after the doPrivileged() is complete. This poses an unacceptable security risk. A much safer version would be to return an immutable copy of the list, such as:

      return AccessController.doPrivileged(
         new PrivilegedAction<List<Integer>>() {
            public List<Integer> run() {
               return Collections.unmodifiableList(codes);
            }
         });

Note that this works because Integer values are immutable. If the contents of the List were mutable, such as List<StringBuilder>, you want to copy them as well.

4. Don’t Elevate Permissions

Privilege elevation or escalation occurs when a user is mistakenly given access to a higher privilege than they should have access to. One way to prevent privilege elevation is to use to the AccessController.checkPermission() method before calling doPrivileged(), then execute the command with limited permissions.

import java.security.*;
public class MySecretReader {
   public void readData(Runnable task, String path) {
      // Check permission
      Permission permission = new java.io.FilePermission(path,"read");
      AccessController.checkPermission(permission);

      // Execute task with limited permission
      final var permissions = permission.newPermissionCollection();
      permissions.add(permission);
      AccessController.doPrivileged(
         new PrivilegedAction<Void>() {
            public Void run() {
               task.run();
               return null;
            }
         },
         // Using a limited context prevents privilege elevation
         new AccessControlContext(
            new ProtectionDomain[] {
               new ProtectionDomain(null, permissions)
            })
         );
   }
}

Don’t worry if you can’t write code like this, most developers never have to. For the exam, though, you should understand that the permission is being checked and the action is executed with a specific context.

5. Be wary of Permission Caching

The last rule you need to know for the exam is to be weary of cached permissions. It is perfectly acceptable to cache permission information, but the permission needs to be checked every time the user accesses it.

For example, assuming there’s a User class with appropriate attributes, methods and constructors, can you spot the problem in this code?

import java.security.*;
import java.util.*;
public class SecretFile {
   private static Map<String, User> data = new HashMap<>();
   public static SecretFile get(String key) {
      var cacheRecord = data.get(key);
      if (cacheRecord != null) {
         // DON'T DO THIS!
         return cacheRecord.getValue();
      }
      
      final var permission = Permission permission 
         = new PropertyPermission(key,"read");
      AccessController.checkPermission(permission);

      final var permissions = permission.newPermissionCollection();
      permissions.add(permission);
      var secret = AccessController.doPrivileged(
         new PrivilegedAction<SecretFile>() {
            public SecretFile run() {
               return new SecretFile();
            }
         }, new AccessControlContext(new ProtectionDomain[] {
               new ProtectionDomain(null, permissions) }));
      data.put(key, new User(secret, permission));
      return secret;
   }
}

Did you spot it? It might be hard to see, but there’s no permission check when the data is read from the cache! The permission is checked when the data is first read from the cache but not on subsequent calls. We can easily fix this though by checking the permission when it is read from the cache:

      var cacheRecord = data.get(key);
      if (cacheRecord != null) {
         AccessController.checkPermission(cacheRecord.getPermission());
         return cacheRecord.getValue();
      }

In this example, we see that cached permissions can be safe to use but we have to make sure the permission is validated when it is read the first time and on each request from the cache.

Conclusion

There, you’re done! This post covered the overall topics around Privileged Access that you need to know for the 1Z0-819 Exam. The following bullet points summarize the kinds of things you should be watching for on the 1Z0-819 Exam:

  • Always validate user input and never allow it to grant access to arbitrary data
  • Never give the user unlimited access to the system
  • Prevent privilege elevation by validating security
  • Never return privileged objects directly or in a way that they can be modified
  • Ensure cached permissions are validated on every call

If you enjoyed this section, you can read more about it in Oracle’s Secure Coding Guidelines for Java SE document.

Win a Free Copy of Our New Java 11 OCP Book!

Update (11/05/2020): Read The 1Z0-819 Exam page to learn how you can easily our Java 11 Study Guides to prepare for Oracle’s 1Z0-819 Exam, as well as the 1Z0-817 Upgrade Exam.

This week only, CodeRanch.com is hosting a book promotion for our new book: Java OCP 11 Programmer I Study Guide. The book will be released this month and is available for preorder on Amazon.com, Barnes and Nobles, and Wiley Publishing.

The giveaway starts today, November 19th, 2019 with the drawing on Friday, November 15, 2019.

The promotion will be held in the Programmer Certification (OCPJP) forum which can be found here: https://coderanch.com/f/24/

Simply post a question to the authors (Jeanne and Scott) in the forum to be entered for a chance to win a copy of our new book!

My Experience taking the new Java SE 11 Programmer II 1Z0-816 Exam

Update (11/05/2020): Read The 1Z0-819 Exam page to learn how you can easily our Java 11 Study Guides to prepare for Oracle’s 1Z0-819 Exam, as well as the 1Z0-817 Upgrade Exam.

Back in March, I took the new Java SE 11 Programmer I 1Z0-815 Exam only 2 days after it was released. Going into the exam blind, I wasn’t too worried because the previous OCA 8 1Z0-808 exam had been such a breeze. Boy was I surprised! While I passed with a decent margin, I was shocked the level of difficulty of the Programmer I 1Z0-815 exam. It was nothing like the 1Z0-808 exam it inherits from, especially in terms of question difficulty!

This past month, Jeanne and I finished writing our new Java OCP 11 Programmer I Study Guide (now available for preorder), which meant it was time to turn our attention to our upcoming Java OCP 11 Programmer II Study Guide. Rather than go in blind, and especially given all of the new material, I decided to spend some time studying *before* taking the 1Z0-816 exam. Well, it paid off because I passed today with a quite a wide margin. Below are some of my impressions of the exam.

Level of Difficulty

This might sound crazy, and I’m sure I’m biased, but overall I found the 1Z0-816 OCP11 exam less difficult than the OCP 8 1Z0-809 exam it inherits from. Don’t get me wrong, it was a difficult exam, but I felt like there were so many topics and they were so broad, the exam rarely went into especially deep detail on some of them. For example, many of the questions regarding SQL injection had pretty clear answers. In most of the questions, I was able to eliminate completely “ridiculous” answers right away, getting the answer choices down to 2 (or 3 if it was pick 2, or 4 if it was pick 3, etc). In fact, some questions I didn’t even need to read the text to whittle down the answer choices. For example, if an answer choice is an invalid lambda expression, it clearly cannot be a valid answer. With that in mind, most questions boiled down eliminating bad answers, then reading the question text to know which of the two remaining choices was correct.

Better Focused

One of the best changes they made in the new 1Z0-815/1Z0-816 exam series was to move most of the core Java syntactical questions to the first exam. While they made the 1Z0-815 exam harder, it made the 1Z0-816 exam a lot clearer. For example, if a question appears to be about NIO.2 on the 1Z0-816 exam, then it’s about NIO.2! On the older 1Z0-809 exam, I always felt like they mixed common Java topics with advanced ones. For example, a question that appears to be about NIO.2 on the 1Z0-809 exam might actually be about constructor overloading or overriding methods. In other words, the 1Z0-816 exam is better because the questions are derived from the objectives more cleanly, and there aren’t as many trick questions. You still have to know a lot to pass, but at least they aren’t mixing topics as much as they did in previous exams.

Streams, Streams, Streams

While the exam seemed reasonable to me, I’m also very proficient in streams. It is an understatement to say they are all over the exam. If you don’t use them regularly, you’ll need a lot of practice before taking the exam. Remember, they can show up in almost any topic like NIO.2, Concurrency, Collections, etc.

Modules

Modules are on the exam but I found the questions a lot more straight-forward than the module questions I saw on the 1Z0-815 exam. I had a lot of trouble with the module questions on the 1Z0-815 exam, in part because a lot of them didn’t make sense or didn’t appear to have a correct answer. Given how early I took the exam, Jeanne suspects I might have been exposed to beta/experimental/broken questions. That said, I thought the module questions on the 1Z0-816 exam were a lot more fair than they were on the 1Z0-815 exam. You need to know a lot about modules, of course, but the topics the questions were testing were a lot clearer.

Still a Very Broad Exam

While questions within a topic were relatively straight-forward, the amount of topics you had to know for the 1Z0-816 exam dwarfs the 1Z0-809 exam. Annotations, Security, Local Type Inference, Private/Static Interface Methods, and Modules are completely new. You should read the Secure Coding Guideline and Annotations Trail prior to taking the exam. Unfortunately, there’s not one single source of material for modules so you have to study from what you can piece together on the web… that is until our new 1Z0-816 study guide is released!

So You Want to Take the Exam?

Great! If you’re not in a hurry, I would wait for our new study guides to come out. The first book is already on its way to print and the second book will be available early next year. You can use our OCP 8 Study Guide to take exam, but you will have to supplement it with a lot of reading from a dozen different sources. And as I said earlier, if you’re not using streams regularly, you will definitely need a lot of practice. Regardless of which path you take, we wish you the best in studying!