Removed useless "normalizing" code.
[shibboleth/sp.git] / mod_shire / mod_shire.cpp
1 /*
2  * mod_shire.cpp -- the SHIRE Apache Module
3  *
4  * Created by:  Derek Atkins <derek@ihtfp.com>
5  *
6  * $Id$
7  */
8
9 // SAML Runtime
10 #include <saml/saml.h>
11 #include <shib/shib.h>
12 #include <shib/shib-threads.h>
13 #include <shib-target/shib-target.h>
14
15 // Apache specific header files
16 #include "httpd.h"
17 #include "http_config.h"
18 #include "http_protocol.h"
19 #include "http_main.h"
20 #include "util_script.h"
21 #define CORE_PRIVATE
22 #include "http_core.h"
23 #include "http_log.h"
24
25 #include <fstream>
26 #include <sstream>
27 #include <stdexcept>
28
29 // For POST processing from Apache
30 #undef _XOPEN_SOURCE            // bombs on solaris
31 #include <libapreq/apache_request.h>
32
33 using namespace std;
34 using namespace saml;
35 using namespace shibboleth;
36 using namespace shibtarget;
37
38 extern "C" module MODULE_VAR_EXPORT shire_module;
39
40 namespace {
41     char* g_szSHIREURL = NULL;
42     char* g_szSHIREConfig = NULL;
43     ThreadKey* rpc_handle_key = NULL;
44     ShibTargetConfig* g_Config = NULL;
45 }
46
47 // per-dir module configuration structure
48 struct shire_dir_config
49 {
50     int bBasicHijack;           // activate for AuthType Basic?
51     int bSSLOnly;               // only over SSL?
52     SHIREConfig config;         // SHIRE Configuration
53 };
54
55 // creates per-directory config structure
56 extern "C" void* create_shire_dir_config (pool* p, char* d)
57 {
58     shire_dir_config* dc=(shire_dir_config*)ap_pcalloc(p,sizeof(shire_dir_config));
59     dc->bBasicHijack = -1;
60     dc->bSSLOnly = -1;
61     dc->config.lifetime = -1;
62     dc->config.timeout = -1;
63     return dc;
64 }
65
66 // overrides server configuration in directories
67 extern "C" void* merge_shire_dir_config (pool* p, void* base, void* sub)
68 {
69     shire_dir_config* dc=(shire_dir_config*)ap_pcalloc(p,sizeof(shire_dir_config));
70     shire_dir_config* parent=(shire_dir_config*)base;
71     shire_dir_config* child=(shire_dir_config*)sub;
72
73     dc->bBasicHijack=((child->bBasicHijack==-1) ? parent->bBasicHijack : child->bBasicHijack);
74     dc->bSSLOnly=((child->bSSLOnly==-1) ? parent->bSSLOnly : child->bSSLOnly);
75     dc->config.lifetime=((child->config.lifetime==-1) ? parent->config.lifetime : child->config.lifetime);
76     dc->config.timeout=((child->config.timeout==-1) ? parent->config.timeout : child->config.timeout);
77     return dc;
78 }
79
80 // generic global slot handlers
81 extern "C" const char* ap_set_global_string_slot(cmd_parms* parms, void*, const char* arg)
82 {
83     *((char**)(parms->info))=ap_pstrdup(parms->pool,arg);
84     return NULL;
85 }
86
87 // some shortcuts for directory config slots
88 extern "C" const char* set_lifetime(cmd_parms* parms, shire_dir_config* dc, const char* arg)
89 {
90     dc->config.lifetime=atoi(arg);
91     return NULL;
92 }
93
94 extern "C" const char* set_timeout(cmd_parms* parms, shire_dir_config* dc, const char* arg)
95 {
96     dc->config.timeout=atoi(arg);
97     return NULL;
98 }
99
100 typedef const char* (*config_fn_t)(void);
101
102 // SHIRE Module commands
103
104 static command_rec shire_cmds[] = {
105   {"SHIREConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIREConfig,
106    RSRC_CONF, TAKE1, "Path to SHIRE ini file."},
107   {"SHIREURL", (config_fn_t)ap_set_global_string_slot, &g_szSHIREURL,
108    RSRC_CONF, TAKE1, "SHIRE POST processor URL."},
109
110   {"ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
111    (void *) XtOffsetOf (shire_dir_config, bBasicHijack),
112    OR_AUTHCFG, FLAG, "Respond to AuthType Basic and convert to shib?"},
113   {"ShibSSLOnly", (config_fn_t)ap_set_flag_slot,
114    (void *) XtOffsetOf (shire_dir_config, bSSLOnly),
115    OR_AUTHCFG, FLAG, "Require SSL when accessing a secured directory?"},
116   {"ShibAuthLifetime", (config_fn_t)set_lifetime, NULL,
117    OR_AUTHCFG, TAKE1, "Lifetime of session in seconds."},
118   {"ShibAuthTimeout", (config_fn_t)set_timeout, NULL,
119    OR_AUTHCFG, TAKE1, "Timeout for session in seconds."},
120
121   {NULL}
122 };
123
124 namespace {
125     void destroy_handle(void* data)
126     {
127         delete (RPCHandle*)data;
128     }
129 }
130
131 /* 
132  * shire_child_init()
133  *  Things to do when the child process is initialized.
134  */
135 extern "C" void shire_child_init(server_rec* s, pool* p)
136 {
137     // Initialize runtime components.
138
139     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,
140                  "shire_child_init() starting");
141
142     if (g_Config) {
143       ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,s,
144                    "shire_child_init(): already initialized!");
145       exit (1);
146     }
147
148     try {
149       g_Config = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, g_szSHIREConfig));
150     } catch (...) {
151       ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,
152                    "shire_child_init() failed to initialize SHIB Target");
153       exit (1);
154     }
155
156     // Create the RPC Handle TLS key.
157     rpc_handle_key=ThreadKey::create(destroy_handle);
158
159     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_init() done");
160 }
161
162
163 /*
164  * shire_child_exit()
165  *  Cleanup.
166  */
167 extern "C" void shire_child_exit(server_rec* s, pool* p)
168 {
169     delete rpc_handle_key;
170     g_Config->shutdown();
171     g_Config = NULL;
172     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_exit() done");
173 }
174
175 inline char hexchar(unsigned short s)
176 {
177     return (s<=9) ? ('0' + s) : ('A' + s - 10);
178 }
179
180 static char* url_encode(request_rec* r, const char* s)
181 {
182     static char badchars[]="\"\\+<>#%{}|^~[]`;/?:@=&";
183     char* ret=(char*)ap_palloc(r->pool,sizeof(char)*3*strlen(s)+1);
184
185     unsigned long count=0;
186     for (; *s; s++)
187     {
188         if (strchr(badchars,*s)!=NULL || *s<=0x1F || *s>=0x7F)
189         {
190             ret[count++]='%';
191             ret[count++]=hexchar(*s >> 4);
192             ret[count++]=hexchar(*s & 0x0F);
193         }
194         else
195             ret[count++]=*s;
196     }
197     ret[count++]=*s;
198     return ret;
199 }
200
201 static const char* get_shire_location(request_rec* r, const char* target, bool encode)
202 {
203   ShibINI& ini = g_Config->getINI();
204   string shire_location;
205
206   if (g_szSHIREURL)
207     shire_location = g_szSHIREURL;
208   else if (! ini.get_tag (ap_get_server_name(r), "shireURL", true, &shire_location)) {
209     ap_log_rerror(APLOG_MARK,APLOG_ERR,r,
210                   "shire_get_location() no shireURL configuration for %s",
211                   ap_get_server_name(r));
212     return NULL;
213   }
214
215   const char* shire = shire_location.c_str();
216
217   if (*shire != '/') {
218     if (encode)
219       return url_encode(r,shire);
220     else
221       return ap_pstrdup(r->pool,shire);
222     }    
223     const char* colon=strchr(target,':');
224     const char* slash=strchr(colon+3,'/');
225     if (encode)
226       return url_encode(r,ap_pstrcat(r->pool,
227                                      ap_pstrndup(r->pool,target,slash-target),
228                                      shire,NULL));
229     else
230       return ap_pstrcat(r->pool, ap_pstrndup(r->pool,target,slash-target),
231                         shire, NULL);
232 }
233
234 static bool is_shire_location(request_rec* r, const char* target)
235 {
236   const char* shire = get_shire_location(r, target, false);
237
238   if (!shire) return false;
239
240   if (!strstr(target, shire))
241     return false;
242
243   return (!strcmp(target,shire));
244 }
245
246 static int shire_error_page(request_rec* r, const char* filename, ShibMLP& mlp)
247 {
248   ifstream infile (filename);
249   if (!infile) {
250       ap_log_rerror(APLOG_MARK,APLOG_ERR,r,
251                     "shire_error_page() cannot open %s", filename);
252       return SERVER_ERROR;
253   }
254
255   string res = mlp.run(infile);
256   r->content_type = ap_psprintf(r->pool, "text/html");
257   ap_send_http_header(r);
258   ap_rprintf(r, res.c_str());
259   return DONE;
260 }
261
262 extern "C" int shire_check_user(request_rec* r)
263 {
264     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user: ENTER");
265     shire_dir_config* dc=(shire_dir_config*)ap_get_module_config(r->per_dir_config,&shire_module);
266
267     // This will always be normalized, because Apache uses ap_get_server_name in this API call.
268     char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
269
270     if (is_shire_location (r, targeturl)) {
271       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
272            "shire_check_user: REQUEST FOR SHIRE!  Maybe you did not configure the SHIRE Handler?");
273       return SERVER_ERROR;
274     }
275     else {
276       // Regular access to arbitrary resource...check AuthType
277       const char *auth_type=ap_auth_type (r);
278       if (!auth_type)
279         return DECLINED;
280
281       if (strcasecmp(auth_type,"shibboleth"))
282       {
283         if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1)
284         {
285             core_dir_config* conf=
286                 (core_dir_config*)ap_get_module_config(r->per_dir_config,
287                     ap_find_linked_module("http_core.c"));
288             conf->ap_auth_type="shibboleth";
289         }
290         else
291             return DECLINED;
292       }
293
294       // set the connection authtype
295       if (r->connection)
296         r->connection->ap_auth_type = "shibboleth";
297
298       // SSL check.
299       if (dc->bSSLOnly==1 && strcmp(ap_http_method(r),"https"))
300       {
301         ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
302            "shire_check_user() blocked non-SSL access");
303         return SERVER_ERROR;
304       }
305     }
306
307     ostringstream threadid;
308     threadid << "[" << getpid() << "] shire" << '\0';
309     saml::NDC ndc(threadid.str().c_str());
310
311     ShibINI& ini = g_Config->getINI();
312
313     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
314                     "shire_check_user() Shib check for %s", targeturl);
315
316
317     const char * shire_location = get_shire_location(r,targeturl,true);
318     if (!shire_location)
319         return SERVER_ERROR;
320     string shire_url = get_shire_location(r,targeturl,false);
321
322     const char* serverName = ap_get_server_name(r);
323     string tag;
324     bool has_tag = ini.get_tag (serverName, "checkIPAddress", true, &tag);
325     dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false);
326
327     string shib_cookie;
328     if (! ini.get_tag(serverName, "cookieName", true, &shib_cookie)) {
329       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
330                     "shire_check_user: no cookieName configuration for %s",
331                     serverName);
332       return SERVER_ERROR;
333     }
334
335     string wayfLocation;
336     if (! ini.get_tag(serverName, "wayfURL", true, &wayfLocation)) {
337       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
338                     "shire_check_user: no wayfURL configuration for %s",
339                     serverName);
340       return SERVER_ERROR;
341     }
342
343     string shireError;
344     if (! ini.get_tag(serverName, "shireError", true, &shireError)) {
345       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
346                     "shire_check_user: no shireError configuration for %s",
347                     serverName);
348       return SERVER_ERROR;
349     }
350     
351     // Get an RPC handle and build the SHIRE object.
352     RPCHandle* rpc_handle = (RPCHandle*)rpc_handle_key->getData();
353     if (!rpc_handle)
354     {
355         rpc_handle = new RPCHandle(shib_target_sockname(), SHIBRPC_PROG, SHIBRPC_VERS_1);
356         rpc_handle_key->setData(rpc_handle);
357     }
358     SHIRE shire(rpc_handle, dc->config, shire_url);
359
360     // We're in charge, so check for cookie.
361     const char* session_id=NULL;
362     const char* cookies=ap_table_get(r->headers_in,"Cookie");
363
364     if (cookies)
365       ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
366                     "shire_check_user() cookies found: %s",cookies);                  
367
368     if (!cookies || !(session_id=strstr(cookies,shib_cookie.c_str())))
369     {
370         // No cookie.  Redirect to WAYF.
371         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
372                       "shire_check_user() no cookie found -- redirecting to WAYF");
373         char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
374                               "?shire=",shire_location,
375                               "&target=",url_encode(r,targeturl),NULL);
376         ap_table_setn(r->headers_out,"Location",wayf);
377         return REDIRECT;
378     }
379
380     // Yep, we found a cookie -- pull it out (our session_id)
381     session_id+=strlen(shib_cookie.c_str()) + 1;        /* Skip over the '=' */
382     char* cookiebuf = ap_pstrdup(r->pool,session_id);
383     char* cookieend = strchr(cookiebuf,';');
384     if (cookieend)
385         *cookieend = '\0';      /* Ignore anyting after a ; */
386     session_id=cookiebuf;
387
388     // Make sure this session is still valid
389     RPCError* status = NULL;
390     ShibMLP markupProcessor;
391     has_tag = ini.get_tag(serverName, "supportContact", true, &tag);
392     markupProcessor.insert("supportContact", has_tag ? tag : "");
393     has_tag = ini.get_tag(serverName, "logoLocation", true, &tag);
394     markupProcessor.insert("logoLocation", has_tag ? tag : "");
395     markupProcessor.insert("requestURL", targeturl);
396
397     try {
398         status = shire.sessionIsValid(session_id, r->connection->remote_ip,targeturl);
399     }
400     catch (ShibTargetException &e) {
401         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): %s", e.what());
402         markupProcessor.insert ("errorType", "SHIRE Processing Error");
403         markupProcessor.insert ("errorText", e.what());
404         markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
405         return shire_error_page (r, shireError.c_str(), markupProcessor);
406     }
407     catch (...) {
408         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): caught unexpected error");
409         markupProcessor.insert ("errorType", "SHIRE Processing Error");
410         markupProcessor.insert ("errorText", "Unexpected Exception");
411         markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
412         return shire_error_page (r, shireError.c_str(), markupProcessor);
413     }
414
415     // Check the status
416     if (status->isError()) {
417         ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
418                       "shire_check_user() session invalid: %s",
419                       status->getText());
420
421         if (status->isRetryable()) {
422             // Oops, session is invalid.  Redirect to WAYF.
423             char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
424                                 "?shire=",shire_location,
425                                 "&target=",url_encode(r,targeturl),NULL);
426             ap_table_setn(r->headers_out,"Location",wayf);
427
428             delete status;
429             return REDIRECT;
430         }
431         else {
432             // return the error page to the user
433             markupProcessor.insert (*status);
434             delete status;
435             return shire_error_page (r, shireError.c_str(), markupProcessor);
436         }
437     }
438     else {
439         delete status;
440         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
441                       "shire_check_user() success");
442         return OK;
443     }
444
445     ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() server error");
446     return SERVER_ERROR;
447 }
448
449 extern "C" int shire_post_handler (request_rec* r)
450 {
451   ostringstream threadid;
452   threadid << "[" << getpid() << "] shire" << '\0';
453   saml::NDC ndc(threadid.str().c_str());
454
455   ShibINI& ini = g_Config->getINI();
456   ShibMLP markupProcessor;
457
458   ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler() ENTER");
459
460   const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
461  
462   const char * shire_location = get_shire_location(r,targeturl,true);
463   if (!shire_location)
464       return SERVER_ERROR;
465   string shire_url = get_shire_location(r,targeturl,false);
466
467   const char* serverName = ap_get_server_name(r);
468   string tag;
469   bool has_tag = ini.get_tag(serverName, "checkIPAddress", true, &tag);
470   SHIREConfig config;
471   config.checkIPAddress = (has_tag ? ShibINI::boolean(tag) : false);
472
473   string shib_cookie;
474   if (! ini.get_tag(serverName, "cookieName", true, &shib_cookie)) {
475     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
476                   "shire_check_user: no cookieName configuration for %s",
477                   serverName);
478     return SERVER_ERROR;
479   }
480
481   string wayfLocation;
482   if (! ini.get_tag(serverName, "wayfURL", true, &wayfLocation)) {
483     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
484                   "shire_check_user: no wayfURL configuration for %s",
485                   serverName);
486     return SERVER_ERROR;
487   }
488
489   string shireError;
490   if (! ini.get_tag(serverName, "shireError", true, &shireError)) {
491     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
492                   "shire_check_user: no shireError configuration for %s",
493                   serverName);
494     return SERVER_ERROR;
495   }
496
497   has_tag = ini.get_tag(serverName, "supportContact", true, &tag);
498   markupProcessor.insert("supportContact", has_tag ? tag : "");
499   has_tag = ini.get_tag(serverName, "logoLocation", true, &tag);
500   markupProcessor.insert("logoLocation", has_tag ? tag : "");
501   markupProcessor.insert("requestURL", targeturl);
502   
503     // Get an RPC handle and build the SHIRE object.
504     RPCHandle* rpc_handle = (RPCHandle*)rpc_handle_key->getData();
505     if (!rpc_handle)
506     {
507         rpc_handle = new RPCHandle(shib_target_sockname(), SHIBRPC_PROG, SHIBRPC_VERS_1);
508         rpc_handle_key->setData(rpc_handle);
509     }
510     SHIRE shire(rpc_handle, config, shire_url);
511
512   // Process SHIRE POST
513
514   ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
515                 "shire_post_handler() Beginning SHIRE POST processing");
516       
517   try {
518     string sslonly;
519     if (!ini.get_tag(serverName, "shireSSLOnly", true, &sslonly))
520       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
521                     "shire_post_handler: no shireSSLOnly configuration");
522     
523     // Make sure this is SSL, if it should be
524     if (ShibINI::boolean(sslonly) && strcmp(ap_http_method(r),"https"))
525       throw ShibTargetException (SHIBRPC_OK,
526                                  "blocked non-SSL access to SHIRE POST processor");
527
528     // Make sure this is a POST
529     if (strcasecmp (r->method, "POST"))
530       throw ShibTargetException (SHIBRPC_OK,
531                                  "blocked non-POST to SHIRE POST processor");
532
533     // Sure sure this POST is an appropriate content type
534     const char *ct = ap_table_get (r->headers_in, "Content-type");
535     if (!ct || strcasecmp (ct, "application/x-www-form-urlencoded"))
536       throw ShibTargetException (SHIBRPC_OK,
537                                  ap_psprintf(r->pool,
538                              "blocked bad content-type to SHIRE POST processor: %s",
539                                              (ct ? ct : "")));
540         
541     // Make sure the "bytes sent" is a reasonable number
542     if (r->bytes_sent > 1024*1024) // 1MB?
543       throw ShibTargetException (SHIBRPC_OK,
544                                  "blocked too-large a post to SHIRE POST processor");
545
546     // Read the posted data
547     ApacheRequest *ap_req = ApacheRequest_new(r);
548     int err = ApacheRequest_parse(ap_req);
549     if (err != OK)
550       throw ShibTargetException (SHIBRPC_OK,
551                                  ap_psprintf(r->pool,
552                              "ApacheRequest_parse() failed with %d.", err));
553
554     
555     // Make sure the target parameter exists
556     const char *target = ApacheRequest_param(ap_req, "TARGET");
557     if (!target || *target == '\0')
558       // invalid post
559       throw ShibTargetException (SHIBRPC_OK,
560                                  "SHIRE POST failed to find TARGET");
561
562     // Make sure the SAML Response parameter exists
563     const char *post = ApacheRequest_param(ap_req, "SAMLResponse");
564     if (!post || *post == '\0')
565       // invalid post
566       throw ShibTargetException (SHIBRPC_OK,
567                                  "SHIRE POST failed to find SAMLResponse");
568
569     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
570                   "shire_post_handler() Processing POST for target: %s", target);
571
572     // process the post
573     string cookie;
574     RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, cookie);
575
576     if (status->isError()) {
577       ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
578                     "shire_post_handler() POST process failed (%d): %s",
579                     status->getCode(), status->getText());
580
581       if (status->isRetryable()) {
582         ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
583                       "shire_post_handler() Retrying POST by redirecting to WAYF");
584         
585         char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
586                               "?shire=",shire_location,
587                               "&target=",url_encode(r,target),NULL);
588         ap_table_setn(r->headers_out,"Location",wayf);
589         delete status;
590         return REDIRECT;
591       }
592
593       // return this error to the user.
594       markupProcessor.insert (*status);
595       delete status;
596       return shire_error_page (r, shireError.c_str(), markupProcessor);
597     }
598     delete status;
599
600     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
601                   "shire_post_handler() POST process succeeded.  New cookie: %s",
602                   cookie.c_str());
603
604     // We've got a good session, set the cookie...
605     char * domain = NULL;
606     char * new_cookie = ap_psprintf(r->pool, "%s=%s; path=/%s%s",
607                                     shib_cookie.c_str(),
608                                     cookie.c_str(),
609                                     (domain ? "; domain=" : ""),
610                                     (domain ? domain : ""));
611     
612     ap_table_setn(r->err_headers_out, "Set-Cookie", new_cookie);
613     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
614                   "shire_post_handler() Set cookie: %s", new_cookie);
615                     
616     // ... and redirect to the target
617     char* redir=ap_pstrcat(r->pool,url_encode(r,target),NULL);
618     ap_table_setn(r->headers_out, "Location", target);
619     return REDIRECT;
620
621   } catch (ShibTargetException &e) {
622     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
623                   "shire_post_handler(): %s", e.what());
624         
625     markupProcessor.insert ("errorType", "SHIRE Processing Error");
626     markupProcessor.insert ("errorText", e.what());
627     markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
628     return shire_error_page (r, shireError.c_str(), markupProcessor);
629   }
630   catch (...) {
631     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler(): unexpected exception");
632   
633     markupProcessor.insert ("errorType", "SHIRE Processing Error");
634     markupProcessor.insert ("errorText", "Unexpected Exception");
635     markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
636     return shire_error_page (r, shireError.c_str(), markupProcessor);
637   }
638
639   ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_post_handler() server error");
640   return SERVER_ERROR;
641 }
642
643 extern "C"{
644 handler_rec shire_handlers[] = {
645   { "shib-shire-post", shire_post_handler },
646   { NULL }
647 };
648
649 extern "C" void mod_shire_init (server_rec*r, pool* p)
650 {
651   ShibTargetConfig::preinit();
652 }
653
654 module MODULE_VAR_EXPORT shire_module = {
655     STANDARD_MODULE_STUFF,
656     mod_shire_init,             /* initializer */
657     create_shire_dir_config,    /* dir config creater */
658     merge_shire_dir_config,     /* dir merger --- default is to override */
659     NULL,                       /* server config */
660     NULL,                       /* merge server config */
661     shire_cmds,                 /* command table */
662     shire_handlers,             /* handlers */
663     NULL,                       /* filename translation */
664     shire_check_user,           /* check_user_id */
665     NULL,                       /* check auth */
666     NULL,                       /* check access */
667     NULL,                       /* type_checker */
668     NULL,                       /* fixups */
669     NULL,                       /* logger */
670     NULL,                       /* header parser */
671     shire_child_init,           /* child_init */
672     shire_child_exit,           /* child_exit */
673     NULL                        /* post read-request */
674 };
675 }