From: Eric Covener Date: Tue, 1 Jun 2010 21:19:06 +0000 (+0000) Subject: mod_authnz_ldap: Search or Comparison during authorization phase X-Git-Tag: 2.3.6~79 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a8720fa901ad02235780ef0830d9e5bc4aea1223;p=apache mod_authnz_ldap: Search or Comparison during authorization phase can use the credentials from the authentication phase (AuthLDAPSearchAsUSer,AuthLDAPCompareAsUser). PR 48340 Submitted by: Domenico Rotiroti, Eric Covener Reviewed by: Eric Covener git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@950248 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index a468fa732e..7e565b985d 100644 --- a/CHANGES +++ b/CHANGES @@ -28,6 +28,11 @@ Changes with Apache 2.3.7 processing is completed, avoiding orphaned callback pointers. [Brett Gervasoni , Jeff Trawick] + *) mod_authnz_ldap: Search or Comparison during authorization phase + can use the credentials from the authentication phase + (AuthLDAPSearchAsUSer,AuthLDAPCompareAsUser). + PR 48340 [Domenico Rotiroti, Eric Covener] + *) mod_authnz_ldap: Allow the initial DN search during authentication to use the HTTP username/pass instead of an anonymous or hard-coded LDAP id (AuthLDAPInitialBindAsUser, AuthLDAPInitialBindPattern). diff --git a/docs/manual/mod/mod_authnz_ldap.html.en b/docs/manual/mod/mod_authnz_ldap.html.en index 831f8536ab..f1f53dd1ac 100644 --- a/docs/manual/mod/mod_authnz_ldap.html.en +++ b/docs/manual/mod/mod_authnz_ldap.html.en @@ -64,6 +64,7 @@ for HTTP Basic authentication.
  • AuthLDAPBindDN
  • AuthLDAPBindPassword
  • AuthLDAPCharsetConfig
  • +
  • AuthLDAPCompareAsUser
  • AuthLDAPCompareDNOnServer
  • AuthLDAPDereferenceAliases
  • AuthLDAPGroupAttribute
  • @@ -73,6 +74,7 @@ for HTTP Basic authentication.
  • AuthLDAPMaxSubGroupDepth
  • AuthLDAPRemoteUserAttribute
  • AuthLDAPRemoteUserIsDN
  • +
  • AuthLDAPSearchAsUser
  • AuthLDAPSubGroupAttribute
  • AuthLDAPSubGroupClass
  • AuthLDAPUrl
  • @@ -870,6 +872,40 @@ authorization

    The case of the extension does not matter. Blank lines, and lines beginning with a hash character (#) are ignored.

    + +
    top
    +

    AuthLDAPCompareAsUser Directive

    + + + + + + + + + +
    Description:Use the authenticated users credentials to perform authorization comparisons
    Syntax:AuthLDAPCompareAsUser on|off
    Default:AuthLDAPCompareAsUser off
    Context:directory, .htaccess
    Override:AuthConfig
    Status:Extension
    Module:mod_authnz_ldap
    Compatibility:Available in version 2.3.7 and later
    +

    When set, and mod_authnz_ldap has authenticated the + user, comparisons for authorization use the credentials provided via + HTTP basic authentication instead of the servers own credentials.

    + +

    The ldap-attribute, ldap-user, and ldap-group (single-level only) + authorization checks use comparisons.

    + +

    This directive only has effect on the comparisons performed during + nested group processing when + AuthLDAPSearchAsUser is also enabled.

    + +

    This directive should only be used when your LDAP server doesn't + accept anonymous comparisons and you cannot use a dedicated + AuthLDAPBindDN. +

    + +

    See also

    +
    top

    AuthLDAPCompareDNOnServer Directive

    @@ -990,6 +1026,8 @@ own username, instead of anonymously or with hard-coded credentials for the serv
    top
    @@ -1099,6 +1137,40 @@ environment variable the username that was passed by the client. It is turned off by default.

    + +
    top
    +

    AuthLDAPSearchAsUser Directive

    + + + + + + + + + +
    Description:Use the authenticated users credentials to perform authorization searches
    Syntax:AuthLDAPSearchAsUser on|off
    Default:AuthLDAPSearchAsUser off
    Context:directory, .htaccess
    Override:AuthConfig
    Status:Extension
    Module:mod_authnz_ldap
    Compatibility:Available in version 2.3.7 and later
    +

    When set, and mod_authnz_ldap has authenticated the + user, searches for authorization use the credentials provided via + HTTP basic authentication instead of the servers own credentials.

    + +

    The ldap-filter and ldap-dn authorization + checks use searches.

    + +

    This directive only has effect on the comparisons performed during + nested group processing when + AuthLDAPCompareAsUser is also enabled.

    + +

    This directive should only be used when your LDAP server doesn't + accept anonymous searches and you cannot use a dedicated + AuthLDAPBindDN. +

    + +

    See also

    +
    top

    AuthLDAPSubGroupAttribute Directive

    diff --git a/docs/manual/mod/mod_authnz_ldap.xml b/docs/manual/mod/mod_authnz_ldap.xml index 281c0f41f0..6aa45eb7c5 100644 --- a/docs/manual/mod/mod_authnz_ldap.xml +++ b/docs/manual/mod/mod_authnz_ldap.xml @@ -837,6 +837,8 @@ own username, instead of anonymously or with hard-coded credentials for the serv AuthLDAPInitialBindPattern AuthLDAPBindDN +AuthLDAPCompareAsUser +AuthLDAPSearchAsUser @@ -938,6 +940,38 @@ to perform a DN lookup + +AuthLDAPCompareAsUser +Use the authenticated users credentials to perform authorization comparisons +AuthLDAPCompareAsUser on|off +AuthLDAPCompareAsUser off +directory.htaccess + +Available in version 2.3.7 and later +AuthConfig + + +

    When set, and mod_authnz_ldap has authenticated the + user, LDAP comparisons for authorization use the queried distinguished name (DN) + and HTTP basic authentication password of the authenticated user instead of + the servers configured credentials.

    + +

    The ldap-attribute, ldap-user, and ldap-group (single-level only) + authorization checks use comparisons.

    + +

    This directive only has effect on the comparisons performed during + nested group processing when + AuthLDAPSearchAsUser is also enabled.

    + +

    This directive should only be used when your LDAP server doesn't + accept anonymous comparisons and you cannot use a dedicated + AuthLDAPBindDN. +

    +
    +AuthLDAPInitialBindAsUser +AuthLDAPSearchAsUser +
    + AuthLDAPCompareDNOnServer Use the LDAP server to compare the DNs @@ -1085,6 +1119,38 @@ environment variable + +AuthLDAPSearchAsUser +Use the authenticated users credentials to perform authorization searches +AuthLDAPSearchAsUser on|off +AuthLDAPSearchAsUser off +directory.htaccess + +Available in version 2.3.7 and later +AuthConfig + + +

    When set, and mod_authnz_ldap has authenticated the + user, LDAP searches for authorization use the queried distinguished name (DN) + and HTTP basic authentication password of the authenticated user instead of + the servers configured credentials.

    + +

    The ldap-filter and ldap-dn authorization + checks use searches.

    + +

    This directive only has effect on the comparisons performed during + nested group processing when + AuthLDAPCompareAsUser is also enabled.

    + +

    This directive should only be used when your LDAP server doesn't + accept anonymous searches and you cannot use a dedicated + AuthLDAPBindDN. +

    +
    +AuthLDAPInitialBindAsUser +AuthLDAPCompareAsUser +
    + AuthLDAPSubGroupAttribute Specifies the attribute labels, one value per diff --git a/modules/aaa/mod_authnz_ldap.c b/modules/aaa/mod_authnz_ldap.c index 0ec97ae674..2a6826f10d 100644 --- a/modules/aaa/mod_authnz_ldap.c +++ b/modules/aaa/mod_authnz_ldap.c @@ -83,18 +83,25 @@ typedef struct { int initial_bind_as_user; /* true if we should try to bind (to lookup DN) directly with the basic auth username */ ap_regex_t *bind_regex; /* basic auth -> bind'able username regex */ const char *bind_subst; /* basic auth -> bind'able username substitution */ + int search_as_user; /* true if authz searches should be done with the users credentials (when we did authn) */ + int compare_as_user; /* true if authz compares should be done with the users credentials (when we did authn) */ } authn_ldap_config_t; typedef struct { char *dn; /* The saved dn from a successful search */ char *user; /* The username provided by the client */ const char **vals; /* The additional values pulled during the DN search*/ + char *password; /* if this module successfully authenticates, the basic auth password, else null */ } authn_ldap_request_t; -enum auth_ldap_phase{ +enum auth_ldap_phase { LDAP_AUTHN, LDAP_AUTHZ }; - + +enum auth_ldap_optype { + LDAP_SEARCH, LDAP_COMPARE, LDAP_COMPARE_AND_SEARCH /* nested groups */ +}; + /* maximum group elements supported */ #define GROUPATTR_MAX_ELTS 10 @@ -412,6 +419,32 @@ static const char *ldap_determine_binddn(request_rec *r, const char *user) { return result; } + +/* Some LDAP servers restrict who can search or compare, and the hard-coded ID + * might be good for the DN lookup but not for later operations. + */ +static util_ldap_connection_t *get_connection_for_authz(request_rec *r, enum auth_ldap_optype type) { + authn_ldap_request_t *req = + (authn_ldap_request_t *)ap_get_module_config(r->request_config, &authnz_ldap_module); + authn_ldap_config_t *sec = + (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module); + + char *binddn = sec->binddn; + char *bindpw = sec->bindpw; + + /* If the per-request config isn't set, we didn't authenticate this user, and leave the default credentials */ + if (req && req->password && + ((type == LDAP_SEARCH && sec->search_as_user) || + (type == LDAP_COMPARE && sec->compare_as_user) || + (type == LDAP_COMPARE_AND_SEARCH && sec->compare_as_user && sec->search_as_user))){ + binddn = req->dn; + bindpw = req->password; + } + + return util_ldap_connection_find(r, sec->host, sec->port, + binddn, bindpw, + sec->deref, sec->secure); +} /* * Authentication Phase * -------------------- @@ -545,6 +578,7 @@ start_over: /* mark the user and DN */ req->dn = apr_pstrdup(r->pool, dn); req->user = apr_pstrdup(r->pool, user); + req->password = apr_pstrdup(r->pool, password); if (sec->user_is_dn) { r->user = req->dn; } @@ -591,9 +625,7 @@ static authz_status ldapuser_check_authorization(request_rec *r, } if (sec->host) { - ldc = util_ldap_connection_find(r, sec->host, sec->port, - sec->binddn, sec->bindpw, sec->deref, - sec->secure); + ldc = get_connection_for_authz(r, LDAP_COMPARE); apr_pool_cleanup_register(r->pool, ldc, authnz_ldap_cleanup_connection_close, apr_pool_cleanup_null); @@ -732,9 +764,7 @@ static authz_status ldapgroup_check_authorization(request_rec *r, } if (sec->host) { - ldc = util_ldap_connection_find(r, sec->host, sec->port, - sec->binddn, sec->bindpw, sec->deref, - sec->secure); + ldc = get_connection_for_authz(r, LDAP_COMPARE); /* for the top-level group only */ apr_pool_cleanup_register(r->pool, ldc, authnz_ldap_cleanup_connection_close, apr_pool_cleanup_null); @@ -869,6 +899,15 @@ static authz_status ldapgroup_check_authorization(request_rec *r, return AUTHZ_GRANTED; } case LDAP_COMPARE_FALSE: { + /* nested groups need searches and compares, so grab a new handle */ + authnz_ldap_cleanup_connection_close(ldc); + apr_pool_cleanup_kill(r->pool, ldc,authnz_ldap_cleanup_connection_close); + + ldc = get_connection_for_authz(r, LDAP_COMPARE_AND_SEARCH); + apr_pool_cleanup_register(r->pool, ldc, + authnz_ldap_cleanup_connection_close, + apr_pool_cleanup_null); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] auth_ldap authorise: require group \"%s\": " "failed [%s][%d - %s], checking sub-groups", @@ -932,9 +971,7 @@ static authz_status ldapdn_check_authorization(request_rec *r, } if (sec->host) { - ldc = util_ldap_connection_find(r, sec->host, sec->port, - sec->binddn, sec->bindpw, sec->deref, - sec->secure); + ldc = get_connection_for_authz(r, LDAP_SEARCH); /* _comparedn is a searche */ apr_pool_cleanup_register(r->pool, ldc, authnz_ldap_cleanup_connection_close, apr_pool_cleanup_null); @@ -1046,9 +1083,7 @@ static authz_status ldapattribute_check_authorization(request_rec *r, } if (sec->host) { - ldc = util_ldap_connection_find(r, sec->host, sec->port, - sec->binddn, sec->bindpw, sec->deref, - sec->secure); + ldc = get_connection_for_authz(r, LDAP_COMPARE); apr_pool_cleanup_register(r->pool, ldc, authnz_ldap_cleanup_connection_close, apr_pool_cleanup_null); @@ -1165,9 +1200,7 @@ static authz_status ldapfilter_check_authorization(request_rec *r, } if (sec->host) { - ldc = util_ldap_connection_find(r, sec->host, sec->port, - sec->binddn, sec->bindpw, sec->deref, - sec->secure); + ldc = get_connection_for_authz(r, LDAP_SEARCH); apr_pool_cleanup_register(r->pool, ldc, authnz_ldap_cleanup_connection_close, apr_pool_cleanup_null); @@ -1249,8 +1282,14 @@ static authz_status ldapfilter_check_authorization(request_rec *r, ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] auth_ldap authorize: checking dn match %s", getpid(), dn); + if (sec->compare_as_user) { + /* ldap-filter is the only authz that requires a search and a compare */ + apr_pool_cleanup_kill(r->pool, ldc, authnz_ldap_cleanup_connection_close); + authnz_ldap_cleanup_connection_close(ldc); + ldc = get_connection_for_authz(r, LDAP_COMPARE); + } result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, dn, - sec->compare_dn_on_server); + sec->compare_dn_on_server); } switch(result) { @@ -1607,6 +1646,14 @@ static const command_rec authnz_ldap_cmds[] = AP_INIT_TAKE2("AuthLDAPInitialBindPattern", set_bind_pattern, NULL, OR_AUTHCFG, "The regex and substitution to determine a username that can bind based on an HTTP basic auth username"), + AP_INIT_FLAG("AuthLDAPSearchAsUser", ap_set_flag_slot, + (void *)APR_OFFSETOF(authn_ldap_config_t, search_as_user), OR_AUTHCFG, + "Set to 'on' to perform authorization-based searches with the users credentials, when this module" + " has also performed authentication. Does not affect nested groups lookup."), + AP_INIT_FLAG("AuthLDAPCompareAsUser", ap_set_flag_slot, + (void *)APR_OFFSETOF(authn_ldap_config_t, compare_as_user), OR_AUTHCFG, + "Set to 'on' to perform authorization-based compares with the users credentials, when this module" + " has also performed authentication. Does not affect nested groups lookups."), {NULL} };