开发者

Apache, SSL Client certificate, LDAP authorizations

I posted this question on serverfault.com, but I had no answer, so I'm trying here... Is it possible to mix mod_ssl and 开发者_如何学编程mod_auth_ldap so that the authentication is done with the client certificate and authorizations with mod_auth_ldap (Require ldap-group)? If so, can you give me some pointer? Thanks in advance


OK, for those interested, apache requires the presence of an AuthType directive and the validation of the username by some module.

So I have written a very short module that accepts AuthType Any and accepts any username.

The configuration looks like that:

<Location /slaptest>
    Allow from all
    SSLVerifyClient require
    SSLVerifyDepth 1

    SSLUserName SSL_CLIENT_S_DN_CN

    AuthType Any
    AuthAnyAuthoritative on

    AuthLDAPURL "ldaps://vldap-rectech/ou=XXX,ou=YYY,o=ZZZ?cn"
    AuthzLDAPAuthoritative on
    AuthLDAPBindDN "cn=UUU,ou=Users,ou=XXX,ou=YYY,o=ZZZ"
    AuthLDAPBindPassword "******"
    AuthLDAPGroupAttributeIsDN on
    AuthLDAPGroupAttribute member
    AuthLDAPRemoteUserIsDN off
    Require valid-user
    Require ldap-group cn=ADMIN,ou=Groups,ou=XXX,ou=YYY,o=ZZZ
</Location>

UPDATE:

The code of the module is listed below. It defines the following directives:

AuthAnyAuthoritative on/off

AuthAnyCheckBasic on/off

If AuthAnyCheckBasic is on, the module will check that the username obtained from the certificate matches the on in the Authorization header.

#include "apr_strings.h"
#include "apr_md5.h"            /* for apr_password_validate */
#include "apr_lib.h"            /* for apr_isspace */
#include "apr_base64.h"         /* for apr_base64_decode et al */
#define APR_WANT_STRFUNC        /* for strcasecmp */
#include "apr_want.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 "ap_provider.h"

#include "mod_auth.h"

typedef struct {
    int authoritative;
    int checkBasic;
} auth_any_config_rec;

static void *create_auth_any_dir_config(apr_pool_t *p, char *d)
{
    auth_any_config_rec *conf = apr_pcalloc(p, sizeof(*conf));

    /* Any failures are fatal. */
    conf->authoritative = 1;
    conf->checkBasic = 0;

    return conf;
}

static const command_rec auth_any_cmds[] =
{
    AP_INIT_FLAG("AuthAnyAuthoritative", ap_set_flag_slot,
                 (void *)APR_OFFSETOF(auth_any_config_rec, authoritative),
                 OR_AUTHCFG,
                 "Set to 'Off' to allow access control to be passed along to "
                 "lower modules if the UserID is not known to this module"),
    AP_INIT_FLAG("AuthAnyCheckBasic", ap_set_flag_slot,
                 (void *)APR_OFFSETOF(auth_any_config_rec, checkBasic),
                 OR_AUTHCFG,
                 "Set to 'On' to compare the username with the one in the "
                 "Authorization header"),
    {NULL}
};

module AP_MODULE_DECLARE_DATA auth_any_module;

static void note_basic_auth_failure(request_rec *r)
{
    apr_table_setn(r->err_headers_out,
                   (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate"
                                                   : "WWW-Authenticate",
                   apr_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r),
                               "\"", NULL));
}

/* Determine user ID, and check if it really is that user, for HTTP
 * basic authentication...
 */
static int authenticate_any_user(request_rec *r)
{
    auth_any_config_rec *conf = ap_get_module_config(r->per_dir_config,
                                                       &auth_any_module);

    /* Are we configured to be Basic auth? */
    const char *current_auth = ap_auth_type(r);
    if (!current_auth || strcasecmp(current_auth, "Any")) {
        return DECLINED;
    }

    if (!r->user) {
        return conf->authoritative ? HTTP_UNAUTHORIZED : DECLINED;
    }

    if (conf->checkBasic) {
        /* Get the appropriate header */
        const char *auth_line = apr_table_get(r->headers_in,
                (PROXYREQ_PROXY == r->proxyreq)
                        ? "Proxy-Authorization"
                        : "Authorization");

        if (!auth_line) {
            note_basic_auth_failure(r);
            return HTTP_UNAUTHORIZED;
        }

        if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
            /* Client tried to authenticate using wrong auth scheme */
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                          "client used wrong authentication scheme: %s", r->uri);
            note_basic_auth_failure(r);
            return HTTP_UNAUTHORIZED;
        }

        /* Skip leading spaces. */
        while (apr_isspace(*auth_line)) {
            auth_line++;
        }

        char *decoded_line = apr_palloc(r->pool, apr_base64_decode_len(auth_line) + 1);
        int length = apr_base64_decode(decoded_line, auth_line);
        /* Null-terminate the string. */
        decoded_line[length] = '\0';

        const char *user = ap_getword_nulls(r->pool, (const char**)&decoded_line, ':');

        if (strcasecmp(user, r->user)) {
            return HTTP_UNAUTHORIZED;
        }
    }

    r->ap_auth_type = "Any";
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
            "Accepting user: %s", r->user);

    return OK;
}

static void register_hooks(apr_pool_t *p)
{
    ap_hook_check_user_id(authenticate_any_user,NULL,NULL,APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA auth_any_module =
{
    STANDARD20_MODULE_STUFF,
    create_auth_any_dir_config,    /* dir config creater */
    NULL,                          /* dir merger --- default is to override */
    NULL,                          /* server config */
    NULL,                          /* merge server config */
    auth_any_cmds,                 /* command apr_table_t */
    register_hooks                 /* register hooks */
};
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜