Apache, SSL Client certificate, LDAP authorizations

后端 未结 1 1443
逝去的感伤
逝去的感伤 2021-01-01 07:30

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 wit

相关标签:
1条回答
  • 2021-01-01 08:07

    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 讨论(0)
提交回复
热议问题