Apache,SSL客户端证书,LDAP授权

问题描述:

高那里, 我在serverfault.com上发布了这个问题,但我没有答案,所以我在这里尝试... 是否可以混合使用mod_ssl和mod_auth_ldap,使用客户端证书和mod_auth_ldap(Require ldap-group)授权完成身份验证?如果是这样,你能给我一些指针吗?在此先感谢Apache,SSL客户端证书,LDAP授权

好的,对于那些感兴趣的人,apache需要存在一个AuthType指令,并通过某个模块验证用户名。

所以我写了一个很短的模块,它接受AuthType Any并接受任何用户名。

配置看起来像这样:

<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:

模块的代码如下所示。它定义了下面的指令:

AuthAnyAuthoritative开/关

AuthAnyCheckBasic开/关

如果AuthAnyCheckBasic是上,模块将检查从证书中获得的用户名在授权报头相匹配的上。

#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 */ 
};