Назад | Перейти на главную страницу

Замена Apache 2.4 для mod_auth_shadow?

Мой работодатель уже много лет использует RHEL 6.x и Apache httpd 2.2. В настоящее время мы находимся в процессе перехода на новое оборудование под управлением RHEL 7.1 и Apache httpd 2.4. На нашем текущем веб-сайте есть разные места, где есть загружаемые материалы для разных групп клиентов. У всех клиентов есть системные учетные записи на сервере. В настоящее время мы контролируем доступ к локациям на основе членства в группах клиентов.

Например:

<Location /xyzzy/*>
    AuthName "xyzzy product support"
    AuthShadow on
    AuthType Basic
    require group xyzzy
    Options Includes ExecCGI Indexes FollowSymLinks MultiViews
</Location>

Мы успешно использовали mod_auth_shadow для реализации этого контроля доступа в Apache 2.2. Однако мы обнаружили, что этот модуль не загружается в версии 2.4, потому что модуль вызывает ap_requires(), которого нет в 2.4.

Мы заметили, что RHEL 7 по умолчанию запускается

/usr/sbin/saslauthd -m /run/saslauthd -a pam

поэтому я смотрел на использование PAM через mod_authn_sasl в качестве замены mod_auth_shadow. У меня был частичный успех с этой конфигурацией apache:

<Location /xyzzy/*>
    AuthType Basic
    AuthName "xyzzy product support"
    AuthBasicProvider sasl
    AuthBasicAuthoritative On
    AuthSaslPwcheckMethod saslauthd
    Require valid-user
</Location>

в сочетании с этим /etc/pam.d/http файл:

#%PAM-1.0
auth       include      password-auth
auth       include      pam_group
account    include      password-auth

С этой комбинацией любой пользователь с действующими учетными данными может получить доступ к местоположению xyzzy. Я считаю, что это подтверждает, что базовое соединение между Apache -> saslauthd -> PAM работает. Но это не тот уровень детализации, который нам нужен.

Эта альтернативная конфигурация httpd:

<Location /xyzzy/*>
    AuthType Basic
    AuthName "xyzzy product support"
    AuthBasicProvider sasl
    AuthBasicAuthoritative On
    AuthSaslPwcheckMethod saslauthd
    Require group xyzzy
</Location>

генерирует эту ошибку в журнале httpd:

AH01664: No group file was specified in the configuration

Это говорит о том, что httpd не прохождение saslauthd для проверки членства в группе. До сих пор я не нашел директивы httpd, которая принудительно использовала бы групповую аутентификацию через sasl, как это делает аутентификация пользователя / пароля.

(Почему я использую системные файлы passwd, shadow и group для аутентификации вместо отдельной базы данных для http? Некоторые клиенты предпочитают загружать свои файлы поддержки через ftp, а не через http. Таким образом, мы используем систему для того, чтобы наши клиенты могли относительно легко переключение между двумя протоколами)

В крайнем случае, я готов попробовать обновить mod_auth_shadow для версии 2.4. Но я никогда не кодировал и не отлаживал модуль apache, поэтому в этом подходе есть неизвестная кривая обучения. Так что я полностью открыт для предложений!

Посмотрев на некоторые альтернативы, в том числе предложенные Unbeliever, я решил пойти дальше и попытаться переписать исходный mod_auth_shadow, чтобы он был совместим с текущей архитектурой аутентификации / авторизации. Я создал очень простой, урезанный модуль, смоделированный по образцу модуля mod_authnz_ldap.

/*
 * mod_auth_shadow.c
 *
 * An apache module to authenticate using the /etc/shadow file.
 * This module interacts with another program "validate", which
 * is setuid root.  Thus the /etc/shadow file can remain 
 * root:root 0400.
 *
 * Author: Brian Duggan <bduggan@matatu.org>
 * Some code was taken from the sample code supplied with
 * _Apache Modules_ by Stein and MacEachern.  Parts of this
 * were also influenced by mod_auth.c.
 *
 * Adapted for Apache2: Bernard du Breuil 
 *  <bernard.l.dubreuil@erdc.usace.army.mil>
 * I went back to mod_auth.c to see how it was converted.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 */

#include "apr_strings.h"
#include "ap_config.h"

#include "httpd.h"  
#include "http_config.h"  
#include "http_core.h"  
#include "http_log.h"  
#include "http_protocol.h"  
#include "http_request.h"  

#include "mod_auth.h"

#include <shadow.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pwd.h>
#include <grp.h>
#include "validate.h"


static const char module_name[] = "authnz_shadow_module";


static authn_status authn_shadow_check_password(request_rec *r, const char *user,
                                              const char *password)
{
    return AUTH_GRANTED;
}


static authz_status valid_user_check_authorization(request_rec *r,
                                              const char *require_args,
                                              const void *parsed_require_args)
{
    return AUTH_GRANTED;
}


static authz_status group_check_authorization(request_rec *r,
                                              const char *require_args,
                                              const void *parsed_require_args)
{
    return AUTH_GRANTED;
}




typedef struct
{
    int auth_shadow_flag; /* 1 for yes, 0 for no */
}
auth_shadow_config_rec;


static const authn_provider authn_shadow_provider =
{
    &authn_shadow_check_password,
    NULL,
};


static const authz_provider authz_valid_user_provider =
{
    &valid_user_check_authorization,
    NULL,
};


static const authz_provider authz_group_provider =
{
    &group_check_authorization,
    NULL,
};


static void register_hooks(apr_pool_t *p)
{
    /* Register authn provider */
    ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "shadow",
                              AUTHN_PROVIDER_VERSION,
                              &authn_shadow_provider, AP_AUTH_INTERNAL_PER_CONF);

    /* Register authz providers */
    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "shadow-valid-user",
                              AUTHZ_PROVIDER_VERSION,
                              &authz_valid_user_provider,
                              AP_AUTH_INTERNAL_PER_CONF);
    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "shadow-group",
                              AUTHZ_PROVIDER_VERSION,
                              &authz_group_provider,
                              AP_AUTH_INTERNAL_PER_CONF);
}


static void *create_auth_shadow_dir_config(apr_pool_t *p, char *d)
{
    auth_shadow_config_rec *sec =
    (auth_shadow_config_rec *) apr_palloc(p, sizeof(*sec));
    sec->auth_shadow_flag = 0;  
    return sec;
}


static const command_rec auth_shadow_cmds[] =
{
    AP_INIT_FLAG("AuthShadow", ap_set_flag_slot,
    (void *)APR_OFFSETOF(auth_shadow_config_rec, auth_shadow_flag),
        OR_AUTHCFG, "On or Off depending on whether to use /etc/shadow"),
    {NULL}
};


module AP_MODULE_DECLARE_DATA authnz_shadow_module = 
{
    STANDARD20_MODULE_STUFF, 
    create_auth_shadow_dir_config , /* dir config creator */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    auth_shadow_cmds,      /* [config file] command table */
    register_hooks     /* register hooks */
};

Прямо сейчас я просто пытаюсь понять общую логическую последовательность модулей аутентификации. Я создал безопасный тестовый каталог на своем веб-сервере, определенный как:

<Location /secure>
    AuthName SecureDocument
    AuthType Basic
    AuthBasicProvider shadow
    AuthShadow on
    Require shadow-valid-user
    Require shadow-group xyzzy
</Location>

И вот здесь я очень запутался: во время тестирования я обнаружил, что valid_user_check_authorization и group_check_authorization процедуры вызываются с r->user установлен в NULL. Но процедура аутентификации authn_shadow_check_password является никогда вызван.

В кодировке модуль mod_authnz_ldap.c подразумевает, что аутентификация и авторизацию можно объединить в единый модуль. Но я предполагаю, что функция аутентификации, если она есть, будет всегда вызываться перед любыми функциями авторизации. И я также предполагаю, что если учетные данные, предоставленные браузером, действительны в соответствии с функцией аутентификации, идентификатор пользователя будет передан последующим функциям авторизации. Но я так или иначе не нашел какой-либо исчерпывающей документации по этой теме.

Я открыт для предложений, подсказок и исправлений моих предположений!

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

mod_auth_external: https://github.com/phokz/mod-auth-external
mod_auth_kerb: http://modauthkerb.sourceforge.net/

Я также столкнулся с этим ограничением mod_authn_sasl. Однако достаточно легко добиться желаемого эффекта, установив групповое ограничение на уровне PAM вместо уровня Apache.

В исходном примере оставьте конфигурацию Apache, требующую только valid-user но добавьте ограничение на нужную группу в соответствующей конфигурации службы PAM, /etc/pam.d/http:

#%PAM-1.0
auth       require      pam_succeed_if.so user ingroup xyzzy
auth       include      password-auth
auth       include      pam_group
account    include      password-auth

Чтобы ограничить любой список групп / пользователей, сделайте это первым auth строка что-то вроде:

auth       require      pam_listfile.so onerr=fail item=group sense=allow file=/path/to/allowed.groups

Доступно гораздо больше возможностей; видеть man pam_succeed_if и man pam_listfile...

В случае нескольких местоположений, для каждого из которых требуются разные ограничения, создайте для них отдельные службы PAM, выбранные через AuthSaslServiceName в конфигурации Apache. Например. переименовать выше /etc/pam.d/http к /etc/pam.d/http-xyzzy, скопируйте, например, /etc/pam.d/http-abcd и измените, чтобы ограничить группу abcd, затем настройте Apache следующим образом:

<Location /abcd/*>
    AuthType Basic
    AuthName "abcd product support"
    AuthBasicProvider sasl
    AuthBasicAuthoritative On
    AuthSaslPwcheckMethod saslauthd
    AuthSaslServiceName http-abcd
    Require valid-user
</Location>
<Location /xyzzy/*>
    AuthType Basic
    AuthName "xyzzy product support"
    AuthBasicProvider sasl
    AuthBasicAuthoritative On
    AuthSaslPwcheckMethod saslauthd
    AuthSaslServiceName http-xyzzy
    Require valid-user
</Location>