static int do_redirect(request_rec *request, am_status_t status, const am_map_t advice_map, const char *original_url) { boolean_t allocated; char *redirect_url; int apache_status; redirect_url = am_web_get_redirect_url(status, advice_map, original_url, &allocated); if (redirect_url != NULL) { apache_status = HTTP_MOVED_TEMPORARILY; am_web_log_debug("do_redirect() policy status = %s, redirection URL " "is %s", am_status_to_string(status), redirect_url); ap_custom_response(request, apache_status, redirect_url); if (B_TRUE==allocated) { am_web_free_memory(redirect_url); } } else { apache_status = HTTP_FORBIDDEN; am_web_log_debug("do_redirect() policy status = %s, returning %d", am_status_to_string(status), apache_status); } return apache_status; }
static int psx_auth_fail(request_rec *r, qEnvApache *renv) { // this is kinda wrong.... but for now we keep it.... if (!r->header_only) { CStr resp = renv->GetCtx()->Eval("http-noauth"); if (!resp.IsEmpty()) { qStrBuf bufin(resp); qStrBuf bufout; renv->GetCtx()->ParseTry(&bufin, &bufout); ap_custom_response(r, HTTP_UNAUTHORIZED, bufout.GetBuffer()); } } if (!ap_auth_type(r)) { ap_table_setn(r->err_headers_out, r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate", ap_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r), "\"", NULL)); } else { ap_note_basic_auth_failure(r); } renv->Free(); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, AP2STATUS r, "returning unauthorized: %d, status : %d", HTTP_UNAUTHORIZED, r->status); return HTTP_UNAUTHORIZED; }
static am_status_t set_custom_response(am_request_t *rq, const char *text, const char *cont_type) { request_rec *r = (request_rec *) (rq != NULL ? rq->ctx : NULL); if (r == NULL || !ISVALID(text)) return AM_EINVAL; if (rq->status == AM_INTERNAL_REDIRECT) { ap_internal_redirect(text, r); rq->status = AM_DONE; } else if (rq->status == AM_REDIRECT) { apr_table_add(r->headers_out, "Location", text); ap_custom_response(r, HTTP_MOVED_TEMPORARILY, text); } else { if (rq->status == AM_PDP_DONE) { request_rec *sr = ap_sub_req_method_uri(am_method_num_to_str(rq->method), rq->post_data_url, r, NULL); sr->headers_in = r->headers_in; sr->notes = r->notes; am_log_debug(rq->instance_id, "set_custom_response(): issuing sub-request %s to %s", sr->method, rq->post_data_url); ap_run_sub_req(sr); ap_destroy_sub_req(sr); rq->status = AM_DONE; } else { size_t tl = strlen(text); if (ISVALID(cont_type)) { ap_set_content_type(r, cont_type); } ap_set_content_length(r, tl); ap_rwrite(text, (int) tl, r); ap_custom_response(r, am_status_value(rq->status == AM_SUCCESS || rq->status == AM_DONE ? AM_SUCCESS : rq->status), text); ap_rflush(r); } } am_log_info(rq->instance_id, "set_custom_response(): status: %s", am_strerror(rq->status)); return AM_SUCCESS; }
// // Main functions. // static int check_auth_handler(request_rec *rec) { auth_conf* conf = (auth_conf*)ap_get_module_config(rec->per_dir_config, &auth_httprequest_module); context ctx; CURLcode ret; const char* secret, *url; int threaded_mpm; int code=0; AP_LOG_DEBUG(rec, "Incomming %s URI=%s", __FUNCTION__, conf->url); // Check requires. if(!is_auth_httprequest_required(rec)) return DECLINED; // Not required. if(!conf->url[0]) return OK; // URL is empty. AP_LOG_DEBUG(rec, " %s %s", rec->method, rec->uri); // Enable to dump authorize result. if(conf->dump==ENABLED) { ap_add_output_filter(DUMP_AUTH_RESULT, apr_pmemdup(rec->pool, &ctx, sizeof(ctx)), rec, rec->connection); } // Skip nested request. secret = apr_table_get(rec->headers_in, SECRET); if(secret) { AP_LOG_DEBUG(rec, " %s: %s", SECRET, secret); if(strstr(secret, conf->secret)) { AP_LOG_DEBUG(rec, "Check config. Nested request."); rec->user = apr_pstrdup(rec->pool, conf->url); return OK; } } // Initialize callback-context. ctx.curl = curl_easy_init(); ctx.rec = rec; ctx.headers = NULL; ctx.status = 0; // Initialize libcurl for MPM. ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm); curl_easy_setopt(ctx.curl, CURLOPT_NOSIGNAL, threaded_mpm); // Bypass request headers, set 'X-Auth-HttpRequest-URI'. apr_table_do(each_headers_proc, &ctx, rec->headers_in, NULL); each_headers_proc(&ctx, X_AUTH_HTTPREQUEST_URL, rec->uri); each_headers_proc(&ctx, X_AUTH_HTTPREQUEST_METHOD, rec->method); if(conf->secret[0]) each_headers_proc(&ctx, SECRET, conf->secret); // Setup URL to bypass response headers and body. curl_easy_setopt(ctx.curl, CURLOPT_URL, url = apr_psprintf(rec->pool, conf->url, rec->uri)); curl_easy_setopt(ctx.curl, CURLOPT_CUSTOMREQUEST, "HEAD"); curl_easy_setopt(ctx.curl, CURLOPT_HTTPHEADER, ctx.headers); curl_easy_setopt(ctx.curl, CURLOPT_USERAGENT, apr_psprintf(rec->pool, "%s %s", VERSION, curl_version())); curl_easy_setopt(ctx.curl, CURLOPT_WRITEHEADER, &ctx); curl_easy_setopt(ctx.curl, CURLOPT_HEADERFUNCTION, curl_header_proc); // Request. ret = curl_easy_perform(ctx.curl); curl_easy_getinfo(ctx.curl, CURLINFO_RESPONSE_CODE, &code); AP_LOG_DEBUG(rec, "curl result(%d) %d", ret, code); // Cleanup. curl_slist_free_all(ctx.headers); curl_easy_cleanup(ctx.curl); // Result. if(ret==0) { if(is_break_status(code)) { // Break request, set custom response. if(conf->errdoc) { char* msg = apr_psprintf(rec->pool, conf->errdoc, code); AP_LOG_DEBUG(rec, "Custom response: %s", msg); ap_custom_response(rec, code, msg); } return code; } if(is_authorized_status(code)) { // Set 'REMOTE_USER' and 'AUTH_TYPE'. rec->user = apr_pstrdup(rec->pool, conf->url); // => ENV['REMOTE_USER'] AP_LOG_DEBUG(rec, "== AUTHORIZED(%s, %s)", rec->ap_auth_type, rec->user); } else { AP_LOG_DEBUG(rec, "== PATH THRU"); } } else { static const char* const ce[8] = { "", "E_PROTOCOL", "E_INIT", "E_MALFORMAT", "E_MALFORMAT_USER", "E_PROXY", "E_HOST", "E_CONNECT", }; AP_LOG_WARN(rec, "Check config. http resuest failed [%s] %s(CURLcode = %d)", url, ((ret<8)? ce[ret]: ce[0]), ret); } return OK; }
/************************************************** * Authentication phase * * - If AuthType != Persona, do nothing * - Handle POSTed assertions ("null" -> logout) * - If we have a cookie, set up user context **************************************************/ static int Auth_persona_check_cookie(request_rec *r) { char *szCookieValue=NULL; char *szRemoteIP=NULL; const char *assertion=NULL; if (!persona_authn_active(r)) { return DECLINED; } ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, ERRTAG "Auth_persona_check_cookie"); // We'll trade you a valid assertion for a session cookie! // this is a programmatic XHR request. persona_config_t *conf = ap_get_module_config(r->server->module_config, &authnz_persona_module); assertion = apr_table_get(r->headers_in, PERSONA_ASSERTION_HEADER); if (assertion) { if (strcmp(r->method, "POST")) { r->status = HTTP_METHOD_NOT_ALLOWED; ap_set_content_type(r, "application/json"); const char *error = "{\"status\": \"failure\", \"reason\":" "\"login must be performed with POST\"}"; ap_rwrite(error, strlen(error), r); return DONE; } if (!strcmp(assertion, "null")) { sendResetCookie(r); r->status = HTTP_OK; const char *status = "{\"status\": \"okay\"}"; ap_set_content_type(r, "application/json"); ap_rwrite(status, strlen(status), r); return DONE; } VerifyResult res = processAssertion(r, assertion); ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO, 0,r,ERRTAG "Assertion received '%s'", assertion); if (res->verifiedEmail) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, ERRTAG "email '%s' verified, vouched for by issuer '%s'", res->verifiedEmail, res->identityIssuer); Cookie cookie = apr_pcalloc(r->pool, sizeof(struct _Cookie)); cookie->verifiedEmail = res->verifiedEmail; cookie->identityIssuer = res->identityIssuer; cookie->created = apr_time_sec(r->request_time); sendSignedCookie(r, conf->secret, cookie); return DONE; } else { assert(res->errorResponse != NULL); r->status = HTTP_INTERNAL_SERVER_ERROR; ap_set_content_type(r, "application/json"); ap_rwrite(res->errorResponse, strlen(res->errorResponse), r); // upon assertion verification failure we return JSON explaining why return DONE; } } // handle logout via LogoutPath hit before letting valid cookies through if (conf->logout_path->len && !strncmp(r->uri, conf->logout_path->data, conf->logout_path->len)) { return process_logout(r); } // if there's a valid cookie, allow the user through szCookieValue = extractCookie(r, conf->secret, PERSONA_COOKIE_NAME); Cookie cookie = NULL; if (szCookieValue && (cookie = validateCookie(r, conf->secret, szCookieValue))) { r->user = (char *) cookie->verifiedEmail; apr_table_setn(r->notes, PERSONA_ISSUER_NOTE, cookie->identityIssuer); apr_table_setn(r->subprocess_env, "REMOTE_USER", cookie->verifiedEmail); ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r, ERRTAG "Valid auth cookie found, passthrough"); ap_custom_response(r, 401, (const char*) build_error_html); ap_custom_response(r, 403, (const char*) build_error_html); return OK; } ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r, ERRTAG "Persona cookie not found; not authorized! RemoteIP:%s",szRemoteIP); r->status = HTTP_UNAUTHORIZED; ap_set_content_type(r, "text/html"); ap_rwrite(src_signin_html, sizeof(src_signin_html), r); ap_rprintf(r, "var loggedInUser = undefined;\n"); ap_rwrite(PERSONA_END_PAGE, sizeof(PERSONA_END_PAGE), r); return DONE; }