High there, 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
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
回答1:
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 */
};