summaryrefslogtreecommitdiffstats
path: root/auth_mellon_config.c
diff options
context:
space:
mode:
authorolavmrk <olavmrk@a716ebb1-153a-0410-b759-cfb97c6a1b53>2007-09-24 09:56:34 +0000
committerolavmrk <olavmrk@a716ebb1-153a-0410-b759-cfb97c6a1b53>2007-09-24 09:56:34 +0000
commit1fa6146abe8ee1b8f224646866a855d969bbb0b6 (patch)
tree30a81b462b338316625daf61e2527a3a4262554d /auth_mellon_config.c
downloadmod_auth_mellon-1fa6146abe8ee1b8f224646866a855d969bbb0b6.tar.gz
mod_auth_mellon-1fa6146abe8ee1b8f224646866a855d969bbb0b6.tar.xz
mod_auth_mellon-1fa6146abe8ee1b8f224646866a855d969bbb0b6.zip
Initial import of version 0.0.6
git-svn-id: https://modmellon.googlecode.com/svn/trunk@3 a716ebb1-153a-0410-b759-cfb97c6a1b53
Diffstat (limited to 'auth_mellon_config.c')
-rw-r--r--auth_mellon_config.c580
1 files changed, 580 insertions, 0 deletions
diff --git a/auth_mellon_config.c b/auth_mellon_config.c
new file mode 100644
index 0000000..250bb8f
--- /dev/null
+++ b/auth_mellon_config.c
@@ -0,0 +1,580 @@
+/*
+ *
+ * auth_mellon_config.c: an authentication apache module
+ * Copyright © 2003-2007 UNINETT (http://www.uninett.no/)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include "auth_mellon.h"
+
+/* This is the default endpoint path. Remember to update the description of
+ * the MellonEndpointPath configuration directive if you change this.
+ */
+static const char *default_endpoint_path = "/mellon/";
+
+/* This is the default name of the attribute we use as a username. Remember
+ * to update the description of the MellonUser configuration directive if
+ * you change this.
+ */
+static const char *default_user_attribute = "NAME_ID";
+
+/* This is the default name of the cookie which mod_auth_mellon will set.
+ * If you change this, then you should also update the description of the
+ * MellonVar configuration directive.
+ */
+static const char *default_cookie_name = "cookie";
+
+
+/* This function handles configuration directives which set a string
+ * slot in the module configuration.
+ *
+ * Parameters:
+ * cmd_parms *cmd The command structure for this configuration
+ * directive.
+ * void *struct_ptr Pointer to the current directory configuration.
+ * NULL if we are not in a directory configuration.
+ * This value isn't used by this function.
+ * const char *arg The string argument following this configuration
+ * directive in the configuraion file.
+ *
+ * Returns:
+ * NULL on success or an error string on failure.
+ */
+static const char *am_set_module_config_string_slot(cmd_parms *cmd,
+ void *struct_ptr,
+ const char *arg)
+{
+ return ap_set_string_slot(cmd, am_get_mod_cfg(cmd->server), arg);
+}
+
+/* This function handles configuration directives which set an int
+ * slot in the module configuration.
+ *
+ * Parameters:
+ * cmd_parms *cmd The command structure for this configuration
+ * directive.
+ * void *struct_ptr Pointer to the current directory configuration.
+ * NULL if we are not in a directory configuration.
+ * This value isn't used by this function.
+ * const char *arg The string argument following this configuration
+ * directive in the configuraion file.
+ *
+ * Returns:
+ * NULL on success or an error string on failure.
+ */
+static const char *am_set_module_config_int_slot(cmd_parms *cmd,
+ void *struct_ptr,
+ const char *arg)
+{
+ return ap_set_int_slot(cmd, am_get_mod_cfg(cmd->server), arg);
+}
+
+
+/* This function handles the MellonEnable configuration directive.
+ * This directive can be set to "off", "info" or "auth".
+ *
+ * Parameters:
+ * cmd_parms *cmd The command structure for this configuration
+ * directive.
+ * void *struct_ptr Pointer to the current directory configuration.
+ * const char *arg The string argument following this configuration
+ * directive in the configuraion file.
+ *
+ * Returns:
+ * NULL on success or an error string if the argument is wrong.
+ */
+static const char *am_set_enable_slot(cmd_parms *cmd,
+ void *struct_ptr,
+ const char *arg)
+{
+ am_dir_cfg_rec *d = (am_dir_cfg_rec *)struct_ptr;
+
+ if(!strcasecmp(arg, "auth")) {
+ d->enable_mellon = am_enable_auth;
+ } else if(!strcasecmp(arg, "info")) {
+ d->enable_mellon = am_enable_info;
+ } else if(!strcasecmp(arg, "off")) {
+ d->enable_mellon = am_enable_off;
+ } else {
+ return "parameter must be 'off', 'info' or 'auth'";
+ }
+
+ return NULL;
+}
+
+
+/* This function handles the MellonDecoder configuration directive.
+ * This directive can be set to "none" or "feide".
+ *
+ * Parameters:
+ * cmd_parms *cmd The command structure for this configuration
+ * directive.
+ * void *struct_ptr Pointer to the current directory configuration.
+ * const char *arg The string argument following this configuration
+ * directive in the configuraion file.
+ *
+ * Returns:
+ * NULL on success or an error string if the argument is wrong.
+ */
+static const char *am_set_decoder_slot(cmd_parms *cmd,
+ void *struct_ptr,
+ const char *arg)
+{
+ am_dir_cfg_rec *d = (am_dir_cfg_rec *)struct_ptr;
+
+ if(!strcasecmp(arg, "none")) {
+ d->decoder = am_decoder_none;
+ } else if(!strcasecmp(arg, "feide")) {
+ d->decoder = am_decoder_feide;
+ } else {
+ return "MellonDecoder must be 'none' or 'feide'";
+ }
+
+ return NULL;
+}
+
+
+/* This function handles the MellonEndpointPath configuration directive.
+ * If the path doesn't end with a '/', then we will append one.
+ *
+ * Parameters:
+ * cmd_parms *cmd The command structure for the MellonEndpointPath
+ * configuration directive.
+ * void *struct_ptr Pointer to the current directory configuration.
+ * NULL if we are not in a directory configuration.
+ * const char *arg The string argument containing the path of the
+ * endpoint directory.
+ *
+ * Returns:
+ * This function will always return NULL.
+ */
+static const char *am_set_endpoint_path(cmd_parms *cmd,
+ void *struct_ptr,
+ const char *arg)
+{
+ am_dir_cfg_rec *d = (am_dir_cfg_rec *)struct_ptr;
+
+ /* Make sure that the path ends with '/'. */
+ if(strlen(arg) == 0 || arg[strlen(arg) - 1] != '/') {
+ d->endpoint_path = apr_pstrcat(cmd->pool, arg, "/", 0);
+ } else {
+ d->endpoint_path = arg;
+ }
+
+ return NULL;
+}
+
+
+/* This function handles the MellonSetEnv configuration directive.
+ * This directive allows the user to change the name of attributes.
+ *
+ * Parameters:
+ * cmd_parms *cmd The command structure for the MellonSetEnv
+ * configuration directive.
+ * void *struct_ptr Pointer to the current directory configuration.
+ * const char *newName The new name of the attribute.
+ * const char *oldName The old name of the attribute.
+ *
+ * Returns:
+ * This function will always return NULL.
+ */
+static const char *am_set_setenv_slot(cmd_parms *cmd,
+ void *struct_ptr,
+ const char *newName,
+ const char *oldName)
+{
+ am_dir_cfg_rec *d = (am_dir_cfg_rec *)struct_ptr;
+ apr_hash_set(d->envattr, oldName, APR_HASH_KEY_STRING, newName);
+ return NULL;
+}
+
+
+/* This function handles the MellonRequire configuration directive, which
+ * allows the user to restrict access based on attributes received from
+ * the IdP.
+ *
+ * Parameters:
+ * cmd_parms *cmd The command structure for the MellonRequire
+ * configuration directive.
+ * void *struct_ptr Pointer to the current directory configuration.
+ * const char *arg Pointer to the configuration string.
+ *
+ * Returns:
+ * NULL on success or an error string on failure.
+ */
+static const char *am_set_require_slot(cmd_parms *cmd,
+ void *struct_ptr,
+ const char *arg)
+{
+ apr_array_header_t *r;
+ am_dir_cfg_rec *d = struct_ptr;
+ char *attribute, *value;
+ const char **element;
+
+ attribute = ap_getword_conf(cmd->pool, &arg);
+ value = ap_getword_conf(cmd->pool, &arg);
+
+ if (*attribute == '\0' || *value == '\0') {
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
+ " takes at least two arguments", NULL);
+ }
+
+ do {
+ r = (apr_array_header_t *)apr_hash_get(d->require, attribute,
+ APR_HASH_KEY_STRING);
+
+ if (r == NULL) {
+ r = apr_array_make(cmd->pool, 2, sizeof(const char *));
+ apr_hash_set(d->require, attribute, APR_HASH_KEY_STRING, r);
+ }
+
+ element = (const char **)apr_array_push(r);
+ *element = value;
+
+ } while (*(value = ap_getword_conf(cmd->pool, &arg)) != '\0');
+
+ return NULL;
+}
+
+
+/* This array contains all the configuration directive which are handled
+ * by auth_mellon.
+ */
+const command_rec auth_mellon_commands[] = {
+
+ /* Global configuration directives. */
+
+ AP_INIT_TAKE1(
+ "MellonCacheSize",
+ am_set_module_config_int_slot,
+ (void *)APR_OFFSETOF(am_mod_cfg_rec, cache_size),
+ RSRC_CONF,
+ "The number of sessions we can keep track of at once. You must"
+ " restart the server before any changes to this directive will"
+ " take effect. The default value is 100."
+ ),
+ AP_INIT_TAKE1(
+ "MellonLockFile",
+ am_set_module_config_string_slot,
+ (void *)APR_OFFSETOF(am_mod_cfg_rec, lock_file),
+ RSRC_CONF,
+ "The lock file for session synchronization."
+ " Default value is \"/tmp/mellonLock\"."
+ ),
+
+
+ /* Per-location configuration directives. */
+
+ AP_INIT_TAKE1(
+ "MellonEnable",
+ am_set_enable_slot,
+ NULL,
+ OR_AUTHCFG,
+ "Enable auth_mellon on a location. This can be set to 'off', 'info'"
+ " and 'auth'. 'off' disables auth_mellon for a location, 'info'"
+ " will only populate the environment with attributes if the user"
+ " has logged in already. 'auth' will redirect the user to the IdP"
+ " if he hasn't logged in yet, but otherwise behaves like 'info'."
+ ),
+ AP_INIT_TAKE1(
+ "MellonDecoder",
+ am_set_decoder_slot,
+ NULL,
+ OR_AUTHCFG,
+ "Select which decoder mod_auth_mellon should use to decode attribute"
+ " values. This option can be se to either 'none' or 'feide'. 'none'"
+ " is the default, and will store the attributes as they are received"
+ " from the IdP. 'feide' is for decoding base64-encoded values which"
+ " are separated by a underscore."
+ ),
+ AP_INIT_TAKE1(
+ "MellonVariable",
+ ap_set_string_slot,
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, varname),
+ OR_AUTHCFG,
+ "The name of the cookie which auth_mellon will set. Defaults to"
+ " 'cookie'. This string is appended to 'mellon-' to create the"
+ " cookie name, and the default name of the cookie will therefore"
+ " be 'mellon-cookie'."
+ ),
+ AP_INIT_TAKE1(
+ "MellonUser",
+ ap_set_string_slot,
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, userattr),
+ OR_AUTHCFG,
+ "Attribute to set as r->user. Defaults to NAME_ID, which is the"
+ " attribute we set to the identifier we receive from the IdP."
+ ),
+ AP_INIT_TAKE2(
+ "MellonSetEnv",
+ am_set_setenv_slot,
+ NULL,
+ OR_AUTHCFG,
+ "Renames attributes received from the server. The format is"
+ " MellonSetEnv <old name> <new name>."
+ ),
+ AP_INIT_RAW_ARGS(
+ "MellonRequire",
+ am_set_require_slot,
+ NULL,
+ OR_AUTHCFG,
+ "Attribute requirements for authorization. Allows you to restrict"
+ " access based on attributes received from the IdP. If you list"
+ " several MellonRequire configuration directives, then all of them"
+ " must match. Every MellonRequire can list several allowed values"
+ " for the attribute. The syntax is:"
+ " MellonRequire <attribute> <value1> [value2....]."
+ ),
+ AP_INIT_TAKE1(
+ "MellonSessionLength",
+ ap_set_int_slot,
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, session_length),
+ OR_AUTHCFG,
+ "Maximum number of seconds a session will be valid for. Defaults"
+ " to 86400 seconds (1 day)."
+ ),
+ AP_INIT_TAKE1(
+ "MellonNoCookieErrorPage",
+ ap_set_string_slot,
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, no_cookie_error_page),
+ OR_AUTHCFG,
+ "Web page to display if the user has disabled cookies. We will"
+ " return a 400 Bad Request error if this is unset and the user"
+ " ha disabled cookies."
+ ),
+ AP_INIT_TAKE1(
+ "MellonSPMetadataFile",
+ ap_set_string_slot,
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, sp_metadata_file),
+ OR_AUTHCFG,
+ "Full path to xml file with metadata for the SP."
+ ),
+ AP_INIT_TAKE1(
+ "MellonSPPrivateKeyFile",
+ ap_set_string_slot,
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, sp_private_key_file),
+ OR_AUTHCFG,
+ "Full path to pem file with the private key for the SP."
+ ),
+ AP_INIT_TAKE1(
+ "MellonIdPMetadataFile",
+ ap_set_string_slot,
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, idp_metadata_file),
+ OR_AUTHCFG,
+ "Full path to xml metadata file for the IdP."
+ ),
+ AP_INIT_TAKE1(
+ "MellonIdPPublicKeyFile",
+ ap_set_string_slot,
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, idp_public_key_file),
+ OR_AUTHCFG,
+ "Full path to pem file with the public key for the IdP."
+ ),
+ AP_INIT_TAKE1(
+ "MellonEndpointPath",
+ am_set_endpoint_path,
+ NULL,
+ OR_AUTHCFG,
+ "The root directory of the SAML2 endpoints, relative to the root"
+ " of the web server. Default value is \"/mellon/\", which will"
+ " make mod_mellon to the handler for every request to"
+ " \"http://<servername>/mellon/*\". The path you specify must"
+ " be contained within the current Location directive."
+ ),
+ {NULL}
+};
+
+
+/* This function creates and initializes a directory configuration
+ * object for auth_mellon.
+ *
+ * Parameters:
+ * apr_pool_t *p The pool we should allocate memory from.
+ * char *d Unused, always NULL.
+ *
+ * Returns:
+ * The new directory configuration object.
+ */
+void *auth_mellon_dir_config(apr_pool_t *p, char *d)
+{
+ am_dir_cfg_rec *dir = apr_palloc(p, sizeof(*dir));
+
+ dir->enable_mellon = am_enable_default;
+
+ dir->decoder = am_decoder_default;
+
+ dir->varname = default_cookie_name;
+ dir->require = apr_hash_make(p);
+ dir->envattr = apr_hash_make(p);
+ dir->userattr = default_user_attribute;
+
+ dir->endpoint_path = default_endpoint_path;
+
+ dir->session_length = -1; /* -1 means use default. */
+
+ dir->no_cookie_error_page = NULL;
+
+ dir->sp_metadata_file = NULL;
+ dir->sp_private_key_file = NULL;
+ dir->idp_metadata_file = NULL;
+ dir->idp_public_key_file = NULL;
+
+
+ apr_thread_mutex_create(&dir->server_mutex, APR_THREAD_MUTEX_DEFAULT, p);
+
+ dir->server = NULL;
+
+ return dir;
+}
+
+
+/* This function merges two am_dir_cfg_rec structures.
+ * It will try to inherit from the base where possible.
+ *
+ * Parameters:
+ * apr_pool_t *p The pool we should allocate memory from.
+ * void *base The original structure.
+ * void *add The structure we should add to base.
+ *
+ * Returns:
+ * The merged structure.
+ */
+void *auth_mellon_dir_merge(apr_pool_t *p, void *base, void *add)
+{
+ am_dir_cfg_rec *base_cfg = (am_dir_cfg_rec *)base;
+ am_dir_cfg_rec *add_cfg = (am_dir_cfg_rec *)add;
+ am_dir_cfg_rec *new_cfg;
+
+ new_cfg = (am_dir_cfg_rec *)apr_palloc(p, sizeof(*new_cfg));
+
+
+ new_cfg->enable_mellon = (add_cfg->enable_mellon != am_enable_default ?
+ add_cfg->enable_mellon :
+ base_cfg->enable_mellon);
+
+
+ new_cfg->decoder = (add_cfg->decoder != am_decoder_default ?
+ add_cfg->decoder :
+ base_cfg->decoder);
+
+
+ new_cfg->varname = (add_cfg->varname != default_cookie_name ?
+ add_cfg->varname :
+ base_cfg->varname);
+
+ new_cfg->require = apr_hash_copy(p,
+ (apr_hash_count(add_cfg->require) > 0) ?
+ add_cfg->require :
+ base_cfg->require);
+
+ new_cfg->envattr = apr_hash_copy(p,
+ (apr_hash_count(add_cfg->envattr) > 0) ?
+ add_cfg->envattr :
+ base_cfg->envattr);
+
+ new_cfg->userattr = (add_cfg->userattr != default_user_attribute ?
+ add_cfg->userattr :
+ base_cfg->userattr);
+
+
+ new_cfg->endpoint_path = (
+ add_cfg->endpoint_path != default_endpoint_path ?
+ add_cfg->endpoint_path :
+ base_cfg->endpoint_path
+ );
+
+ new_cfg->session_length = (add_cfg->session_length != -1 ?
+ add_cfg->session_length :
+ base_cfg->session_length);
+
+ new_cfg->no_cookie_error_page = (add_cfg->no_cookie_error_page != NULL ?
+ add_cfg->no_cookie_error_page :
+ base_cfg->no_cookie_error_page);
+
+
+ new_cfg->sp_metadata_file = (add_cfg->sp_metadata_file ?
+ add_cfg->sp_metadata_file :
+ base_cfg->sp_metadata_file);
+
+ new_cfg->sp_private_key_file = (add_cfg->sp_private_key_file ?
+ add_cfg->sp_private_key_file :
+ base_cfg->sp_private_key_file);
+
+ new_cfg->idp_metadata_file = (add_cfg->idp_metadata_file ?
+ add_cfg->idp_metadata_file :
+ base_cfg->idp_metadata_file);
+
+ new_cfg->idp_public_key_file = (add_cfg->idp_public_key_file ?
+ add_cfg->idp_public_key_file :
+ base_cfg->idp_public_key_file);
+
+
+ apr_thread_mutex_create(&new_cfg->server_mutex,
+ APR_THREAD_MUTEX_DEFAULT, p);
+ new_cfg->server = NULL;
+
+ return new_cfg;
+}
+
+
+/* This function creates a new per-server configuration.
+ * auth_mellon uses the server configuration to store a pointer
+ * to the global module configuration.
+ *
+ * Parameters:
+ * apr_pool_t *p The pool we should allocate memory from.
+ * server_rec *s The server we should add our configuration to.
+ *
+ * Returns:
+ * The new per-server configuration.
+ */
+void *auth_mellon_server_config(apr_pool_t *p, server_rec *s)
+{
+ am_srv_cfg_rec *srv;
+ am_mod_cfg_rec *mod;
+ const char key[] = "auth_mellon_server_config";
+
+ srv = apr_palloc(p, sizeof(*srv));
+
+ /* we want to keeep our global configuration of shared memory and
+ * mutexes, so we try to find it in the userdata before doing anything
+ * else */
+ apr_pool_userdata_get((void **)&mod, key, p);
+ if (mod) {
+ srv->mc = mod;
+ return srv;
+ }
+
+ /* the module has not been initiated at all */
+ mod = apr_palloc(p, sizeof(*mod));
+
+ mod->cache_size = 100; /* ought to be enough for everybody */
+ mod->lock_file = "/tmp/mellonLock";
+
+ mod->init_cache_size = 0;
+ mod->init_lock_file = NULL;
+
+ mod->cache = NULL;
+ mod->lock = NULL;
+
+ apr_pool_userdata_set(mod, key, apr_pool_cleanup_null, p);
+
+ srv->mc = mod;
+ return srv;
+}
+