Embedding Cassandra - Security Manager issues

2019-08-22 00:59发布

问题:

I am attempting to upgrade an application that uses an embedded cassandra 2.1.1 (about time!), but the application in question sets it's own security manager. Cassandra 3.11 seems to not consider this possibility and just attempts to set the security manager on it's own without any consideration that there might already be one (which fails).

2017-06-26T12:05:22,736 ERROR Thread-0 org.apache.cassandra.service.CassandraDaemon Exception encountered during startup
java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "createSecurityManager")
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) ~[?:1.8.0_101]
    at java.security.AccessController.checkPermission(AccessController.java:884) ~[?:1.8.0_101]
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) ~[?:1.8.0_101]
    at java.lang.SecurityManager.<init>(SecurityManager.java:299) ~[?:1.8.0_101]
    at org.apache.cassandra.cql3.functions.ThreadAwareSecurityManager.<init>(ThreadAwareSecurityManager.java:199) ~[?:3.11.0]
    at org.apache.cassandra.cql3.functions.ThreadAwareSecurityManager.install(ThreadAwareSecurityManager.java:80) ~[?:3.11.0]
    at org.apache.cassandra.service.CassandraDaemon.setup(CassandraDaemon.java:192) ~[?:3.11.0]
    at org.apache.cassandra.service.CassandraDaemon.activate(CassandraDaemon.java:600) ~[?:3.11.0]
    at org.jesterj.ingest.persistence.Cassandra.start(Cassandra.java:94) ~[?:?]
    at org.jesterj.ingest.Main.startCassandra(Main.java:190) ~[?:?]
    at org.jesterj.ingest.Main.lambda$main$0(Main.java:125) ~[?:?]
    at java.lang.Thread.run(Thread.java:745) [?:1.8.0_101]

There doesn't seem to be any check for configuration to avoid this when I browse the Cassandra code:

public static void install()
{
    if (installed)
        return;
    System.setSecurityManager(new ThreadAwareSecurityManager());

Comments in ThreadAwareSecurityManager seem to indicate that this is meant to make user defined functions safe, but I have no plans to use user defined functions, so I'd be perfectly happy to turn that off, but I don't see such an option in the code.

static
{
    //
    // Use own security policy to be easier (and faster) since the C* has no fine grained permissions.
    // Either code has access to everything or code has access to nothing (UDFs).
    // This also removes the burden to maintain and configure policy files for production, unit tests etc.

This looks suspiciously like it requires a code change to Cassandra before it will ever work. Does anyone have a better idea?

For reference, this comes about as an attempt to escape issues that old cqlsh has with current versions of python:

https://github.com/nsoft/jesterj/issues/89

EDIT: Figured out why the exception occurs despite my previous installation of security manager. It turns out that they install a policy that fails anything not coming from a codesource with a url starting with 'file'. My app loads via one-jar so all my code sources have a url like: onejar:lib/docopt-0.6.1.jar. Thus when they try to install their own security manager, they run afoul of their own policy and die.

回答1:

If possible you could make sure your existing security manager allows it. Maybe something like this is causing issues since it will be applied globally to the JVM.

Alternatively you can just skip it... Its a much worse option and it may break things but you could use reflection.

(inside whatever main class or something loaded very early in application)

static {
        Field installed = ThreadAwareSecurityManager.class.getField("installed");
        installed.setAccessible(true);
        installed.set(null, true);
}

but that may cause issues during runtime so I'd test it throughly.



回答2:

I got past this particular problem like this:

  1. Set my all perms policy (making sure to also override implies())
  2. Temporarily set a security manager that ignores calls to check permission()
  3. Class.forName("org.apache.cassandra.cql3.functions.ThreadAwareSecurityManager") Which causes the class to initialize and install the offending policy
  4. Set my all perms policy again
  5. Set a vanilla SecurityManager()

Here's the commit: https://github.com/nsoft/jesterj/commit/37c0206eac144e9076600f64bb298039212058f5#diff-6bdddcc8f3676796dbad2f7b694fa7fcL268

This prevents the above stack trace, and leads to a different problem, so I'll end this question here, and open another if needed, but for reference the next problem is still related to ThreadAwareSecurityManager...

java.lang.ClassCastException: org.apache.logging.slf4j.Log4jLogger cannot be cast to ch.qos.logback.classic.Logger
    at org.apache.cassandra.cql3.functions.ThreadAwareSecurityManager.install(ThreadAwareSecurityManager.java:92) ~[cassandra-all-3.11.0.jar:3.11.0]
    at org.apache.cassandra.service.CassandraDaemon.setup(CassandraDaemon.java:192) ~[cassandra-all-3.11.0.jar:3.11.0]
    at org.apache.cassandra.service.CassandraDaemon.activate(CassandraDaemon.java:600) ~[cassandra-all-3.11.0.jar:3.11.0]
    at org.jesterj.ingest.persistence.Cassandra.start(Cassandra.java:94) ~[main.jar:?]
    at org.jesterj.ingest.Main.startCassandra(Main.java:198) ~[main.jar:?]
    at org.jesterj.ingest.Main.lambda$main$0(Main.java:132) ~[main.jar:?]
    at java.lang.Thread.run(Thread.java:745) [?:1.8.0_101]