On 2/25/14, 12:52 PM, Ben Reser wrote:
> 2) Write a custom authz hook that always returns HTTP_FORBIDDEN that hooks
> after the ldap module.  Configure your custom module to be turned on for your
> location.  Then set 'AuthzLDAPAuthoritative off', meaning that the ldap module
> will DECLINE and the final module should handle this.
> 
> I'm off to lunch but when I get back I can probably write a quick authz module
> that does the second bit for you.

First of all I was able to duplicate this with a SVN 1.6.x server, 1.8.x client
and the following setup (without needing LDAP since group file module has the
same behavior):

httpd.conf:
[[[
<Location /svn>
  DAV svn
  SVNPath ${HOME}/iprops
  AuthType Basic
  AuthName "Subversion Repository"
  AuthUserFile ${HOME}/iprops/conf/users
  AuthGroupFile ${HOME}/iprops/conf/groups
  Require group constant
  AuthzSVNAuthoritative off
  AuthzSVNAccessFile ${HOME}/iprops/conf/authz
</Location>
]]]

users (password is rayjandom for both):
[[[
jrandom:xCGl35kV9oWCY
jconstant:xCGl35kV9oWCY
]]]

groups:
[[[
constant: jconstant
]]]

authz:
[[[
[/random]
jrandom = rw
]]]

I was able to make it work by adding the attached module.  It's a slightly
hacked version of mod_authz_default, which comes with httpd 2.2.x (and also
returns a 401).  The only differences are I changed the name of the symbols and
configuration settings so that it doesn't conflict with mod_authz_default.

The following should install it (note that on Debian use apxs2 instead of apxs):
apxs -cia mod_authz_forbid.c

Now add the following extra options to the Location block for SVN:
[[[
  AuthzDefaultAuthoritative Off
  AuthzGroupFileAuthoritative Off
]]]

And now it works with a 1.8 client.  The first directive is only needed if
mod_authz_default is built in or loaded as a module.  The second line is the
correct option to disable authoritative in the group module.  In your case
you'd want to use "AuthzLDAPAuthoritative off".

The mod_authz_default module is intended as a fallback in case of there are
Requires lines but no authz hooks is configured as authoritative, which default
behavior in httpd would be to allow that access.  So it is desirable to leave
this module enabled but simply enable it for where you're using the
mod_authz_forbid module I've attached.

Both mod_authz_default and mod_authz_forbid are registering in the
APR_HOOK_LAST group.  So their order is not determinate.  If you want to avoid
mod_authz_forbid activating for any other traffic (with or without
mod_authz_default) loaded you should add the following directive inside your
server level of your httpd.conf (i.e. outside a Location/Directory block):
AuthzForbidAuthoritative On
/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "apr_strings.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"

typedef struct {
    int authoritative;
} authz_forbid_config_rec;

static void *create_authz_forbid_dir_config(apr_pool_t *p, char *d)
{
    authz_forbid_config_rec *conf = apr_palloc(p, sizeof(*conf));

    conf->authoritative = 1; /* keep the fortress secure by default */
    return conf;
}

static const command_rec authz_forbid_cmds[] =
{
    AP_INIT_FLAG("AuthzForbidAuthoritative", ap_set_flag_slot,
                 (void *)APR_OFFSETOF(authz_forbid_config_rec, authoritative),
                 OR_AUTHCFG,
                 "Set to 'Off' to allow access control to be passed along to "
                 "lower modules. (default is On.)"),
    {NULL}
};

module AP_MODULE_DECLARE_DATA authz_forbid_module;

static int check_user_access(request_rec *r)
{
    authz_forbid_config_rec *conf = ap_get_module_config(r->per_dir_config,
                                                 &authz_forbid_module);
    int m = r->method_number;
    int method_restricted = 0;
    register int x;
    const apr_array_header_t *reqs_arr = ap_requires(r);
    require_line *reqs;

    /* BUG FIX: tadc, 11-Nov-1995.  If there is no "requires" directive,
     * then any user will do.
     */
    if (!reqs_arr) {
        return OK;
    }
    reqs = (require_line *)reqs_arr->elts;

    for (x = 0; x < reqs_arr->nelts; x++) {
        if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) {
            continue;
        }
        method_restricted = 1;
        break;
    }

    if (method_restricted == 0) {
        return OK;
    }

    if (!(conf->authoritative)) {
        return DECLINED;
    }

    /* if we aren't authoritative, any require directive could be
     * considered valid even if noone groked it.  However, if we are
     * authoritative, we can warn the user they did something wrong.
     *
     * That something could be a missing "AuthAuthoritative off", but
     * more likely is a typo in the require directive.
     */
    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                          "access to %s failed, reason: require directives "
                          "present and no Authoritative handler.", r->uri);

    return HTTP_FORBIDDEN;
}

static void register_hooks(apr_pool_t *p)
{
    ap_hook_auth_checker(check_user_access,NULL,NULL,APR_HOOK_LAST);
}

module AP_MODULE_DECLARE_DATA authz_forbid_module =
{
    STANDARD20_MODULE_STUFF,
    create_authz_forbid_dir_config,  /* dir config creater */
    NULL,                            /* dir merger --- default is to override */
    NULL,                            /* server config */
    NULL,                            /* merge server config */
    authz_forbid_cmds,               /* command apr_table_t */
    register_hooks                   /* register hooks */
};

Reply via email to