diff options
-rw-r--r-- | README | 5 | ||||
-rw-r--r-- | mod_authnz_pam.c | 48 | ||||
-rw-r--r-- | tests/auth.conf | 10 | ||||
-rwxr-xr-x | tests/run.sh | 3 |
4 files changed, 52 insertions, 14 deletions
@@ -95,7 +95,7 @@ two separate account PAM checks during the Basic Authentication. Handling expired password: - AuthPAMExpiredRedirect <URL> + AuthPAMExpiredRedirect <URL> [<status>] For both the authorization and HTTP Basic authentication case, if the password the user has presented has expired (PAM return codes @@ -117,6 +117,9 @@ For example for FreeIPA 4.1+, the value can actually be https://<IPA-server>/ipa/ui/reset_password.html?url=%s +By default the redirect is done using 303 See Other. The redirect +status can be specified as numerical value in the 3xx range. + SELinux: On SELinux enabled systems, boolean httpd_mod_auth_pam needs to diff --git a/mod_authnz_pam.c b/mod_authnz_pam.c index 7da820f..71db4ea 100644 --- a/mod_authnz_pam.c +++ b/mod_authnz_pam.c @@ -32,9 +32,16 @@ #include "mod_auth.h" +#ifdef APLOG_USE_MODULE +#define SHOW_MODULE "" +#else +#define SHOW_MODULE "mod_authnz_pam: " +#endif + typedef struct { char * pam_service; char * expired_redirect_url; + int expired_redirect_status; } authnz_pam_config_rec; static void * create_dir_conf(apr_pool_t * pool, char * dir) { @@ -42,13 +49,36 @@ static void * create_dir_conf(apr_pool_t * pool, char * dir) { return cfg; } +static const char * set_redirect_and_status(cmd_parms * cmd, void * conf_void, char * url, char * status) { + authnz_pam_config_rec * cfg = (authnz_pam_config_rec *) conf_void; + if (cfg) { + cfg->expired_redirect_url = apr_pstrdup(cmd->pool, url); + cfg->expired_redirect_status = HTTP_SEE_OTHER; + if (status) { + cfg->expired_redirect_status = apr_atoi64(status); + if (cfg->expired_redirect_status == 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, + SHOW_MODULE "AuthPAMExpiredRedirect status has to be a number, setting to %d", + HTTP_SEE_OTHER); + cfg->expired_redirect_status = HTTP_SEE_OTHER; + } else if (cfg->expired_redirect_status < 300 || cfg->expired_redirect_status > 399) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, + SHOW_MODULE "AuthPAMExpiredRedirect status has to be in the 3xx range, setting to %d", + HTTP_SEE_OTHER); + cfg->expired_redirect_status = HTTP_SEE_OTHER; + } + } + } + return NULL; +} + static const command_rec authnz_pam_cmds[] = { AP_INIT_TAKE1("AuthPAMService", ap_set_string_slot, (void *)APR_OFFSETOF(authnz_pam_config_rec, pam_service), OR_AUTHCFG, "PAM service to authenticate against"), - AP_INIT_TAKE1("AuthPAMExpiredRedirect", ap_set_string_slot, - (void *)APR_OFFSETOF(authnz_pam_config_rec, expired_redirect_url), - OR_AUTHCFG, "URL to redirect to user credentials expired have expired"), + AP_INIT_TAKE12("AuthPAMExpiredRedirect", set_redirect_and_status, + NULL, + ACCESS_CONF|OR_AUTHCFG, "URL (and optional status) to redirect to should user have expired credentials"), {NULL} }; @@ -138,12 +168,6 @@ static const char * format_location(request_rec * r, const char * url, const cha module AP_MODULE_DECLARE_DATA authnz_pam_module; -#ifdef APLOG_USE_MODULE -#define SHOW_MODULE "" -#else -#define SHOW_MODULE "mod_authnz_pam: " -#endif - #if AP_MODULE_MAGIC_AT_LEAST(20100625,0) static APR_OPTIONAL_FN_TYPE(ap_authn_cache_store) *authn_cache_store = NULL; @@ -210,10 +234,10 @@ static authn_status pam_authenticate_with_login_password(request_rec * r, const authnz_pam_config_rec * conf = ap_get_module_config(r->per_dir_config, &authnz_pam_module); if (conf && conf->expired_redirect_url) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - SHOW_MODULE "PAM_NEW_AUTHTOK_REQD: redirect to [%s]", - conf->expired_redirect_url); + SHOW_MODULE "PAM_NEW_AUTHTOK_REQD: redirect to [%s] using [%d]", + conf->expired_redirect_url, conf->expired_redirect_status); apr_table_addn(r->headers_out, "Location", format_location(r, conf->expired_redirect_url, login)); - r->status = HTTP_TEMPORARY_REDIRECT; + r->status = conf->expired_redirect_status; ap_send_error_response(r, 0); return AUTH_DENIED; } diff --git a/tests/auth.conf b/tests/auth.conf index 2ee519e..c728d91 100644 --- a/tests/auth.conf +++ b/tests/auth.conf @@ -54,3 +54,13 @@ ScriptAlias /authnp4 /var/www/cgi-bin/auth.cgi AuthPAMExpiredRedirect http://localhost/fix-password?return=%s&percent=%%&user=%u Require pam-account webl </LocationMatch> + +ScriptAlias /authnp5 /var/www/cgi-bin/auth.cgi +<LocationMatch ^/authnp5> + AuthType Basic + AuthName "private area" + AuthBasicProvider PAM + AuthPAMService webl + AuthPAMExpiredRedirect http://localhost/login?realm=ježek&return=%s 307 + Require pam-account webl +</LocationMatch> diff --git a/tests/run.sh b/tests/run.sh index 28235f8..3b24f9b 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -55,7 +55,8 @@ curl -u user1:heslo1 -s http://localhost/authnp3 | tee /dev/stderr | grep 'User curl -u user1:heslo1 -s http://localhost/authnp4 | tee /dev/stderr | grep 'User user1' chage -d $(date -d -2days +%Y-%m-%d) -M 1 user1 curl -u user1:heslo1 -s http://localhost/authnp3 | tee /dev/stderr | grep 401 -curl -i -u user1:heslo1 -s 'http://localhost/authnp4?id=123&data=M%26M' | tee /dev/stderr | grep -F -e 'Location: http://localhost/fix-password?return=http%3a%2f%2flocalhost%2fauthnp4%3fid%3d123%26data%3dM%2526M&percent=%25&user=user1' -e 'HTTP/1.1 307 Temporary Redirect' | wc -l | grep 2 +curl -i -u user1:heslo1 -s 'http://localhost/authnp4?id=123&data=M%26M' | tee /dev/stderr | grep -F -e 'Location: http://localhost/fix-password?return=http%3a%2f%2flocalhost%2fauthnp4%3fid%3d123%26data%3dM%2526M&percent=%25&user=user1' -e 'HTTP/1.1 303 See Other' | wc -l | grep 2 +curl -i -u user1:heslo1 -s 'http://localhost/authnp5?data=křížala' | tee /dev/stderr | grep -F -e 'Location: http://localhost/login?realm=ježek&return=http%3a%2f%2flocalhost%2fauthnp5%3fdata%3dk%c5%99%c3%ad%c5%beala' -e 'HTTP/1.1 307 Temporary Redirect' | wc -l | grep 2 chage -d $(date -d -2days +%Y-%m-%d) -M 3 user1 curl -u user1:heslo1 -s http://localhost/authnp3 | tee /dev/stderr | grep 'User user1' curl -u user1:heslo1 -s http://localhost/authnp4 | tee /dev/stderr | grep 'User user1' |