Обеспечение безопасности Java-приложений с помощью Acegi: Часть 3. Управление доступом для Java-объектов

Использование безопасности, основанной на методах, для защиты экземпляров Java-классов

Билал Сиддикви завершает цикл из трех статей, знакомящий с системой безопасности Acegi, статьей, показывающей как обеспечить безопасный доступ к экземплярам Java-классов. Узнайте, зачем необходимо обеспечивать безопасность доступа к Java-классам, как Spring создает и защищает экземпляры Java-классов, и как настроить Acegi для реализации безопасности классов в Java-приложениях.

Билал Сиддикви, внештатный консультант, WaxSys

Билал Сиддикви (Bilal Siddiqui) является инженером-электронщиком, консультантом по XML и соучредителем WaxSys, компании, чья деятельность направлена на упрощение электронного бизнеса. После окончания в 1995 г. Инженерно-технологического Университета, г. Лахор, и получения степени по электронной технике, он начал разрабатывать программные продукты для промышленных систем управления. В дальнейшем он занимался XML и использовал свой опыт в программировании C++ для разработки Web- и Wap-базируемых инструментов для XML-технологий, серверных парсинговых программных продуктов и служебных приложений. Билал – проповедник передовых технологий и часто публикуется в этой области.



25.06.2008

Это серия из трех статей является введением в использование системы безопасности Acegi для обеспечения безопасности корпоративных Java приложений. Первая статья этой серии знакомит с Acegi и объясняет, как использовать встроенные в Acegi фильтры безопасности для реализации простой основанной на URL системы безопасности. Вторая статья показывает, как написать политику управления доступом и сохранить ее в сервере каталогов LDAP, а также как настроить взаимодействие Acegi с сервером каталогов для реализации политики управления доступом. Третья, последняя, статья этой серии демонстрирует, как использовать Acegi для обеспечения безопасного доступа к экземплярам Java классов в корпоративном приложении.

Для начала будет кратко рассмотрено, почему может потребоваться обеспечить безопасность для доступа к Java классам, для примера продемонстрировав пару сценариев для типичного корпоративного приложения. Далее будет показано, как среда Spring IOC (Inversion of Control - инвертирование управления) создает экземпляры Java-классов, доступные из JSP-страниц и сервлетов. Также мы познакомимся с важным понятием прокси-компонентов (bean proxies), используемых Spring для фильтрации доступа к Java-объектам. В конце будет показано, как настроить компонент-перехватчик Acegi для безопасного вызова методов, чтобы обеспечить управление доступом к Java классам. В заключение последней статьи этого цикла мы усовершенствуем пример приложения из второй части, чтобы обеспечить поддержку защищенных Java-объектов.

Так как обсуждение в этой статье построено на двух других статьях этого цикла, в ней часто будут использоваться ссылки на рассуждения и примеры из первой и второй статей цикла. Поэтому может оказаться полезным открыть эти две статьи в других окнах Web-браузера, прежде чем двигаться дальше.

Примеры, требующие обеспечения безопасности для Java-классов

Напомню, что я уже кратко обсуждал безопасность корпоративных приложений в начале этой серии статей. В предварительном обсуждении упоминался сценарий, когда безопасности, основанной на URL адресах, оказывается недостаточно:

Рассмотрим PDF-документ, содержащий данные о конкретном продукте, выпускаемом компанией на своем производстве. Часть документа содержит инженерные данные, которые должны редактироваться и обновляться проектным отделом. Другая часть документа содержит производственные данные, используемые менеджерами производства. Для подобного сценария необходимо реализовать более тонкую политику безопасности, применяя различные права доступа к различным фрагментам документа.

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

Автоматизация бизнес-процессов

Потоки операций (workflows) в приложениях для автоматизации бизнеса состоят из процессов. Например, последовательность проведения анализа крови в клинической лаборатории может состоять из нескольких шагов, и каждый шаг считается бизнес-процессом:

  1. Сотрудник берет образец крови пациента и присваивает этому образцу идентификационный номер.
  2. Лаборант производит требуемый анализ образца и готовит результаты анализа.
  3. Квалифицированный врач-диагност пишет отчет, основываясь на результатах анализа.

Очевидно, что каждый процесс выполняется отдельным пользователем, уполномоченным для выполнения этого процесса. Тот, кто не уполномочен для выполнения процесса, не должен иметь возможности запустить этот процесс. Например, лаборант должен иметь возможность подготовить результаты анализа, но не должен иметь возможности написать отчет об анализе.

Уполномоченные бизнес-процессы обычно имеются во всех приложениях для автоматизации бизнеса. Обычно каждый бизнес-процесс реализуется в виде Java-класса, и все эти классы должны быть защищены средствами соответствующей политики управления доступом.

Межкорпоративная интеграция

Межкорпоративной (business-to-business (B2B)) интеграцией обычно называется сценарий, когда двум компаниям необходимо предоставить друг другу доступ к своей функциональности. Например, отель может открыть туроператору доступ к своей функциональности для резервирования номеров, которую туроператор сможет использовать для бронирования номеров туристам. В качестве партнера туроператор может получить специальную скидку при бронировании номеров. В этом случае система бронирования номеров в отеле должна иметь возможность аутентифицировать туроператора, прежде чем предоставить ему доступ к специальным классам для бронирования номеров со скидкой.


Создание Java-объектов в Spring

Сейчас мы разобрали, почему так важно обеспечить безопасность доступа к объектам Java-классов. Прежде чем познакомиться с функциональностью Acegi для обеспечения подобного расширенного уровня безопасности, хотелось бы освежить в памяти ключевую функциональность среды Spring, которая потребуется для понимания представленных примеров.

Начнем с конфигурирования нескольких Java-классов и создания объектов на их основе. Как было написано в первой части, Java-классы настраиваются в конфигурационном XML-файле Spring. Конфигурация Java-класса в конфигурационном файле Spring выглядит точно так же, как и конфигурация фильтра Acegi, так что мы не будем разбирать этот вопрос повторно. Вместо этого разберем листинг 1, где приведена конфигурация для bean-компонента publicCatalog:

Листинг 1. Конфигурационный XML-файл Acegi
<beans>
    <bean id="publicCatalog" 
       class="com.catalog.PublicCatalog" />
    <!--теги других bean-компонентов -->
<beans>

Важно понять, что среда Spring IOC считывает информацию о Java-классах из конфигурационного XML-файла и создает экземпляры этих классов. Если помните, в первой статье этой серии использовался файл web.xml для конфигурации тега <listener>, указывающего на класс ContextLoaderListener. Класс ContextLoaderListener загружает среду Spring IOC и создает Java-объекты. Все это можно увидеть в листинге 8 первой части статьи. Также этот процесс изображен на рисунке 1:

Рисунок 1. Загрузка среды Spring IOC и создание Java-объектов
Рисунок 1. Загрузка среды Spring IOC и создание Java-объектов

Теперь подробно разберем эти действия:

  1. При запуске Acegi-приложения сервлет-контейнер (в данном случае Apache Tomcat) создает специальный объект - контекст сервлета (servlet context), в котором хранится информация о ресурсах приложения, таких как JSP-страницы и классы.
  2. Сервлет-контейнер извещает класс ContextLoaderListener о том, что приложение запущено.
  3. Класс ContextLoaderListener создает контекст Web-приложения (Web application context) для хранения информации о ресурсах приложения, относящихся к Spring. С помощью среды Spring IOC можно загрузить собственный контекст приложения (custom application context). Для создания контекста приложения используется класс загрузки контекста - ContextLoader, который и загружает контекст приложения.
  4. Если приложение не хочет определять собственный контекст приложения, можно воспользоваться классом XMLWebApplicationContext, входящим в среду Spring и предоставляющим функциональность для анализа конфигурационных XML-файлов Spring. Приложения Acegi используют конфигурационный XML-файл Spring, так что в этой статье обсуждается только контекст приложения, представляемый классом XMLWebApplicationContext. В этом случае загрузчик контекста (context loader) создает экземпляр класса XMLWebApplicationContext, представляющий контекст приложения для приложения на базе Acegi. Загрузчик также сохраняет ссылку на контекст сервлета, созданный на первом шаге, в контекст Web-приложения.
  5. Класс XMLWebApplicationContext выполняет анализ конфигурационного XML-файла на предмет информации о Java-классах и загружает информацию в свои внутренние объекты.
  6. Класс XMLWebApplicationContext создает экземпляры всех Java-классов, указанных в конфигурационном XML-файле. Класс XMLWebApplicationContext проверяет, не зависит ли Java bean-компонент, определенный в конфигурационном XML-файле, от других Java-объектов. Если зависит, то класс XMLWebApplicationContext сначала создает bean-компоненты, от которых зависят другие bean-компоненты. Действуя таким образом, класс XMLWebApplicationContext создает экземпляры всех bean-компонентов, объявленных в конфигурационном XML-файле. Отметим, что шестой шаг предполагает, что для bean-компонентов, сконфигурированных в XML-файле, не нужно обеспечивать безопасность. В следующем разделе описываются дополнительные действия, происходящие между пятым и шестым шагом, для обеспечения безопасного доступа к создаваемым Java-объектам.
  7. Класс XMLWebApplicationContext сохраняет все bean-компоненты в массиве.

Мы разобрали, как загрузить определения bean-компонентов из конфигурационного XML-файла и создать экземпляры Java-классов. Теперь нужно познакомиться с прокси-компонентами Spring для bean-компонентов и пояснить их важность при обеспечении безопасного доступа к экземплярам Java-классов.


Использование прокси-компонентов

В предыдущем разделе обсуждалось, как среда Spring IOC создает Java-объекты. Для обеспечения безопасного доступа к Java объектам среда Spring IOC использует концепцию прокси-компонентов (bean proxies). В этом разделе сначала показывается, как настроить прокси-компонент, а потом как среда Spring IOC создает прокси-объект.

Конфигурация прокси-компонента для Java-объекта

Если необходимо создать прокси-компонент, то среда Spring IOC сначала потребует настроить экземпляр bean-компонента для создания прокси (proxy creator bean). Среда Spring IOC использует этот компонент для создания прокси-объектов. В листинге 2 приведен конфигурационный файл для bean-компонента для создания прокси, используемого, чтобы обеспечить безопасный доступ к Java-объекту privateCatalog:

Листинг 2. Конфигурация bean-компонента для создания прокси
<bean id="proxyCreator"
   class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
      <list>
        <value>privateCatalog</value>
        <--названия других bean-компонентов, для которых надо создать прокси -->
      </list>
    </property>
    <property name="interceptorNames">
      <list>
         <value>privateCatalogSecurityInterceptor</value>
       </list>
    </property>
</bean>

Как видно из листинга 2, у тега <bean> есть атрибут class со значением org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator. Класс BeanNameAutoProxyCreator входит в состав среды Spring IOC и автоматически создает прокси-компоненты для bean-компонентов. Среда Spring предоставляет интерфейс BeanPostProcessor, предоставляющий механизм расширения, позволяющий приложениям писать собственную логику для создания прокси-компонентов. Класс BeanNameAutoProxyCreator реализует интерфейс BeanPostProcessor и предоставляет всю логику для создания прокси, необходимую для обеспечения безопасности Java-классов. Так что для задач этой статьи нет необходимости реализовывать интерфейс BeanPostProcessor.

Во время создания прокси-компонентов класс BeanNameAutoProxyCreator создает прокси для всех bean-компонентов, определенных в свойстве beanNames (см. первый потомок тега <bean> в листинге 2 - тег <property>). Свойство beanNames принимает в качестве значений список названий bean-компонентов в теге <list>. В листинге 2 настраивается всего один bean-компонент с названием privateCatalog, для которого нужно создать прокси.

Теперь рассмотрим второй элемент <property>, тоже являющийся потомком тега <bean> из листинга 2. Он определяет свойство interceptorNames, в котором хранятся названия одного или нескольких компонентов-перехватчиков (interceptors). Концепция компонентов-перехватчиков более подробно обсуждается в этой статье несколько позже. Сейчас просто отметим, что компонент-перехватчик может перехватить запрос пользователя и реализовать политику управления доступом, до того как откроет пользователю доступ к защищаемому bean-компоненту.

Сейчас мы разобрали, как настроить прокси-компоненты для bean-компонентов, которые необходимо защитить. Далее мы изучим, как среда Spring IOC внутри себя создает прокси-объекты для bean-компонентов приложения.

Spring IOC принимает управление

На пятом и шестом шагах раздела "Создание Java-объектов в Spring" было показано, как класс XMLWebApplicationContext считывает определения bean-компонентов из конфигурационного XML-файла и затем создает экземпляры bean-компонентов. Прежде чем создавать экземпляр bean-компонента, класс XMLWebApplicationContext проверяет, не содержит ли конфигурационный XML-файл настройки для компонентов, создающих прокси, реализующих интерфейс BeanPostProcessor для защищаемых bean-компонентов. Если класс обнаруживает хотя бы один такой компонент, он просит bean-компонент для создания прокси создать прокси-компоненты для bean-компонентов, которые необходимо защитить.

Теперь изучим, как этот bean-компонент создает прокси-объекты внутри себя:

  1. Класс BeanNameAutoProxyCreator для создания классов загружает названия bean-компонентов, определенных в свойстве beanNames в файле, который был сконфигурирован в листинге 2.
  2. Компонент для создания прокси на основании названий bean-компонентов загружает соответствующие Java-классы, определяя класс по значению атрибута class в определении bean-компонента.
  3. Компонент для создания прокси создает экземпляр компонента-перехватчика, определенный в свойстве interceptorNames в листинге 2.
  4. В конечном итоге компонент для создания прокси создает экземпляр класса Cglib2AopProxy, передавая названия всех bean-компонентов (с шага 2) и компонент-перехватчик (с шага 3) классу Cglib2AopProxy. Класс Cglib2AopProxy входит в состав среды Spring и используется для создания динамических прокси-объектов. В этом случае класс Cglib2AopProxy создает прокси-объекты, требующиеся для управления доступом к защищаемым bean-компонентом.

Класс Cglib2AopProxy реализует два интерфейса AOPProxy и MethodInterceptor. Интерфейс AOPProxy входит в состав среды Spring и представляет реальный bean-компонент, для которого нужно создать прокси-компонент, так что он предоставляет те же методы, что и bean-компонент. Интерфейс MethodInterceptor также входит в спецификацию AOP и имеет методы, получающие управление, когда пользователь пытается получить доступ к bean-компоненту, защищаемому прокси. Это значит, что интерфейс MethodInterceptor обрабатывает запросы пользователя на доступ к bean-компоненту, обладающему прокси-компонентом. Так как класс Cglib2AopProxy реализует оба интерфейса AOPProxy и MethodInterceptor, понятно, что он предлагает полную функциональность для представления bean-компонентов через прокси компонентов и обработки запросов пользователя на доступ к таким bean-компонентам. (В разделе Ресурсы приведены ссылки на статьи об AOP.)

После выполнения предыдущих шагов создаются необходимые прокси-объекты. Таким образом, класс XMLWebApplicationContext сохраняет прокси-компоненты для защищаемых bean-компонентов вместо самих компонентов в том же массиве, что разбирался на седьмом этапе в разделе "Создание Java-объектов в Spring."


Доступ через созданные прокси к Java-объектам

В предыдущих разделах было рассмотрено, как Spring создает открытые (public) и закрытые (private) bean-компоненты. В этой статье открытые bean-компоненты можно рассматривать как незащищенные, а закрытые - как защищенные с помощью прокси-компонентов. Теперь нужно исследовать последовательность действий, которые должно выполнить клиентское приложение для доступа к открытым и закрытым bean-компонентам.

В листинге 3 приведена XML-конфигурация для двух bean-компонентов: publicCatalog и privateCatalog. Bean-компонент publicCatalog предназначен для открытого доступа и потому не требует прокси-компонента. Bean-компонент privateCatalog предназначен для доступа только определенных пользователей, так что он должен быть защищен. Конфигурация прокси-компонента для bean-компонента privateCatalog приведена в листинге 3:

Листинг 3. XML-конфигурация для bean-компонентов publicCatalog и privateCatalog
<beans>
  <bean id="publicCatalog" class="sample.PublicCatalog"/>
  <bean id="privateCatalog" class="sample.PrivateCatalog"/>

  <-- конфигурация прокси для bean-компонента privateCatalog -->
  <bean id="proxyCreator"
    class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
      <list>
        <value>privateCatalog</value>
        <--названия других bean-компонентов, для которых надо создать прокси -->
      </list>
    </property>    
    <property name="interceptorNames">
      <list>
         <value>privateCatalogSecurityInterceptor</value>
       </list>
    </property>
  </bean>
<beans>

В листинге 4 приведен код, с помощью которого приложение может получить доступ к Java bean-компонентам publicCatalog и privateCatalog, настроенных в листинге 3. Заметим, что Java-код из листинга 4 может находиться и в JSP-странице, и в другом bean-компоненте, относящимся к серверной части Java приложения.

Листинг 4. Код клиентского приложения для доступа к защищенным и незащищенным Java bean-компонентам
//шаг 1: получение доступа к экземпляру контекста приложения
XMLWebApplicationContext applicationCtx =
    WebApplicationContextUtils.getWebApplicationContext(
        this.getServletConfig().getServletContext());

//шаг 2: извлечение незащищенного bean-компонента из контекста приложения
PublicCatalog publicCatalog = 
    (PublicCatalog) applicationCtx.getBean("publicCatalog");

//шаг 3: вызов метода незащищенного bean-компонента
String publicData = publicCatalog.getData();

//шаг 4: извлечение защищенного bean-компонента из контекста приложения
PrivateCatalog privateCatalog = 
    (PrivateCatalog) applicationCtx.getBean("privateCatalog");

//шаг 5: вызов метода защищенного bean-компонента
String privateData = privateCatalog.getData();

Разберем действия из листинга 4 более подробно:

  • Шаг 1: получение доступа к экземпляру контекста приложения
    Когда приложению требуется доступ к Java bean-компоненту, настроенному в конфигурационном XML-файле, оно сначала должно получить доступ к объекту XMLWebApplicationContext, обсуждавшемуся раньше (см. шаг 4 в разделе "Создание Java-объектов в Spring.") Объект XMLWebApplicationContext содержит ссылки на все Java bean-компоненты, настроенные в конфигурационном XML-файле.
  • Шаг 2: извлечение незащищенного bean-компонента из контекста приложения
    Теперь у приложения есть ссылка на объект XMLWebApplicationContext. Класс XMLWebApplicationContext предоставляет метод getBean(), который принимает на вход название bean-компонента и ищет bean-компонент в массиве, подготовленном на шаге 7 раздела "Создание Java объектов в Spring." В этом случае это bean-компонент publicCatalog, не имеющий прокси-компонента, так что XMLWebApplicationContext возвращает сам bean-компонент.
  • Шаг 3: вызов метода незащищенного bean-компонента
    Теперь можно вызывать любой метод bean-компонента publicCatalog, полученного на шаге 2. Например, вызов метод getData(), показанный в листинге 4, выполняется без всякой проверки доступа и возвращает данные каталога клиентскому приложению.
  • Шаг 4: извлечение защищенного bean-компонента из контекста приложения
    Получение доступа к защищенному bean-компоненту похоже на получение доступа к незащищенным bean-компонентам. Единственное отличие состоит в том, что при получении доступа к защищенному bean-компоненту через метод getBean() возвращает прокси компонент для защищаемого компонента, а не сам компонент. Прокси-компонент - это объект, созданный средой Spring, как было описано в шаге 4 раздела "Spring IOC принимает управление."
  • Шаг 5: вызов метода защищенного bean-компонента
    При вызове метода защищенного bean-компонента прокси-компонент, полученный на шаге 4, обрабатывает запрос на вызов метода с помощью компонента-перехватчика. Компонент-перехватчик обрабатывает запрос на вызов метода, проверяя, имеет ли пользователь, пытающийся вызвать метод, достаточные для этого права доступа.

Теперь у вас должно возникнуть ясное понимание того, как среда Spring создает Java-объекты и как клиентские приложения взаимодействуют с ними. Обладая этими знаниями, проще понять и освоить использование компонента-перехватчика Acegi для обеспечения безопасности вызовов методов, рассматриваемого в следующем разделе.


Конфигурация компонента-перехватчика Acegi для обеспечения безопасного вызова методов

Когда приложение пытается получить доступ к методу bean-компонента, защищенного системой безопасности Acegi, запрос автоматически передается в компонент-перехватчик Acegi, обеспечивающий безопасность при вызове методов. Задача компонента-перехватчика, обеспечивающего безопасность при вызове методов, - контролировать доступ к методам защищенного bean-компонента. Компонент-перехватчик использует функциональность для аутентификации и авторизации среды Acegi, чтобы проверить, авторизован ли пользователь для вызова метода защищенного Java bean-компонента, и среагировать соответствующим образом.

В листинге 5 приведен пример конфигурации для компонента-перехватчика Acegi, обеспечивающего безопасность при вызове методов:

Листинг 5. Конфигурация компонента-перехватчика Acegi для безопасного вызова методов
<bean id="privateCatalogSecurityInterceptor"
  class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
  <property name="authenticationManager">
     <ref bean="authenticationManager"/>    
  </property>
  <property name="accessDecisionManager">
     <ref bean="accessDecisionManager"/>
  </property>
  <property name="objectDefinitionSource">
    <value>
      sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING
      <-- роли, требующиеся для других bean-компонентов -->
    </value>
  </property>
</bean>

Компонент-перехватчик, настроенный в листинге 5, содержит три свойства, которые надо задать, чтобы обеспечить безопасный доступ к Java bean-компонентам: authenticationManager, accessDecisionManager и objectDefinitionSource.

Напомню, что мы уже настраивали свойство authenticationManager во время конфигурации фильтра для выполнения аутентификации в первой статье этой серии. Задача свойства authenticationManager - аутентифицировать пользователя.

Свойство accessDecisionManager разбиралось во второй статье этой серии. Этот менеджер принятия решений отвечает за принятие решений по авторизации. Компонент-перехватчик, обеспечивающий безопасный вызов методов, использует свойства authenticationManager и accessDecisionManager для аутентификации и авторизации пользователя, прежде чем разрешить ему доступ к защищенному bean-компоненту.

Теперь рассмотрим свойство objectDefinitionSource, заданное в листинге 5. Оно похоже на свойство objectDefinitionSource, рассматривавшееся в первой части. Если исходное свойство objectDefinitionSource содержало URL-адреса, такие как /protected/* и /**, то свойство objectDefinitionSource из листинга 5 определяет класс и названия методов, например, sample.PrivateCatalog - это имя класса, для которого раньше был создан прокси-компонент, а getData - название метода, доступ пользователей к которому нужно контролировать.

Когда пользователь вызывает метод getData() bean-компонента PrivateCatalog, управление автоматически передается в компонент-перехватчик. В этом примере компонент-перехватчик с помощью среды Acegi проверяет, обладает ли пользователь бизнес-ролью ROLE_HEAD_OF_ENGINEERING. Если это так, то компонент-перехватчик разрешает доступ к методу getData(). Если же компонент-перехватчик обнаруживает, что пользователь не обладает ролью ROLE_HEAD_OF_ENGINEERING, доступ запрещается.

В следующем разделе мы рассмотрим пример Acegi-приложения, использующего все обсужденные к этому моменту концепции.


Пример Acegi-приложения

Исходный код этой статьи, приведенный в материалах для скачивания, содержит пример приложения AcegiMethodSecurity, которое можно настроить и развернуть с помощью следующих шагов:

  1. Заполнить LDAP-сервер информацией о пользователях. Предлагаемое приложение-пример содержит LDIF-файл, хранящий информацию о пользователях, подготовленную к загрузке в LDAP-сервер. В разделе "Заполнение сервера данными" во второй части приведена информация по импортированию LDIF-файла в LDAP-сервер. Заметим, что в приложении используются те же пользователи alice, bob и specialUser, что и во второй статье цикла.
  2. Скопировать файл acegiMethodSecurity.war из загруженного исходного кода этой статьи в каталог webapps, находящийся в установочном каталоге сервера Tomcat.
  3. Скопировать JAR-файлы Acegi в папку WEB-INF/lib примера приложения. Дополнительная информация приведена в разделе "Развертывание и запуск приложения" в первой статье цикла.
  4. Скачать файл cglib-full-2.0.2.jar и скопировать его в папку WEB-INF/lib примера приложения.

Осталось запустить Tomcat и проверить работу примера приложения.

Знакомство с примером приложения

Приложение-пример можно вызвать, введя URL-адрес http://localhost:8080/acegiMethodSecurity в Web-браузере. Приложение AcegiMethodSecurity отобразит главную страницу с двумя ссылками (Catalog и Login), как показано на рисунке 2:

Рисунок 2. Главная страница приложения-примера
Рисунок 2. Главная страница приложения-примера

Если выбрать ссылку Catalog, приложение попросит войти в систему. Если войти в систему как alice или specialUser, приложение предоставит доступ к полному каталогу, включая открытые и закрытые данные. Это произойдет потому, что в листинге 5, компонент-перехватчик для безопасного вызова методов был настроен разрешать пользователям с ролью ROLE_HEAD_OF_ENGINEERING доступ к закрытым данным каталога, а alice и specialUser обладают этой ролью, и, следовательно, и доступом. С другой стороны, если войти в систему как bob, приложение покажет только открытые данные.


Назначение дополнительных ролей аутентифицированным пользователям

В этом разделе демонстрируется усовершенствованная версия примера приложения. Она показывает, как Acegi позволяет временно назначать дополнительные роли аутентифицированным пользователям прямо во время работы приложения.

Дополнительные роли могут потребоваться, когда защищаемому bean-компоненту, например, privateCatalog в листинге 3, требуется доступ к удаленному ресурсу. Можно предположить, что защищаемому bean-компоненту нужен доступ к удаленному приложению через инфраструктуру Java RMI (Java's Remote Method Invocation - вызов методов удаленных Java-объектов) или Web-сервис. Пользователь, получивший доступ к защищенному bean-компоненту, не обладает бизнес-ролью, которую необходимо иметь для доступа к удаленному приложению.

В этом случае Acegi сначала проверит, имеет ли пользователь право на доступ к защищаемому bean-компоненту. После проверки Acegi разрешит пользователю доступ к этому bean-компоненту. Когда bean-компонент попытается получить доступ к удаленной службе, ему потребуются дополнительные бизнес-роли. Если пользователь, вызвавший bean-компонент, не обладает этими дополнительными ролями, то защищаемый компонент не сможет получить доступ к удаленной службе.

Механизм изменения роли во время работы приложения

Инфраструктура Acegi предоставляет простой механизм для изменения роли во время работы приложения, называемый run-as-replacement и позволяющий настроить назначение одной или нескольких дополнительных ролей аутентифицированному пользователю только на время вызова метода. Этот механизм можно использовать, чтобы настроить дополнительные роли для защищенного bean-компонента для доступа к удаленным приложениям. В результате, когда защищенному bean-компоненту потребуется доступ к удаленному приложению, Acegi загрузит дополнительные роли для пользователя, чтобы позволить защищенному bean-компоненту получить доступ к удаленному приложению.

В листинге 6 приведена усовершенствованная конфигурация компонента-перехватчика для безопасного вызова методов, ранее показанная в листинге 5. Усовершенствованная версия использует механизм run-as-replacement.

Листинг 6. Усовершенствованная конфигурация компонента-перехватчика Acegi для обеспечения безопасного вызова методов

Кликните, чтобы увидеть код

Листинг 6. Усовершенствованная конфигурация компонента-перехватчика Acegi для обеспечения безопасного вызова методов

<bean id="privateCatalogSecurityInterceptor"
  class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
  <property name="authenticationManager">
     <ref bean="authenticationManager"/>    
  </property>
  <property name="accessDecisionManager">
     <ref bean="accessDecisionManager"/>
  </property>
  <property name="runAsManager">
<bean id="runAsManager" class="org.acegisecurity.runas.RunAsManagerImpl">
<property name="key"> <value>myKeyPass</value> </property> </bean> </property> <property name="objectDefinitionSource"> <value> sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING,RUN_AS_MANAGER </value> </property> </bean>

В листинге 6 заметны два изменения, выделенные жирным шрифтом, если сравнивать его с листингом 5. Первое усовершенствование - это свойство runAsManager для реализации поддержки динамического добавления ролей аутентифицированному пользователю. Для этого свойство runAsManager содержит определение bean-компонента RunAsManagerImpl. Bean-компонент RunAsManagerImpl активизируется, только если он находит роль с префиксом RUN_AS_ в списке определенных для метода ролей в свойстве objectDefinitionSource. Например, список определенных ролей для метода PrivateCatalog.getData(), второе изменение в листинге 6, выделенное жирным шрифтом, содержит роль RUN_AS_MANAGER.

Bean-компонент RunAsManagerImpl содержит свойство key, хранящее криптографический ключ, используемый для гарантии того, что дополнительная роль может быть применена только в рамках процедуры run-as-replacement.

Когда пользователь вызывает метод getData(), bean-компонент RunAsManagerImpl активизируется и создает дополнительную роль RUN_AS_MANAGER, позволяющую методу getData() получать доступ к удаленному приложению.

Усовершенствованная безопасность методов

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

После входа в систему приложение EnhancedAcegiMethodSecurity предоставит полную информацию о вошедшем пользователе и его ролях. Например, если войти как alice или specialUser, будут показаны все бизнес-роли пользователя, включая временную роль RUN_AS_MANAGER.

Заключение

В этой третьей статье серии я показал, как использовать систему безопасности Acegi, чтобы усилить безопасность, основанную на URL-адресах, и безопасность, основанную на вызове методов. Мы разобрали, как спроектировать политику управления доступом и сохранить ее в сервере каталогов, как настроить взаимодействие Acegi с сервером каталогов и как принимать решения по аутентификации и авторизации на основе хранящейся в каталоге политики доступа.

Последняя статья серии фокусируется на использовании безопасности, основанной на методах, для защиты экземпляров Java-классов. Также разбирается, как Acegi и Spring на внутреннем уровне создают Java-объекты и прокси-компоненты для этих объектов, и как эти прокси-компоненты используются для реализации политики доступа. В статью включены два приложения примера, которые можно использовать для дальнейшего исследования концепций, изученных в этих статьях. В разделе Ресурсы можно узнать больше об обеспечении безопасности приложений с помощью Acegi.


Загрузка

ОписаниеИмяРазмер
Исходный код для статьиj-acegi3-source.zip36KB

Ресурсы

Научиться

Получить продукты и технологии

  • IBM trial software: ознакомительные версии программного обеспечения для разработчика, которые можно загрузить со страницы developerWorks.(EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=316346
ArticleTitle=Обеспечение безопасности Java-приложений с помощью Acegi: Часть 3. Управление доступом для Java-объектов
publish-date=06252008