diff --git a/README.Config b/README.Config index ff2cbf0..6435528 100644 --- a/README.Config +++ b/README.Config @@ -146,26 +146,29 @@ a particular directory to anybody with a Ucam-WebAuth login is, e.g. An alternative simple configuration will allow access to the resources -to users with a Ucam-WebAuth login or to client computers with -hostnames ending .cam.ac.uk, but not otherwise: +to users with a Ucam-WebAuth login, to client computers with hostnames +ending .cam.ac.uk, or to those using a CUDN IPv6 address, but not +otherwise: AACookieKey "some random string" - Order allow,deny - Allow from .cam.ac.uk + Require host .cam.ac.uk + Require ip 2001:630:210::/44 AuthType Ucam-WebAuth Require valid-user - Satisfy any In these examples the resources to be protected are selected by a directive; resources specified by or directives can also be protected in the same way. 'AuthType' must be -set to 'Ucam-WebAuth'. A 'Require' directive must appear before -authentication will take place. +set to 'Ucam-WebAuth'. A directive 'Require user', 'Require group' or +'Require valid-user' must appear before authentication will take +place. -See standard Apache documentation for more details of the 'Order', -'Allow', 'Require', and 'Satisfy' directives. +See standard Apache 2.4 documentation for more details of the +'Require' directive. (Apache 2.2 and earlier use a more complictated +authorization language involving 'Order', 'Allow', 'Require', and +'Satisfy' directives.) The AACookieKey directive is required, though it can appear either outside the block, in which case it provides a default for @@ -377,7 +380,7 @@ AACacheControl AACookieKey - Syntax: AACookieKey "text" + Syntax: AACookieKey "text" | "file:filename" Context: all Override: AuthConfig Module: mod_ucam_webauth @@ -389,16 +392,49 @@ AACookieKey cookies (see AACookieName, AACookiePath, AACookieDomain below). This parameter has no default and must be set. + If the parameter starts with "file:", the key will instead be read + from the file named in the rest of the string. Relative paths will + be interpreted from the server root. The key will be formed from the + first 64 bytes of the named file, or the entire file, whichever is + shorter. If the file does not provide at least 16 bytes, the server + will abort with an error. Using the "file:" prefix is not permitted + in .htaccess files. + + On Linux, create a separate cookie.key file with e.g. + + $ sudo bash + # ( umask 0077 ; head -c 64 /dev/random >/etc/apache2/cookie.key ) + + and then use that with + + AACookieKey file:cookie.key + + Alternatively, + + AACookieKey file:/dev/urandom + + will request from the kernel's random-byte generator a new cookie + key each time the server rereads its configuration, and avoids a + secret on the file system. However, this will trigger a round trip + to Raven for all currently-authenticated users every time Apache is + restarted/reloaded. While not a major issue, this will, for example, + result in the loss of POST data. (On the other hand, using + "AAHeaderKey file:/dev/urandom" would be pointless: the whole point + of AAHeaderKey is to establish a shared secret with other systems.) + The key must not disclosed, since with knowledge of the key an - attacker can forge authentication. For preference, AACookieKey - should be placed in a file that is only readable by the user used to - start Apache, commonly root. One way to achieve this, while leaving - the main configuration file mainly readable, would be to put the - AACookieKey directive in a file only readable by root (or whoever) - that is incorporated into the main configuration using the 'Include' - directive. It may also be necessary to disable the standard mod_info - module since this can be use to display the Apache configuration and - this will include the value assigned to AACookieKey. + attacker can forge authentication. Putting the key directly into + a main configuration file can cause two problems: + + - Read access to this Apache configuration file must be + restricted. + + - Access to the server information page generated by the standard + mod_info module must also be restricted, since that will also + reveal the parameter of the AACookieKey directive. + + Storing the key in a separate cookie.key file, only readable to + root, avoids both these risks. AACookieName @@ -683,7 +719,7 @@ AAHeaders AAHeaderKey - Syntax: AAHeaderKey "text" | none + Syntax: AAHeaderKey "text" | "file:filename" | none Context: all Override: AuthConfig Module: mod_ucam_webauth @@ -697,17 +733,10 @@ AAHeaderKey string 'none' in which case no hash generation will take place. Knowledge of this key could allow an attacker to forge a request - containing what appear to be header values set by this module. As - with AACookieKey, for preference this directive should be placed in - a file that is only readable by the user used to start Apache, - commonly root. One way to achieve this, while leaving the main - configuration file mainly readable, would be to put the AACookieKey - directive in a file only readable by root (or whoever) that is - incorporated into the main configuration using the 'Include' - directive. It may also be necessary to disable the standard mod_info - module since this can be use to display the Apache configuration and - this will include the value assigned to AAHeaderKey. - + containing what appear to be header values set by this module. See + the description of AACookieKey for more information on how to read + the key from a file only readable by the user used to start Apache, + commonly root. AAIgnoreResponseLife diff --git a/mod_ucam_webauth.c b/mod_ucam_webauth.c index 53a5fce..ca00309 100644 --- a/mod_ucam_webauth.c +++ b/mod_ucam_webauth.c @@ -1879,7 +1879,7 @@ dump_config(request_rec *r, apr_pool_t *p, /* --- */ /* Note that most string and flag parameters are processed by the generic - ap_set_string_slot and ap_set flag_slot routines */ + ap_set_string_slot and ap_set_flag_slot routines */ static const char * set_response_timeout(cmd_parms *cmd, @@ -1996,6 +1996,74 @@ set_cache_control(cmd_parms *cmd, /* --- */ +/* process argument of AACookieKey and AAHeaderKey */ +static const char * +set_key(cmd_parms *cmd, + void *mconfig, + const char *arg) + +{ + int offset = (int)(long)cmd->info; + char **key = (char **)((char *)mconfig + offset); + const char *directive = + cmd->directive->directive; /* "AACookieKey" or "AAHeaderKey" */ + const char *path; + apr_file_t *file; + apr_size_t len = 64; /* maximum number of bytes to read from file */ + apr_status_t status; + char buf[256]; + int i; + + if (strncmp(arg, "file:", 5) == 0) { + /* load HMAC key bytes from file */ + if (ap_check_cmd_context(cmd, NOT_IN_HTACCESS)) { + /* Reasons for not allowing 'file:' access in .htaccess: + * - file would be read for each request (performance) + * - could be abused by someone with control over + * a .htaccess file to extract confidential information + * from a file only readable to the Apache process. + * - cmd->temp_pool no longer available + */ + return "AACookieKey/AAHeaderKey: 'file:' key not permitted in .htaccess"; + } + if (!arg[5] || !(path = ap_server_root_relative(cmd->temp_pool, arg + 5))) { + return apr_pstrcat(cmd->pool, directive, " 'file:", arg+5, + "': invalid file path", NULL); + } + status = apr_file_open(&file, path, APR_FOPEN_READ | APR_FOPEN_BINARY, + 0, cmd->temp_pool); + if (status != APR_SUCCESS) + return apr_pstrcat(cmd->pool, directive, " 'file:", + path, "': ", apr_strerror(status, buf, sizeof(buf)), + NULL); + *key = apr_pcalloc(cmd->pool, len+1); + if (!*key) return "apr_pcalloc() == NULL"; + apr_file_read(file, *key, &len); + apr_file_close(file); + if (len < 16) + return apr_pstrcat(cmd->pool, directive, " 'file:", arg+5, + "': key file too short (16 bytes required)", NULL); + /* Substitute \0 in binary input, so key can be handled as string. */ + for (i = 0; i < len; i++) { + if ((*key)[i] == 0) + (*key)[i] = '@'; + } + (*key)[len] = '\0'; + } else { + /* use string argument directly as HMAC key */ + *key = (char *) arg; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_STARTUP, 0, cmd->server, + "setting %s '%-.4s...' (%lu bytes)", + directive, *key, strlen(*key)); + + return NULL; + +} + +/* --- */ + static const char * set_log_level(cmd_parms *cmd, void *mconfig, @@ -3182,7 +3250,7 @@ static const command_rec webauth_commands[] = { "re-use of cached content"), AP_INIT_TAKE1("AACookieKey", - ap_set_string_slot, + set_key, (void *)APR_OFFSETOF (mod_ucam_webauth_cfg,cookie_key), RSRC_CONF | OR_AUTHCFG, @@ -3296,7 +3364,7 @@ static const command_rec webauth_commands[] = { "a list of additional headers to include in the request"), AP_INIT_TAKE1("AAHeaderKey", - ap_set_string_slot, + set_key, (void *)APR_OFFSETOF (mod_ucam_webauth_cfg,header_key), RSRC_CONF | OR_AUTHCFG,