FreeRadius Notes: различия между версиями
Sirmax (обсуждение | вклад) |
Sirmax (обсуждение | вклад) |
||
(не показано 70 промежуточных версий этого же участника) | |||
Строка 6: | Строка 6: | ||
=Минимальный рабочий конфиг= |
=Минимальный рабочий конфиг= |
||
Тут чертовски важен порядок модулей - если переставить местами pap/files то получится что pap не сможет получить пароль |
Тут чертовски важен порядок модулей - если переставить местами pap/files то получится что pap не сможет получить пароль |
||
+ | ==<code>sites-enabled/default</code>== |
||
− | <BR> |
||
− | По сути тут логика такая |
||
− | * Пришел пользователь <code>User-Name = "bob"</code> <code> <code>User-Password = "hello"</code> |
||
− | * |
||
<PRE> |
<PRE> |
||
server default { |
server default { |
||
Строка 48: | Строка 45: | ||
} # end of SERVER |
} # end of SERVER |
||
</PRE> |
</PRE> |
||
+ | |||
+ | ==Клиенты <code>clients.conf</code>== |
||
+ | |||
+ | <PRE> |
||
+ | client localhost { |
||
+ | ipaddr = 127.0.0.1 |
||
+ | proto = * |
||
+ | secret = secret |
||
+ | require_message_authenticator = no |
||
+ | limit { |
||
+ | max_connections = 16 |
||
+ | lifetime = 0 |
||
+ | idle_timeout = 30 |
||
+ | } |
||
+ | } |
||
+ | </PRE> |
||
+ | ==Модуль PAP <code>mods-enabled/pap</code>== |
||
+ | <PRE> |
||
+ | pap { |
||
+ | # normalise = yes |
||
+ | auto_header = no |
||
+ | } |
||
+ | </PRE> |
||
+ | |||
+ | ==Модуль files== |
||
+ | ===<code>mods-enabled/files</code>=== |
||
+ | <PRE> |
||
+ | files { |
||
+ | moddir = ${modconfdir}/${.:instance} |
||
+ | #key = "%{%{Stripped-User-Name}:-%{User-Name}}" |
||
+ | filename = ${moddir}/authorize |
||
+ | usersfile = ${moddir}/authorize |
||
+ | # acctusersfile = ${moddir}/accounting |
||
+ | } |
||
+ | </PRE> |
||
+ | ===<code>mods-config/files/authorize</code>=== |
||
+ | <PRE> |
||
+ | bob Cleartext-Password := "hello" |
||
+ | Reply-Message := "Hello, %{User-Name}" |
||
+ | </PRE> |
||
+ | |||
+ | =Проверка работы минимальной конфигурации= |
||
+ | <BR> |
||
+ | |||
+ | * Для проверки использую команду <code>radtest bob hello localhost 0 secret</code> |
||
+ | ** <code>bob</code> - имя пользователя, атрибут <code>User-Name</code> |
||
+ | ** <code>hello</code> - пароль, который будет передан в атрибуте <code>User-Password</code> |
||
+ | ** <code>localhost</code> - адрес куда отправить запрос |
||
+ | ** <code>0</code> - номер (виртуального) порта, <code>NAS-Port</code> |
||
+ | ** <code>secret</code> - radius shared secret, который указан в настройках сервера и клиента |
||
+ | |||
+ | По сути тут логика такая |
||
+ | * "Пришел" пользователь <code>User-Name = "bob"</code> <code>User-Password = "hello"</code> |
||
+ | * Его проверили по файлу (модуль <code>files</code> ищет пользователя в файле, имя файла определено конфигурацией модуля) и находит, о чем говорит запись <code>files: users: Matched entry bob at line 4</code> |
||
+ | * Далее для модулей вызываных ниже по конфигу будут доступны атрибуты которые добавил модуль <code>files</code> а именно: |
||
+ | <PRE> |
||
+ | bob Cleartext-Password := "hello" |
||
+ | Reply-Message := "Hello, %{User-Name}" |
||
+ | </PRE> |
||
+ | * При этом модуль <code>files</code> по сути не делает проверок - он только сопоставляет запрос, и по ключу который определен в конфигурации (<code>key = "%{%{Stripped-User-Name}:-%{User-Name}}"</code>) находит (или не находит) атрибуты. |
||
+ | <BR> |
||
+ | Запись в логах вида: |
||
+ | <PRE> |
||
+ | [files] = ok |
||
+ | </PRE> |
||
+ | Означает что такой пользователь существует, НО не означает что он успешно авторизован. |
||
+ | * Далее модуль PAP осуществляет проверку пароля. Важно то, что пароль в описании пользователя должен содержаться в атрибутах "known good", в нашем случае - <code>Cleartext-Password</code> |
||
+ | <BR> |
||
+ | {{#spoiler:show=Выдержка из man rlm_pap | |
||
+ | |||
+ | <PRE> |
||
+ | The module looks for the Password-With-Header control attribute to find the "known good" password. The attribute value comprises the header followed immediately by the password data. The |
||
+ | header is given by the following table. |
||
+ | |||
+ | Header Attribute Description |
||
+ | ------ --------- ----------- |
||
+ | {clear} Cleartext-Password Clear-text passwords |
||
+ | {cleartext} Cleartext-Password Clear-text passwords |
||
+ | {crypt} Crypt-Password Unix-style "crypt"ed passwords |
||
+ | {md5} MD5-Password MD5 hashed passwords |
||
+ | {base64_md5} MD5-Password MD5 hashed passwords |
||
+ | {smd5} SMD5-Password MD5 hashed passwords, with a salt |
||
+ | {sha} SHA-Password SHA1 hashed passwords |
||
+ | SHA1-Password SHA1 hashed passwords |
||
+ | {ssha} SSHA-Password SHA1 hashed passwords, with a salt |
||
+ | {sha2} SHA2-Password SHA2 hashed passwords |
||
+ | {sha224} SHA2-Password SHA2 hashed passwords |
||
+ | {sha256} SHA2-Password SHA2 hashed passwords |
||
+ | {sha384} SHA2-Password SHA2 hashed passwords |
||
+ | {sha512} SHA2-Password SHA2 hashed passwords |
||
+ | {ssha224} SSHA2-224-Password SHA2 hashed passwords, with a salt |
||
+ | {ssha256} SSHA2-256-Password SHA2 hashed passwords, with a salt |
||
+ | {ssha384} SSHA2-384-Password SHA2 hashed passwords, with a salt |
||
+ | {ssha512} SSHA2-512-Password SHA2 hashed passwords, with a salt |
||
+ | {nt} NT-Password Windows NT hashed passwords |
||
+ | {nthash} NT-Password Windows NT hashed passwords |
||
+ | {md4} NT-Password Windows NT hashed passwords |
||
+ | {x-nthash} NT-Password Windows NT hashed passwords |
||
+ | {ns-mta-md5} NS-MTA-MD5-Password Netscape MTA MD5 hashed passwords |
||
+ | {x- orcllmv} LM-Password Windows LANMAN hashed passwords |
||
+ | {X- orclntv} NT-Password Windows NT hashed passwords |
||
+ | </PRE> |
||
+ | }} |
||
+ | |||
+ | |||
+ | * Собственно на этом все. |
||
<PRE> |
<PRE> |
||
Строка 95: | Строка 198: | ||
Fri Jul 14 18:07:17 2023 : Debug: Waking up in 4.9 seconds. |
Fri Jul 14 18:07:17 2023 : Debug: Waking up in 4.9 seconds. |
||
</PRe> |
</PRe> |
||
+ | |||
+ | |||
+ | =Ошибочная конфигурация= |
||
+ | Если переставить модули местами и вместо |
||
+ | <PRE> |
||
+ | authorize { |
||
+ | files |
||
+ | pap |
||
+ | } |
||
+ | </PRE> |
||
+ | Написать модули в обратном порядке |
||
+ | <PRE> |
||
+ | authorize { |
||
+ | pap |
||
+ | files |
||
+ | } |
||
+ | </PRE> |
||
+ | |||
+ | То на момент проверки пароля модулем PAP, атрибут <code>Cleartext-Password</code> еще не будет доступен о чем и будет сказано в логах: |
||
+ | <PRE> |
||
+ | 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 |
||
+ | </PRE> |
||
+ | Не смотря на то что модуль <code>files</code> говорит что "все хорошо" авторизация не работает. |
||
+ | <PRE> |
||
+ | 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> |
Текущая версия на 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 secret
bob
- имя пользователя, атрибутUser-Name
hello
- пароль, который будет передан в атрибутеUser-Password
localhost
- адрес куда отправить запрос0
- номер (виртуального) порта,NAS-Port
secret
- 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) или с помощьюulang
reply
- содержит список атрибутов которые будут отправлены назад на 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"