Apache 2.4 替代 mod_auth_shadow?

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 进行组身份验证。

(为什么我要使用系统密码、影子和组文件进行身份验证,而不是使用单独的 http 数据库?有些客户端更喜欢通过 ftp 而不是 http 下载他们的支持文件。因此,我们使用系统是为了让我们的客户能够相对轻松地在两种协议之间切换)

作为最后的手段,我准备尝试将 mod_auth_shadow 更新为 2.4。但我从未编写或调试过 Apache 模块,因此这种方法涉及未知的学习曲线。所以我完全愿意接受建议!

答案1

看起来您已经探索过一个选项,这里还有几个可能性,尽管看起来两者都需要一些工作。

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

答案2

在研究了一些替代方案(包括 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 <[email protected]>
 * 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 
 *  <[email protected]>
 * 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 */
};

现在,我只是想了解 auth 模块的整体逻辑顺序。我在我的 Web 服务器上创建了一个安全测试目录,其定义为:

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

这正是我感到困惑的地方:在测试过程中,我发现valid_user_check_authorizationgroup_check_authorization例程被调用时设置r->user为 NULL。但身份验证例程authn_shadow_check_password绝不被援引。

根据代码,mod_authnz_ldap.c 模块似乎暗示身份验证授权可以合并到一个模块中。但我假设身份验证功能(如果存在)将总是在任何授权函数之前调用。我进一步假设,如果浏览器提供的凭据根据身份验证函数有效,则用户 ID 将被传递给后续授权函数。但我还没有找到关于该主题的任何权威文档。

我愿意接受对我的假设的建议、提示和更正!

答案3

我也遇到过 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_ifman pam_listfile...

对于多个位置,每个位置都需要不同的限制,请为它们创建单独的 PAM 服务,通过AuthSaslServiceNameApache 配置进行选择。例如,将上述内容重命名/etc/pam.d/http/etc/pam.d/http-xyzzy,复制到 eg/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>

相关内容