2004 г.
Настройка доменов контроля доступа в JBoss 3.х.х
Yuriy Larin aka Blandger
Оригинал статьи - на сайте http://blandger.pisem.net
Частые обращения и вопросы на форуме www.jboss.ru, связанные с заголовком данной страницы, "сподвигли" меня на написание этой статьи. Все что написанно здесь - это мой личный опыт, какие-то детали связанные с темой я понимаю "вполне прилично" (век живи - век учись), какие-то почти нет, но описанный здесь подход "вообщем-то" рабочий и "почти правильный", хотя он НЕ единственный. Если у вас другие способы настроек, использования JAAS аутентификации, авторизации и/или дополнения - вносите свои предложения, замечания.
К сожалению, я не буду вдаваться в подробности и описание JAAS, ее реализацию в JBoss, потому что: 1. по причине нехватки времени, 2. вы наверное хотите сначала настроить JBoss, а потом уже разбираться в теории, 3. я не совсем уверен, что все объясню правильно согласно "науке-ботанике" J2EE. Так что, если мои рассуждения или объяснения будут неверными - можете смело меня "пинать", а лучше - напишите правильнее чем я. Этим вы сделаете приятное себе и полезное людям.
Исходные требования/данные в моей системе были таковы - JBoss 3.0.x (потом это был 3.2.x), используемый SQL сервер - FireBird 1.х (или Interbase), это также означает, что "пул соединений" (Connection Pool или DataSource) также необходимо настроить самостоятельно. По поводу настроек для других SQL серверов - все операции выполняются аналогично.
Ко всему прочему "контроль доступа" в моем случае должен был осуществляться с помощью "групп пользователей" и их "ролей", которые описаны и храняться ВНУТРИ СУБД, т.е. имеются отдельные таблицы (USERS, ROLES, GROUPS и т.д.), в которые это все заноситься и описывается. Еще замечание, данная статья описывает процесс настройки "доменов контроля доступа", который предназначен для доступа из GUI-приложения, хотя для WEB-приложения это будет "как-то похоже", но все-таки несколько отличается !!
1. Настройка пула соедиений.
Первое что для этого необходимо - сам JDBC драйвер для используемого вами SQL сервера. Также очень хорошо, если он специально написан в соответствии с одной из J2EE спецификаций, которая называется JCA (Java Connector Architecture).
Если вы не знаете, что это такое, то говоря кратко и очень упрощенно - это набор некоторых правил, по которым необходимо писать "встраиваемые" в "сервер-приложений" модули, через которые выполняется обращение в некоторым ресурсам, особенно внешним. Если высказывать мое личное мнение (поправьте, если ошибаюсь), то вся архитектура сервера JBoss - это некоторое "ядро" написанное с помощью другой технологии JMX (Java Management Extension), к которому через "адаптеры" (в том числе и JCA) подключаются все необходимые для работы модули/подсистемы - подсистема логирования (на основе библиотеки Log4J), EJB-контейнер, Web-контейнер (TomCat или Jetty), JAAS (Java Authentication and Authorization Service) модуль идентификации и авторизации, JMS (Java Message Service) и т.д. То есть, как видите - JBoss сам сделан "как конструктор " и широко использует JCA. Если именно JCA драйвера нет, то можно пользоваться "простым" или спросите чем пользуются другие люди.
Что касается JCA драйвера для FireBird, то последнюю версию надо брать там же где вы скачивали саму СУБД, а именно здесь - http://sourceforge.net/projects/firebird/ , в списке архивов для скачивания, нас в данном случае интересует пункт с названием - firebird-jca-jdbc-driver. Если говорить про драйвера других СУБД - ищите в инете и/или на сайтах "производителя" СУБД.
В первую очередь в архиве адаптера нас интересует "документация" (которую надо хотя бы просмотреть), и еще файл - firebirdsql.rar. Расширение RAR у данного файла - это на самом деле НЕ файл от архиватора "WinRAR", а "специальный" файл-архив, упакованный стандартным JAR-ом, но имеющий дополнительные данные внутри, там есть файл \META-INF\ra.xml . Он вообще-то кое-что значит, но "как правило" никаким настройкам (пока что) не подлежит.
Основные настройки производятся в другом XML файле, копию которого вы должны сначала взять как образец из каталога ...\jboss\docs\examples\jca\ (для более "старых или "новых" версий сервера название каталога может отличаться), затем поместить копию в каталог для "деплоймента" - это каталог: ...\jboss\server\default\deploy\ (если говорить о "конфигурации" по умолчанию), а затем - исправить внутри него настройки для вашего конкретного случая.
Небольшое отступление...
Мне кажется не все знают, что JBoss "умеет" запускаться с "разными конфигурациями". Создание конфигурации в JBoss означает, что в каждой конфигурации, можно выполнить настройки так, чтобы загружать разное количество сервисов. Какими-то сервисами вы иногда наверняка не пользуетесь, например JMS, и поэтому можете исключить определенные сервисы из запуска в определенной конфигурации.
Например, в каталоге JBoss после его установки, по умолчанию имеются 3 конфигурации сервера:
...\jboss\server\all\
...\jboss\server\default\
...\jboss\server\minimal\
Если вы запускаете сервер простым стартом файла ...\jboss\bin\run.bat , то запускается "default" конфигурация. Но кроме этого всегда есть возможность создать, например на ее основе, СВОЮ конфигурацию и запускать ее "отдельным номером".
Я обычно предпочитаю взять "default" конфигурацию и скопировать все ее содержимое со всеми подкаталогами в "новую конфигурацию", с которой потом и работаю, ну например так:
...\jboss\server\my_configuration\...
При "обычном" запуске JBoss сервера с помощью "стандартного батника" ...\jboss\bin\run.bat , по умолчанию запускается "default" конфигурация, а чтобы запустить "свою конфигурацию", достаточно в этом же каталоге написать любой другой my_configation.bat файл, который содержит единственную строку запуска с параметром:
run.bat -c=my_configuration
или в последних версиях через пробел
run.bat -c my_configuration
где в "run.bat" передается дополнительный параметр -C со значением равным "названию конфигурации" =my_configuration , что приведет к запуску JBoss-а с указанной вами конфигурацией. Вот так все просто...
Продолжим дальше с настройкой пула. ...\jboss\docs\examples\jca\ - содержит образцы файлов "пула соединений" для всех самых распространенных СУБД. Для меня это был - firebird-service.xml (или firebird-ds.xml, для более свежих версии JBoss). По причине того, что файлы "пула соединений" от версии к версии JBoss-а немного отличаются, то я опишу только "ключевые" параметры, которые необходимо отредактировать.
Для версий JBoss 3.0.x firebird-service.xm обычно выглядит так:
.......
<mbean code =
"org.jboss.resource.connectionmanager.
RARDeployment"
name = "jboss.jca:service=XaTxDS,name=FirebirdDS" >
.................
<depends optional-attribute-name="
ManagedConnectionFactoryName">
<mbean code="org.jboss.resource.connectionmanager.
RARDeployment"
name="jboss.jca:service=XaTxDS,name=
FirebirdDS" >
..............
<config-property>
<config-property-
name>Database</config-property-name>
<config-property-type>java.lang.String<
/config-property-type>
<config-property-value>localhost/3050:С:/DataBase/test.gdb</
config-property-value>
</config-property>
<config-property>
<config-property-name>UserName<
/config-property-name>
<config-property-type>java.lang.String<
/config-property-type>
<config-property-value>sysdba<
/config-property-value>
</config-property>
<config-property>
<config-property-name>Password<
/config-property-name>
<config-property-type>java.lang.String<
/config-property-type>
<config-property-value>masterkey<
/config-property-value>
<config-property>
<config-property-name>Encoding<
/config-property-name>
<config-property-type>java.lang.String<
/config-property-type>
<config-property-value>WIN1251<
/config-property-value>
................
FirebirdDS - это JNDI имя вашего пула, это то как оно будет "привязываться" (binding - байндиться) в JNDI (Java Naming Directory Interface) сервера, и под каким именем (в виде - java:/FirebirdDS) вы его будете искать внутри кода. Во всех местах XML файла крайне желательно иметь это имя ОДИНАКОВЫМ, чтобы избежать лишних проблем. Лично я предпочитаю переименовать его с указанием "подветки", например так: jdbc/FirebirdDS (или по другому ), тогда java-код его поиска в JNDI будет осуществляться по имени - java:/jdbc/FirebirdDS. Почему пул соединений помещен "в подветку" с именем jdbc - объяснять не буду.
Свойство "Database" указывает путь (или URL) к вашему файлу/ресурсу/сервису, например, localhost/3050:С:/DataBase/test.gdb. Правила написания этого пути (URL-а) для каждого SQL сервера свои, и значительно отличаются друг от друга, смотрите примеры в соответствующих файлах.
Свойства "UserName", "Password" - указываются для вашей БД. Если вы уже работали с Interbase, то значения: sysdba, masterkey должны быть вам знакомы.
Если вы читаете этот файл, то свойство "Encoding" стоит указывать равным WIN1251, но для других СУБД способ задания кодировки может отличаться, например, его (редко) можно поместить внутри строки соединения, как некоторый параметр, что-то типа - localhost/3050:С:/DataBase/test.gdb?lc_ctype=WIN1251. Но "пройдет ли" этот номер с передачей дополнительного параметра, зависит от вашей СУБД и успользуемого вами драйвера. "Буржуи" иногда про это ничего не знают, поэтому вам придется самим это выяснить.
Другие настройки, если не знаете, что они означают - лучше сначала не менять.
Для версий JBoss 3.2.x файл "пула соединений" отличается в лучшую сторону и имеет более понятно описанные параметры (<jndi-name>,<connection-url> и т.д. ), например для Sybase:
................
<jndi-name>jdbc/SybaseDB</jndi-name>
<connection-url>
jdbc:sybase:Tds:host.at.some.domain:5000/db_name?
JCONNECT_VERSION=6
</connection-url>
................
2. Модель контроля доступа в JBoss.
Сильно не хочется зарываться в эту тему "по теории", но все-таки придеться немного написать, хотя бы в простейшем и неполном виде.
Как правило , под "контролем доступа" понимаются ДВА процесса.
Первый процесс - это идентификация (authentication) пользователя, который как правило происходит один раз при начале работы клиента с сервером/сервисом. Это означает, что производиться проверка, что "вы - это вы". Обычно используется самый распространенный способ - "имя + пароль", хотя можно использовать и более "замысловатые варианты", например сертификаты. При этом сервер проверяет, что он "знает" о пользователе с предоставленным именем, и проверяет совпадает ли введенный пароль (или не сам пароль, а ХЭШ значения сравниваемых паролей) с тем, который известен ему в системе.
Второй процесс - это авторизация (authorization) или проверка полномочий или прав доступа пользователя к каждому ресурсу. Этот процесс происходит каждый раз при обращении клиента к сервисам/ресурсам, например методам бинов, сервлетам, JSP, очередям JMS у JBoss-а. Суть этого процесса заключается в том, что сервер все время проверяет, имеет ли данный клиент права доступа, которые описаны как "необходимые и достаточные" для доступа к сервису. Существует два типа авторизации - "программная" и "декларативная".
Рассматривать программный способ я не буду, только кратко скажу о его сути. Суть программного метода заключается в том, что в методе бина программист должен написать код, который проверяет - достаточно ли у пользователя прав для вызова этого метода, т.е. мы сами должны написать код проверки и выполнить ее.
Смысл декларативной авторизации в том, что в файле-дескрипторе описываются необходимые для доступа "роли-права доступа " и все проверки выполняются самим сервером без нашего вмешательства.
Согласно J2EE спецификации, JBoss реализует "контроль доступа" к своему контейнеру (в первую очередь EJB-контейнеру, но и к другим контейнерам тоже), используя технологию JAAS. Эта технология позволяет на ее основе писать "свои" модули контроля доступа (логин-модули) и "встраивать" их в сервер "как плагины". Назначение "логин-модуля" - проверка идентификации пользователя и получение для указанного имени пользователя "ролей-прав", которые сервер "кэширует", ассоциируя их с security context-ом пользователя. Что такое "роли", которые я называю "роли-права доступа " - см. дальше.
Каждый вызов, каждое обращение любого клиента к ресурсам сервера - методу(ам) EJB, обращение к сервелету, обращение к JSP, JMS, происходит через "специальные" в JBoss-е объекты - "security interceptor". "Security interceptor" - это специальные прокси-объекты JBoss, обращение к которым происходит ДО того, как клиент получит доступ к ресурсу и именно в них выполняется авторизация клиента, т.е. проверяется "разрешение" на доступ. Это выполняется самим сервером, с помощью сравнения списка "ролей-прав" клиента, извлеченных и кэшированных при первом входе клиента в систему, со списком "ролей-прав" описанных для "ресурса", к которому выполняется обращение.
Возможно, вам НЕ придеться писать самостоятельно ни объекты "security interceptor", ни "логин-модули", т.к. сервер имеет уже несколько готовых модулей и вы просто воспользуетесь ими. Это может быть простейший способ на основе двух файлов users.properties + roles.properties. Есть и другие модули - на основе обращения к СУБД, есть с использованием LDAP сервера. Подойдут ли они вам и работают ли они так как требуется вам - решать и проверять только вам.
Итак, объекты "security interceptor" управляются некоторым объектом "security-manager", который для своей работы, использует подключенные JAAS логин-модули. Такой "логин-модуль" определяет некоторый способ получения и извлечения информации об пользователе, обычно: имя, пароль + права доступа (роли) к ресурсам/сервисам. Всю эту кухню (вместе с другими security объетками) принятно называть "доменами контроля доступа", security domain, security realm.
Если вы ранее ни разу НЕ устанавливали и НЕ настраивали security JBoss-е, то скорее всего оба этих процесса идентификации и авторизации, происходили и происходят у вас совершенно "прозрачно" и незаметно, вы возможно даже НЕ думали, что они вообще происходят. Но на самом деле все проверки выполняются, но правила для проверки "не применяется", потому что вы НЕ указали ни одного "домена контроля доступа" в вашем J2EE приложении.
Указание JNDI имени домена контроля доступа делается в "vendor specific" файлах, т.е. файлах именно специфичных для JBoss-а. Для EJB компонент это файл jboss.xml (парный для ejb-jar.xml), например так:
jboss.xml
<?xml version="1.0"?>
<jboss>
<security-domain>java:/jaas/MySuperSecurityDomain</
security-domain>
<enterprise-beans>
................<!-- ЗДЕСЬ ОПИСАНЫ БИНЫ -->
</enterprise-beans>
................
<jboss>
Или для web-компонент это jboss-web.xml, таким образом:
jboss-web.xml
<?xml version="1.0"?>
<jboss-web>
<security-domain>java:/jaas/MySuperSecurityDomain<
/security-domain>
</jboss-web>
Где "java:/jaas/MySuperSecurityDomain" - это JNDI имя настроенного вами "домена контроля доступа", с помощью которого будет проверяться идентификация и права доступа. ЧТО он обозначает, ГДЕ и КАК он настраивается, об этом поговорим немного позже. Пока достаточно знать, что таким образом мы "включаем" проверки контроля доступа на серверной части. Указание "домена" - это обычно единственные настройки, которые необходимо выполнить в двух указанных файлах. Указание "домена контроля доступа", просто сообщает серверу, каким "доменом" необходимо пользоваться для проверки доступа и что он находиться в JNDI под указанным именем.
Как только вы подключили "домен" в указанные файлы, то после сборки приложения и его деплоймента на сервер, доступ к методам бинов (авторизация) будет контролироваться подсистемой контроля доступа Jboss. Это также означает, что методам необходимо назначить (описать) "роли-права доступа " в файле-дескрипторе ejb-jar.xml бина. А также "раздать" (описать) эти "роли-права" пользователям. КАК это делается рассмотрим ниже.
Если вы НЕ назначили "роли" в файле-дескрипторе, то скорее всего при обращении к методам бина увидите в логе сообщение, что права доступа не назначены для методов.
ERROR [SecurityInterceptor - org.jboss.logging.Logger.
error(Logger.java:xxx)]
No method permissions assigned to method=findAll
ERROR [SecurityInterceptor - org.jboss.logging.Logger.
error(Logger.java:xxx)]
No method permissions assigned to method=
findByPrimaryKey
Или что более вероятно, о том что происходит ошибка идентификации пользователя:
2004-03-07 11:44:11,137 ERROR [org.jboss.ejb.plugins.
SecurityInterceptor]
Authentication exeption, principal=null
Что касается идентификации, то в указанном домене контроля доступа (jboss.xml, jboss-web.xml) должна быть доступна информация типа: имя пользователя, пароль, назначенные каждому пользователю роли-права. "Способ хранения и доступа" к такой информации определяется используемым при настройке классом "логин-модуля". Способы хранения этой информации, ее извлечения и "проверки соответствия" мы сейчас не обсуждаем. Что касается прав доступа - разбираемся дальше...
3. Декларативное описание прав доступа в J2EE.
В данном разделе я расскажу "совсем кратко" КАК подключать и описывать права доступа в EJB компонентах и не утверждаю, что для Web ресурсов все "точно так же", хотя сам принцип - точно такой же. При этом я не собираюсь изложить "все тонкости" и возможности, которые присутствуют в J2EE дескрипторах бинов, я только описываю "простейший подход", который далек от совершенства, но все-таки дает представление о сути темы "контроля доступа".
Как правило EJB компоненты, прежде чем их поместить в EAR модуль-приложение, компоненты группируются в отдельные JAR модули. Каждому такому модулю соответствует файл-дескриптор внутри него - ejb-jar.xml, в котором описываются все возможные параметры, описывающие разные характеристики, в том числе и касаемые "контроля доступа". Группировать ли EJB по некоторым логическим соображениям или "свалить их в кучу", создав только один JAR файл - это ваше личное дело и предпочтение. Я всегда стараюсь как в коде, так и в сборках, разные логические части системы "содержать отдельно" друг от друга.
Что вообще такое "роль"? Это некоторая строка, значение которой обозначает "разрешение, право доступа". В качестве значения этому разрешению лучше давать "логически понятное" название, исходя из вашего проекта, смысла этой роли и т.д. По своей сути, роль - это название "разрешения" (permission) для доступа к описанному этой ролью сервису (методу, интерфейсу, бину). Поэтому я дальше так и буду называть - "роль-право доступа ", хотя это, наверное, и не совсем правильно с "научной" точки зрения.
Контроль доступа в J2EE серверах, а значит и в JBoss, выполняется при помощи простой проверки двух списков. С одной стороны - это список "ролей-прав", которые будут извлечены и кэшированы для вызывающего клиента, когда он будет идентифицирован в системе. Данный список "прав доступа" в литературе имеет еще названия: client identity, security identities. С другой стороны - это список "ролей-прав", назначенных у EJB компонент в ejb-jar.xml дескрипторном файле. В литературе он обычно называется security roles. При обращении клиента к методам EJB, отдельные строки ролей-разрешений из этих двух списков "проверяются на совпадение", и должны присутствовать в обоих для успешного вызова определенного метода клиентом с определенным именем.
Если вы еще НЕ настраивали ejb-jar.xml дескрипторы на работу с "контролем доступа", то скорее всего он выглядит приблизительно так:
<ejb-jar>
.............
<enterprise-beans>
............. <!-- ЗДЕСЬ ОПИСАНЫ БИНЫ с именами:
EJB_1, EJB_2, EJB_3 -->
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
............... <!-- ЗДЕСЬ ОПИСАНЫ АТТРИБУТЫ
ТРАНЗАКЦИЙ -->
</container-transaction>
</assembly-descriptor>
<ejb-jar>
Т.к. нас интересует только часть <assembly-descriptor>, то остальную часть я приводить не буду.
ejb-jar.xml
.................................
<assembly-descriptor>
<security-role>
<description>Права вызова ЛЮБЫХ методов
у EJB компонент модуля</description>
<role-name>ManageObjects</role-name>
</security-role>
<security-role>
<description>
Права вызова методов поиска
(findAll, findByPK, getFullObject) EJB компонент
</description>
<role-name>ViewObjects</role-name>
</security-role>
...................................
</assembly-descriptor>
В дескрипторе мы определили две роли или два разрешения с названиями - ManageObjects и ViewObjects. Далее эти роли мы назначим методам бинов. В этом же дескрипторе появляется описание такого вида:
<assembly-descriptor>
........................
<method-permission>
<role-name>ManageObjects<
/role-name>
<method>
<ejb-name>EJB_1</ejb-name>
<method-name>*</method-name>
</method>
</method-permission>
<method-permission>
<role-name>ManageObjects</role-name>
<method>
<ejb-name>EJB_2</ejb-name>
<method-name>*</method-name>
</method>
</method-permission>
<method-permission>
<role-name>ManageObjects</role-name>
<method>
<ejb-name>EJB_3</ejb-name>
<method-name>*</method-name>
</method>
</method-permission>
<!-- Пользователи имеющие у себя роль-разрешение
ManageObjects,
получат доступ к ЛЮБОМУ методу на ЛЮБОМ интерфейсе
бинов EJB_1, EJB_2, EJB_3,
что указывается символом (*) в названии метода -->
<method-permission>
<role-name>ViewObjects</role-name>
<method>
<ejb-name>EJB_1</ejb-name>
<method-intf>Home</method-intf>
<method-name>findAll</method-name>
</method>
</method-permission>
<method-permission>
<role-name>ViewObjects</role-name>
<method>
<ejb-name>EJB_1</ejb-name>
<method-intf>Home</method-intf>
<method-name>findByPrimaryKey</method-name>
</method>
</method-permission>
<method-permission>
<role-name>ViewObjects</role-name>
<method>
<ejb-name>EJB_1</ejb-name>
<method-intf>Remote</method-intf>
<method-name>getFullObject</method-name>
</method>
</method-permission>
<!-- Пользователи имеющие у себя роль-разрешение
ViewObjects, получат доступ
только к методам findAll, findByPrimaryKey на Home интерфейсе
и getFullObject на Remote интерфейсе бина EJB_1 -->
<method-permission>
<unchecked/>
<method>
<ejb-name>EJB_1</ejb-name>
<method-intf>Local</method-intf>
<method-name>*</method-name>
</method>
</method-permission>
<method-permission>
<unchecked/>
<method>
<ejb-name>EJB_1</ejb-name>
<method-intf>LocalHome</method-intf>
<method-name>*</method-name>
</method>
</method-permission>
<!-- Это обозначает, что проверку ролей при обращении к
ЛОКАЛЬНЫМ (Home и Remote)
интерфейсам EJB_1 НЕ выполнять -->
.....................................
<!-- Описания доступа к EJB_2, EJB_3 для краткости ПРОПУСКАЕМ -->
</assembly-descriptor>
Стоит упомянуть, что назначение НЕСКОЛЬКИХ ролей-прав доступа одному и тому же ресурсу (методу, интерфейсу, бину) совершенно НЕ запрещается.
4. Использование простейшего логин-модуля для контроля доступа в JBoss.
Теперь, назначив роли, права доступа методам EJB в файле(ах) ejb-jar.xml, мы можем продолжить настройки контроля доступа. Здесь я расскажу, КАК можно использовать готовые логин-модули, которые имеются в JBoss. Одни из них будут использоваться на (GUI) клиенте, другие на сервере.
Необходимые настройки и код доступа клиента.
Прежде чем мы продолжим настройку контроля доступа на сервере, я хотел бы рассказать и показать ЧТО и КАК делается на стороне клиента (например GUI), для того чтобы выполнялась идентификация и авторизация, используя возможности JAAS.
Вот часть кода, который у меня используется для идентификации и авторизации клиента в JUnit тесте:
Hashtable props = new Hashtable();
props.put(Context.INITIAL_CONTEXT_FACTORY, "localhost:1099");
props.put(Context.PROVIDER_URL, "org.jnp.interfaces.NamingContextFactory");
props.put(Context.URL_PKG_PREFIXES, "
org.jboss.naming");
try {
context = new InitialContext(props);
// поиск бина с именем "MyEntityBean"
Object ref = context.lookup("MyEntityBean");
home = (MyEntityBeanHome)
PortableRemoteObject.narrow(
ref, MyEntityBeanHome.class);
// имя пользователя и пароль доступа к серверу
String userName = "test";
String password = "testpass";
// установка свойства, для указания файла
конфигурации
// JAAS логин-модуля на клиентском приложении
System.setProperty(
"java.security.auth.login.config",
"X:/.../jboss/client/auth.conf");
// используемый обработчик, которому передаются
вводимые имя и пароль
org.jboss.security.auth.callback.
UsernamePasswordHandler handler =
new org.jboss.security.auth.callback.
UsernamePasswordHandler(
userName, password.toCharArray());
// создание логин-контекста на клиенте
final javax.security.auth.login.LoginContext lc =
new javax.security.auth.login.LoginContext
("simple", handler);
// логин в систему
lc.login();
} catch (javax.security.auth.login.
LoginException e) {
System.out.println("Login
Exception: " + e);
e.printStackTrace();
} catch (NamingException e) {
System.out.println("Naming
Exception: " + e);
e.printStackTrace();
}
Интересной частью, является содержимое файла - auth.conf., который используется клиентом и должен поставляться вместе с клиентским приложением. А также название клиентского логин-модуля - "simple".
Файл auth.conf создан по образцу имеющегося в JBoss файла, только упрощен. Не вдаваясь в подробности, стоит сказать, что необходимо "точное" соблюдение формата данного файла, с учетом всех символов-разделителей (;).
Содержимое файла - auth.conf
simple {
org.jboss.security.ClientLoginModule
required;
};
Клиент использует файл конфигурации с указанным классом (org.jboss.security.ClientLoginModule) , который реализован как JAAS логин-модуль. Данный класс просто "делегирует", передает вводимые пользователем "имя и пароль" на сервер.
На этом можно закончить настройку клиента и его кода. Этого достаточно для работы клиента, хотя возможны варианты использования других классов "клиентского" логин-модуля. Для использования на клиентской стороне существует еще один класс для логин-модуля - SRPLoginModule, но мне не удалось его настроить.
Продолжим настройку серверной части JAAS, простейший серверный логин-модуль.
Для настройки домена контроля доступа на сервере, мы воспользуемся логин-модулем, реализованным классом org.jboss.security.auth.spi.UsersRolesLoginModule. Данным модулем удобно пользоваться в процессе разработки системы, в силу простоты его использования, но для "production" системы, вы скорее всего воспользуетесь более "продвинутым" вариантом, который описан в конце статьи.
Для работы он использует два файла. Первый файл должен иметь название - users.properties. Он используется для хранения на сервере имени пользователей и их пароли, которые будут проверяться сервером на "совпадение" с теми значениями, которые будут предоставлены клиентами.
Второй файл должен иметь название - roles.properties. Он используется для хранения на сервере "ролей-прав". Эти права назначаются (относятся) к именам пользователей, которые предварительно описаны в файле users.properties . Все подробности об этих файлах я напишу немного позже.
В запускаемой вами конфигурации есть уже готовая настройка логин-модуля, если вы загляните в файл:
........\jboss\server\my_configuration\conf\login-config.xml
Внутри данного файла вы должны увидеть несколько настроенных "доменов контроля доступа", один из них приблизительно такой:
login-config.xml
..........................
<application-policy name =
"other">
<authentication>
<login-module code = "org.jboss.security.auth.spi.UsersRolesLoginModule"
flag = "required" />
</authentication>
</application-policy>
.........................
Как видите данный контроллер имеет название "other" и использует JAAS логин-модуль, реализованный в классе org.jboss.security.auth.spi.UsersRolesLoginModule. Данный логин-модуль использует ДВА файла свойств для хранения имен пользователей, паролях и ролях-разрешениях.
Вы можете дать этому домену другое название в указанном XML файле, или использовать название указанное по умолчанию (other). Мы будем использовать указанное. Тогда наши JBoss файлы-дескрипторы для EJB модулей будут выглядеть так:
jboss.xml
<?xml version="1.0"?>
<jboss>
<security-domain>java:/jaas/other<
/security-domain>
<enterprise-beans>
................<!-- ЗДЕСЬ ОПИСАНЫ БИНЫ -->
</enterprise-beans>
................
<jboss>
Теперь, если вы попробуете вызвать метод вашего бина из клиента, то скорее всего получите следующее сообщение об ошибке в лог-файле сервера:
server.log
2004-03-07 11:35:05,602 ERROR
[org.jboss.security.auth.spi.UsersRolesLoginModule]
Failed to load users/passwords/
role files java.io.IOException:
Properties file users.properties
not found
at org.jboss.security.auth.spi.
UsersRolesLoginModule.loadProperties(
UsersRolesLoginModule.java)
..........................
Это говорит о том на клиенте мы воспользовались одним из JAAS логин-модулем. При этом клиент выполнял вход в систему с использованием JAAS логин-модуля на основе класса ClientLoginModule. Затем эта информация для идентификации пользователя была передана на сервер.
После чего была выполнена попытка инициализации "домена контроля доступа" при обращении к методам EJB, с использованием подключенного в ejb-jar.xml файле "другого" домена контроля доступа на основе JAAS. Этот серверный домен реализован в классе UsersRolesLoginModule. Но при попытке сервера считать информацию об "имени и пароле" для выполенения идентификации пользователя, на сервере произошла ошибка. Для устранения ошибки нам необходимо продолжить настройку и поместить данную информацию на сервер. Для этого в каталоге нашей конфигурации мы создаем файл ...\jboss\server\my_configuration\conf\users.properties со следующим содержимым:
test=testpass
#также можно поместить имена других пользователей и их пароли
user2=password2
Теперь, выполнив доступ к серверу, вы скорее всего получите следующую ошибку в логе сервера:
server.log
2004-03-07 11:35:53,000 ERROR [org.
jboss.security.auth.spi.UsersRolesLoginModule]
Failed to load users/passwords/
role files java.io.IOException:
Properties file roles.properties
not found
at org.jboss.security.auth.spi.
UsersRolesLoginModule.loadProperties(
UsersRolesLoginModule.java)
..................
Теперь мы видим, что сервер при попытке инициализации нашего подключенного домена, не нашел второй файл - roles.properties. Для исправления данной ситуации, в каталоге нашей конфигурации мы создаем файл ...\jboss\server\my_configuration\conf\roles.properties со следующим содержимым:
test=ViewObjects
#также можно поместить имена других пользователей
и назначить им роли-разрешения
user2=ManageObjects
#user3=ManageObjects,Admin,
DocumentPrinting
Определив таким образом двух пользователей в системе мы назначили им "роли-права". Пользователь "test" при успешном подключении получит список ролей-прав, который состоит только из одной роли - ViewObjects. Другие пользователи получать свои права, например "user2" - ManageObjects. Если вы все-таки получаете ошибку:
2004-03-07 10:31:29,735 ERROR
[org.jboss.ejb.plugins.SecurityInterceptor]
Authentication exception,
principal=null
это означает, что где-то в настройках вы ошиблись.
Рассмотрим, что происходит при обращении пользователя к серверу через GUI клиента. Когда информация о пользователе, проходя через класс ClientLoginModule, попадает на сервер при обращении к EJB, инициализируется класс логин-модуля UsersRolesLoginModule. Он считывет файл users.properties и проверяет наличие такого же имени и соответствие паролей. Также происходит считывание и кэширование "прав доступа" из файла roles.properties и ассоциирование их с security context-ом данного клиента внутри EJB контейнера. В процессе авторизации набор прав доступа сравнивается с правами доступа определенного ресурса. Например, вот что можно будет увидеть в логе сервера, если клиент "test" не имет прав для доступа к методу "create" бина:
ERROR [org.jboss.ejb.plugins.
SecurityInterceptor]
Insufficient method permissions,
principal=test, method=create,
requiredRoles=[ManageObjects],
principalRoles=[ViewObjects]
Контейнер выдает исключение и сообщает о недостатке прав доступа, указывая имя клиента, название метода, требуемые ресурсом права и существующие у пользователя права доступа.
5. Пример логин-модуля контроля доступа, использующий СУБД.
Теперь я расскажу, как настроить более удобный домен контроля доступа с использованием СУБД.
Обратимся с очередной раз к файлу настроек контроля доступа - ....\jboss\server\my_configuration\conf\login-config.xml . В данный файл мы поместим еще один серверный домен контроля доступа, который использует СУБД. Настроенный домен будет основан на использовании готового класса - org.jboss.security.auth.spi.DatabaseServerLoginModule. Пример описания домена и его параметры таковы:
login-config.xml
...............
<application-policy name = "
databaseSecurityDomain">
<authentication>
<login-module code = "org.jboss.
security.auth.spi.DatabaseServerLoginModule"
flag = "required">
<module-option name = "dsJndiName">java:
/jdbc/FirebirdDS</module-option>
<module-option name = "
principalsQuery">
select USER_PASSWORD from
USERS where NAME=?
</module-option>
<module-option name = "
rolesQuery">
select ROLE_NAME, 'Roles'
from USERS u .....
................
and u.name=?
</module-option>
<module-option name = "
debug">true</module-option>
</login-module>
</authentication>
</application-policy>
...........................
JNDI имя указанного домена контроля доступа - databaseSecurityDomain, вы можете указать любое другое имя, но именно это имя вы будете указывать в ejb-jar.xml в виде - java:/jaas/databaseSecurityDomain.
jboss.xml
<?xml version="1.0"?>
<jboss>
<security-domain>java:/jaas/
databaseSecurityDomain</security-domain>
<enterprise-beans>
................<!-- ЗДЕСЬ ОПИСАНЫ БИНЫ -->
</enterprise-beans>
................
<jboss>
Данному модулю для корректной работы требуется три обязательных параметра. Если быть до конца точным, обязательный параметр один -JNDI имя пула, но тогда данные будут выбираться из таблиц с именами "по умолчанию" и с предопределенной структурой, а из каких именно - вы скорее всего не узнаете, пока не прочтете в документации.
Параметр "dsJndiName" должен указывать на корректно настроенный пул соединений к СУБД, где содержаться все необходимые таблицы.
Параметр "principalsQuery" должен содержать запрос, который из указанной таблицы (USERS) сделает выборку "пароля" пользователя (поле USER_PASSWORD) по переданному в виде параметра имени пользователя (NAME=?). Как видно из данного запроса, недостаток данной реализации логин-модуля, заключается в том, что в таблице храниться "открытый пароль", а не его ХЭШ значение.
Параметр "rolesQuery" должен содержать запрос, который из указанной(ых) таблиц выбирает список ролей-прав. Данная выборка состоит из двух столбцов. Первый столбец должен содержать значения ролей-прав (ROLE_NAME), в нашем случае это были ViewObjects, ManageObjects. Второй столбец содержит постоянное значение, равное 'Roles'. КАК и из каких таблиц вы будете делать данную выборку - это ваше решение. Вариантов реализации может быть несколько.
Например, если вы создали такую структуру таблиц:
то запрос ролей-прав будет выглядеть, например, так:
SELECT PERMISSIONS.ROLE_NAME, 'Roles'
FROM PERMISSIONS, USERS
WHERE (USERS.ID = PERMISSIONS.USER_ID) and (USERS.NAME = ?)
Как вы можете увидеть, структура таблиц аналогична использованию модуля на основе users, roles файлов, где для каждого пользователя перечисляется его права. Данный подход достаточен для "условно НЕбольшого" количества пользователей и ролей, но становиться трудоемким при "условно большом" количестве пользователей и ролей.
Если выбрана более сложная структура с правами, группами, пользователями, например, так:
то запрос на выборку может выглядеть так:
SELECT ROLE_NAME, 'Roles'
FROM USERS U, USERS_GROUPS UG, GROUPS G,
GROUPS_PERMISSIONS GP, PERMISSIONS P
WHERE
U.ID = UG.USER_ID AND UG.GROUP_ID = G.ID AND
G.ID = GP.GROUP_ID AND GP.PERMISSION_ID = P.ID
AND U.NAME = ?
В данном варианте, структура таблиц сделана так, что с одной стороны "роли-права доступа" указываются для предопределенных групп пользователей - это связка таблиц PERMISSIONS - GROUPS_PERMISSIONS - GROUPS. С другой стороны мы можем каждого пользователя назначить в любую группу (или группы) и он сразу получит все права доступа группы. Это обеспечивается связкой таблиц USERS - USERS_GROUPS - GROUPS. Данный подход становиться гораздо гибче, особенно для "условно большого" количества пользователей и ролей в системе.
Вы сами можете реализовать и другие варианты. Но как было уже сказано, недостаток использованного (DatabaseServerLoginModule) логин-модуля - "открытое хранение пароля" в БД. Другого класса, реализующего более "закрытый" вариант реализации мне, к сожалению, не известно.