FreeRadius Notes: различия между версиями
Sirmax (обсуждение | вклад) |
Sirmax (обсуждение | вклад) |
||
| (не показано 58 промежуточных версий этого же участника) | |||
| Строка 229: | Строка 229: | ||
<PRE> |
<PRE> |
||
Sat Jul 15 12:49:59 2023 : Debug: (0) [files] = ok |
Sat Jul 15 12:49:59 2023 : Debug: (0) [files] = ok |
||
| + | </PRE> |
||
| + | |||
| + | |||
| + | =How the <code>users</code> file works= |
||
| + | |||
| + | Существуют три списка атрибутов (точнее пар атрибут - значение ) |
||
| + | <BR> |
||
| + | Они привязаны к конкретному запросу/ответу к серверу, и не доступны из других запросов/ответов |
||
| + | |||
| + | * <code>request</code> - содержит список атрибут-значение которые получены в запросе от NAS |
||
| + | * <code>control</code> - изначально это пустой список, который определяет как и какие модули будут обрабатывать запрос. Этот список заполняется содулями (например files или python) или с помощью <code>ulang</code> |
||
| + | * <code>reply</code> - содержит список атрибутов которые будут отправлены назад на NAS |
||
| + | |||
| + | Модуль <code>users file</code> определяет какие пары проверять а какие пары добавлять в зависимости их расположения в конфигурационном файле а так же в зависимости от операторов. |
||
| + | <BR> |
||
| + | Пример: |
||
| + | <PRE> |
||
| + | bob Cleartext-Password := "hello" |
||
| + | Reply-Message := "Hello, %{User-Name}" |
||
| + | |||
| + | </PRE> |
||
| + | Первая строка содержит пары атрибут-значение для проверки и пары которые будут добавлены в список <code>control</code>, <BR> |
||
| + | добавление в список <code>control</code> происходит при полном совпадении всех проверок. |
||
| + | <BR> |
||
| + | Пары (в первой строке!) которые проверяются которые добавляются в список <code> control</code> можно отличить по используемым операторам |
||
| + | |||
| + | * Если используются операторы присвоения <code>:=</code> or <code>=</code> то пара атрибут-значение обрабатывается как <code>control</code> (добавляется в список) |
||
| + | * Если используются операторы сравнения <code>></code>, <code><</code>, <code>==</code>, <code>>=</code>, <code><=</code>, <code>=~</code> то пара атрибут-значение используются для проверки соответвия |
||
| + | |||
| + | В примере выше используется только одна пара <code>Cleartext-Password := "hello"</code> где используется присвоение, те для этого пользователя будет только добавлена пара в список control (а проверка будет выполнена на другой стадии и другим модулем) |
||
| + | <BR> |
||
| + | Все пары кроме первой строки содержат только пары которые будут добавлены в ответ. |
||
| + | ==Описание операторов== |
||
| + | {| class="wikitable" |
||
| + | |+ Файлы |
||
| + | |- |
||
| + | ! Operator !! Пример !!Использование в <code>check</code> <BR> (users и тому подобное), или в условиях unlang !! Использование в <code>reply</code><BR>(users и тому подобное), или в блоках unlang update |
||
| + | |- |
||
| + | | <code>=</code> |
||
| + | || |
||
| + | <code>Attribute = Value</code> |
||
| + | || |
||
| + | * Используется для установки атрибутов конфигурации сервера |
||
| + | * Не допускается для операторов проверки атрибутов (например проверки пароля) |
||
| + | || |
||
| + | * Используется для добавления пары атрибут-значение, только если такой атрибут не был добавлен раньше (если был то значение изменено не будет) |
||
| + | |- |
||
| + | | <code> :=</code> |
||
| + | || |
||
| + | <PRE> |
||
| + | lameuser Auth-Type := Reject |
||
| + | Reply-Message = "Your account has been disabled." |
||
| + | </PRE> |
||
| + | <PRE> |
||
| + | steve Cleartext-Password := "testing" |
||
| + | Service-Type = Framed-User |
||
| + | </PRE> |
||
| + | || |
||
| + | Всегда совпадает при проверках, и добавляет в <code>control</code> атрибут-значение, если такой атрибут уже был, то замещает значение. (по сути оператор присвоения) |
||
| + | В первом примере пользователь всегда получит <BR> <code>Auth-Type := Reject </code>, если ниже нет другого условия (например для группы), которое переопределит <code>Auth-Type</code> |
||
| + | <BR> |
||
| + | Второй пример показывает как правильно установить пользователю пароль. Эта конструкция может показаться странной, так как присвоение пароля <code>:=</code> а не сравнение. |
||
| + | <BR>Тут важно понимать следующее |
||
| + | * Эта запись будет работать если в запросе есть атрибут <code>User-Name</code> со значением "steve" |
||
| + | * В <code>control</code> словарь будет помещен атрибут <code>Cleartext-Password</code> со значением "testing" |
||
| + | * В <code>reply</code> словарь будет помещен атрибут <code>Service-Type</code> со значением "Framed-User" |
||
| + | * При этом проверка пароля будет происходить в зависимости от того что опеределено в настройке сервера |
||
| + | |||
| + | <PRE> |
||
| + | server { |
||
| + | |||
| + | authorize { |
||
| + | files |
||
| + | pap |
||
| + | } |
||
| + | authenticate { |
||
| + | Auth-Type PAP { |
||
| + | pap |
||
| + | } |
||
| + | } |
||
| + | </PRE> |
||
| + | * В примере в секции <code> authorize</code> выше модуль <code>files</code> добавит атрибут <code>Cleartext-Password</code>, модуль <code>pap</code> добавит атрибут <code>Auth-Type</code> со значением "PAP" |
||
| + | * И только в секции <code> authenticate </code> будет происходить проверка пароля |
||
| + | || |
||
| + | Для атрибутов в ответе (<code>reply</code>) работает так же, как оператор присвоения (добавляет атрибут-значение если его не было, переопределяет значение если атрибут уже был) |
||
| + | <PRE> |
||
| + | automate Cleartext-Password := "pppassss" |
||
| + | User-Service-Type := 6 |
||
| + | </PRE> |
||
| + | |- |
||
| + | | <code> ==</code> |
||
| + | || <PRE> |
||
| + | swilson Service-Type == Framed-User, Huntgroup-Name == "alphen" |
||
| + | Framed-IP-Address = 192.0.2.65, |
||
| + | Fall-Through = Yes |
||
| + | </PRE> |
||
| + | || |
||
| + | Операция сравнения для <code>check</code> атрибутов, успешна если совпадает атрибут присутствует и его значение совпадает с указанным.<BR> |
||
| + | В примере при совпадении <code>User-Name</code> со значением "swilson" и если в запросе |
||
| + | присутвуют атрибут <code>Service-Type</code> со значением "Framed-User" и <code>Huntgroup-Name</code> со значением "alphen" |
||
| + | <BR> |
||
| + | Сам атрибут <code>Huntgroup-Name</code> должен быть установлен дополнительно в модуле <code>preprocess</code> |
||
| + | <PRE> |
||
| + | authorize { |
||
| + | preprocess |
||
| + | ... |
||
| + | } |
||
| + | </PRE> |
||
| + | || |
||
| + | Не применимо |
||
| + | |- |
||
| + | | <code> +=</code> |
||
| + | || <code>Attribute += Value</code> |
||
| + | <PRE> |
||
| + | Cisco-Account-Info += "APOLICY_MAP_SERVICE_ON_SESSION_START_", |
||
| + | Cisco-Account-Info += "NPOLICY_MAP_SERVICE_ON_SESSION_START_" |
||
| + | </PRE> |
||
| + | || При проверке атрибутов - всегда дает совпадение и добавляет атрибут-значение к словарю конфигурационных атрибутов |
||
| + | || При формировании ответа добавляет атрибуты к ответу (не переписывая существующие) |
||
| + | |- |
||
| + | | <code> !=</code> |
||
| + | || Текст ячейки |
||
| + | || Дает совпадение, если атрибут присутствует в запросе и его значение не равно указанному (соответственно если атрибута нет то совпадение невозможно) |
||
| + | || Не применимо |
||
| + | |- |
||
| + | | <code> > </code> |
||
| + | || Текст ячейки |
||
| + | || Дает совпадение, если атрибут присутствует в запросе и его значение больше указанного |
||
| + | || Не применимо |
||
| + | |- |
||
| + | | <code> >= </code> |
||
| + | || Текст ячейки |
||
| + | || Дает совпадение, если атрибут присутствует в запросе и его значение больше или равно указанному |
||
| + | || Не применимо |
||
| + | |- |
||
| + | | |
||
| + | <code> < </code> |
||
| + | || Текст ячейки |
||
| + | || Дает совпадение, если атрибут присутствует в запросе и его значение меньше указанного |
||
| + | || Не применимо |
||
| + | |- |
||
| + | | <code> <= </code> |
||
| + | || Текст ячейки |
||
| + | || Дает совпадение, если атрибут присутствует в запросе и его значение меньше или равно указанному |
||
| + | || Не применимо |
||
| + | |- |
||
| + | | <code> =~ </code> |
||
| + | || Текст ячейки |
||
| + | || Дает совпадение, если атрибут присутствует в запросе и его значение совпадает с регулярным выражением, применим только для строк |
||
| + | || Не применимо |
||
| + | |- |
||
| + | | <code> !~ </code> |
||
| + | || Текст ячейки |
||
| + | || Дает совпадение, если атрибут присутствует в запросе и его значение НЕ совпадает с регулярным выражением, применим только для строк |
||
| + | || Не применимо |
||
| + | |- |
||
| + | | <code> =*</code> |
||
| + | || Текст ячейки |
||
| + | || Дает совпадение, если атрибут присутствует в запросе и его (значение не проверяется) |
||
| + | || Не применимо |
||
| + | |- |
||
| + | | <code> !*</code> |
||
| + | || Текст ячейки |
||
| + | || Дает совпадение, если атрибут НЕ присутствует в запросе и его (значение не проверяется по причине отсутвия) |
||
| + | || Не применимо |
||
| + | |} |
||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==<code>Cleartext-Password</code>== |
||
| + | |||
| + | <code>Cleartext-Password</code> это исключительно <code>control</code> пара атрибут-гачение и эта пара не должна присутвовать ни в каком другом списке |
||
| + | <BR> |
||
| + | <code>Cleartext-Password</code> это один из списка атрибутов известных как <B>'known good' password</B> <BR> который содержит пользовательский пароль в открытом виде. |
||
| + | <BR> |
||
| + | Другой пример из этого набора "хорошо известных" <code>SSHA-Password</code> - который содержит salted SHA hash от пользовательского пароля. |
||
| + | <BR> |
||
| + | Проверка пользовательского пароля происходит cопоставлением атрибута из списка the <B>'known good' password</B> атрибутов <BR> |
||
| + | которые содержаться в списке <code>control</code> модулями которые могут <code>authenticate</code> пользователя - это может быть модуль <code>rlm_pap</code> |
||
| + | <BR> |
||
| + | или другой - например самописный на python |
||
| + | <PRE> |
||
| + | authenticate { |
||
| + | Auth-Type ISG { |
||
| + | python3_isg |
||
| + | } |
||
| + | } |
||
| + | </PRE> |
||
| + | |||
| + | По сути, модуль <code>rlm_pap</code> сравнивает значение <code>User-Password</code> которое вставил другой модуль - <code>files</code> как в этом примере или <code>sql</code> или еще какой-то |
||
| + | |||
| + | ==<code>User-Password</code>== |
||
| + | |||
| + | <code>User-Password</code> это атрибут который должен содержаться только в запросе и более нигде |
||
| + | <BR> |
||
| + | <code>User-Password</code> этот атрибут который пользователь передал на NAS в том видже в котором он был передан <BR> |
||
| + | |||
| + | Что бы <code>authenticate</code> пользователя модуль сравнивает значение атрибута <code>User-Password</code> со значением (например) <code>Cleartext-Password</code> из списка атрибутов <code>control</code>. |
||
| + | <BR> |
||
| + | В файле <code>users</code> соответвенно нужно указать: |
||
| + | <PRE> |
||
| + | my_username Cleartext-Password := "known_good_password" |
||
| + | </PRE> |
||
| + | |||
| + | Эта запись означает что при совпадении атрибута <code>User-Name</code> со значением слева (my_username), нужно в словарь <code>contro</code> добавить атрибут <code>Cleartext-Password</code> со значением "known_good_password". |
||
| + | <BR> |
||
| + | Соответвенно ответ на вопрос "почему писать так не правильно": |
||
| + | <PRE> |
||
| + | shad Cleartext-Password == "test" |
||
| + | </PRE> |
||
| + | <BR> |
||
| + | такой: |
||
| + | Эта конструкция работает не так как ожидается (не работает авторизация) по-тому что она говорит что при совпадении <code>User-Name</code> в списке атрибутов запроса (которые прислал NAS)следует найти атрибут |
||
| + | <code>Cleartext-Password</code> и сравнить его значение со значением "test". |
||
| + | Так как никакой NAS не присылает такой запрос (атрибут <code>Cleartext-Password</code> отсутствует) то поведение отличается от ожидаемого. |
||
| + | <BR> |
||
| + | Можно было бы предположить, что если указать <code>User-Password == "test"</code> то конструкция заработает<BR> |
||
| + | К сожалению, это не так. |
||
| + | <BR> |
||
| + | Действительно, пользователей будет соответствовать и пароль на этой стадии пройдет проверку, но далее все равно пользователь (за исключением специальных конфигураций) получит <code>Reject</code> |
||
| + | <BR> |
||
| + | <BR> |
||
| + | Ниже подробности как и почему это происходит. |
||
| + | |||
| + | ==<code>Auth-Type</code>== |
||
| + | |||
| + | <code>Auth-Type</code> это атрибут который может помещаться только в список атрибутов <code>control</code>, <BR> |
||
| + | и никогда не помещаться ни в какие другие списки. |
||
| + | <BR> |
||
| + | |||
| + | На сервере есть три основных раздела для обработки запросов |
||
| + | * authorize |
||
| + | * authenticate |
||
| + | * post-auth |
||
| + | и этот список атрибутов <code>control</code> используется для передачи атрибутов между разными разделами. |
||
| + | |||
| + | ==<code>authorize</code>== |
||
| + | Секция <code>authorize</code> предназначена для сборки информации о пользователе. |
||
| + | Например в этой секции: |
||
| + | * Может происходить запрос к базе данных для проверки существования пользователя и получения его пароля. |
||
| + | * В этой секции определяется значение атрибута <code>Auth-Type</code> на основании которого будет производиться дальнейшая обработка запроса в секции <code>authentication</code> |
||
| + | |||
| + | ==<code>authenticate</code>== |
||
| + | <code>Authenticate</code> это секция где происходит вызов модуля <code>authentication</code>. |
||
| + | <BR> |
||
| + | Какой именно модуль будет использоваться определяется значением атрибута <code>Auth-Type</code> |
||
| + | <BR> |
||
| + | Например |
||
| + | <PRE> |
||
| + | authenticate { |
||
| + | Auth-Type ISG { |
||
| + | python3_isg |
||
| + | } |
||
| + | } |
||
| + | </PRE> |
||
| + | При этом значение <code>Auth-Type</code>=<code>ISG</code> выставляет модуль в секции <code> authorize</code> |
||
| + | <PRE> |
||
| + | authorize { |
||
| + | preprocess |
||
| + | python3_isg |
||
| + | } |
||
| + | </PRE> |
||
| + | Пример кода из <code>rlm_python</code> |
||
| + | <PRE> |
||
| + | ... |
||
| + | config = ( ('Auth-Type', 'ISG') ) |
||
| + | ... |
||
| + | </PRE> |
||
| + | |||
| + | ==<code>Post-Auth</code>== |
||
| + | <code>Post-Auth</code> используется в основном для логгирования и примерения других политик (а может и вообще не использоваться), список модулей запускаемых в этой секции определяются результатами работы модулей в секции <code>authenticate</code> |
||
| + | |||
| + | ==По шагам== |
||
| + | * Модули в секции <code>authorize</code> проверяют запрос |
||
| + | * Если запрос удовлетворяет условиям (модуль "думает" что знает как работать с запросом на стадии <code> authenticate</code>) и атрибут <code>Auth-Type</code> еще не установлен то модуль выставляет атрибут <code>Auth-Type </code> (значение атрибута зависит от модуля) |
||
| + | * В случае модуля <code>rlm_pap</code> модуль выставляет атрибут <code>Auth-Type</code> в значение <code>PAP</code> если находит в запросе атрибут <code>User-Password</code> |
||
| + | * Если ни один из модулей не выставил атрибут <code>Auth-Type</code> то запрос будет отброшен (Rejected) |
||
| + | |||
| + | <BR> |
||
| + | Теперь можно вернуться к вопросу что не так с конструкцией <code> User-Password == "test" </code> |
||
| + | * Модуль <code>rlm_pap</code> в секции <code> authorize</code> выставит code>Auth-Type</code> в значение <code>PAP</code> так как в запросе присутствует <code> User-Password</code> |
||
| + | * Модуль <code>rlm_pap</code> в секции <code> authenticate</code> попробует сравнить найти в списке атрибутов |
||
| + | <code>config</code> один из "известных хороших" атрибутов с паролем, например <code>Cleartext-Password</code> |
||
| + | или любой другой, и не найдя их вернет статус <code>Reject</code> |
||
| + | |||
| + | <BR> |
||
| + | Если такое поведение не желательно, то его можно обойти с помощью "волшебного" значения <code>Auth-Type</code>, <code>Accept</code>, |
||
| + | которое позволяет пропустить секцию <code>authenticate</code> |
||
| + | |||
| + | Если нужно реализовать такое поведение и не вызывать модуль <code>rlm_pap</code>: |
||
| + | <PRE> |
||
| + | shad Auth-Type := Accept, User-Password == "test" |
||
</PRE> |
</PRE> |
||
Текущая версия на 20:16, 20 марта 2024
Это просто сборник ссылок и заметок
- https://shop.nag.ru/article/ericsson-smartedge-freeradius-billing
- https://code.google.com/archive/p/cakebilling/wikis/ConfiguringFreeRadius.wiki
Минимальный рабочий конфиг
Тут чертовски важен порядок модулей - если переставить местами pap/files то получится что pap не сможет получить пароль
sites-enabled/default
server default {
listen {
type = auth
ipv4addr = *
port = 1812
limit {
max_connections = 16
lifetime = 0
idle_timeout = 30
}
}
listen {
ipv4addr = *
port = 1813
type = acct
}
instantiate {
exec
expr
expiration
}
authorize {
files
pap
}
authenticate {
Auth-Type PAP {
pap
}
}
} # end of SERVER
Клиенты clients.conf
client localhost {
ipaddr = 127.0.0.1
proto = *
secret = secret
require_message_authenticator = no
limit {
max_connections = 16
lifetime = 0
idle_timeout = 30
}
}
Модуль PAP mods-enabled/pap
pap {
# normalise = yes
auto_header = no
}
Модуль files
mods-enabled/files
files {
moddir = ${modconfdir}/${.:instance}
#key = "%{%{Stripped-User-Name}:-%{User-Name}}"
filename = ${moddir}/authorize
usersfile = ${moddir}/authorize
# acctusersfile = ${moddir}/accounting
}
mods-config/files/authorize
bob Cleartext-Password := "hello"
Reply-Message := "Hello, %{User-Name}"
Проверка работы минимальной конфигурации
- Для проверки использую команду
radtest bob hello localhost 0 secretbob- имя пользователя, атрибутUser-Namehello- пароль, который будет передан в атрибутеUser-Passwordlocalhost- адрес куда отправить запрос0- номер (виртуального) порта,NAS-Portsecret- radius shared secret, который указан в настройках сервера и клиента
По сути тут логика такая
- "Пришел" пользователь
User-Name = "bob"User-Password = "hello" - Его проверили по файлу (модуль
filesищет пользователя в файле, имя файла определено конфигурацией модуля) и находит, о чем говорит записьfiles: users: Matched entry bob at line 4 - Далее для модулей вызываных ниже по конфигу будут доступны атрибуты которые добавил модуль
filesа именно:
bob Cleartext-Password := "hello"
Reply-Message := "Hello, %{User-Name}"
- При этом модуль
filesпо сути не делает проверок - он только сопоставляет запрос, и по ключу который определен в конфигурации (key = "%{%{Stripped-User-Name}:-%{User-Name}}") находит (или не находит) атрибуты.
Запись в логах вида:
[files] = ok
Означает что такой пользователь существует, НО не означает что он успешно авторизован.
- Далее модуль PAP осуществляет проверку пароля. Важно то, что пароль в описании пользователя должен содержаться в атрибутах "known good", в нашем случае -
Cleartext-Password
- Собственно на этом все.
Fri Jul 14 18:07:17 2023 : Debug: (0) Received Access-Request Id 51 from 127.0.0.1:54599 to 127.0.0.1:1812 length 73
Fri Jul 14 18:07:17 2023 : Debug: (0) User-Name = "bob"
Fri Jul 14 18:07:17 2023 : Debug: (0) User-Password = "hello"
Fri Jul 14 18:07:17 2023 : Debug: (0) NAS-IP-Address = 10.90.1.213
Fri Jul 14 18:07:17 2023 : Debug: (0) NAS-Port = 0
Fri Jul 14 18:07:17 2023 : Debug: (0) Message-Authenticator = 0xa051e8612e62faaa98baa723ceb98219
Fri Jul 14 18:07:17 2023 : Debug: (0) session-state: No State attribute
Fri Jul 14 18:07:17 2023 : Debug: (0) # Executing section authorize from file /etc/freeradius/3.0/sites-enabled/default
Fri Jul 14 18:07:17 2023 : Debug: (0) authorize {
Fri Jul 14 18:07:17 2023 : Debug: (0) modsingle[authorize]: calling files (rlm_files)
Fri Jul 14 18:07:17 2023 : Debug: (0) files: users: Matched entry bob at line 4
Fri Jul 14 18:07:17 2023 : Debug: (0) files: ::: FROM 1 TO 0 MAX 1
Fri Jul 14 18:07:17 2023 : Debug: (0) files: ::: Examining Reply-Message
Fri Jul 14 18:07:17 2023 : Debug: Hello, %{User-Name}
Fri Jul 14 18:07:17 2023 : Debug: Parsed xlat tree:
Fri Jul 14 18:07:17 2023 : Debug: literal --> Hello,
Fri Jul 14 18:07:17 2023 : Debug: attribute --> User-Name
Fri Jul 14 18:07:17 2023 : Debug: (0) files: EXPAND Hello, %{User-Name}
Fri Jul 14 18:07:17 2023 : Debug: (0) files: --> Hello, bob
Fri Jul 14 18:07:17 2023 : Debug: (0) files: ::: APPENDING Reply-Message FROM 0 TO 0
Fri Jul 14 18:07:17 2023 : Debug: (0) files: ::: TO in 0 out 0
Fri Jul 14 18:07:17 2023 : Debug: (0) modsingle[authorize]: returned from files (rlm_files)
Fri Jul 14 18:07:17 2023 : Debug: (0) [files] = ok
Fri Jul 14 18:07:17 2023 : Debug: (0) modsingle[authorize]: calling pap (rlm_pap)
Fri Jul 14 18:07:17 2023 : Debug: (0) modsingle[authorize]: returned from pap (rlm_pap)
Fri Jul 14 18:07:17 2023 : Debug: (0) [pap] = updated
Fri Jul 14 18:07:17 2023 : Debug: (0) } # authorize = updated
Fri Jul 14 18:07:17 2023 : Debug: (0) Found Auth-Type = PAP
Fri Jul 14 18:07:17 2023 : Debug: (0) # Executing group from file /etc/freeradius/3.0/sites-enabled/default
Fri Jul 14 18:07:17 2023 : Debug: (0) Auth-Type PAP {
Fri Jul 14 18:07:17 2023 : Debug: (0) modsingle[authenticate]: calling pap (rlm_pap)
Fri Jul 14 18:07:17 2023 : Debug: (0) pap: Login attempt with password "hello" (5)
Fri Jul 14 18:07:17 2023 : Debug: (0) pap: Comparing with "known good" Cleartext-Password "hello" (5)
Fri Jul 14 18:07:17 2023 : Debug: (0) pap: User authenticated successfully
Fri Jul 14 18:07:17 2023 : Debug: (0) modsingle[authenticate]: returned from pap (rlm_pap)
Fri Jul 14 18:07:17 2023 : Debug: (0) [pap] = ok
Fri Jul 14 18:07:17 2023 : Debug: (0) } # Auth-Type PAP = ok
Fri Jul 14 18:07:17 2023 : ERROR: (0) Cannot proxy packets unless 'proxy_requests = yes'
Fri Jul 14 18:07:17 2023 : Debug: (0) Empty post-auth section in virtual server "default". Using default return values.
Fri Jul 14 18:07:17 2023 : Auth: (0) Login OK: [bob/hello] (from client localhost port 0)
Fri Jul 14 18:07:17 2023 : Debug: (0) Sent Access-Accept Id 51 from 127.0.0.1:1812 to 127.0.0.1:54599 length 32
Fri Jul 14 18:07:17 2023 : Debug: (0) Reply-Message = "Hello, bob"
Fri Jul 14 18:07:17 2023 : Debug: (0) Finished request
Fri Jul 14 18:07:17 2023 : Debug: Waking up in 4.9 seconds.
Ошибочная конфигурация
Если переставить модули местами и вместо
authorize {
files
pap
}
Написать модули в обратном порядке
authorize {
pap
files
}
То на момент проверки пароля модулем PAP, атрибут Cleartext-Password еще не будет доступен о чем и будет сказано в логах:
Sat Jul 15 12:49:59 2023 : WARNING: (0) pap: No "known good" password found for the user. Not setting Auth-Type
Sat Jul 15 12:49:59 2023 : WARNING: (0) pap: Authentication will fail unless a "known good" password is available
...
Sat Jul 15 12:49:59 2023 : WARNING: (0) No module configured to handle comparisons with &control:Cleartext-Password
Sat Jul 15 12:49:59 2023 : WARNING: (0) Add pap or chap to the authorize { ... } and authenticate { ... } sections of this virtual server to handle this "known good" password type
Sat Jul 15 12:49:59 2023 : ERROR: (0) No Auth-Type found: rejecting the user via Post-Auth-Type = Reject
Не смотря на то что модуль files говорит что "все хорошо" авторизация не работает.
Sat Jul 15 12:49:59 2023 : Debug: (0) [files] = ok
How the users file works
Существуют три списка атрибутов (точнее пар атрибут - значение )
Они привязаны к конкретному запросу/ответу к серверу, и не доступны из других запросов/ответов
request- содержит список атрибут-значение которые получены в запросе от NAScontrol- изначально это пустой список, который определяет как и какие модули будут обрабатывать запрос. Этот список заполняется содулями (например files или python) или с помощьюulangreply- содержит список атрибутов которые будут отправлены назад на NAS
Модуль users file определяет какие пары проверять а какие пары добавлять в зависимости их расположения в конфигурационном файле а так же в зависимости от операторов.
Пример:
bob Cleartext-Password := "hello"
Reply-Message := "Hello, %{User-Name}"
Первая строка содержит пары атрибут-значение для проверки и пары которые будут добавлены в список control,
добавление в список control происходит при полном совпадении всех проверок.
Пары (в первой строке!) которые проверяются которые добавляются в список control можно отличить по используемым операторам
- Если используются операторы присвоения
:=or=то пара атрибут-значение обрабатывается какcontrol(добавляется в список) - Если используются операторы сравнения
>,<,==,>=,<=,=~то пара атрибут-значение используются для проверки соответвия
В примере выше используется только одна пара Cleartext-Password := "hello" где используется присвоение, те для этого пользователя будет только добавлена пара в список control (а проверка будет выполнена на другой стадии и другим модулем)
Все пары кроме первой строки содержат только пары которые будут добавлены в ответ.
Описание операторов
| Operator | Пример | Использование в check (users и тому подобное), или в условиях unlang |
Использование в reply(users и тому подобное), или в блоках unlang update |
|---|---|---|---|
=
|
|
|
|
:=
|
lameuser Auth-Type := Reject
Reply-Message = "Your account has been disabled."
steve Cleartext-Password := "testing"
Service-Type = Framed-User
|
Всегда совпадает при проверках, и добавляет в
server {
authorize {
files
pap
}
authenticate {
Auth-Type PAP {
pap
}
}
|
Для атрибутов в ответе ( automate Cleartext-Password := "pppassss"
User-Service-Type := 6
|
==
|
swilson Service-Type == Framed-User, Huntgroup-Name == "alphen"
Framed-IP-Address = 192.0.2.65,
Fall-Through = Yes
|
Операция сравнения для authorize {
preprocess
...
}
|
Не применимо |
+=
|
Attribute += Value
Cisco-Account-Info += "APOLICY_MAP_SERVICE_ON_SESSION_START_", Cisco-Account-Info += "NPOLICY_MAP_SERVICE_ON_SESSION_START_" |
При проверке атрибутов - всегда дает совпадение и добавляет атрибут-значение к словарю конфигурационных атрибутов | При формировании ответа добавляет атрибуты к ответу (не переписывая существующие) |
!=
|
Текст ячейки | Дает совпадение, если атрибут присутствует в запросе и его значение не равно указанному (соответственно если атрибута нет то совпадение невозможно) | Не применимо |
>
|
Текст ячейки | Дает совпадение, если атрибут присутствует в запросе и его значение больше указанного | Не применимо |
>=
|
Текст ячейки | Дает совпадение, если атрибут присутствует в запросе и его значение больше или равно указанному | Не применимо |
|
|
Текст ячейки | Дает совпадение, если атрибут присутствует в запросе и его значение меньше указанного | Не применимо |
<=
|
Текст ячейки | Дает совпадение, если атрибут присутствует в запросе и его значение меньше или равно указанному | Не применимо |
=~
|
Текст ячейки | Дает совпадение, если атрибут присутствует в запросе и его значение совпадает с регулярным выражением, применим только для строк | Не применимо |
!~
|
Текст ячейки | Дает совпадение, если атрибут присутствует в запросе и его значение НЕ совпадает с регулярным выражением, применим только для строк | Не применимо |
=*
|
Текст ячейки | Дает совпадение, если атрибут присутствует в запросе и его (значение не проверяется) | Не применимо |
!*
|
Текст ячейки | Дает совпадение, если атрибут НЕ присутствует в запросе и его (значение не проверяется по причине отсутвия) | Не применимо |
Cleartext-Password
Cleartext-Password это исключительно control пара атрибут-гачение и эта пара не должна присутвовать ни в каком другом списке
Cleartext-Password это один из списка атрибутов известных как 'known good' password
который содержит пользовательский пароль в открытом виде.
Другой пример из этого набора "хорошо известных" SSHA-Password - который содержит salted SHA hash от пользовательского пароля.
Проверка пользовательского пароля происходит cопоставлением атрибута из списка the 'known good' password атрибутов
которые содержаться в списке control модулями которые могут authenticate пользователя - это может быть модуль rlm_pap
или другой - например самописный на python
authenticate {
Auth-Type ISG {
python3_isg
}
}
По сути, модуль rlm_pap сравнивает значение User-Password которое вставил другой модуль - files как в этом примере или sql или еще какой-то
User-Password
User-Password это атрибут который должен содержаться только в запросе и более нигде
User-Password этот атрибут который пользователь передал на NAS в том видже в котором он был передан
Что бы authenticate пользователя модуль сравнивает значение атрибута User-Password со значением (например) Cleartext-Password из списка атрибутов control.
В файле users соответвенно нужно указать:
my_username Cleartext-Password := "known_good_password"
Эта запись означает что при совпадении атрибута User-Name со значением слева (my_username), нужно в словарь contro добавить атрибут Cleartext-Password со значением "known_good_password".
Соответвенно ответ на вопрос "почему писать так не правильно":
shad Cleartext-Password == "test"
такой:
Эта конструкция работает не так как ожидается (не работает авторизация) по-тому что она говорит что при совпадении User-Name в списке атрибутов запроса (которые прислал NAS)следует найти атрибут
Cleartext-Password и сравнить его значение со значением "test".
Так как никакой NAS не присылает такой запрос (атрибут Cleartext-Password отсутствует) то поведение отличается от ожидаемого.
Можно было бы предположить, что если указать User-Password == "test" то конструкция заработает
К сожалению, это не так.
Действительно, пользователей будет соответствовать и пароль на этой стадии пройдет проверку, но далее все равно пользователь (за исключением специальных конфигураций) получит Reject
Ниже подробности как и почему это происходит.
Auth-Type
Auth-Type это атрибут который может помещаться только в список атрибутов control,
и никогда не помещаться ни в какие другие списки.
На сервере есть три основных раздела для обработки запросов
- authorize
- authenticate
- post-auth
и этот список атрибутов control используется для передачи атрибутов между разными разделами.
authorize
Секция authorize предназначена для сборки информации о пользователе.
Например в этой секции:
- Может происходить запрос к базе данных для проверки существования пользователя и получения его пароля.
- В этой секции определяется значение атрибута
Auth-Typeна основании которого будет производиться дальнейшая обработка запроса в секцииauthentication
authenticate
Authenticate это секция где происходит вызов модуля authentication.
Какой именно модуль будет использоваться определяется значением атрибута Auth-Type
Например
authenticate {
Auth-Type ISG {
python3_isg
}
}
При этом значение Auth-Type=ISG выставляет модуль в секции authorize
authorize {
preprocess
python3_isg
}
Пример кода из rlm_python
...
config = ( ('Auth-Type', 'ISG') )
...
Post-Auth
Post-Auth используется в основном для логгирования и примерения других политик (а может и вообще не использоваться), список модулей запускаемых в этой секции определяются результатами работы модулей в секции authenticate
По шагам
- Модули в секции
authorizeпроверяют запрос - Если запрос удовлетворяет условиям (модуль "думает" что знает как работать с запросом на стадии
authenticate) и атрибутAuth-Typeеще не установлен то модуль выставляет атрибутAuth-Type(значение атрибута зависит от модуля) - В случае модуля
rlm_papмодуль выставляет атрибутAuth-Typeв значениеPAPесли находит в запросе атрибутUser-Password - Если ни один из модулей не выставил атрибут
Auth-Typeто запрос будет отброшен (Rejected)
Теперь можно вернуться к вопросу что не так с конструкцией User-Password == "test"
- Модуль
rlm_papв секцииauthorizeвыставит code>Auth-Type в значениеPAPтак как в запросе присутствуетUser-Password - Модуль
rlm_papв секцииauthenticateпопробует сравнить найти в списке атрибутов
config один из "известных хороших" атрибутов с паролем, например Cleartext-Password
или любой другой, и не найдя их вернет статус Reject
Если такое поведение не желательно, то его можно обойти с помощью "волшебного" значения Auth-Type, Accept,
которое позволяет пропустить секцию authenticate
Если нужно реализовать такое поведение и не вызывать модуль rlm_pap:
shad Auth-Type := Accept, User-Password == "test"