Monday 25 August 2014

A Per-Thread Java Security Manager

This post explains how you can customise the Java SecurityManager to so that it can be programatically enabled and disabled on a per-thread basis.

The security manager mechanism in Java is great (Java 1.7 bugs notwithstanding): it gives you a simple, reliable way to restrict what different parts of your code can do. Most of the time, the standard SecurityManager implementation along with a carefully-defined security policy will meet your security needs, which is lovely. However, there are times when the standard SecurityManager implementation doesn't cut it. This post address a couple of those cases.

One of the main problems with the SecurityManager is that it introduces a performance overhead. This is because every time a restricted method is called, the SecurityManager has to check the call stack to make sure that the necessary permissions have been granted to the code in every frame. A lot of the time this isn't an issue, but if your application is performance-sensitive and makes a lot of calls to restricted functions, these checks can add up.

It's also not uncommon to find applications that only need to place restrictions on code running in specific threads: most of the threads in the application will only ever run trusted code, but one or two threads will be used to call some un-trusted libraries. The standard SecurityManager, when installed, applies to all code running in the JVM, even if the majority of the threads in the VM won't run un-trusted code. Even if you define your security policy such that your trusted code is granted all the permissions it needs, a lot of unnecessary checks will be made by the SecurityManager.

A nice solution to this is to define a custom SecurityManager that can be enabled and disabled programatically on a per-thread basis. This can be achieved pretty easily using ThreadLocal variables to store the enabled/disabled state of the SecurityManager on each thread:

package demo;

import java.security.Permission;

public class SelectiveSecurityManager extends SecurityManager {

  private static final ToggleSecurityManagerPermission TOGGLE_PERMISSION = new ToggleSecurityManagerPermission();

  ThreadLocal enabledFlag = null;

  public SelectiveSecurityManager(final boolean enabledByDefault) {

    enabledFlag = new ThreadLocal() {

      @Override
      protected Boolean initialValue() {
        return enabledByDefault;
      }

      @Override
      public void set(Boolean value) {
        SecurityManager securityManager = System.getSecurityManager();
        if (securityManager != null) {
          securityManager.checkPermission(TOGGLE_PERMISSION);
        }
        super.set(value);
      }
    };
  }

  @Override
  public void checkPermission(Permission permission) {
    if (shouldCheck(permission)) {
      super.checkPermission(permission);
    }
  }

  @Override
  public void checkPermission(Permission permission, Object context) {
    if (shouldCheck(permission)) {
      super.checkPermission(permission, context);
    }
  }

  private boolean shouldCheck(Permission permission) {
    return isEnabled() || permission instanceof ToggleSecurityManagerPermission;
  }

  public void enable() {
    enabledFlag.set(true);
  }

  public void disable() {
    enabledFlag.set(false);
  }

  public boolean isEnabled() {
    return enabledFlag.get();
  }

}

The custom SecurityManager simply sub-classes the standard SecurityManager and overrides the checkPermisson methods so that a ThreadLocal boolean is tested to see if the check is necessary before it's carried out. The ThredLocal boolean can be set programatically via an enable/disable methods, and we make sure that only authorised code can enable/disable the security manager by checking a special ToggleSecurityManagerPermission in the set method of the ThredLocal. The ToggleSecurityManagerPermission class is very simple, and looks like this:

package demo;

import java.security.Permission;

public class ToggleSecurityManagerPermission extends Permission {

  private static final long serialVersionUID = 4812713037565136922L;
  private static final String NAME = "ToggleSecurityManagerPermission";

  public ToggleSecurityManagerPermission() {
    super(NAME);
  }

  @Override
  public boolean implies(Permission permission) {
    return this.equals(permission);
  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof ToggleSecurityManagerPermission) {
      return true;
    }
    return false;
  }

  @Override
  public int hashCode() {
    return NAME.hashCode();
  }

  @Override
  public String getActions() {
    return "";
  }

}

That's pretty much all there is to it. You need to define a security policy that will ensure that any trusted code on the stack for threads where the SecurityManager will be enabled has the necessary permissions, and that trusted code has permission to enabled and disable the SecurityManager, but that's it. For a working example of the above with some simple tests, see the Github repository https://github.com/alphaloop/selective-security-manager.

8 comments:

Anonymous said...
This comment has been removed by the author.
mamta said...

Wohh I love it, I mean this blog is just awesome. I personally love this informative article… Keep Posting such information… Keep Going!
India VPS Hosting

mamta said...

I am really grateful to read this article, this is nice and informative thanks for sharing.
India VPS Hosting

mamta said...

Nicely you explained everything in your article. Thanks for your information, this is nice and helpful… Definitely going to share this article to my friends.
Dubai VPS Hosting

mamta said...

Thanks for your information, this is nice and helpful… Definitely going to share this article to my friends.
Dubai VPS Hosting

mamta said...

Impressive, this is very important to know for all of us about this knowledge. I really love this blog and surely recommend to my friends. Thanks keep it up
UK VPS Hosting

mamta said...

This Article is Worth of sharing. The information is helpful for sure! Keep going like this!
UK VPS Hosting

Anonymous said...

Really I read and like this such types of blog post. One of the main problems with the Security Manager is that it introduces a performance overhead. You can also enjoy their services when you choose a USA VPS Hosting. Onlive server services and plans are available at on very cheapest price.
Thanks you!!