Spec-Zone .ru
спецификации, руководства, описания, API
|
СОДЕРЖАНИЕ | ПРЕДЫДУЩИЙ | NEXT |
ProtectionDomain создается с CodeSource, ClassLoder, массивом Принципалов, и набором Полномочий. CodeSource инкапсулирует кодовую базу (java.net. URL) для всех классов в этом домене, так же как ряда сертификатов (типа java.security.cert. Сертификат) для открытых ключей, которые соответствуют закрытым ключам, которые подписали весь код в этом домене. Принципалы представляют пользователя, на имени которого работает код.
Полномочия, которые передают в во время создания ProtectionDomain, представляют статический набор полномочий, связанных с доменом независимо от Политики в силе. ProtectionDomain впоследствии консультируется с текущей политикой во время каждой проверки защиты, чтобы получить динамические полномочия, предоставленные домену.
Классы от различного CodeSources, или которые выполняются от имени различных принципалов, принадлежат различным доменам.
Сегодня весь код, поставленный как часть Java 2 SDK, считают системным кодом и выполняется в уникальном системном домене. Каждый апплет или приложение работают в его соответствующем домене, определенном политикой.
Возможно гарантировать, что объекты в любом несистемном домене не могут автоматически обнаружить объекты в другом несистемном домене. Этот раздел может быть достигнут осторожным разрешением класса и загрузкой, например, используя различный classloaders для различных доменов. Однако, SecureClassLoader (или его подклассы), по его выбору, может загрузить классы из различных доменов, таким образом позволяя эти классы сосуществовать в пределах того же самого пространства имен (как разделено classloader).
Например, типичным способом вызвать управление доступом был следующий код (взятый от более ранней версии JDK):
ClassLoader loader = this.getClass().getClassLoader(); if (loader != null) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead("path/file"); } }Под новой архитектурой обычно должна вызываться проверка, есть ли classloader, связанный с классом вызова. Это могло быть просто, например:
FilePermission perm = new FilePermission("path/file", "read"); AccessController.checkPermission(perm);AccessController
checkPermission
метод исследует текущий контекст выполнения и принимает правильное решение относительно того, позволяется ли запрошенный доступ. Если это, эта проверка возвращается спокойно. Иначе, AccessControlException (подкласс java.lang. SecurityException), бросается. Отметьте, что есть (наследство) случаи, например, в некоторых браузерах, где, есть ли установленный SecurityManager, имеет значение один или другое состояние безопасности, которое может привести к различным предпринятым мерам. Для обратной совместимости, checkPermission
метод на SecurityManager может использоваться.
SecurityManager security = System.getSecurityManager(); if (security != null) { FilePermission perm = new FilePermission("path/file", "read"); security.checkPermission(perm); }Мы в настоящий момент не изменяем этот аспект использования SecurityManager, но поощрили бы разработчиков приложений использовать новые методы, представленные в Java 2 SDK в их программировании будущего, когда встроенный алгоритм управления доступом является соответствующим.
Поведение по умолчанию SecurityManager checkPermission
метод должен фактически вызвать AccessController checkPermission
метод. Различная реализация SecurityManager может реализовать свой собственный подход управления безопасностью, возможно включая добавление дальнейших ограничений, используемых в определении, разрешается ли доступ.
Когда checkPermission
метод AccessController вызывается новой вызывающей стороной (например, метод в классе Файла), основной алгоритм для того, чтобы решить, позволить ли или отрицать, что запрошенный доступ следующие.
Поэтому, алгоритм для того, чтобы проверить полномочия в настоящий момент реализуется как "отложенные вычисления". Предположите текущий поток пересеченный м. вызывающих сторон в порядке вызывающей стороны 1 к вызывающей стороне 2 к вызывающей стороне м. Затем вызывающая сторона м. вызвала checkPermission
метод. Основной алгоритм checkPermission
использование, чтобы определить, предоставляется ли доступ или отрицается, является следующим (см. последующие разделы для усовершенствований):
i = m; while (i > 0) { if (caller i's domain does not have the permission) throw AccessControlException else if (caller i is marked as privileged) return; i = i - 1; };
Таким образом, вызывающая сторона может быть отмечена как "привилегированный", когда она вызывает doPrivileged
метод. Принимая решения управления доступом, checkPermission
метод прекращает проверять, достигает ли он вызывающей стороны, которая была отмечена как "привилегированный" через a doPrivileged
вызовите без параметра контекста (см. последующий раздел для информации о параметре контекста). Если у домена той вызывающей стороны есть указанное разрешение, никакая дальнейшая проверка не делается и checkPermission
возвраты спокойно, указывая, что запрошенный доступ позволяется. Если у того домена нет указанного разрешения, исключение выдается, как обычно.
Нормальная эксплуатация "привилегированной" функции следующие:
Если Вы не должны возвратить значение изнутри "привилегированного" блока, сделайте следующее:
somemethod() { ...normal code here... AccessController.doPrivileged(new PrivilegedAction() { public Object run() { // privileged code goes here, for example: System.loadLibrary("awt"); return null; // nothing to return } }); ...normal code here... }PrivilegedAction является интерфейсом с единственным методом, названным
run
, это возвращает Объект. Вышеупомянутый пример показывает создание анонимного внутреннего класса, реализовывая тот интерфейс; конкретная реализация run
метод предоставляется. Когда звонок doPrivileged
делается, экземпляр реализации PrivilegedAction передают к этому. doPrivileged
вызовы метода run
метод от реализации PrivilegedAction после включения полномочиям, и возвратам run
возвращаемое значение метода как doPrivileged
возвращаемое значение, которое игнорируется в этом примере. (Для получения дополнительной информации о внутренних классах, см. Внутреннюю Спецификацию Классов в http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html
или Вложенные Классы в http://download.oracle.com/javase/tutorial/java/javaOO/nested.html
.)
Если Вы должны возвратить значение, можно сделать что-то как следующее:
somemethod() { ...normal code here... String user = (String) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { return System.getProperty("user.name"); } } ); ...normal code here... }Если действие, выполняемое в Вашем
run
метод мог выдать "проверенное" исключение (один перечисленный в throws
пункт метода), тогда Вы должны использовать интерфейс PrivilegedExceptionAction вместо интерфейса PrivilegedAction: somemethod() throws FileNotFoundException { ...normal code here... try { FileInputStream fis = (FileInputStream) AccessController.doPrivileged( new PrivilegedExceptionAction() { public Object run() throws FileNotFoundException { return new FileInputStream("someFile"); } } ); } catch (PrivilegedActionException e) { // e.getException() should be an instance of // FileNotFoundException, // as only "checked" exceptions will be "wrapped" in a // <code>PrivilegedActionException</code>. throw (FileNotFoundException) e.getException(); } ...normal code here... }Некоторые важные моменты о том, чтобы быть привилегированным: Во-первых, это понятие только существует в пределах единственного потока. Как только привилегированный код завершается, полномочие, как гарантируют, будет стерто или отменено.
Во-вторых, в этом примере, теле кода в run
метод привилегирован. Однако, если это вызовет меньше защищенного кода, который менее привилегирован, то тот код не будет получать полномочий в результате; разрешение только предоставляют, если у привилегированного кода есть разрешение и так сделайте все последующие вызывающие стороны в цепочке вызовов до checkPermission
вызвать.
Для получения дополнительной информации о маркировке кода как "привилегированный", см. http://java.sun.com/j2se/sdk/1.2/docs/guide/security/doprivileged.html
.
AccessController.checkPermission
был вызван в новом потоке, решение безопасности будет принято основанное исключительно на контексте нового потока, не учитывая тот из родительского потока. Этой чистой проблемой стека не была бы проблема безопасности по существу, но она сделает запись безопасного кода, и особенно системного кода, более склонного к тонким ошибкам. Например, разработчик неспециалиста мог бы предположить, вполне разумно, что дочерний поток (например, тот, который не включает недоверяемый код) наследовал тот же самый контекст защиты от родительского потока (например, тот, который включает недоверяемый код). Это вызвало бы непреднамеренные дыры в системе безопасности, когда доступ управляемые ресурсы изнутри нового потока (и затем передача ресурсов менее доверяемому коду), если бы родительский контекст не был фактически сохранен.
Таким образом, когда новый поток создается, мы фактически гарантируем (через создание потока и другой код), что это автоматически наследовало контекст защиты родительского потока во время создания дочернего потока таким способом который последующий checkPermission
вызовы в дочернем потоке учтут наследованный родительский контекст.
Другими словами логический контекст потока расширяется, чтобы включать обоих родительский контекст (в форме AccessControlContext, описанного в следующем разделе) и текущий контекст, и алгоритм для того, чтобы проверить, что полномочия расширяются до следующего. (Отзыв есть м. вызывающих сторон до звонка checkPermission
, и см. следующий раздел для информации о AccessControlContext checkPermission
метод.)
i = m; while (i > 0) { if (caller i's domain does not have the permission) throw AccessControlException else if (caller i is marked as privileged) return; i = i - 1; }; // Next, check the context inherited when // the thread was created. Whenever a new thread is created, the // AccessControlContext at that time is // stored and associated with the new thread, as the "inherited" // context. inheritedContext.checkPermission(permission);Отметьте, что это наследование является переходным так, чтобы, например, внук наследовался и от родителя и от прародителя. Также отметьте, что наследованный снимок контекста берется, когда новый дочерний элемент создается, и не, когда дочерний элемент является первым показом. Нет никакого общедоступного изменения API для функции наследования.
checkPermission
метод выполняет проверки безопасности в пределах контекста текущего потока выполнения (включая наследованный контекст). Трудность возникает, когда такая проверка защиты может только быть сделана в различном контексте. Таким образом, иногда проверка защиты, которая должна быть сделана в пределах данного контекста, должна будет фактически быть сделана изнутри различного контекста. Например, когда один поток отправляет событие на другой поток, у второго потока, служащего событию запроса, не было бы надлежащего контекста к управлению полным доступом, если доступ запросов на обслуживание к ресурсам контроллера. Чтобы решить эту проблему, мы предоставляем AccessController getContext
метод и класс AccessControlContext. getContext
метод берет "снимок" текущего контекста вызова, и помещает его в объект AccessControlContext, который он возвращает. Демонстрационный вызов является следующим:
AccessControlContext acc = AccessController.getContext();Этот контекст получает релевантную информацию так, чтобы решение управления доступом могло быть принято, проверяя, изнутри различного контекста, против этой контекстной информации. Например, один поток может отправить событие запроса на второй поток, также предоставляя эту контекстную информацию. У самого AccessControlContext есть a
checkPermission
метод, который делает решения о предоставлении доступа основанными на контексте, который он инкапсулирует, а не тот из текущего потока выполнения. Таким образом второй поток может выполнить соответствующую проверку защиты в случае необходимости, вызывая следующее: acc.checkPermission(permission);Вышеупомянутый вызов метода эквивалентен выполнению той же самой проверки защиты в контексте первого потока, даже при том, что это делается во втором потоке.
Есть также времена, где одни или более полномочий должны быть проверены по контексту управления доступом, но это неясно априорный, какие полномочия должны быть проверены. В этих случаях можно использовать doPrivileged
метод, который берет контекст:
somemethod() { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { // Code goes here. Any permission checks from // this point forward require both the current // context and the snapshot's context to have // the desired permission. } }, acc); ...normal code here...Теперь полный алгоритм используется AccessController
checkPermission
метод может быть дан. Предположите текущий поток пересеченный м. вызывающих сторон в порядке вызывающей стороны 1 к вызывающей стороне 2 к вызывающей стороне м. Затем вызывающая сторона м. вызвала checkPermission
метод. Алгоритм checkPermission
использование, чтобы определить, предоставляется ли доступ или отрицается, является следующим i = m; while (i > 0) { if (caller i's domain does not have the permission) throw AccessControlException else if (caller i is marked as privileged) { if (a context was specified in the call to doPrivileged) context.checkPermission(permission); return; } i = i - 1; }; // Next, check the context inherited when // the thread was created. Whenever a new thread is created, the // AccessControlContext at that time is // stored and associated with the new thread, as the "inherited" // context. inheritedContext.checkPermission(permission);