четверг, 7 марта 2013 г.

Настройка аутентификации на основе JAAS в GlassFish 3

Для начала возьмём за основу наверное самый распространённый вариант аутентификации: учётные данные пользователей хранятся в некой базе данных. У нас также есть некое web-приложение, в котором будет выполняться form-based аутентификация.

Итак, первое что нужно сделать - это настроить на сервере соединение с базой данных (соединяться будем с PostgreSQL). Для этого необходимо создать пул соединений, а также связанный с этим пулом источник данных. Всё это удобно делать через консоль, предварительно создав файл glassfish-resources.xml примерно такого содержания:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" 
        "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <jdbc-connection-pool name="AuthDemoPool"
        allow-non-component-callers="false"
        associate-with-thread="false"
        connection-creation-retry-attempts="0"
        connection-creation-retry-interval-in-seconds="10"
        connection-leak-reclaim="false"
        connection-leak-timeout-in-seconds="0"
        connection-validation-method="auto-commit"
        datasource-classname="org.postgresql.ds.PGSimpleDataSource"
        fail-all-connections="false"
        idle-timeout-in-seconds="300"
        is-connection-validation-required="false"
        is-isolation-level-guaranteed="true"
        lazy-connection-association="false"
        lazy-connection-enlistment="false"
        match-connections="false"
        max-connection-usage-count="0"
        max-pool-size="32"
        max-wait-time-in-millis="60000"
        non-transactional-connections="false"
        pool-resize-quantity="2"
        res-type="javax.sql.DataSource"
        statement-timeout-in-seconds="-1"
        steady-pool-size="8"
        validate-atmost-once-period-in-seconds="0"
        wrap-jdbc-objects="false">
        <property name="ServerName" value="localhost"/>
        <property name="PortNumber" value="5432"/>
        <property name="DatabaseName" value="authdemo"/>
        <property name="User" value="postgres"/>
        <property name="Password" value="changeit"/>
        <property name="Url" value="jdbc:postgresql://localhost:5432/authdemo"/>
        <property name="DriverClass" value="org.postgresql.Driver"/>
    </jdbc-connection-pool>

    <jdbc-resource enabled="true" jndi-name="jdbc/AuthDemoDS" object-type="user" 
        pool-name="AuthDemoPool"/>
</resources>
Затем, чтобы создать на сервере описанные в данном файле ресурсы, достаточно набрать в консоли
asadmin add-resources glassfish-resources.xml
Не забудьте положить в каталог glassfish3/glassfish/domains/<domain_name>/lib необходимые драйверы базы данных.
Для проверки только что созданного пула соединений выполните команду
asadmin ping-connection-pool AuthDemoPool

Следующим шагом будет создание realm'a, -  ресурса сервера, используемого web-приложениями для аутентификации пользователей. Набираем в консоли
asadmin create-auth-realm --classname com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm --property jaas-context=jdbcRealm:datasource-jndi="jdbc/AuthDemoDS":user-table=users:user-name-column=username:password-column=password:group-table=authorities:group-name-column=authority:digest-algorithm=SHA-512 auth-demo-jdbc-realm
В параметре classname необходимо указать имя класса realm'а, который мы хотим использовать для выполнения аутентификации. В параметре property указываются свойства, которые будут переданы realm'у при инициализации. В нашем случае это:
  • jaas-context - сценарий аутентификации, определённый в файле glassfish3/glassfish/domains/<domain_name>/config/login.conf;
  • datasource-jndi - JNDI-имя источника данных, определенного нами ранее в файле glassfish-resources.xml;
  • user-table - имя таблицы базы данных, содержащей логины/пароли пользователей;
  • user-name-column - имя поля в таблице пользователей, хранящего логины;
  • password-column - имя поля в таблице пользователей, хранящего пароли;
  • group-table - имя таблицы базы данных, содержащей группы пользователей;
  • group-name-column - имя поля в таблице групп, хранящего наименования этих самых групп;
  • digest-algorithm - необязательное свойство, определяющее алгоритм хеширования паролей в базе данных.
Группы пользователей связываются с самими пользователями по полю внешнего ключа в таблице групп, имя которого по умолчанию совпадает с именем поля логина в таблице пользователей.
На этом подготовительные мероприятия на сервере закончены. Остаётся научить наше web-приложение пользоваться только что созданным ресурсом realm'а. Для этого редактируем файл web.xml:
<login-config>
    <auth-method>FORM</auth-method>
    <realm-name>auth-demo-jdbc-realm</realm-name>
    <form-login-config>
        <form-login-page>/login.xhtml</form-login-page>
        <form-error-page>/login.xhtml?auth-error=1</form-error-page>
    </form-login-config>
</login-config>

<security-role>
    <role-name>ROLE_USER</role-name>
</security-role>

<security-role>
    <role-name>ROLE_ADMIN</role-name>
</security-role>
Здесь мы тегом realm-name сослались на определённый нами ресурс realm'а, а также объявили пару ролей, используемых в нашем web-приложении для разграничения доступа пользователей к ресурсам системы. На заключительном этапе необходимо задать отображение наименований ролей на группы пользователей. Добиться этого можно создав рядом с web.xml дополнительный дескриптор glassfish-web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN"
        "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
    <security-role-mapping>
        <role-name>ROLE_ADMIN</role-name>
        <group-name>ROLE_ADMIN</group-name>
    </security-role-mapping>

    <security-role-mapping>
        <role-name>ROLE_USER</role-name>
        <group-name>ROLE_USER</group-name>
    </security-role-mapping>
</glassfish-web-app>
В нашем случае наименования групп пользователей совпадают с наименованиями соответствующих им ролей.

Может случиться такое, что функциональности, предоставляемой стандартными realm'ами GlassFish, окажется недостаточно и возникнет идея создания своего собственного realm'а. Нет ничего проще! В базовом случае достаточно расширить классы
com.sun.appserv.security.AppservPasswordLoginModule
и
com.sun.appserv.security.AppservRealm
упаковать всё это добро в jar-архив и положить его в каталог glassfish3/glassfish/domains/<domain_name>/lib. Для того чтобы зарегистрировать на сервере созданный нами модуль логина, отредактируйте упомянутый ранее файл login.conf, добавив в него собственный сценарий аутентификации по аналогии с уже существующими:
customRealm {
    <login_module_class_name> required;
};
Единственное, что остаётся - на этапе создания ресурса realm'а связать его с нужным сценарием аутентификации, сославшись на него в свойстве jaas-context.

В следующей  заметке я планирую рассмотреть тот же процесс настройки аутентификации на сервере JBoss AS 7.

1 комментарий:

  1. Доброго времени суток. А можно пример БД для которой выполнена данная авторизация и пример как использовать права из этой БД в своих сервлетах?

    ОтветитьУдалить