В первой части статьи было описано, каким образом развернуть и настроить систему для сборки CAS-сервера. В реализации по-умолчанию, CAS сервер допускает только тех пользователей, чьи логин и пароль совпадают. Во второй статье хотелось бы остановиться на вопросе создания собственного обработчика аутенфикации. В качестве примера показана привязка аутенфикационных данных учетной записи пользователя к записи в базе данных почтового сервера postfix.
CAS поддерживает достаточно большое количество различных схем аутенфикации, среди которых и LDAP, и OpenId, Radius, X.509. В моем случае, учетные записи пользователей хранились в базе данных почтового сервера корпоративной почты на базе postfix. Такой подход позволяет при создании почтового ящика, например для нового пользователя, автоматически предоставлять ему доступ к существующим сервисам. Postfix позволяет хранить информацию о пользователях в базе данных, в частности при помощи СУБД PostgreSQL.
Напомню, что центральным модулем, на которое будет направлено наше внимание, является cas-server-webapp. Именно в нем будут сосредоточены наши изменения.
Открываем в IDE данный модуль. Прежде всего необходимо определиться с зависимостями для cas-server-webapp. Так как в нашем случае аутенфикационные данные будут запрашиваться из базы данных, то нам потребуется указать зависимости от модуля cas-server-support-jdbc, какой-либо библиотеки, реализующей DataSource, и драйвера нашей СУБД. В моем случае я использовал commons-dbcp и postgresql.
В итоге в раздел dependencies файла pom.xml модуля cas-server-webapp были добавлены следующие строки:
org.jasig.cas cas-server-support-jdbc 3.4.2 postgresql postgresql 8.4-701.jdbc4 commons-dbcp commons-dbcp 1.4
Перейдем к определению обработчика аутенфикации. Основные настройки процесса аутенфикации находятся в файле cas-server-webapp/src/main/webapp/WEB-INF/deployerConfigContext.xml. Данный файл является файлом контекста фреймворка spring (cas-server-webapp реализован с использованием spring framework 3). Ключевым объектом в данном файле является authenticationManager, в рамках которого определен список обработчиков аутенфикации. Если обратить внимание, то мы увидим, что в качестве обработчика аутенфикации используется SimpleTextUsernamePasswordAuthenticationHandler (это тот, который пропускает пользователей с паролем совпадающим с логином). Вот его то и предстоит заменить на нужную реализацию.
Обобщение процесса обработки аутенфикационных данных представлено в виде интерфейса org.jasig.authentication.handler.AuthenticationHandler. Данный интерфейс лежит на самом верху глубокой иерархии абстрактных и конкретных классов, реализующих различные стратегии аутенфикации. Модуль cas-server-support-jdbc содержит набор готовых классов, поддерживающих аутенфикацию с использованием баз данных. В большинстве случаев подойдет org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler. Для настройки данного обработчика надо передать ссылку на DataSource базы данных и шаблон sql-запроса для получения пароля по имени пользователя.
Вот простой пример, настройки схемы аутенфикации с использованием данного класса. Первое - в файл deployerConfigContext.xml довляем bean описывающий DataSource:
Второй шаг - замена класса с SimpleTestUsernamePasswordAuthenticationHandler на QueryDatabaseAuthenticationHandler с указанием его параметров. Это выглядит следующим образом:
В том случае, если в вашей базе данных пароли пользователей хранятся в закрытом виде, то необходимо указать для QueryDatabaseAuthenticationHandler дополнительное свойство - ссылку на класс passwordEncoder (интерфейс PasswordEncoder), в котором определяется механизм закрытия пароля. К сожалению, логика класса QueryDatabaseAuthenticationHandler не подразумевает возможности использования паролей, закрытых при помощи алгоритма хеширования с маркером (salt). А в моем случае сервер postfix использовал именно такой метод закрытия паролей. Таким образом, без собственной реализации AuthenticationHanlder-а было не обойтись.
Создание собственного обработчика аутенфикации не представляет особой сложности. В моем случае в первую очередь необходимо было установить, какой алгоритм использовался для закрытия паролей. При помощи openssl удалось установить, что postfix использует стандартный юниксовый алгоритм crypt на базе md5. На koders.com в течении 2 минут можно найти реализацию данного алгоритма. Далее необходимо реализовать интерфейс AuthenticationHandler. К счастью, модуль cas-server-support-jdbc содержит абстрактный класс AbstractJdbcUsernamePasswordAuthenticationHandler. Все что нам необходимо сделать, это доопределить абстрактный метод authenticateUsernamePasswordInternal. Вот моя реализация:
package insane.code.monkeys.cas.adaptors;
import ...
public class PostfixDatabaseAuthenticationHnalder extends AbstractJdbcUsernamePasswordAuthenticationHandler {
private static final String POSTFIX_MAILBOX_QUERY = "select password from mailbox where username = ?";
protected boolean authenticateUsernamePasswordInternal(UsernamePasswordCredentials credentials) throws AuthenticationException {
final String username = getPrincipalNameTransformer().transform(credentials.getUsername());
final String password = credentials.getPassword();
try {
final String dbPassword = getJdbcTemplate().queryForObject(POSTFIX_MAILBOX_QUERY, String.class, username);
if ( dbPassword.length() != 34 ) return false;
String saltPart = dbPassword.substring(3,11);
String hashedPassword = MD5Crypt(password, saltPart);
return hashedPassword.equals(dbPassword);
} catch(IncorrectResultSizeDataAccessException e) {
// это означает, что пользователя в базе нет
return false;
}
}
}
Как мы можем видеть, абстрактный класс предоставляет все необходимое для комфортной работы, в частности jdbcTemplate от spring-framework.
Данный класс можно добавить непосредственно в директорию исходников модуля cas-server-webapp/src/main/java/.
Остается только убедиться в работоспособности нашего аутенфикационного обработчика, запустив jetty, открыв страницу аутенфикации и введя корректный логин и пароль. Не забудьте проверить на ложном наборе логина и пароля, дабы избежать сюрпризов в дальнейшем.
В случае возникновения ошибок в аутенфикации, всегда можно дополнить аутенфикационный обработчик трассировочными сообщениями.
Не составляет труда понять, что реализация других механизмов аутенфикации проходит по аналогичному сценарию. В модуле cas-server-webapp прописывается соответствующая зависимость cas-server-support-, и в файле deployerConfigContext.xml настраивается authenticationManager путем указания того или иного authenticationHandler (идут в поставке каждого модуля). Так же не должно составить труда реализовать при необходимости собственный модуль аутенфикации, например, получающий аутенфикационные данные из файла.
Комментариев нет:
Отправить комментарий