Регистрация пользователей на сайте с помощью OpenLDAP и сервлетов

Ох уж эти самописные системы учета пользователей, разрабатываемые с нуля создателями веб-сервисов. Уязвимость, немасштабируемость, нестабильность — вот лишь основные их спутники. Другое дело — проверенные методы, такие как использование OpenLDAP. К этому серверу каталогов легко привязываются системы аутентификации распространенных веб-серверов, т.е. при внедрении такой системы приходится заниматься не столько программированием, сколько администрированием. Однако записи о новых пользователях в OpenLDAP как-то должны попадать и простенькую систему для автоматизации этого процесса все-таки создать придется. Но это займет в разы меньше времени и сил, чем написание системы регистрации «с нуля».

Для начала создадим шаблон ldif-файла, в который вместо реальных данных подставит некие поля (набраны заглавными буквами):

dn: o=ORG_ID,dc=example,dc=ru
objectclass: top
objectclass: organization
o: ORG_ID
description: ORG_DESCR

dn: ou=managers,o=ORG_ID,dc=example,dc=ru
objectclass: top
objectclass: organizationalUnit
ou: managers

dn: uid=MANAGER_ID,ou=managers,o=ORG_ID,dc=gps-finder,dc=ru
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn:COMMON_NAME
gn: Undefined
sn: Undefined
mail:MAIL
userPassword: PASSWD
uid: MANAGER_ID


Шаблон может быть сколь угодно сложным, главное хорошо владеть ldif-синтаксисом. В приведенном примере регистрируется не только пользователь, но и организация, к которой он принадлежит, а также подразделение менеджеров.

Теперь пишем и подключаем к веб-серверу сервлет, считывающий параметры http-запроса в переменные, затем считывающий в строку файл ldif-шаблона и выполняющий подстановки реальных данных вместо ключевых слов:



   String org     = req.getParameter("orgName");
   String cn      = req.getParameter("commonName");            
   String mail    = req.getParameter("mail");      
   String passwd  = req.getParameter("passwd");      
   String man     = req.getParameter("manager");      

   // проверка данных на целостность и корректность

    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    // считывание файла в байтовый поток, код не приводится

    String ldif = new String(baos.toByteArray());
    ldif = ldif
	    .replaceAll("ORG_ID",         org)
	    .replaceAll("MANAGER_ID",     man)
	    .replaceAll("COMMON_NAME",    cn)
	    .replaceAll("PASSWD",         passwd)
	    .replaceAll("MAIL",           mail);


Теперь сохраним получившуюся ldif-строку во временный файл и отправим пользователю письмо со ссылкой для активизации аккаунта:

File tmpf = File.createTempFile("example-site-", ".ldif");
    FileOutputStream fos = new FileOutputStream(tmpf);
    fos.write(ldif.getBytes("UTF8"));
    fos.flush();
    fos.close();

    // механизм отправки письма не приводится, о нем в другой раз


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

При переходе пользователя по ссылке происходит следующее.

File tmpf = new File("/tmp/sample-site-" + p + ".ldif");
    String[] sa = ("ldapadd -x -D cn=Admin,dc=example,dc=ru -w secret -f " + tmpf.getAbsolutePath()).split(" ");
    Runtime.getRuntime().exec(sa);
    res.setStatus(res.SC_MOVED_TEMPORARILY);
    res.setHeader("Location", "cabinet.cgi");


Здесь cabinet.cgi — адрес персонального кабинета пользователя, защищенный логином/паролем на уровне веб-сервера, т.е. при переходе по этому адресу аутентификация производится стандартными средствами сервера и браузера, изобретать ничего не надо. Естественно, что обмен данными должен вестись по протоколу https.
  • +12
  • 15 апреля 2011, 21:51
  • yababay

Комментарии (4)

RSS свернуть / развернуть
+
0
Moщно!
avatar

Markony

  • 16 апреля 2011, 10:08
+
0
Красивое решение! А есть ли какие-либо библиотеки для java для работы с LDAP сервером напрямую, не используя выполнение команды ldapadd?
avatar

Sergei_T

  • 16 апреля 2011, 13:25
+
0
А вот в этом-то и фокус-покус. Библиотека есть и надо про нее будет рассказать, но зачем к ней в данном случае прибегать, если прекрасно отрабатывает shell-команда? Ведь она вызывается раз в несколько часов и некритична в работе сервера.

Как видишь, камрад, я в последнее время научился ценить решения в стиле quick&dirty. Произошло это после того, как увидел одно объявление, где умение так работать выдвигалось в качестве требования к соискателю. И все-таки есть грань. Одно дело, когда quick&dirty работает новичок и плодит кучки неуправляемого кода, другое — когда в этом стиле работает человек опытный, который тратит несколько миллионов лишних тактов процессора, но экономит себе пару часов жизни (плюс знает при этом как нужно было бы сделать правильно). Это как черный в смысле инфракрксный и черный в смысле ультрафиолетовый.
avatar

yababay

  • 16 апреля 2011, 14:50
+
0
Это называется 20% времени мы делаем 80% работы, а 80% времени доделываем 20% оставшегося.

Что уж тут говорить, сам прибегаю к костыльным решениям, но со временем стараюсь заменить их на нормальные.
avatar

Sergei_T

  • 16 апреля 2011, 15:42

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.