Эта серия из пяти статей знакомит с системой безопасности Acegi и показывает, как использовать Acegi для обеспечения безопасности корпоративных Java-приложений. Эта заключительная статья продолжает обсуждение использования Acegi для обеспечения безопасности приложений JSF. В части 4 я показал, как можно обеспечить безопасность страницы JavaServer Faces (JSF) с использованием Acegi без написания какого-либо программного кода на Java. Я также подробно разобрал события, которые происходят при развертывании приложения JSF-Acegi и при обращении пользователя к нему. В этот раз я сосредоточусь на методах обеспечения безопасности JavaBeans в приложениях JSF.
Сначала я покажу, что концепции безопасности bean-компонентов, которые я описывал в части 3 этой серии, могут применяться и к приложениям JSF, но не идеальны для них. Затем я продемонстрирую пару новых методов, особенно удобных для обеспечения безопасности JavaBeans, используемых в приложениях JSF. Я закончу обсуждение представлением четырехступенчатой стратегии, которая позволяет использовать Acegi для обеспечения безопасности bean-компонентов в приложениях JSF без написания какой-либо защитной программы на Java.
Самый простой способ использования защищенных bean-компонентов в JSF-приложении состоит в том, чтобы следовать тому же пятиступенчатому подходу, что использовался в листинге 4 части 3. Там я извлекаю объект контекста Web-приложения среды Spring из контекста сервлета. Позже контекст Web-приложения может быть использован для защищенного доступа к bean-компонентам. В листинге 1демонстрируется использование контекста Web-приложения в странице JSF:
Листинг 1. Получение контекста Web-приложения из контекста сервлета и использование его в странице JSF
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@page import="sample.CatalogBean"%>
<%@page import="org.springframework.web.context.support.WebApplicationContextUtils" %>
<%@page import="org.springframework.web.context.WebApplicationContext" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<html>
<head>
<title>Acegi simple method security application: TEST PAGE</title>
</head>
<body>
<f:view>
<h2>
<h:outputText value="Protected Resource 1:"/>
</h2>
<%
try {
WebApplicationContext webApplicationContext =
WebApplicationContextUtils.getWebApplicationContext(
this.getServletConfig().getServletContext());
CatalogBean privateCatalog = (CatalogBean)
webApplicationContext.getBean("privateCatalog");
String privateData = catalog.getData();
request.setAttribute("privateData", privateData);
}
catch (Exception e) { }
%>
<h3>
<h:outputText value="#{privateData}"/>
</h3>
</f:view>
</body>
</html>
|
Видно, что в листинге 1 используется класс
WebApplicationContextUtils для извлечения экземпляра контекста Web-приложения. WebApplicationContextUtils является служебным классом, предоставляемым Spring.
После получения контекста Web-приложения можно вызвать его метод
getBean() для получения ссылки на любой bean-компонент, настроенный в конфигурационном файле Acegi. Затем можно вызвать методы-получатели bean-компонента и сохранить данные, возвращенные этими методами, в качестве параметра в объекте запроса сервлета. Эти шаги позволяют тегу
<outputText> из
листинга 1 предоставить данные пользователю.
Непосредственная работа с данными bean-компонента, как это показывается в листинге 1, делается просто, но не рекомендуется. Такой подход нарушает логику «модель-представление-контроллер» (Model-View-Controller, MVC) в JSF (см. Ресурсы), которая требует использовать для хранения данных приложения bean-компоненты модели. Лучше не применять эту стратегию в приложениях JSF, за исключением, может быть, очень простых случаев.
JSF предоставляет всеобъемлющую функциональность для управления bean-компонентами модели в приложении. Такие bean-компоненты — называемые управляемыми bean-компонентами — используются в большинстве JSF-приложений, поэтому в этих приложениях необходимо обеспечить защиту управляемых bean-компонентов.
Далее в этой статье обсуждаются два типа стратегий использования защищенных bean-компонентов в приложениях JSF:
- Использование Acegi для обеспечения безопасности управляемых bean-компонентов JSF
- Использование bean-компонентов с инверсией управления, защищенных Acegi непосредственно в тегах JSF
Защита управляемых bean-компонентов JSF
Посмотрите на JSF-страницу, показанную в листинге 2, в которой используется управляемый bean-компонент JSF catalog:
Листинг 2. Простая JSF-страница, в которой используется управляемый bean-компонент
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<html>
<head>
<title>JSF Acegi simple method security application: TEST PAGE</title>
</head>
<body>
<f:view>
<h2>
<h:outputText value="Protected Resource 1:"/>
</h2>
</br>
<h3>
<h:outputText value="#{catalog.publicData}"/>
</br>
<h:outputText value="#{catalog.privateData}"/>
</h3>
</f:view>
</body>
</html>
|
В
листинге 2 используется два тега JSF
<outputText>. В первом теге
<outputText> есть атрибут
value со значением
#{catalog.publicData}, а во втором — атрибут
value со значением
#{catalog.privateData}. Эти два тега используют свойства
publicData
и privateData bean-компонента
catalog, которые предоставляют соответственно открытые и закрытые данные каталога.
Вспомните, как в разделе "Доступ через созданные прокси к Java-объектам"
части 3 я конфигурировал два bean-компонента Acegi: publicCatalog и
privateCatalog. Теперь я собираюсь отобразить bean-компонент
publicCatalog из части 3 (незащищенный bean-компонент, предназначенный для открытого доступа) на свойство publicData bean-компонента
catalog. Аналогичным образом я собираюсь отобразить
privateCatalog из части 3 (защищенный bean-компонент с прокси, сконфигурированный в листинге 3 в
части 3) на свойство privateData управляемого bean-компонента
catalog из
листинга 2, приведенного выше. Правильно отображенный bean-компонент
catalog ведет себя просто как обертка для открытых и закрытых данных JSF-приложения catalog.
Определение управляемого bean-компонента
В
листинге 3 показывается, как определить bean-компонент
catalog, чтобы его свойства
publicData и privateData
отображались соответственно на bean-компоненты Acegi publicCatalog и
privateCatalog:
Листинг 3. Отображение свойств
catalog на bean-компоненты Acegi
<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
<managed-bean>
<managed-bean-name>catalog</managed-bean-name>
<managed-bean-class>sample.Catalog</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>publicData</property-name>
<value>#{publicCatalog.data}</value>
</managed-property>
<managed-property>
<property-name>privateData</property-name>
<value>#{privateCatalog.data}</value>
</managed-property>
</managed-bean>
<application>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
</application>
</faces-config>
|
В
листинге 3 фактически приведен конфигурационный файл для JSF. Его корневой тег — <faces-config>знаком большинству JSF-программистов. Корневой тег
<faces-config> содержит два дочерних тега с именами
<managed-bean> и
<application>. Теперь я подробно объясню эти два тега.
Объявление свойств bean-компонента в конфигурационном файле JFS
Тег <managed-bean> в
листинге 3 определяет bean-компонент catalog
и его свойства. У тега
<managed-bean> есть три дочерних тега —
<managed-bean-name>,
<managed-bean-class> и <managed-bean-scope>
— и пара тегов
<managed-property>. Первые два дочерних тега определяют соответственно имя bean-компонента (catalog) и класса
(sample.Catalog).
Каждый тег <managed-property> в
листинге 3 определяет свойство bean-компонента
catalog. Каждый тег
<managed-property> имеет два дочерних —
<property-name> и <value>
— которые определяют соответственно имя и значение свойства. Глядя в листинг 3, можно увидеть, что имя первого свойства —
publicData, а его значение —
#{publicCatalog.data}. Аналогично, имя второго свойства — privateData, а его значение —
#{privateCatalog.data}.
Эти два значения фактически являются выражениями, которые сводятся к свойствам другого управляемого bean-компонента. Первое выражение
(#{publicCatalog.data}) сводится к свойству data компонента
publicCatalog. Аналогично, второе выражение
(#{privateCatalog.data}) сводится к свойству data компонента privateCatalog.
JSF предоставляет механизм, который сводит выражения типа
#{publicData.data} к экземплярам фактических управляемых bean-компонентов. Обсуждать механизм разрешения выражений в JSF я буду двумя строчками ниже (в разделе "Определение средства для разрешения выражений").
Но тут есть затруднение. В конфигурационном файле JSF в
листинге 3 нет управляемых bean-компонентов
publicCatalog и
privateCatalog. Вспомните, что я конфигурировал IOC bean-компоненты
publicCatalog и
privateCatalog (а не управляемый bean-компонент JSF) в разделе "Доступ через созданные прокси к Java-объектам" в
части 3.
Следовательно, механизм разрешения выражений JSF должен быть способен разрешить IOC bean-компоненты Acegi.
Определение средства для разрешения выражений
JSF-класс javax.faces.el.VariableResolver является стандартным средством для разрешения выражений, способным сводить выражения к управляемым bean-компонентам JSF. Однако VariableResolver не может разрешать IOC bean-компоненты.
JSF предоставляет механизм расширяемости, дающий разработчикам возможность писать свои собственные средства разрешения выражений. Spring предоставляет средство разрешения выражений для JSF в классе
org.springframework.web.jsf.DelegatingVariableResolver.
Класс DelegatingVariableResolver может делать разрешение выражений в IOC bean-компоненты. DelegatingVariableResolver
также использует стандартный VariableResolver для разрешения выражений в управляемые bean-компоненты JSF.
Чтобы использовать DelegatingVariableResolver, из Spring, необходимо настроить его в конфигурационном файле JSF. Именно для этой цели вставлен тег <application> в
листинге 3 (для удобства воспроизведен в листинге 4
):
Листинг 4. Тег
<application>
<faces-config>
..........
<application>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
</application>
</faces-config>
|
Тег <application> в
листинге 4 содержит только один дочерний тег
<variable-resolver>, который предназначен для конфигурирования внешних средств разрешения для JSF-приложения. Тег
<variable-resolver> обертывает имя класса для разрешения выражений в Spring
(org.springframework.web.jsf.DelegatingVariableResolver),
который обслуживает разрешение выражений в IOC bean-компоненты.
Реализация JSF и IOC bean-компонентов
Ранее было показано, как конфигурировать JSF-приложение для использования IOC bean-компонентов Acegi. Теперь можно взглянуть на эти три bean-компонента, которые мы только что сконфигурировали.
В
листинге 5 показывается реализация класса
Catalog, экземпляр которого, названный catalog , сконфигурирован в JSF как управляемый bean-компонент:
Листинг 5. Класс
Catalog class
package sample;
public class Catalog
{
private String publicData = null;
private String privateData = null;
public Catalog () {
}
public void setPublicData(String publicData) {
this.publicData = publicData;
}
public void setPrivateData(String privateData) {
this.privateData = privateData;
}
public String getPublicData() {
return publicData;
}
public String getPrivateData() {
return privateData;
}
}//Catalog
|
Из листинга 5 видно, что класс
Catalog просто содержит getter- и setter-методы для своих свойств publicData и
privateData. Среда JSF будет вызывать эти методы получения и записи свойств, об этом я расскажу в следующем разделе.
Теперь взглянем на реализацию двух IOC bean-компонентов
(publicCatalog и
privateCatalog) в листинге 6:
Листинг 6. IOC bean-компоненты
publicCatalog и privateCatalog
//PublicCatalog
package sample;
public class PublicCatalog implements CatalogBean {
public PublicCatalog () { }
public String getData() {
return "This is public catalog data";
}
}
//PrivateCatalog
package sample;
public class PrivateCatalog implements CatalogBean {
public PrivateCatalog () { }
public String getData() {
return "This is private catalog data";
}
}
|
В листинге 6 можно видеть, что я жестко запрограммировал фактические открытые и закрытые данные в этих двух IOC bean-компонентах. В реальном приложении эти bean-компоненты считывали бы данные из базы данных.
Итак, мы показали все компоненты и конфигурации, необходимые для обеспечения безопасности данных, заключенных в управляемых bean-компонентах JSF. Теперь настало время увидеть, как JSF и Acegi работают вместе, используя компоненты и конфигурации.
Совместная работа JSF и Acegi по обеспечению безопасности управляемых bean-компонентов
Последовательность событий, показанная на рис. 1 имеет место, когда пользователь пытается обратиться к JSF-странице из листинга 2. Я включил все события, которые задействуют URL-безопасность Acegi, а также безопасность bean-компонентов в JSF-приложениях.
Рис. 1. Совместная работа компонентов JSF и Acegi
События на рис. 1 происходят в такой последовательности:
- Пользователь обращается к JSF-странице.
- Acegi проверяет, разрешен ли этому пользователю доступ к JSF-странице. (См. раздел "Обработка запроса JSF-страницы, защищенной Acegi" в
части 4.
- Если процесс авторизации завершается успешно, управление передается сервлету JSF, который подготавливается предоставить JSF-страницу.
- Во время подготовки JSF находит bean-компонент catalog в JSF-странице, показанной в листинге 2.
- JSF ищет в конфигурационном файле, приведенном в листинге 3,
определение bean-компонента
catalogи создает его экземпляр. JSF также проверяет свойства bean-компонентаcatalogв конфигурационном файле. Он находит, что свойства bean-компонентаcatalogbean'spublicDataиprivateDataотображаются на bean-компонентыpublicCatalogиprivateCatalog, которые не сконфигурированы как управляемые bean-компоненты JSF в листинге 3.
- JSF использует средство разрешения переменных Spring
DelegatingVariableResolver(сконфигурировано в листинге 4) для разрешения bean-компонентовpublicCatalogиprivateCatalog.
- JSF использует Acegi для вызова методов-получателей bean-компонентов
publicCatalogиprivateCatalogдля извлечения открытых и закрытых данных.
- Acegi опять выполняет процесс авторизации для доступа к bean-компонентам. (См. в
части 3
подробное обсуждение этого процесса авторизации для Java-объектов.)
- 1.Если Acegi находит, что пользователь имеет доступ к bean-компонентам, он вызывает методы получения, извлекает открытые и закрытые данные и предоставляет данные JSF.
- JSF вызывает методы записи bean-компонента
catalogдля записи открытых и закрытых данных в bean-компонентcatalog.
- JSF выполняет свой жизненный цикл и выдает JSF-страницу.
Пример приложения JSF-Acegi с защищенными управляемыми bean-компонентами
К этой статье прилагается пример приложения
JSFAcegiSampleWithSecureManagedBeans (см. Загрузки). В нем методы, о которых говорилось в предыдущих разделах, используются для обеспечения безопасного доступа к данным, содержащимся в управляемых bean-компонентах JSF.
Развертывание примера приложения делается в соответствии с двумя шагами в разделе "Установка и запуск приложения" в
части 1. Необходимо также загрузить и распаковать файл jsf-1_1_01.zip с сайта Sun по JSF (см.
Ресурсы). Скопируйте все файлы из jsf-1.1.X.zip в папку WEB-INF/lib приложения
JSFAcegiSampleWithSecureManagedBeans. Потребуется также загрузить файл cglib-full-2.0.2.jar (который использовался в
части 3 этой серии статей) и скопировать его в папку WEB-INF/lib приложения
JSFAcegiSampleWithSecureManagedBeans. Чтобы запустить пример приложения, откройте в браузере страницу http://localhost:8080/JSFAcegiSampleWithSecureManagedBeans.
Непосредственное использование IOC bean-компонентов Acegi в JSF-приложении
Мы рассказали, как отображать свойства управляемых bean-компонентов JSF на IOC bean-компоненты Acegi и как сконфигурировать DelegatingVariableResolver для разрешения выражений в IOC bean-компоненты. Также было показано, как осуществляется совместная работа JSF и Acegi для обеспечения безопасного доступа к данным bean-компонента.
Как вариант можно использовать IOC bean-компоненты непосредственно в JSF-страницах, как показано на странице JSF в листинге 7:
Листинг 7. Использование IOC bean-компонентов непосредственно в JSF-странице
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<html>
<head>
<title>JSF Acegi simple method security application: TEST PAGE</title>
</head>
<body>
<f:view>
<h2>
<h:outputText value="Protected Resource 1:"/>
</h2>
</br>
<h3>
<h:outputText value="#{publicCatalog.data}"/>
</br>
<h:outputText value="#{privateCatalog.data}"/>
</h3>
</f:view>
</body>
</html>
|
Содержание
листинга 7 аналогично JSF-странице из
листинга 2. Единственное отличие между ними заключается в атрибутах
value тегов
<outputText>. В
листинге 2 атрибуты value ссылаются на catalog, который является управляемым bean-компонентом JSF. В
листинге 7 атрибуты value ссылаются непосредственно на IOC bean-компоненты (то есть, publicCatalog
и privateCatalog). Это означает, что когда пользователь обращается к JSF-странице в листинге 7, JSF прямо распознает Acegi IOC с помощью Spring DelegatingVariableResolver.
Обратите внимание, что при разрешении IOC bean-компонентов, используемых в JSF-странице,
DelegatingVariableResolver работает так же, как я объяснял при обсуждении рис. 1.
На рис. 2 представлена последовательность событий, происходящих, когда пользователь обращается к JSF-странице из листинга 7.
Рис. 2. Компоненты JSF и Acegi обслуживают JSF-страницу с защищенными IOC bean-компонентами
Последовательность событий, приведенная на рис. 2, лишь незначительно отличается от последовательности на рис. 1:
- Пользователь обращается к JSF-странице.
- Acegi проверяет, имеет ли пользователь право на доступ к JSF-странице.
- Если процесс авторизации завершается успешно, управление передается JSF, который готовится обслужить JSF-страницу.
- Во время подготовки, JSF ищет bean-компоненты
publicCatalogиprivateCatalogв JSF-странице в листинге 7.
- JSF проверяет конфигурационный файл из листинга 3 и находит, что bean-компоненты
publicCatalogиprivateCatalogне сконфигурированы как управляемые bean-компоненты JSF в конфигурационном файле. JSF использует SpringDelegatingVariableResolverдля разрешения bean-компонентовpublicCatalogиprivateCatalog.
- JSF использует Acegi для вызова методов-получателей bean-компонентов
publicCatalogиprivateCatalogдля извлечения открытых и закрытых данных.
- Acegi выполняет процесс авторизации для доступа к bean-компонентам.
- Если Acegi находит, что пользователь авторизован для доступа к bean-компонентам, он вызывает методы получения, извлекает открытые и закрытые данные и предоставляет данные JSF.
- JSF выполняет свой жизненный цикл и выдает JSF-страницу.
В JSF-странице из листинга 7 не используются управляемые bean-компоненты, поэтому на рис. 2 нет событий, относящихся к управляемым bean-компонентам JSF.
Второй пример приложения, названный
JSFAcegiSampleWithIOCBeans, находится в исходном тексте этой статьи (см. Загрузки). В
JSFAcegiSampleWithIOCBeans используется JSF-страница из
листинга 7 для демонстрации применения IOC bean-компонентов в JSF-страницах.
Применение Acegi для обеспечения безопасности существующих JSF-приложений
В предыдущем разделе было показано, что можно непосредственно использовать IOC bean-компоненты в JSF-приложениях. Если уже есть JSF-приложение и нужно использовать Acegi для его защиты, необходимо просто выполнить четыре конфигурационных шага:
- Написать конфигурационный файл Acegi, как описывалось в первых трех статьях этой серии.
- Написать файл web.xml, как описывалось в части 4.
- Использовать Spring
DelegatingVariableResolverв конфигурационном файле JSF, как описывается в этой статье в разделе "Определение средства разрешения выражений". - Переконфигурировать те управляемые bean-компоненты JSF, которые нужно защитить как IOC bean-компоненты, путем объявления этих bean-компонентов в конфигурационном файле Acegi, а не в конфигурационном файле JSF.
Этот метод дает возможность разрабатывать JSF-приложения без учета вопросов, связанных с безопасностью. После разработки приложения можно в соответствии с этими четырьмя шагами конфигурирования развернуть Acegi без написания программы защиты на Java.
В этой серии статей мы рассказали, как использовать Acegi для обеспечения безопасности Java-приложений. Теперь читатели знают, как усилить безопасность как на основе URL, так и на основе методов, а также как спроектировать политику управления доступом и сохранить ее в сервере каталогов, как настроить взаимодействие Acegi с сервером каталогов и как принимать решения по аутентификации и авторизации на основе хранящейся в каталоге политики доступа. В этой и предыдущей статьях мы сфокусировали внимание на JSF-приложениях и узнали, как можно обеспечить безопасность JSF-приложений без написания программ безопасности на Java.
| Описание | Имя | Размер | Метод загрузки |
|---|---|---|---|
| Sample code for this article | j-acegi5-source.zip | 42KB | HTTP |
Научиться
-
Оригинал статьи: Protecting JavaBeans in JSF applications (EN);
- Серия статей
Securing
Java applications with Acegi
: Введение в использование системы Acegi Security System для обеспечения безопасности корпоративных Java-приложений.
- "Обеспечение безопасности Java-приложений с помощью Acegi: Часть 1. Обзор архитектуры и фильтров безопасности" (Билал Сиддикви, developerWorks, март 2008 г.): архитектура и компоненты Acegi Security System.
- "Обеспечение безопасности Java-приложений с помощью Acegi: Часть 2. Работа с сервером каталогов LDAP" (Билал Сиддикви, developerWorks, июнь 2008 г.): работа серверов каталогов с Acegi.
- "Обеспечение безопасности Java-приложений с помощью Acegi: Часть 3. Управление доступом для Java-объектов" (Билал Сиддикви, developerWorks, июнь 2008 г.): управление доступом для Java-объектов.
- "Securing Java applications with Acegi, Part 4: Protecting JSF applications" ((Bilal Siddiqui, developerWorks, февраль 2008 г.: защита JSF-приложений, работающих в контейнере сервлетов.
-
Acegi Security System: официальный сайт Acegi — главный источник справочной информации по этой теме.(EN)
-
"Acegi Security System for Spring Framework, Part 1"
и
"Acegi Security System for Spring Framework, Part 2":
презентация по системе безопасности Acegi.(EN)
-
"Using JSF technology for XForms applications"
(Faheem Khan, developerWorks, февраль 2005 г.): подробное объяснение жизненного цикла JSF. (EN)
-
Онлайновый магазин технической книги
книги на эти и другие темы. (EN)
Получить продукты и технологии
- Загрузите
cglib-full-2.0.2.jar,
используемый Acegi для создания прокси.(EN)
-
JavaServer Faces technology:
Загрузите JSF с сайта Sun.(EN)
-
Acegi Security System:
Загрузите Acegi.(EN)
Обсудить
- Примите участие в обсуждении материала на форуме.
- Просмотрите
блоги на developerWorks и примите участие в работе
сообщества developerWorks. (EN)
Билал Сиддикви (Bilal Siddiqui) является инженером-электронщиком, консультантом по XML и соучредителем WaxSys, компании, чья деятельность направлена на упрощение электронного бизнеса. После окончания в 1995 г. Инженерно-технологического Университета, г. Лахор, и получения степени по электронной технике, он начал разрабатывать программные продукты для промышленных систем управления. В дальнейшем он занимался XML и использовал свой опыт в программировании C++ для разработки Web- и Wap-базируемых инструментов для XML-технологий, серверных парсинговых программных продуктов и служебных приложений. Билал – проповедник передовых технологий и часто публикуется в этой области.