All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.susom.vertx.base.BasePolicy Maven / Gradle / Ivy

/*
 * Copyright 2016 The Board of Trustees of The Leland Stanford Junior University.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.susom.vertx.base;

import java.io.FilePermission;
import java.lang.reflect.ReflectPermission;
import java.net.NetPermission;
import java.net.SocketPermission;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Paths;
import java.security.AllPermission;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.security.SecurityPermission;
import java.util.HashSet;
import java.util.PropertyPermission;
import java.util.Set;
import java.util.WeakHashMap;

import static com.github.susom.vertx.base.VertxBase.workDir;

/**
 * This is just a convenient base class you can extend to customize the
 * security policy for your application.
 *
 * @author garricko
 */
public class BasePolicy extends Policy {
  private final WeakHashMap cache = new WeakHashMap<>();
  protected final String tempDir;
  protected final String workDir;
  protected final String userDir;
  protected final String javaDir;
  protected final boolean debug;
  private final Set jdkLocations = new HashSet<>();
  private final Set appLocations = new HashSet<>();

  public BasePolicy() throws Exception {
    tempDir = System.getProperty("java.io.tmpdir");
    workDir = workDir();
    userDir = System.getProperty("user.home");
    javaDir = System.getProperty("java.home");
    debug = Boolean.getBoolean("java.security.debug");

    // Walk the classpath to figure out all the relevant codebase locations for our policy
    String javaHome = javaDir;
    if (javaHome.endsWith("/jre")) {
      javaHome = javaHome.substring(0, javaHome.length()-5);
    }
    String[] classpath = System.getProperty("java.class.path").split(":");
    for (String entry : classpath) {
      entry = Paths.get(entry).toAbsolutePath().normalize().toString();
      if (entry.startsWith(javaHome)) {
        jdkLocations.add(entry);
      } else {
        appLocations.add(entry);
      }
      if (debug) {
        System.out.println("Security policy detected classpath entry: " + entry);
      }
    }
    for (URL url : ((URLClassLoader)Thread.currentThread().getContextClassLoader()).getURLs()) {
      String entry = Paths.get(url.toURI()).toAbsolutePath().normalize().toString();
      appLocations.add(entry);
      if (debug) {
        System.out.println("Policy class loader url: " + entry);
      }
    }
  }

  public String dirs() {
    return "Directories for initializing the security policy:\n  temp: " + tempDir + "\n  work: "
        + workDir + "\n  java: " + javaDir + "\n  user: " + userDir;
  }

  public void install() {
    Policy.setPolicy(this);
  }

  @Override
  public boolean implies(ProtectionDomain domain, Permission permission) {
    String path = domain.getCodeSource().getLocation().getPath();
    PermissionCollection pc;

    synchronized (cache) {
      pc = cache.get(path);
    }

    if (pc == null) {
      pc = getPermissions(domain);

      synchronized (cache) {
        cache.put(path, pc);
      }
    }

    return pc.implies(permission);
  }

  protected void addAppPermissions(Permissions appPerms) {
    // Hook for subclasses to add their own permissions
  }

  protected Permissions jdkPermissions() {
    Permissions jdkPerms = new Permissions();
    jdkPerms.add(new AllPermission());
    return jdkPerms;
  }

  @Override
  public PermissionCollection getPermissions(ProtectionDomain domain) {
    String path = domain.getCodeSource().getLocation().getPath();
    if (path.endsWith("/")) {
      path = path.substring(0, path.length() - 1);
    }
    path = path.replaceAll("%20", " ");
    if (jdkLocations.contains(path) || path.startsWith(javaDir)) {
      if (debug) {
        System.out.println("Returning all permissions for code source: " + path);
      }
      return jdkPermissions();
    } else if (appLocations.contains(path)) {
      if (debug) {
        System.out.println("Returning application permissions for code source: " + path);
      }
      Permissions appPerms = new Permissions();

      addAppPermissions(appPerms);

      for (String entry : appLocations) {
        // Make sure we can read the classpath files (e.g. Maven jars) and directories
        appPerms.add(new FilePermission(entry, "read"));
        if (!entry.endsWith(".jar")) {
          appPerms.add(new FilePermission(entry + "/-", "read"));
        }
      }

      // Files and directories the app will access
      appPerms.add(new FilePermission(workDir + "/.vertx", "read,write,delete"));
      appPerms.add(new FilePermission(workDir + "/.vertx/-", "read,write,delete"));
      appPerms.add(new FilePermission(workDir + "/conf/-", "read"));
      appPerms.add(new FilePermission(workDir + "/logs/-", "read,write"));
      appPerms.add(new FilePermission(tempDir, "read,write"));
      // Work-around for the fact Vert.x always checks filesystem before loading classpath resources
      appPerms.add(new FilePermission(workDir + "/static/-", "read"));

      // Accept connections on any dynamic port (this is different from listening on the port)
      appPerms.add(new SocketPermission("*:1024-", "accept"));

      // We register a shutdown hook to stop Vert.x and clean up the database pool
      appPerms.add(new RuntimePermission("shutdownHooks"));
      appPerms.add(new RuntimePermission("modifyThread"));

      // Everything tries to read some system property
      appPerms.add(new PropertyPermission("*", "read"));

      // These seem like bugs in vertx/netty (should not fail if these permissions are not granted)
      appPerms.add(new RuntimePermission("setIO"));
      appPerms.add(new PropertyPermission("io.netty.noJdkZlibDecoder", "write"));
      appPerms.add(new PropertyPermission("sun.nio.ch.bugLevel", "write"));

      // Emailer does DNS lookup on localhost hostname
      appPerms.add(new SocketPermission("*", "resolve"));

      // Not sure about these
      appPerms.add(new ReflectPermission("suppressAccessChecks"));
      appPerms.add(new RuntimePermission("accessDeclaredMembers"));
      appPerms.add(new RuntimePermission("getClassLoader"));
      appPerms.add(new RuntimePermission("getStackTrace"));
      appPerms.add(new RuntimePermission("setContextClassLoader"));
      appPerms.add(new RuntimePermission("loadLibrary.sunec"));
      appPerms.add(new RuntimePermission("accessClassInPackage.sun.*"));
      appPerms.add(new SecurityPermission("putProviderProperty.SunJCE"));
      appPerms.add(new SecurityPermission("putProviderProperty.SunEC"));
      appPerms.add(new NetPermission("getNetworkInformation"));
      appPerms.add(new FilePermission("/proc/sys/net/core/somaxconn", "read"));
      appPerms.add(new FilePermission("/etc/hosts", "read"));
      appPerms.add(new FilePermission("/etc/resolv.conf", "read"));

      return appPerms;
    }
    if (debug) {
      System.out.println("Returning no permissions for code source: " + path);
    }
    return new Permissions();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy