Категорії
Misc, staff, other Security

Radius + LDAP

Виникло завдання зробити зовнішлю авторизацію через LDAP для сервіса, який її не підтримував, зате підтримував авторизацію через Radius. А у radius’a виявився модуль LDAP.

Тестовий стенд: Debian Linux 11.6 + Freeradius.

Нам знадобляться пакети freeradius-ldap, freeradius-utils (для локального тесту через утиліту radtest).

Файл clients.conf (описуються клієнти, які будуть підключатися, на кожного клієнта окрема секція)

client srv_auth {
        ipaddr = X.X.X.X
        secret = supersecretpass
}

Якщо ви невірно напишите secret на клієнті, то в логах (якщо ввімкнути debug паролів) паролі будуть ієрогліфами. Інакше – у відкритому виглядя. Це зовсім не означає, що паролі передаються у відкритому вигляді, вони шифруються цим secret’ом на клієнті і розшифровуються на сервері. Якщо secret не співпадає, то розшифрований пароль виглядає як ієрогліф.

Файл dictionary (типи авторизації, які будемо використовувати)

VALUE           Auth-Type               LDAP                    5

Робимо symlink: mods-available/ldap -> mod-enable/ldap і міняємо таке (бо там багато чого по замовчуванню):

ldap {
        server = 'ldaps://ldap.domain.com:636'
        port = 636
        identity = 'cn=radius,ou=services,dc=domain,dc=com'
        password = 'megapass'
        base_dn = 'dc=domain,dc=com'
        sasl {
        }
...
        user_dn = "LDAP-UserDn"
        user {
                base_dn = "${..base_dn}"
                filter = "(&(objectClass=gosaMailAccount)(uid=%{%{Stripped-User-Name}:-%{User-Name}})(!(sn=blocked_*)))"
                sasl {
                }
                scope = 'sub'
        }
        group {
                base_dn = "${..base_dn}"
                filter = '(objectclass=organizationalRole)'
                scope = 'sub'
                name_attribute = cn
                membership_filter = "(roleOccupant=uid=%{%{Stripped-User-Name}:-%{User-Name}},ou=people,dc=domain,dc=com)"
                membership_attribute = 'memberOf'
        }
...
        tls {
                require_cert    = 'never'
        }
...

Трохи поясню. Заблоковані користувачі у LDAP у мене додатково мають фільтр ‘sn=blocked_’, тому їх треба теж враховувати. Додатково, треба видавати доступи на основі груп, тобто, якщо користувач є у групі developer або vpn – дати доступ. Нагадаю, що належність користувача до груп у LDAP’і має 2 реалізації: користувачі описані в самій групі, або користувач має опис відвовідних груп. У мене перший варіант. Якщо у вас другий – то треба змінити membership_attribute. Умови належності до певних груп будуть далі. Тут лише те, що стосується користувача.

Файл users

DEFAULT         Auth-Type := LDAP
                Fall-Through = 1

DEFAULT LDAP-Group == "developer"

DEFAULT Auth-Type := Reject
  Reply-Message = "Sorry, you're not part of an authorized group."

Файл sites-enabled/default

authorize {
...
        ldap
        if ((ok || updated) && User-Password) {
            update {
                control:Auth-Type := ldap
            }
        }
...
}
...
authenticate {
...
        Auth-Type LDAP {
                ldap
        }
...
}
...
post-auth {
        if (LDAP-Group == "developer") {
            noop
        }
        elsif (LDAP-Group == "vpn") {
            noop
        }
        else {
            reject
        }
...

Ось тут влане і описуються всі 2 групи, які успішно авторизуються.

На цьому з конфігами все. Для тестування авторизації можна застосувати radtest з пакету freeradius-utils:

$ radtest -x testsuser MegaSuperveryPassword 127.0.0.1 2 testing123

Для debug режиму рекомендую вимкнути сервіс і запустити вручну:

# freeradius -X

Ось, як виглядає, коли користувач не в групі:

rlm_ldap (ldap): Released connection (1)
(0)     [ldap] = ok
(0)   } # Auth-Type LDAP = ok
(0) # Executing section post-auth from file /etc/freeradius/3.0/sites-enabled/default
(0)   post-auth {
(0)     if (LDAP-Group == "developer") {
(0)     Searching for user in group "developer"
rlm_ldap (ldap): Reserved connection (0)
(0)     Using user DN from request "uid=testsuser,ou=people,dc=domain,dc=com"
(0)     Checking for user in group objects
(0)       EXPAND (&(cn=developer)(objectclass=organizationalRole)(roleOccupant=uid=%{%{Stripped-User-Name}:-%{User-Name}},ou=people,dc=domain,dc=com))
(0)          --> (&(cn=developer)(objectclass=organizationalRole)(roleOccupant=uid=testsuser,ou=people,dc=domain,dc=com))
(0)       Performing search in "dc=domain,dc=com" with filter "(&(cn=developer)(objectclass=organizationalRole)(roleOccupant=uid=testsuser,ou=people,dc=domain,dc=com))", scope "sub"
(0)       Waiting for search result...
(0)       Search returned no results
(0)     Checking user object's memberOf attributes
(0)       Performing unfiltered search in "uid=testsuser,ou=people,dc=domain,dc=com", scope "base"
(0)       Waiting for search result...
(0)     No group membership attribute(s) found in user object  
rlm_ldap (ldap): Released connection (0)
(0)     User is not a member of "developer"
(0)     if (LDAP-Group == "developer")  -> FALSE
(0)     else {
(0)       [reject] = reject
(0)     } # else = reject
(0)   } # post-auth = reject

А ось так, коли є:

rlm_ldap (ldap): Released connection (0)
(0)     [ldap] = ok
(0)   } # Auth-Type LDAP = ok  
(0) # Executing section post-auth from file /etc/freeradius/3.0/sites-enabled/default
(0)   post-auth {
(0)     if (LDAP-Group == "developer") {
(0)     Searching for user in group "developer"
rlm_ldap (ldap): Reserved connection (1)
(0)     Using user DN from request "uid=testsuser,ou=people,dc=domain,dc=com"
(0)     Checking for user in group objects
(0)       EXPAND (&(cn=developer)(objectclass=organizationalRole)(roleOccupant=uid=%{%{Stripped-User-Name}:-%{User-Name}},ou=people,dc=domain,dc=com))
(0)          --> (&(cn=developer)(objectclass=organizationalRole)(roleOccupant=uid=testsuser,ou=people,dc=domain,dc=com))
(0)       Performing search in "dc=domain,dc=com" with filter "(&(cn=developer)(objectclass=organizationalRole)(roleOccupant=uid=testsuser,ou=people,dc=domain,dc=com))", scope "sub"
(0)       Waiting for search result...
(0)       Search returned no results
(0)     Checking user object's memberOf attributes
(0)       Performing unfiltered search in "uid=testsuser,ou=people,dc=domain,dc=com", scope "base"
(0)       Waiting for search result...
(0)     No group membership attribute(s) found in user object
rlm_ldap (ldap): Released connection (1)
(0)     User is not a member of "developer"
(0)     if (LDAP-Group == "developer")  -> FALSE
(0)     elsif (LDAP-Group == "vpn") {
(0)     Searching for user in group "vpn"
rlm_ldap (ldap): Reserved connection (0)
(0)     Using user DN from request "uid=testsuser,ou=people,dc=domain,dc=com"
(0)     Checking for user in group objects
(0)       EXPAND (&(cn=vpn)(objectclass=organizationalRole)(roleOccupant=uid=%{%{Stripped-User-Name}:-%{User-Name}},ou=people,dc=domain,dc=com))
(0)          --> (&(cn=vpn)(objectclass=organizationalRole)(roleOccupant=uid=testsuser,ou=people,dc=domain,dc=com))
(0)       Waiting for bind result...
(0)       Bind successful
(0)       Performing search in "dc=domain,dc=com" with filter "(&(cn=vpn)(objectclass=organizationalRole)(roleOccupant=uid=testsuser,ou=people,dc=domain,dc=com))", scope "sub"
(0)       Waiting for search result...
(0)     User found in group object "dc=domain,dc=com"
rlm_ldap (ldap): Released connection (0)
(0)     elsif (LDAP-Group == "vpn")  -> TRUE
(0)     elsif (LDAP-Group == "vpn")  {
(0)       [noop] = noop
(0)     } # elsif (LDAP-Group == "vpn")  = noop

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

Домашняя страничка Andy
Записки молодого админа
Самостоятельная подготовка к Cisco CCNA
Самостоятельная подготовка к Cisco CCNP
Powered by Muff