Commit 0a5e2211 authored by Bradley Nicholes's avatar Bradley Nicholes
Browse files

Add general authn and authz modules to hold non-authxxx specific directives...

Add general authn and authz modules to hold non-authxxx specific directives such as authtype, authname and require.  Remove authtype and authname from mod_core.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/authz-dev@354331 13f79535-47bb-0310-9956-ffa450edef68
parent 764d4157
Loading
Loading
Loading
Loading
+6 −8
Original line number Diff line number Diff line
@@ -454,9 +454,9 @@ typedef struct {
    /* Authentication stuff.  Groan... */
    
    int *satisfy; /* for every method one */
    char *ap_auth_type; /* Deprecated see mod_authz_host */
    char *ap_auth_name; /* Deprecated see mod_authz_host */
    apr_array_header_t *ap_requires; /* Deprecated see mod_authz_host */
    char *ap_auth_type; /* Deprecated see mod_authn */
    char *ap_auth_name; /* Deprecated see mod_authn */
    apr_array_header_t *ap_requires; /* Deprecated see mod_authz */

    /* Custom response config. These can contain text or a URL to redirect to.
     * if response_code_strings is NULL then there are none in the config,
@@ -685,13 +685,11 @@ APR_DECLARE_OPTIONAL_FN(const char *, ap_ident_lookup,
 * authorization values with mod_authz_host
 */

APR_DECLARE_OPTIONAL_FN(const apr_array_header_t *, authz_host_ap_requires,
APR_DECLARE_OPTIONAL_FN(const apr_array_header_t *, authz_ap_requires,
                        (request_rec *r));
APR_DECLARE_OPTIONAL_FN(int, authz_some_auth_required, (request_rec *r));
/*
APR_DECLARE_OPTIONAL_FN(const char *, authz_host_ap_auth_type, (request_rec *r));
APR_DECLARE_OPTIONAL_FN(const char *, authz_host_ap_auth_name, (request_rec *r));
*/
APR_DECLARE_OPTIONAL_FN(const char *, authn_ap_auth_type, (request_rec *r));
APR_DECLARE_OPTIONAL_FN(const char *, authn_ap_auth_name, (request_rec *r));

/* ---------------------------------------------------------------------- */

+10 −0
Original line number Diff line number Diff line
@@ -21,6 +21,11 @@ APACHE_MODULE(authn_default, authentication backstopper, , , yes)
dnl Provider alias module.
APACHE_MODULE(authn_alias, auth provider alias, , , no)

dnl General Authentication modules; module which implements the 
dnl non-authn module specific directives.
dnl
APACHE_MODULE(authn, general authentication module, , , yes)

dnl Authorization modules: modules which verify a certain property such as
dnl membership of a group, value of the IP address against a list of pre
dnl configured directives (e.g. require, allow) or against an external file
@@ -33,6 +38,11 @@ APACHE_MODULE(authz_dbm, DBM-based authorization control, , , most)
APACHE_MODULE(authz_owner, 'require file-owner' authorization control, , , most)
APACHE_MODULE(authz_dbd, SQL based authorization and Login/Session support, , , most)

dnl General Authorization modules; provider module which implements the 
dnl non-authz module specific directives.
dnl
APACHE_MODULE(authz, general authorization provider vector module, , , yes)

dnl LDAP authentication module. This module has both the authn and authz
dnl modules in one, so as to share the LDAP server config directives.
APACHE_MODULE(authnz_ldap, LDAP based authentication, , , no)
+5 −1
Original line number Diff line number Diff line
@@ -195,7 +195,11 @@ static int authenticate_basic_user(request_rec *r)
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    r->ap_auth_type = "Basic";
    /*XXX Need to figure out how to remove ap_auth_type from 
      the request_rec yet still make the data available
      on a per-request basis.
    */
    r->ap_auth_type = current_auth;

    res = get_basic_auth(r, &sent_user, &sent_pw);
    if (res) {
+141 −0
Original line number Diff line number Diff line
/* Copyright 2002-2005 The Apache Software Foundation or its licensors, as
 * applicable.
 *
 * Licensed 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.
 */

/*
 * Security options etc.
 *
 * Module derived from code originally written by Rob McCool
 *
 */

#include "apr_strings.h"
#include "apr_network_io.h"
#define APR_WANT_STRFUNC
#define APR_WANT_BYTEFUNC
#include "apr_want.h"

#include "ap_config.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_request.h"
#include "http_protocol.h"

#include "mod_auth.h"

#if APR_HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif

typedef struct {
    char *ap_auth_type;
    char *ap_auth_name;
} authn_dir_conf;

module AP_MODULE_DECLARE_DATA authn_module;

static void *create_authn_dir_config(apr_pool_t *p, char *dummy)
{
    authn_dir_conf *conf =
            (authn_dir_conf *)apr_pcalloc(p, sizeof(authn_dir_conf));

    return (void *)conf;
}

static void *merge_authn_dir_config(apr_pool_t *a, void *basev, void *newv)
{
    authn_dir_conf *base = (authn_dir_conf *)basev;
    authn_dir_conf *new = (authn_dir_conf *)newv;
    authn_dir_conf *conf;

    /* Create this conf by duplicating the base, replacing elements
    * (or creating copies for merging) where new-> values exist.
    */
    conf = (authn_dir_conf *)apr_palloc(a, sizeof(authn_dir_conf));
    memcpy(conf, base, sizeof(authn_dir_conf));

    if (new->ap_auth_type) {
        conf->ap_auth_type = new->ap_auth_type;
    }

    if (new->ap_auth_name) {
        conf->ap_auth_name = new->ap_auth_name;
    }

    return (void*)conf;
}

/*
 * Load an authorisation realm into our location configuration, applying the
 * usual rules that apply to realms.
 */
static const char *set_authname(cmd_parms *cmd, void *mconfig,
                                const char *word1)
{
    authn_dir_conf *aconfig = (authn_dir_conf *)mconfig;

    aconfig->ap_auth_name = ap_escape_quotes(cmd->pool, word1);
    return NULL;
}


static const char *authn_ap_auth_type(request_rec *r)
{
    authn_dir_conf *conf;

    conf = (authn_dir_conf *)ap_get_module_config(r->per_dir_config,
        &authn_module);

    return apr_pstrdup(r->pool, conf->ap_auth_type);
}

static const char *authn_ap_auth_name(request_rec *r)
{
    authn_dir_conf *conf;

    conf = (authn_dir_conf *)ap_get_module_config(r->per_dir_config,
        &authn_module);

    return apr_pstrdup(r->pool, conf->ap_auth_name);
}

static const command_rec authn_cmds[] =
{
    AP_INIT_TAKE1("AuthType", ap_set_string_slot,
                  (void*)APR_OFFSETOF(authn_dir_conf, ap_auth_type), OR_AUTHCFG,
                  "An HTTP authorization type (e.g., \"Basic\")"),
    AP_INIT_TAKE1("AuthName", set_authname, NULL, OR_AUTHCFG,
                  "The authentication realm (e.g. \"Members Only\")"),
    {NULL}
};

static void register_hooks(apr_pool_t *p)
{
    APR_REGISTER_OPTIONAL_FN(authn_ap_auth_type);
    APR_REGISTER_OPTIONAL_FN(authn_ap_auth_name);
}

module AP_MODULE_DECLARE_DATA authn_module =
{
    STANDARD20_MODULE_STUFF,
    create_authn_dir_config,        /* dir config creater */
    merge_authn_dir_config,         /* dir merger --- default is to override */
    NULL,                           /* server config */
    NULL,                           /* merge server config */
    authn_cmds,
    register_hooks                  /* register hooks */
};
+275 −0
Original line number Diff line number Diff line
/* Copyright 2002-2005 The Apache Software Foundation or its licensors, as
 * applicable.
 *
 * Licensed 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.
 */

/*
 * Security options etc.
 *
 * Module derived from code originally written by Rob McCool
 *
 */

#include "apr_strings.h"
#include "apr_network_io.h"
#include "apr_md5.h"

#define APR_WANT_STRFUNC
#define APR_WANT_BYTEFUNC
#include "apr_want.h"

#include "ap_config.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_request.h"
#include "http_protocol.h"
#include "ap_provider.h"

#include "mod_auth.h"

#if APR_HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif

typedef struct {
    apr_array_header_t *ap_requires;
    authz_provider_list *providers;
} authz_dir_conf;

module AP_MODULE_DECLARE_DATA authz_module;

static void *create_authz_dir_config(apr_pool_t *p, char *dummy)
{
    authz_dir_conf *conf =
            (authz_dir_conf *)apr_pcalloc(p, sizeof(authz_dir_conf));

    return (void *)conf;
}

static void *merge_authz_dir_config(apr_pool_t *a, void *basev, void *newv)
{
    authz_dir_conf *base = (authz_dir_conf *)basev;
    authz_dir_conf *new = (authz_dir_conf *)newv;
    authz_dir_conf *conf;

    /* Create this conf by duplicating the base, replacing elements
    * (or creating copies for merging) where new-> values exist.
    */
    conf = (authz_dir_conf *)apr_palloc(a, sizeof(authz_dir_conf));
    memcpy(conf, base, sizeof(authz_dir_conf));

    if (new->ap_requires) {
        conf->ap_requires = new->ap_requires;
    }

    return (void*)conf;
}

static const char *add_authz_provider(cmd_parms *cmd, void *config,
                                      const char *arg)
{
    authz_dir_conf *conf = (authz_dir_conf*)config;
    authz_provider_list *newp;

    newp = apr_pcalloc(cmd->pool, sizeof(authz_provider_list));
    /* XXX: Split this out to the name and then the rest of the directive. */
    newp->provider_name = apr_pstrdup(cmd->pool, arg);
    newp->requirement = apr_pstrdup(cmd->pool, arg);
    newp->method_mask = cmd->limited;

    /* lookup and cache the actual provider now */
    newp->provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP,
                                        newp->provider_name, "0");

    /* by the time the config file is used, the provider should be loaded
     * and registered with us.
     */
    if (newp->provider == NULL) {
        return apr_psprintf(cmd->pool,
                            "Unknown Authz provider: %s",
                            newp->provider_name);
    }

    /* if the provider doesn't provide the appropriate function, reject it */
    if (!newp->provider->check_authorization) {
        return apr_psprintf(cmd->pool,
                            "The '%s' Authz provider is not supported by any "
                            "of the loaded authorization modules ",
                            newp->provider_name);
    }

    /* Add it to the list now. */
    if (!conf->providers) {
        conf->providers = newp;
    }
    else {
        authz_provider_list *last = conf->providers;

        while (last->next) {
            last = last->next;
        }
        last->next = newp;
    }

    return NULL;
}

static const command_rec authz_cmds[] =
{
    AP_INIT_RAW_ARGS("Require", add_authz_provider, NULL, OR_AUTHCFG,
                     "Selects which authenticated users or groups may access "
                     "a protected space"),
    {NULL}
};

static int authorize_user(request_rec *r)
{
    authz_dir_conf *conf = ap_get_module_config(r->per_dir_config,
            &authz_module);
    authz_status auth_result;
    authz_provider_list *current_provider;

    current_provider = conf->providers;
    do {
        const authz_provider *provider;

        /* For now, if a provider isn't set, we'll be nice and use the file
         * provider.
         */
        if (!current_provider) {
            provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP,
                                          AUTHZ_DEFAULT_PROVIDER, "0");

            if (!provider || !provider->check_authorization) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                              "No default authz provider configured");
                auth_result = AUTHZ_GENERAL_ERROR;
                break;
            }
            apr_table_setn(r->notes, AUTHZ_PROVIDER_NAME_NOTE,
                           AUTHZ_DEFAULT_PROVIDER);
        }
        else {
            provider = current_provider->provider;
            apr_table_setn(r->notes, AUTHZ_PROVIDER_NAME_NOTE,
                           current_provider->provider_name);
        }


        auth_result = provider->check_authorization(r,
                        current_provider->method_mask,
                        current_provider->requirement);

        apr_table_unset(r->notes, AUTHZ_PROVIDER_NAME_NOTE);

        /* Something occured. Stop checking. */
        /* XXX: We need to figure out what the implications of multiple
         * require directives are.  Must all satisfy?  Can we leverage
         * satisfy here then?
         */
        if (auth_result != AUTHZ_DENIED) {
            break;
        }

        /* If we're not really configured for providers, stop now. */
        if (!conf->providers) {
            break;
        }

        current_provider = current_provider->next;
    } while (current_provider);

    if (auth_result != AUTHZ_GRANTED) {
        int return_code;

        switch (auth_result) {
            case AUTHZ_DENIED:
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                              "user %s: authorization failure for \"%s\": ",
                              r->user, r->uri);
                return_code = HTTP_UNAUTHORIZED;
                break;
            case AUTHZ_GENERAL_ERROR:
            default:
                /* We'll assume that the module has already said what its
                 * error was in the logs.
                 */
                return_code = HTTP_INTERNAL_SERVER_ERROR;
                break;
        }

        /* If we're returning 403, tell them to try again. */
        if (return_code == HTTP_UNAUTHORIZED) {
            /* XXX: Why is this a basic auth failure? */
            ap_note_basic_auth_failure (r);
        }
        return return_code;
    }

    return OK;
}

static const apr_array_header_t *authz_ap_requires(request_rec *r)
{
    authz_dir_conf *conf;

    conf = (authz_dir_conf *)ap_get_module_config(r->per_dir_config,
        &authz_module);

    return conf->ap_requires;
}

static int authz_some_auth_required(request_rec *r)
{
    authz_dir_conf *conf = ap_get_module_config(r->per_dir_config,
            &authz_module);
    authz_provider_list *current_provider;
    int req_authz = 0;

    current_provider = conf->providers;
    while (current_provider) {

        /* Does this provider config apply for this method */
        if (current_provider->method_mask &
                (AP_METHOD_BIT << r->method_number)) {
            req_authz = 1;
            break;
        }

        current_provider = current_provider->next;
    }

    return req_authz;
}

static void register_hooks(apr_pool_t *p)
{
    APR_REGISTER_OPTIONAL_FN(authz_ap_requires);
    APR_REGISTER_OPTIONAL_FN(authz_some_auth_required);
   
    ap_hook_auth_checker(authorize_user, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA authz_module =
{
    STANDARD20_MODULE_STUFF,
    create_authz_dir_config,   /* dir config creater */
    NULL,                           /* dir merger --- default is to override */
    NULL,                           /* server config */
    NULL,                           /* merge server config */
    authz_cmds,
    register_hooks                  /* register hooks */
};
Loading