summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanu@netbsd.org <manu@netbsd.org@a716ebb1-153a-0410-b759-cfb97c6a1b53>2009-11-09 13:46:28 +0000
committermanu@netbsd.org <manu@netbsd.org@a716ebb1-153a-0410-b759-cfb97c6a1b53>2009-11-09 13:46:28 +0000
commit24d4e2221912ea900648354ada2866802c219e3e (patch)
tree49931ccc90ca983705c483e89e6edcc9e434867f
parent727a60258202b95c3321507c76593cf81980e4e4 (diff)
downloadmod_auth_mellon-24d4e2221912ea900648354ada2866802c219e3e.tar.gz
mod_auth_mellon-24d4e2221912ea900648354ada2866802c219e3e.tar.xz
mod_auth_mellon-24d4e2221912ea900648354ada2866802c219e3e.zip
Replay POST requets after been sent to the IdP
git-svn-id: https://modmellon.googlecode.com/svn/trunk@67 a716ebb1-153a-0410-b759-cfb97c6a1b53
-rw-r--r--NEWS5
-rw-r--r--README19
-rw-r--r--auth_mellon.h10
-rw-r--r--auth_mellon_config.c55
-rw-r--r--auth_mellon_handler.c235
-rw-r--r--auth_mellon_util.c352
-rw-r--r--mod_auth_mellon.c3
7 files changed, 614 insertions, 65 deletions
diff --git a/NEWS b/NEWS
index a9c1621..c6e2dc3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+Version 0.2.5
+---------------------------------------------------------------------------
+
+* Replay POST requests after been sent to the IdP
+
Version 0.2.4
---------------------------------------------------------------------------
diff --git a/README b/README
index c01e00e..894574a 100644
--- a/README
+++ b/README
@@ -104,6 +104,25 @@ MellonCacheSize 100
# Default: MellonLockFile "/tmp/mellonLock"
MellonLockFile "/tmp/mellonLock"
+# MellonPostDir is the full path of a directory where POST requests are
+# saved during authentication. This directory must be owned by the Apache
+# user and be mode 700. We will attempt to create it if it does not exist.
+# Default: MellonPostDir "/var/tmp/mellonpost"
+MellonPostDir "/var/tmp/mellonpost"
+
+# MellonPostTTL is the delay in seconds before a saved POST request can
+# be flushed.
+# Default: MellonPostTTL 900 (15 mn)
+MellonPostTTL 900
+
+# MellonPostSize is the maximum size for saved POST requests
+# Default: MellonPostSize 1073741824 (1 MB)
+MellonPostSize 1073741824
+
+# MellonPostCount is the maxmimum amount of saved POST requests
+# Default: MellonPostCount 100
+MellonPostCount 100
+
###########################################################################
# End of global configuration for mod_auth_mellon.
###########################################################################
diff --git a/auth_mellon.h b/auth_mellon.h
index be56b6d..807668a 100644
--- a/auth_mellon.h
+++ b/auth_mellon.h
@@ -89,6 +89,10 @@
typedef struct am_mod_cfg_rec {
int cache_size;
const char *lock_file;
+ const char *post_dir;
+ apr_time_t post_ttl;
+ int post_count;
+ apr_size_t post_size;
/* These variables can't be allowed to change after the session store
* has been initialized. Therefore we copy them before initializing
@@ -257,11 +261,15 @@ char *am_urlencode(apr_pool_t *pool, const char *str);
int am_urldecode(char *data);
char *am_generate_session_id(request_rec *r);
char *am_getfile(apr_pool_t *conf, server_rec *s, const char *file);
+char *am_get_endpoint_url(request_rec *r);
+int am_postdir_cleanup(request_rec *s);
+char *am_htmlencode(request_rec *r, const char *str);
+int am_save_post(request_rec *r, const char **relay_state);
int am_auth_mellon_user(request_rec *r);
int am_check_uid(request_rec *r);
-int am_handle_metadata(request_rec *r);
+int am_handler(request_rec *r);
int am_httpclient_get(request_rec *r, const char *uri,
diff --git a/auth_mellon_config.c b/auth_mellon_config.c
index e99062d..ada0ee6 100644
--- a/auth_mellon_config.c
+++ b/auth_mellon_config.c
@@ -56,6 +56,25 @@ static const int default_dump_saml_response = 0;
*/
static const char *default_login_path = "/";
+/* This is the directory for storing saved POST sessions
+ * the MellonPostDirectory configuration directive if you change this.
+ */
+static const char *post_dir = "/var/tmp/mellonpost";
+
+/* saved POST session time to live
+ * the MellonPostTTL configuration directive if you change this.
+ */
+static const apr_time_t post_ttl = 15 * 60;
+
+/* saved POST session maximum size
+ * the MellonPostSize configuration directive if you change this.
+ */
+static const apr_size_t post_size = 1024 * 1024 * 1024;
+
+/* maximum saved POST sessions
+ * the MellonPostCount configuration directive if you change this.
+ */
+static const int post_count = 100;
/* This function handles configuration directives which set a file
* slot in the module configuration. If lasso is recent enough, it
@@ -454,6 +473,38 @@ const command_rec auth_mellon_commands[] = {
"The lock file for session synchronization."
" Default value is \"/tmp/mellonLock\"."
),
+ AP_INIT_TAKE1(
+ "MellonPostDirectory",
+ am_set_module_config_string_slot,
+ (void *)APR_OFFSETOF(am_mod_cfg_rec, post_dir),
+ RSRC_CONF,
+ "The directory for saving POST requests."
+ " Default value is \"/var/tmp/mellonpost\"."
+ ),
+ AP_INIT_TAKE1(
+ "MellonPostTTL",
+ am_set_module_config_int_slot,
+ (void *)APR_OFFSETOF(am_mod_cfg_rec, post_ttl),
+ RSRC_CONF,
+ "The time to live for saved POST requests in seconds."
+ " Default value is 15 mn."
+ ),
+ AP_INIT_TAKE1(
+ "MellonPostCount",
+ am_set_module_config_int_slot,
+ (void *)APR_OFFSETOF(am_mod_cfg_rec, post_count),
+ RSRC_CONF,
+ "The maximum saved POST sessions at once."
+ " Default value is 100."
+ ),
+ AP_INIT_TAKE1(
+ "MellonPostSize",
+ am_set_module_config_int_slot,
+ (void *)APR_OFFSETOF(am_mod_cfg_rec, post_size),
+ RSRC_CONF,
+ "The maximum size of a saved POST, in bytes."
+ " Default value is 1 MB."
+ ),
/* Per-location configuration directives. */
@@ -870,6 +921,10 @@ void *auth_mellon_server_config(apr_pool_t *p, server_rec *s)
mod->cache_size = 100; /* ought to be enough for everybody */
mod->lock_file = "/tmp/mellonLock";
+ mod->post_dir = post_dir;
+ mod->post_ttl = post_ttl;
+ mod->post_count = post_count;
+ mod->post_size = post_size;
mod->init_cache_size = 0;
mod->init_lock_file = NULL;
diff --git a/auth_mellon_handler.c b/auth_mellon_handler.c
index b8bc25c..c9b4af4 100644
--- a/auth_mellon_handler.c
+++ b/auth_mellon_handler.c
@@ -30,43 +30,6 @@
#endif /* HAVE_lasso_server_new_from_buffers */
-/* This function produces the endpoint URL
- *
- * Parameters:
- * request_rec *r The request we received.
- *
- * Returns:
- * the endpoint URL
- */
-static char *am_get_endpoint_url(request_rec *r)
-{
- static APR_OPTIONAL_FN_TYPE(ssl_is_https) *am_is_https = NULL;
- am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
- apr_pool_t *p = r->pool;
- server_rec *s = r->server;
- apr_port_t default_port;
- char *port;
- char *scheme;
-
- am_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
-
- if (am_is_https && am_is_https(r->connection)) {
- scheme = "https://";
- default_port = DEFAULT_HTTPS_PORT;
- } else {
- scheme = "http://";
- default_port = DEFAULT_HTTP_PORT;
- }
-
- if (s->addrs->host_port != default_port)
- port = apr_psprintf(p, ":%d", s->addrs->host_port);
- else
- port = "";
-
- return apr_psprintf(p, "%s%s%s%s", scheme,
- s->server_hostname,
- port, cfg->endpoint_path);
-}
#ifdef HAVE_lasso_server_new_from_buffers
/* This function generates optional metadata for a given element
@@ -1730,6 +1693,129 @@ static int am_handle_artifact_reply(request_rec *r)
return am_handle_reply_common(r, login, relay_state, "");
}
+/* This function handles responses to repost request
+ *
+ * Parameters:
+ * request_rec *r The request we received.
+ *
+ * Returns:
+ * OK on success, or an error on failure.
+ */
+static int am_handle_repost(request_rec *r)
+{
+ am_mod_cfg_rec *mod_cfg;
+ const char *query;
+ char *cp;
+ char *psf_id;
+ char *psf_filename;
+ char *post_data;
+ char *post_form;
+ char *output;
+ char *last;
+ char *return_url;
+
+ mod_cfg = am_get_mod_cfg(r->server);
+ query = r->parsed_uri.query;
+
+ psf_id = am_extract_query_parameter(r->pool, query, "id");
+ if (psf_id == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Bad repost query: missing id");
+ return HTTP_BAD_REQUEST;
+ }
+
+ /* Check that Id is sane */
+ for (cp = psf_id; *cp; cp++) {
+ if (!apr_isalnum(*cp)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Bad repost query: invalid id \"%s\"", psf_id);
+ return HTTP_BAD_REQUEST;
+ }
+ }
+
+
+ return_url = am_extract_query_parameter(r->pool, query, "ReturnTo");
+ if (return_url == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Invalid or missing query ReturnTo parameter.");
+ return HTTP_BAD_REQUEST;
+ }
+
+ if (am_urldecode(return_url) != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Bad repost query: return");
+ return HTTP_BAD_REQUEST;
+ }
+
+ psf_filename = apr_psprintf(r->pool, "%s/%s", mod_cfg->post_dir, psf_id);
+ if ((post_data = am_getfile(r->pool, r->server, psf_filename)) == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Bad repost query: cannot find \"%s\"", psf_filename);
+ return HTTP_BAD_REQUEST;
+ }
+
+ post_form = "";
+ for (cp = apr_strtok(post_data, "&", &last); cp;
+ cp = apr_strtok(NULL, "&", &last)) {
+ char *item;
+ char *last2;
+ char *name;
+ char *value;
+ char *input_item;
+
+ item = apr_pstrdup(r->pool, cp);
+
+ name = apr_strtok(item, "=", &last2);
+ value = apr_strtok(NULL, "=", &last2);
+
+ if (name == NULL)
+ continue;
+
+ if (value == NULL)
+ value = (char *)"";
+
+ if (am_urldecode(name) != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "urldecode(\"%s\") failed", name);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if (am_urldecode(value) != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "urldecode(\"%s\") failed", value);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ input_item = apr_psprintf(r->pool,
+ " <input type=\"hidden\" name=\"%s\" value=\"%s\">\n",
+ am_htmlencode(r, name), am_htmlencode(r, value));
+ post_form = apr_pstrcat(r->pool, post_form, input_item, NULL);
+ }
+
+ r->content_type = "text/html";
+ output = apr_psprintf(r->pool,
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
+ "<html>\n"
+ " <head>\n"
+ " <title>SAML rePOST request</title>\n"
+ " </head>\n"
+ " <body onload=\"document.getElementById('form').submit();\">\n"
+ " <noscript>\n"
+ " Your browser does not support Javascript, \n"
+ " you must click the button below to proceed.\n"
+ " </noscript>\n"
+ " <form id=\"form\" method=\"POST\" action=\"%s\">\n%s"
+ " <noscript>\n"
+ " <input type=\"submit\">\n"
+ " </noscript>\n"
+ " </form>\n"
+ " </body>\n"
+ "</html>\n",
+ return_url, post_form);
+
+ ap_rputs(output, r);
+ return OK;
+}
+
/* This function handles responses to metadata request
*
@@ -1739,14 +1825,46 @@ static int am_handle_artifact_reply(request_rec *r)
* Returns:
* OK on success, or an error on failure.
*/
-int am_handle_metadata(request_rec *r)
+static int am_handle_metadata(request_rec *r)
{
am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
- const char *endpoint;
#ifdef HAVE_lasso_server_new_from_buffers
LassoServer *server;
const char *data;
+
+ server = am_get_lasso_server(r);
+ if(server == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+
+ data = cfg->sp_metadata_file;
+ if (data == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+
+ r->content_type = "application/samlmetadata+xml";
+
+ ap_rputs(data, r);
+
+ return OK;
+#else /* ! HAVE_lasso_server_new_from_buffers */
+
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "metadata publishing require lasso 2.2.2 or higher");
+ return HTTP_NOT_FOUND;
#endif
+}
+
+/* This function handles responses to request on our endpoint
+ *
+ * Parameters:
+ * request_rec *r The request we received.
+ *
+ * Returns:
+ * OK on success, or an error on failure.
+ */
+int am_handler(request_rec *r)
+{
+ am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
+ const char *endpoint;
/* Check if this is a request for one of our endpoints. We check if
* the uri starts with the path set with the MellonEndpointPath
@@ -1755,11 +1873,6 @@ int am_handle_metadata(request_rec *r)
if(strstr(r->uri, cfg->endpoint_path) != r->uri)
return DECLINED;
- endpoint = &r->uri[strlen(cfg->endpoint_path)];
- if (strcmp(endpoint, "metadata") != 0)
- return DECLINED;
-
-#ifdef HAVE_lasso_server_new_from_buffers
/* Make sure that this is a GET request. */
if(r->method_number != M_GET) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
@@ -1779,27 +1892,17 @@ int am_handle_metadata(request_rec *r)
return DECLINED;
}
- server = am_get_lasso_server(r);
- if(server == NULL)
- return HTTP_INTERNAL_SERVER_ERROR;
-
- data = cfg->sp_metadata_file;
- if (data == NULL)
- return HTTP_INTERNAL_SERVER_ERROR;
-
- r->content_type = "application/samlmetadata+xml";
-
- ap_rputs(data, r);
-
- return OK;
-#else /* ! HAVE_lasso_server_new_from_buffers */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "metadata publishing require lasso 2.2.2 or higher");
- return HTTP_NOT_FOUND;
-#endif
+ endpoint = &r->uri[strlen(cfg->endpoint_path)];
+ if (strcmp(endpoint, "metadata") == 0)
+ return am_handle_metadata(r);
+ else if (strcmp(endpoint, "repost") == 0)
+ return am_handle_repost(r);
+ else
+ return DECLINED;
}
+
static int am_auth_new_ticket(request_rec *r)
{
am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
@@ -1812,6 +1915,12 @@ static int am_auth_new_ticket(request_rec *r)
relay_state = am_reconstruct_url(r);
+ /* If this is a POST request, attempt to save it */
+ if (r->method_number == M_POST) {
+ if (am_save_post(r, &relay_state) != OK)
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
/* Check if IdP discovery is in use and no IdP was selected yet */
if ((cfg->discovery_url != NULL) &&
(am_builtin_discovery_timeout(r) == -1) && /* no built-in discovery */
@@ -1965,6 +2074,8 @@ static int am_endpoint_handler(request_rec *r)
return am_auth_new_ticket(r);
} else if(!strcmp(endpoint, "metadata")) {
return OK;
+ } else if(!strcmp(endpoint, "repost")) {
+ return OK;
} else if(!strcmp(endpoint, "logout")
|| !strcmp(endpoint, "logoutRequest")) {
/* logoutRequest is included for backwards-compatibility
diff --git a/auth_mellon_util.c b/auth_mellon_util.c
index 8f4e3bb..57dc653 100644
--- a/auth_mellon_util.c
+++ b/auth_mellon_util.c
@@ -587,3 +587,355 @@ char *am_getfile(apr_pool_t *conf, server_rec *s, const char *file)
return data;
}
+
+/*
+ * Create a directory for saved POST sessions, check for proper permissions
+ *
+ * Parameters:
+ * request_rec *r The current request
+ *
+ * Returns:
+ * OK on success, or HTTP_INTERNAL_SERVER on failure.
+ */
+static int am_postdir_mkdir(request_rec *r)
+{
+ apr_int32_t wanted;
+ apr_finfo_t afi;
+ apr_status_t rv;
+ char buffer[512];
+ am_mod_cfg_rec *mod_cfg;
+ apr_fileperms_t mode;
+ apr_uid_t user;
+ apr_uid_t group;
+ apr_fileperms_t prot;
+
+ mod_cfg = am_get_mod_cfg(r->server);
+
+ mode = APR_FPROT_UREAD|APR_FPROT_UWRITE|APR_FPROT_UEXECUTE;
+ if ((rv = apr_dir_make_recursive(mod_cfg->post_dir, mode, r->pool)) != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "cannot create POST directory \"%s\": %s",
+ mod_cfg->post_dir,
+ apr_strerror(rv, buffer, sizeof(buffer)));
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /*
+ * The directory may have already existed. Check we really own it
+ */
+ wanted = APR_FINFO_USER|APR_FINFO_UPROT|APR_FINFO_GPROT|APR_FINFO_WPROT;
+ if (apr_stat(&afi, mod_cfg->post_dir, wanted, r->pool) == OK) {
+ if (apr_uid_current(&user, &group, r->pool) != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "apr_uid_current failed");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if (afi.user != user) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "POST directory \"%s\" must be owned by the same "
+ "user as the web server is running as.",
+ mod_cfg->post_dir);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ prot = APR_FPROT_UREAD|APR_FPROT_UWRITE|APR_FPROT_UEXECUTE;
+ if (afi.protection != prot) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Premissions on POST directory \"%s\" must be 0700.",
+ mod_cfg->post_dir);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Purge outdated saved POST requests. If the MellonPostDir directory
+ * does not exist, create it first.
+ *
+ * Parameters:
+ * request_rec *r The current request
+ *
+ * Returns:
+ * OK on success, or HTTP_INTERNAL_SERVER on failure.
+ */
+int am_postdir_cleanup(request_rec *r)
+{
+ am_mod_cfg_rec *mod_cfg;
+ apr_dir_t *postdir;
+ apr_status_t rv;
+ apr_finfo_t afi;
+ char *fname;
+ int count;
+
+ mod_cfg = am_get_mod_cfg(r->server);
+
+ /*
+ * Open our POST directory or create it.
+ */
+ if (apr_dir_open(&postdir, mod_cfg->post_dir, r->pool) != OK)
+ return am_postdir_mkdir(r);
+
+ /*
+ * Purge outdated items
+ */
+ count = 0;
+ do {
+ rv = apr_dir_read(&afi, APR_FINFO_NAME|APR_FINFO_CTIME, postdir);
+ if (rv != OK)
+ break;
+
+ /* Skip dot_files */
+ if (afi.name[0] == '.')
+ continue;
+
+ if (afi.ctime + mod_cfg->post_ttl > apr_time_sec(apr_time_now())) {
+ fname = apr_psprintf(r->pool, "%s/%s", mod_cfg->post_dir, afi.name);
+ (void)apr_file_remove(fname , r->pool);
+ } else {
+ count++;
+ }
+ } while (1 /* CONSTCOND */);
+
+ (void)apr_dir_close(postdir);
+
+ if (count >= mod_cfg->post_count) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Too many saved POST sessions. "
+ "Increase MellonPostCount directive.");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ return OK;
+}
+
+/*
+ * HTML-encode a string
+ *
+ * Parameters:
+ * request_rec *r The current request
+ * const char *str The string to encode
+ *
+ * Returns:
+ * The encoded string
+ */
+char *am_htmlencode(request_rec *r, const char *str)
+{
+ const char *cp;
+ char *output;
+ apr_size_t outputlen;
+ int i;
+
+ outputlen = 0;
+ for (cp = str; *cp; cp++) {
+ switch (*cp) {
+ case '&':
+ outputlen += 5;
+ break;
+ case '"':
+ outputlen += 6;
+ break;
+ default:
+ outputlen += 1;
+ break;
+ }
+ }
+
+ i = 0;
+ output = apr_palloc(r->pool, outputlen + 1);
+ for (cp = str; *cp; cp++) {
+ switch (*cp) {
+ case '&':
+ (void)strcpy(&output[i], "&amp;");
+ i += 5;
+ break;
+ case '"':
+ (void)strcpy(&output[i], "&quot;");
+ i += 6;
+ break;
+ default:
+ output[i] = *cp;
+ i += 1;
+ break;
+ }
+ }
+ output[i] = '\0';
+
+ return output;
+}
+
+/* This function produces the endpoint URL
+ *
+ * Parameters:
+ * request_rec *r The request we received.
+ *
+ * Returns:
+ * the endpoint URL
+ */
+char *am_get_endpoint_url(request_rec *r)
+{
+ static APR_OPTIONAL_FN_TYPE(ssl_is_https) *am_is_https = NULL;
+ am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
+ apr_pool_t *p = r->pool;
+ server_rec *s = r->server;
+ apr_port_t default_port;
+ char *port;
+ char *scheme;
+
+ am_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
+
+ if (am_is_https && am_is_https(r->connection)) {
+ scheme = "https://";
+ default_port = DEFAULT_HTTPS_PORT;
+ } else {
+ scheme = "http://";
+ default_port = DEFAULT_HTTP_PORT;
+ }
+
+ if (s->addrs->host_port != default_port)
+ port = apr_psprintf(p, ":%d", s->addrs->host_port);
+ else
+ port = "";
+
+ return apr_psprintf(p, "%s%s%s%s", scheme,
+ s->server_hostname,
+ port, cfg->endpoint_path);
+}
+
+/*
+ * The two functions below extract an HTTP header from the request.
+ *
+ * Parameters:
+ * request_rec *r The current request.
+ *
+ * Returns:
+ * 1 if multipart/form-data, 0 otherwise.
+ */
+struct am_get_header_state {
+ request_rec *req;
+ const char *header;
+ const char *value;
+};
+
+static int am_get_header_callback(void *s, const char *key, const char *val)
+{
+ struct am_get_header_state *state;
+
+ state = (struct am_get_header_state *)s;
+
+ if (strcmp(key, state->header) != 0)
+ return 1;
+
+ state->value = val;
+ return 0;
+}
+
+static const char *am_get_header(request_rec *r, const char *header)
+{
+ struct am_get_header_state state;
+
+ state.req = r;
+ state.header = header;
+ state.value = NULL;
+
+ (void)apr_table_do(am_get_header_callback, &state, r->headers_in, NULL);
+
+ return state.value;
+}
+
+/*
+ * This function saves a POST request for later replay and updates
+ * the return URL.
+ *
+ * Parameters:
+ * request_rec *r The current request.
+ * const char **relay_state The returl URL
+ *
+ * Returns:
+ * OK on success, HTTP_INTERNAL_SERVER_ERROR otherwise
+ */
+int am_save_post(request_rec *r, const char **relay_state)
+{
+ am_mod_cfg_rec *mod_cfg;
+ const char *content_type;
+ const char *psf_id;
+ char *psf_name;
+ char *post_data;
+ apr_size_t post_data_len;
+ apr_size_t written;
+ apr_file_t *psf;
+
+ if (am_postdir_cleanup(r) != OK)
+ return HTTP_INTERNAL_SERVER_ERROR;
+
+ /* Check Content-Type */
+ content_type = am_get_header(r, "Content-Type");
+ if ((content_type != NULL) &&
+ (strcmp(content_type, "application/x-www-form-urlencoded") != 0)) {
+ /*
+ * This is probably "multipart/form-data; boundary=XXXXXXXXXX"
+ * The POST request then contains MIME data. We are not yet
+ * able to manage that, so issue an error 500.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Unsupported POST Content-Type \"%s\"", content_type);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ mod_cfg = am_get_mod_cfg(r->server);
+
+ if ((psf_id = am_generate_session_id(r)) == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "cannot generate id");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ psf_name = apr_psprintf(r->pool, "%s/%s", mod_cfg->post_dir, psf_id);
+
+ if (apr_file_open(&psf, psf_name,
+ APR_WRITE|APR_CREATE|APR_BINARY,
+ APR_FPROT_UREAD|APR_FPROT_UWRITE,
+ r->pool) != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "cannot create POST session file");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if (am_read_post_data(r, &post_data, &post_data_len) != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "cannot read POST data");
+ (void)apr_file_close(psf);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if (post_data_len > mod_cfg->post_size) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "POST data size %" APR_SIZE_T_FMT
+ " exceeds maximum %" APR_SIZE_T_FMT ". "
+ "Increase MellonPostSize directive.",
+ post_data_len, mod_cfg->post_size);
+ (void)apr_file_close(psf);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ written = post_data_len;
+ if ((apr_file_write(psf, post_data, &written) != OK) ||
+ (written != post_data_len)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "cannot write to POST session file");
+ (void)apr_file_close(psf);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if (apr_file_close(psf) != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "cannot close POST session file");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ *relay_state = apr_psprintf(r->pool, "%srepost?id=%s&ReturnTo=%s",
+ am_get_endpoint_url(r), psf_id,
+ am_urlencode(r->pool, *relay_state));
+
+ return OK;
+}
diff --git a/mod_auth_mellon.c b/mod_auth_mellon.c
index 809ce5d..b7d8349 100644
--- a/mod_auth_mellon.c
+++ b/mod_auth_mellon.c
@@ -94,7 +94,6 @@ static int am_global_init(apr_pool_t *conf, apr_pool_t *log,
mod->init_cache_size = mod->cache_size;
mod->init_lock_file = apr_pstrdup(conf, mod->lock_file);
-
/* find out the memory size of the cache */
mem_size = sizeof(am_cache_entry_t) * mod->init_cache_size;
@@ -195,7 +194,7 @@ static void register_hooks(apr_pool_t *p)
ap_hook_check_user_id(am_check_uid, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(am_global_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_child_init(am_child_init, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_handler(am_handle_metadata, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_handler(am_handler, NULL, NULL, APR_HOOK_MIDDLE);
return;
}