Прозрачная аутентификация в Redmine


JScript для взаимодействия с Redmine по средствам REST API в WSH среде операционной системы Windows. В первую очередь скрипт предназначен для использования в планировщике задач. С помощью скрипта можно организовать синхронизацию пользователей с Active Directory через LDAP и автоматическое изменение (закрытие) задач. Для взаимодействия с Redmine используется XML формат.


Сразу оговорюсь, что я простой админ локал-хоста и в таких энтерпрайзных вещах, как сервера директорий ничего не понимал до сегодняшнего дня, так что статья из разряда “чайникам от чайника” – что и как понял, то и рассказываю. Энтерпрайзных задач тоже не стояло – пока просто сделать централизованную авторизацию сервисов, без всяких там ACL и прочих заморочек.

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

Ну, по крайней мере, мне не удалось найти таких статей. В свете этого, я попробую пойти с обратной стороны – не буду много писать о том, что делать, а сконцентрируюсь на вопросах почему именно так делают.Процесс настройки я разбил на три этапа – запуск OpenLDAP в базовой конфигурации с парой тестовых пользователей, организация ауторизации с авторегистрацией пользователей redmine из LDAP и доступ на чтение/запись в SVN. Излагать буду в том же порядке.

2-х факторная аутентификация

Плагин реализует 2-х факторную аутентификацию в Redmine с отправкой кода через SMS. Правда нужен собственный SMS-шлюз, который будет отправлять SMS-сообщения.

Можно настраивать различные параметры для 2-х факторной аутентификации. Например, можно отключить аутентификацию на определенных доменах или IP-адресах. Это удобно, когда хочется получить дополнительную проверку только для пользователей, работающих снаружи.

Можно отключить 2-х факторную аутентификацию для пользователей из определенных групп безопасности Redmine, например, для админов.

Debugging active directory ldap authentication in redmine

What else does a geek do on Christmas eve? How about some ruby on rails debugging, especially when I don’t really know anything other than the basics of Ruby on Rails. 🙂

So here’s what I’ve done and what I’ve learned, for the great search engine in the sky and the next time I find myself in this pickle.

I’ve installed Redmine on a CentOS box, which worked out really well. I cribbed the install notes from http://blog.itsmine.co.uk/2009/01/22/howto-install-subversion-and-redmine-on-centos5-rhel5/, which is a fantastic walk-through to the process.

So first is getting authentication working with Redmine. It includes a nice LDAPS:// based built-in mechanism, but there’s little detail around configuring it. The best is the wiki page RedmineLDAP on the Redmine wiki. If you’re doing LDAP authentication, you probably want LDAPS – otherwise you’re shipping passwords in clear over the wire. The default port of LDAPS on Active Directory is 636.

The other key thing you need to know is that even though you configure an LDAP connection in the redmine application (under http://YourRedmineHost/auth_sources/list), when you test it – it’ll test positive even if it isn’t binding into Active Directory and returning a result. Why? Now that another story – and one I don’t have clearly nailed.

To start, I enabled debugging in Redmine by editing /var/www/rails/redmine/config/environments/production.rb and inserting the line:

config.log_level = :debug

(the default, if you’re curious, is config.log_level = :info)

Restarted the service and now I’m getting a lot more detail. Turns out the LDAP authentication pieces really only trigger useful logging if the search mechanism that looks for the ID is successful. I found the ruby code doing the lifting at redmine/app/models/auth_source_ldap.rb – and starting adding in additional debugging methods. What I found was that the system wasn’t throwing any exceptions, but the result of a call to ldap_con.search() wasn’t returning any values.

Похожее:  Личный кабинет Uber такси: для водителей и пассажиров

What I haven’t been able to solve is why that search wasn’t returning any values.

Since I’m not super conversant on hacking on ruby (yet – I think I’m about to learn the hard way), I switched to a different tactic to see what was happening: tcpdump.

The command line to watch the LDAP protocol stream in plain-text as it flows is:

tcpdump -l -s 1024 -A -vv port 389

(you’ll need to run that as root, and turn of LDAPS so you can actually see the darned protocol). Wireshark would be a hell of a lot easier, but I’m doing this on a remote RHEL server and didn’t have a GUI to wrap into the darn thing. What I saw from that was a string embedded in the protocol noise:

LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 525, vece.

Why this wasn’t propagating an exception or error in Rails is not clear to me (which is why I think I’m about to learn more rails hacking, the hard way). I’ve tweaked things around to get different exceptions, but what it all amounts to is that I’m not yet getting a good/successful bind on LDAP from which I can do searches.

I’ve managed to get LDAP authentication working from python (and Django) within my environment, so I’m familiar with the proper base DN and some of the attributes that are available for use from our Active Directory – but so far, no love in the ruby world.

When you’re configuring the LDAP, the code is written so that Redmine has to have an account and password that will bind with LDAPS properly and be able to return search results. If you’re doing this against active directory, make sure you include the domain in the account you’re binding (i.e. YOURDOMAINyouraccount). That made the difference in getting a successful bind to LDAP. Using the correct domain is what got me past the bind issue. The fact that it wasn’t successfully binding and not propogating an error seems like a bug – that’s been logged today as issue 4483

(by the way – the time when I want more screen real estate is when I have 5 terminal consoles and two different web browsers open debugging something like the redmine application)

More later… still debugging, but now I’m diving into using ruby script/console to interactively figure out this LDAP code in ruby.

UPDATE: So the final solution was all about having the right configuration entries in the fields to make it work. I ended up using ruby script/console to manually drive values until I had a success, and then the results were really clear as to what I needed to use.

For anyone else coming along and trying to same thing, here’s what worked for me (minus my password…) to learn what attributes were being passed back from LDAP:

ruby script/console
require 'net/ldap'
options = { :host => 'my.adhost.com', :port => 389, :encryption => nil, :method => :simple, :username => 'DOMAINjheck', :password => 'mypassword' }
ldap_conn = Net::LDAP.new options
ldap_conn.open { }
filter = Net::LDAP::Filter.eq('sAMAccountName','jheck')
ldap_conn.search(:base => 'DC=MYDOMAIN1,DC=MYDOMAIN2', :filter => filter)

A related update/patch submitted to Redmine a few months ago is issue 4283 which solves a quandry I have about needing a separate account to authenticate through LDAP. I’ll be trying out that patch next monday.

Deploy & test¶

Save your new class in app/model/ and restart Redmine.

Похожее:  Работа в Самаре - свежие вакансии Самары на 63 работа ру

Dynamic bind account

The above setup would need a special account on the directory server which Easy Redmine uses to pre-authenticate. It is possible to use the keyword $login in the account field which then would be replaced by the current login. The password can be left empty in this case, for example:

Account: company$login

Implement your authsource subclass¶

Create a new file for your


subclass in


, following the naming scheme of the existing




  • Here we’ll use app/models/auth_source_my_custom_app.rb

Implement the class such that a call to its authenticate() method will contact the other database and use the table there to check the provided login credentials. The values in your auth_sources table record above are available via instances variables (e.g. self.host, self.base_dn, self.attr_firstname).

Here’s our commented class:

Implementing an alternative authentication source¶

This article assumes the alternative authentication involves querying a table (or tables) in some other database. However, the approach can be generalized to authenticate against pretty much anything else (some secret file, some network service, whatever fun scenario you have); you may want to examine the Redmine code in app/models/auth_source_ldap.rb for a non-database alternative authentication example.

Insert a sensible auth_sources record¶

First, we should decide what our auth_sources record will look like. Redmine core and our AuthSource subclass code will make use of that info, so it’s good to figure this out up front.

For reference, here is the (Redmine 2.4.1) auth_sources table:

 ------------------- -------------- ------ ----- --------- ---------------- 
| Field             | Type         | Null | Key | Default | Extra          |
 ------------------- -------------- ------ ----- --------- ---------------- 
| id                | int(11)      | NO   | PRI | NULL    | auto_increment |
| type              | varchar(30)  | NO   |     |         |                |
| name              | varchar(60)  | NO   |     |         |                |
| host              | varchar(60)  | YES  |     | NULL    |                |
| port              | int(11)      | YES  |     | NULL    |                |
| account           | varchar(255) | YES  |     | NULL    |                |
| account_password  | varchar(255) | YES  |     |         |                |
| base_dn           | varchar(255) | YES  |     | NULL    |                |
| attr_login        | varchar(30)  | YES  |     | NULL    |                |
| attr_firstname    | varchar(30)  | YES  |     | NULL    |                |
| attr_lastname     | varchar(30)  | YES  |     | NULL    |                |
| attr_mail         | varchar(30)  | YES  |     | NULL    |                |
| onthefly_register | tinyint(1)   | NO   |     | 0       |                |
| tls               | tinyint(1)   | NO   |     | 0       |                |
| filter            | varchar(255) | YES  |     | NULL    |                |
| timeout           | int(11)      | YES  |     | NULL    |                |
 ------------------- -------------- ------ ----- --------- ---------------- 

This schema has been relatively stable, although older Redmine versions may be missing the last 2 columns (e.g. Redmine 0.9 doesn’t have them).

How our


subclass code will make use of these fields is more-or-less up to us, but there are two key constraints from Redmine:

    type must be the name of your AuthSource subclass

    • Redmine will use this field to instantiate your class and call its authenticate() method when attempting to authenticate a login attempt using your custom source.
    • This class name should begin with AuthSource.
    • We’ll put “AuthSourceMyCustomApp

    onthefly_register has a 1 or 0

Here’s how we’ll use these fields (substitute your own values):

Note: The attr_* fields are not always needed. They are used by the LDAP authentication source to map LDAP attributes to Redmine attributes. I recommend using them, however, since they make the authentication() code more widely applicable (fewer changes necessary for you to use the code in your specific situation).

So we insert the record into our Redmine’s (v2.4.1) auth_sources table with SQL like the following:


We’ve customized the code to integrate Redmine with Joomla. Please, check the attachment to review an implementation for Joomla 2.5 and Redmine 2.0.3.


LDAP (Lightweight Directory Access Protocol) is a software protocol for enabling anyone to locate organizations, individuals, and other resources such as files and devices in a network, whether on the public Internet or on a corporate intranet. LDAP is a “lightweight” (smaller amount of code)

version of Directory Access Protocol (DAP), which is part of X.500, a standard for directory services in a network. LDAP is lighter because in its initial version it did not include security features. Easy Redmine natively supports LDAP authentication using one or multiple LDAP directories.

An LDAP directory is organized in a simple “tree” hierarchy consisting of the following levels:

  1. The root directory (the starting place or the source of the tree), which branches out to
  2. Countries, each of which branches out to
  3. Organizations, which branch out to
  4. Organizational units (divisions, departments, and so forth), which branches out to (includes an entry for)
  5. Individuals (which includes people, files, and shared resources such as printers)


Ну тут всё просто. Инструкция по настройке есть в

, единственное, что она заточена под виндовую схему авторизации. Как дружить с более привычной схемой можно посмотреть в

. Ниже приведу скрин своей конфигурации.

Конфигурация LDAP в redmine

В ЛДАПе редмайн проводит авторизацию, но пользователь всё равно должен храниться в базе редмайна. Для того, что бы не заботиться о создании пользователей, предусмотрена галка авторегистрации (а что бы не заботиться об удалении есть плугин

Redmine support for alternative authentication¶

Redmine has specific support for alternative/custom authentication which makes implementing it very easy.

    • You will add a record here specific to your custom authentication.
    • You will create your own subclass of this, and implement the authenticate() method.

Redmine’s authentication process is along these lines (LDAP & OpenID assumed to be disabled):

Screen saver внутри окна браузера

Это такое своеобразное костыльное решение для тех, у кого нет нормальной блокировки пользователя по бездействию в операционной системе. Можно выставить интервал, после которого, в случаи бездействия пользователя в окне браузера, вместо интерфейса Redmine появляется заставка из матрицы.

Дополнительно можно включить автоматический выход из системы по таймауту.

Надеюсь, моя статья и наш плагин будут полезны вам. Если у вас есть какие-то вопросы по использованию Redmine, то пишите в комментариях. Постараюсь ответить.

Slow ldap authentification

If LDAP authentification is slow and you have an AD cluster, try to specify in Host field one of the AD physical servers. It may help.


В командной строке Windows введите следующую команду:

Прозрачная аутентификация

Во-первых, в самом Redmine есть прекрасная возможность авторизации через LDAP (Active Directory является надстройкой над LDAP). Заполнив небольшое количество полей, можно быстро получить возможность аутентифицировать пользователей в домене, и даже, создавать их налету. Эта функция избавляет администратора от необходимости заводить каждого нового пользователя.

Но проблема в том, что у среднестатистического пользователя, впервые пришедшего в компанию, моментально возникает вопрос «Какой пароль вводить?». Этот вопрос, как правило, оттягивает влияние специалистов. Поэтому, мы написали небольшой плагин (надстройку над родным механизмом аутентификации Redmine) – SSO (Single sign-on) .


В параметрах и значениях, которые поддерживают шаблонизацию, можно указывать шаблоны. Шаблон из себя представляет строку которая может содержать (а может и не содержать) один или несколько разделителей |.

Разделитель делит строку на фрагменты. В фрагменте текста может содержаться (а может и не содержаться) один или несколько указателей на значение. Указатель на значение {object.key.id>filter} представляет из себя последовательность ключей по которым нужно пройти в объекте чтобы получить значение.

Если значение отсутствует, то фрагмент удаляется (для удаления фрагмента значение должно именно отсутствовать, а не быть пустым). В качестве объекта используется сущность с которой работает задача.

В указателях на значения можно указывать последовательность фильров для изменения значений. Поддерживаються следующие фильтры:

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 4,00 из 5)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *