Встраивание Cassandra - проблемы с диспетчером безопасности
Я пытаюсь обновить приложение, которое использует встроенную кассандру 2.1.1 (о времени!), Но рассматриваемое приложение устанавливает свой собственный менеджер безопасности. Cassandra 3.11, похоже, не рассматривает эту возможность, а просто пытается настроить диспетчер безопасности самостоятельно, не думая, что он уже может существовать (что не удается).
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]
Кажется, что нет никакой проверки конфигурации, чтобы избежать этого, когда я просматриваю код Cassandra:
public static void install()
{
if (installed)
return;
System.setSecurityManager(new ThreadAwareSecurityManager());
Комментарии в ThreadAwareSecurityManager, похоже, указывают на то, что это сделано для того, чтобы сделать пользовательские функции безопасными, но я не планирую использовать пользовательские функции, поэтому я был бы очень рад отключить это, но я не вижу такой опции в код.
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.
Это выглядит подозрительно, как будто требуется изменить код Cassandra, прежде чем он когда-либо будет работать. У кого-нибудь есть идея получше?
Для справки, это попытка избежать проблем, которые старые cqlsh сталкивались с текущими версиями python:
https://github.com/nsoft/jesterj/issues/89
РЕДАКТИРОВАТЬ: выяснил, почему происходит исключение, несмотря на мою предыдущую установку диспетчера безопасности. Оказывается, они устанавливают политику, которая не выполняет ничего, не поступая из источника кода с URL, начинающимся с 'file'. Мое приложение загружается через one-jar, поэтому все мои исходные коды имеют URL-адрес: onejar:lib/docopt-0.6.1.jar. Таким образом, когда они пытаются установить своего собственного менеджера безопасности, они нарушают свою собственную политику и умирают.
2 ответа
Я преодолел эту конкретную проблему, как это:
- Установите мою политику для всех разрешений (убедитесь, что она также переопределяет подразумевает ())
- Временно установите менеджер безопасности, который игнорирует вызовы для проверки разрешения ()
Class.forName("org.apache.cassandra.cql3.functions.ThreadAwareSecurityManager")
Что заставляет класс инициализировать и устанавливать нарушающую политику- Снова установите политику "Все перми"
- Установить ванильный SecurityManager()
Вот коммит: https://github.com/nsoft/jesterj/commit/37c0206eac144e9076600f64bb298039212058f5
Это предотвращает описанную выше трассировку стека и приводит к другой проблеме, поэтому я закончу этот вопрос здесь и открою другой, если необходимо, но для справки следующая проблема по-прежнему связана с 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]
Если возможно, вы можете убедиться, что ваш существующий менеджер безопасности это позволяет. Возможно, что-то подобное вызывает проблемы, так как это будет применено глобально к JVM.
В качестве альтернативы вы можете просто пропустить это... Это гораздо худший вариант, и это может сломать вещи, но вы можете использовать отражение.
(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);
}
но это может вызвать проблемы во время выполнения, поэтому я бы тщательно его протестировал.