Spec-Zone .ru
спецификации, руководства, описания, API
Содержание документации
СОДЕРЖАНИЕ | ПРЕДЫДУЩИЙ | NEXT

4 Механизма управления доступом и Алгоритмы


4.1 java.security. ProtectionDomain

Класс ProtectionDomain инкапсулирует характеристики домена. Такой домен включает ряд классов, экземплярам которых предоставляют ряд полномочий, будучи выполненным от имени данного набора Принципалов.

ProtectionDomain создается с CodeSource, ClassLoder, массивом Принципалов, и набором Полномочий. CodeSource инкапсулирует кодовую базу (java.net. URL) для всех классов в этом домене, так же как ряда сертификатов (типа java.security.cert. Сертификат) для открытых ключей, которые соответствуют закрытым ключам, которые подписали весь код в этом домене. Принципалы представляют пользователя, на имени которого работает код.

Полномочия, которые передают в во время создания ProtectionDomain, представляют статический набор полномочий, связанных с доменом независимо от Политики в силе. ProtectionDomain впоследствии консультируется с текущей политикой во время каждой проверки защиты, чтобы получить динамические полномочия, предоставленные домену.

Классы от различного CodeSources, или которые выполняются от имени различных принципалов, принадлежат различным доменам.

Сегодня весь код, поставленный как часть Java 2 SDK, считают системным кодом и выполняется в уникальном системном домене. Каждый апплет или приложение работают в его соответствующем домене, определенном политикой.

Возможно гарантировать, что объекты в любом несистемном домене не могут автоматически обнаружить объекты в другом несистемном домене. Этот раздел может быть достигнут осторожным разрешением класса и загрузкой, например, используя различный classloaders для различных доменов. Однако, SecureClassLoader (или его подклассы), по его выбору, может загрузить классы из различных доменов, таким образом позволяя эти классы сосуществовать в пределах того же самого пространства имен (как разделено classloader).


4.2 java.security. AccessController

Класс AccessController используется в трех целях, каждая из которых описывается в дальнейших деталях в разделах ниже: Любой код, который управляет доступом к системным ресурсам, должен вызвать методы AccessController, если это хочет использовать определенную модель обеспечения безопасности и алгоритм управления доступом, используемый этими методами. Если с другой стороны приложение хочет задержать модель обеспечения безопасности к тому из SecurityManager, установленных во время выполнения, то это должно вместо этого вызвать соответствующие методы в классе SecurityManager.

Например, типичным способом вызвать управление доступом был следующий код (взятый от более ранней версии 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 может реализовать свой собственный подход управления безопасностью, возможно включая добавление дальнейших ограничений, используемых в определении, разрешается ли доступ.


4.2.1 Алгоритм для Проверки Полномочий

Предположите, что проверка управления доступом происходит в потоке вычисления, у которого есть цепочка многократных вызывающих сторон (думайте об этом как о многократных вызовах метода, которые пересекают границы домена защиты), как иллюстрировано в следующем числе.

Иллюстрация управления доступом

Когда checkPermission метод AccessController вызывается новой вызывающей стороной (например, метод в классе Файла), основной алгоритм для того, чтобы решить, позволить ли или отрицать, что запрошенный доступ следующие.

Если у какой-либо вызывающей стороны в цепочке вызовов нет требуемого разрешения, AccessControlException бросается, если следующее не является истиной - вызывающая сторона, домен которой предоставляют, упомянутое разрешение было отмечено как "привилегированный" (см. следующий раздел), и все стороны, впоследствии вызванные этой вызывающей стороной (прямо или косвенно), у всех есть упомянутое разрешение. Есть, очевидно, две стратегии реализации: Преимущество - то, что проверка, позволяется ли разрешение, упрощается и может быть быстрее во многих случаях. Недостаток - то, что, потому что проверка разрешения происходит намного менее часто чем междоменные вызовы, большой процент обновлений разрешения, вероятно, будет бесполезным усилием. Одна потенциальная нижняя сторона этого подхода является потерей производительности в разрешении, проверяющем время, хотя этот штраф был бы понесен так или иначе в "нетерпеливой оценке" подход (хотя в прежние времена и распространялся среди каждого междоменного вызова). Наша реализация до сих пор приводила к приемлемой производительности, таким образом, мы чувствуем, что отложенные вычисления являются самым экономичным подходом повсюду.

Поэтому, алгоритм для того, чтобы проверить полномочия в настоящий момент реализуется как "отложенные вычисления". Предположите текущий поток пересеченный м. вызывающих сторон в порядке вызывающей стороны 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;
 };

4.2.2 Обработка Полномочий

Новый, статический метод в классе AccessController позволяет коду в экземпляре класса сообщать AccessController, что тело его кода "привилегировано", в котором это исключительно ответственно за то, что запросило доступ к его доступным ресурсам, независимо от того что код, вызванный это, чтобы сделать так.

Таким образом, вызывающая сторона может быть отмечена как "привилегированный", когда она вызывает 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.


4.3 Inheritence Контекста Управления доступом

Когда поток создает новый поток, новый стек создается. Если текущий контекст защиты не был сохранен, когда этот новый поток создавался, то когда 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 для функции наследования.

4.4 java.security. AccessControlContext

Вспомните что AccessController 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);


СОДЕРЖАНИЕ | ПРЕДЫДУЩИЙ | NEXT
Авторское право © 1997-1999 Sun Microsystems, Inc. Все права защищены.

Oracle и/или его филиалы Авторское право © 1993, 2011, Oracle и/или его филиалы. Все права защищены.
Свяжитесь с Нами