Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Jetty/Tutorial/Jetty-Policy"

 
(No difference)

Latest revision as of 18:06, 7 April 2011



Introduction

Jetty Policy provides a mechanism for integrating with the core JDK security mechanisms.

Details

Do I need this?

Typically users do not need to deal with java security permissions or what is called the SecurityManager or Policy objects in java. Normally a user trusts the application they are developing or are trusting enough to deploy a webapp into an instance of jetty. If you don't know that you need to use the security manager setup, you probably don't.

However, if you are running untrusted webapps and you want to gain a bit more control over the application this is an option. Using the Jetty policy setup allows you to declaratively specify permissions that jetty and the webapp will operate under. These permissions can be FilePermissions restricting read and write access, to PropertyPermissions which detail what system properties are available to be read.

How does it all work?

An excellent reference is available at Oracle -> http://download.oracle.com/javase/6/docs/technotes/guides/security/permissions.html

But beyond that we have made a few changes to make dealing with this system a bit easier. This involves our own subclass of the Policy object that allows for multiple policy files to be loaded and aggregated together for easier management. There is a debug mode and dump() method for the jetty policy that will all cached protection domains to be printed out. There is a reload mode that allows changes to the policy files to be loaded and changes to protection domains resolve while the security manager is running.

In broad strokes, when jetty is started the SecurityManager and JettyPolicy objects are loaded so that from then on all security sensitive actions are taken, the entire call stack of code up to that point is checked to validate that every object has been granted that permission. This will be explained in greater detail below.

Jetty Policy

Typically the JettyPolicy object is configured through the use of policy files that adhere to the specification laid out by Sun/Oracle in the link in the previous section. We have expanded on this a bit to make it easier to manage these files. To understand the layout it is important to understand what a codesource is. In java security land, a codesource is simply a location where classes can be found. A codesource can be specified to a specific location on disk or it can refer to a directory where jar files or class files are located. The binding of specific permissions to a codesource is referred to as a protection domain.

We have broken out our policy files along the following lines. It should be noted that this is just how we have laid out the files, you are free to alter as desired.

lib/policy/global.policy
permissions that are applied to all protection domains
lib/policy/jetty-start.policy 
permissions which apply to start.jar and immediate startup of jetty
lib/policy/jetty.policy 
permissions that apply to jetty as a whole, and any jar files under the lib directory
lib/policy/temp-dirs.policy 
permission that apply to the contents of tmp directories, this can include unpacked webapps unless you follow the recommended conventions
lib/policy/jetty-work.policy 
permissions that apply to webapps unpacked to the work directory.

Adding and removing permissions required a lot of in-depth knowledge about how whatever java code your running operates and it is no different with jetty or webapps running inside of jetty, it is just a little more complex.

Web Application Policies

A common concern with dealing with this sort of system is how to grant permissions to one webapp without having to grant permissions to another. For this approach we recommend something along the following lines:

  • use context deployment so you can specify where your war file will unpack to
  • create a policy file in lib/policy for that webapp
    • this policy file should contain two codebases
      • ${jetty.home}/work/<webapp dir>
      • ${jetty.home}/lib/-
    • this allows you to grant both the webapp and jetty itself any permissions needed

Remember that when permission is checked for any call, the entire call stack is checked for permission being granted. What this means in practice is that if you are granting permission to read and write directory A, then both the webapp classes and the jetty classes have to be granted access to read and write that directory. What having per webapp permissions setup allows you is the ability to _not_ grant another webapp read and write access to that directory. This could be potentially important if your running untrusted webapps, or some combination of trusted and untrusted webapps. Below is an example of what a typical webapp policy file might look like.

//
// Permissions granted to the webapp
//
grant codebase "file:${jetty.home}/work/policy-tests/-" {
  // testSystemPropertyAccess
  permission java.util.PropertyPermission "__ALLOWED_READ_PROPERTY", "read";
  permission java.util.PropertyPermission "__ALLOWED_WRITE_PROPERTY", "write";
}
 
//
// Permissions granted to jetty lib
//
grant codeBase "file:${jetty.home}/lib/-" {
   // testSystemPropertyAccess
  permission java.util.PropertyPermission "__ALLOWED_READ_PROPERTY", "read";
  permission java.util.PropertyPermission "__ALLOWED_WRITE_PROPERTY", "write";
}

How do I figure out permissions I need?

There are a number of ways to do this, easily the most common is to just run your software, look in logs for an AccessControlException, analyze the stack trace and declare that permission for the codebases that need it. This is a long and tedious process and it no wholly effective as it is predicated on your exercising your software in all necessary ways to ensure you have triggered all possible ACE exceptions and assigned permissions accordingly. This is also a long process if you have many permissions that need assigned. Another viable option on this approach is to use a custom security manager that logs all permissions being requests but does not make the actual permission checks. This is a pretty simple approach to wire up and we might support the mode ourselves someday if there is interest. Anyway, after gathering up all the permissions that were logged you would then carefully go through them and assign them accordingly. You can also statically audit your code, either manually or programmatically to detect all permissions that have been granted. We don't really have recommended tooling for this, but there was a project called Sword4J that helped in this area that might still work.

How do I start JettyPolicy?

Jetty Policy is an implementation on top of the java Policy object. The Policy object in the jdk is an abstract class and the one that is typically used is generally jvm specific, Sun has one, IBM has one, Apache Harmony has one. We built off of the Apache Harmony one and enhanced it to allow for changing policy files during runtime (really helps with getting those permissions declared) and supporting multiple files.

As for actually starting this system up, we have a jetty.xml file that will initialize and startup the relevant bits.

<Configure id="Policy" class="org.eclipse.jetty.policy.JettyPolicyConfigurator">
    <Call name="setPolicyDirectory">
       <Arg><Property name="jetty.home"/>/lib/policy</Arg>
    </Call>
    <Call name="addProperty">
      <Arg>jetty.home</Arg>
      <Arg><Property name="jetty.home"/></Arg>
    </Call> 
    <Call name="initialize"/>
</Configure>

When this xml is processed by the XMLConfiguration classes it will set the location of the directory that policy files are loaded up from and create the JettyPolicy object. Inside of the policy files you can use properties of the form ${jetty.home} in various locations, and the addProperty line in the xml above will set that property. If you want to use other ${} properties you may set them in the same way with a new <Call> element. Lastly the initialize method on the configurator is called which actually creates the SecurityManager, set the System Policy object (to our JettyPolicy class) and then form that point all, the jdk is locked down and checking permissions.

If you want to do this while your embedding jetty, odds are you are already up to speed on permissions and security managers, but if you would like to use our JettyPolicy implementation you are welcome to. To setup in embedded mode you can either use the configurator above or directly create the JettyPolicy object and set it to the System object.

A quick note, during your reading about how to initialize security managers and policy objects you might see the recommendations on setting these things on the java command line. That is a completely valid use case and the ultimate step for security, but for our purposes of just allowing webapps to declare their own policies it seemed a bit much. You can support that mechanism yourself when you invoke java or using the --exec option in the start.ini with the jetty-start project.

Why a jetty-start.policy file?

The jetty start project is a standalone project for launching java code. It leverages the jetty-xml artifact which is really a snazzy implementation of processing xml code as java code, its how jetty has been started up in the traditional sense for years. Anyway, because jetty-start (otherwise known as the start.jar in the root of the distribution) is outside of the lib/- codesource declaration, i would actually be at the root of most any stack trace for the purposes of permission declaration. Since the xml code can never call back to the start classes, and jetty itself when started can't call back to those classes, we have the jetty-start.policy configured with just what is required the for the start code to execution. Immediately before control is passed over to the XMLConfiguration objects we invoke the AccessController with the doPrivledged() action, this acts as a barrier when the execution stack is checked for permissions. What this means in practice is that you do not have to declare permissions that your webapp might need for the start.jar codebase. That is why we have the jetty-start.policy file.

Additional Resources

Insert more here.

Back to the top