/* Licensed to the Apache Software Foundation (ASF) under one or more *contributorlicenseagreements.SeetheNOTICEfiledistributedwith *thisworkforadditionalinformationregardingcopyrightownership. *TheASFlicensesthisfiletoYouundertheApacheLicense,Version2.0 *(the"License");youmaynotusethisfileexceptincompliancewith *theLicense.YoumayobtainacopyoftheLicenseat * *http://www.apache.org/licenses/LICENSE-2.0 * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense.
*/
#include"apr_strings.h" #include"apr_lib.h"/* for apr_isspace */ #include"apr_base64.h"/* for apr_base64_decode et al */ #define APR_WANT_STRFUNC /* for strcasecmp */ #include"apr_want.h"
typedefstruct {
authn_provider_list *providers; char *dir; int authoritative; int authoritative_set; constchar *site; int site_set; constchar *username; int username_set; constchar *password; int password_set;
apr_size_t form_size; int form_size_set; int fakebasicauth; int fakebasicauth_set; constchar *location; int location_set; constchar *method; int method_set; constchar *mimetype; int mimetype_set; constchar *body; int body_set; int disable_no_store; int disable_no_store_set;
ap_expr_info_t *loginsuccess; int loginsuccess_set;
ap_expr_info_t *loginrequired; int loginrequired_set;
ap_expr_info_t *logout; int logout_set;
} auth_form_config_rec;
if (!newp->provider->check_password) { /* if it doesn't provide the appropriate function, reject it */ return apr_psprintf(cmd->pool, "The '%s' Authn provider doesn't support " "Form Authentication", newp->provider_name);
}
/* Add it to the list now. */ if (!conf->providers) {
conf->providers = newp;
} else {
authn_provider_list *last = conf->providers;
while (last->next) {
last = last->next;
}
last->next = newp;
}
return NULL;
}
/** *Sanitycheckagivenstringthatitexists,isnotempty, *anddoesnotcontainspecialcharacters.
*/ staticconstchar *check_string(cmd_parms * cmd, constchar *string)
{ if (!string || !*string || ap_strchr_c(string, '=') || ap_strchr_c(string, '&')) { return apr_pstrcat(cmd->pool, cmd->directive->directive, " cannot be empty, or contain '=' or '&'.",
NULL);
} return NULL;
}
staticconst command_rec auth_form_cmds[] =
{
AP_INIT_ITERATE("AuthFormProvider", add_authn_provider, NULL, OR_AUTHCFG, "specify the auth providers for a directory or location"),
AP_INIT_TAKE1("AuthFormUsername", set_cookie_form_username, NULL, OR_AUTHCFG, "The field of the login form carrying the username"),
AP_INIT_TAKE1("AuthFormPassword", set_cookie_form_password, NULL, OR_AUTHCFG, "The field of the login form carrying the password"),
AP_INIT_TAKE1("AuthFormLocation", set_cookie_form_location, NULL, OR_AUTHCFG, "The field of the login form carrying the URL to redirect on " "successful login."),
AP_INIT_TAKE1("AuthFormMethod", set_cookie_form_method, NULL, OR_AUTHCFG, "The field of the login form carrying the original request method."),
AP_INIT_TAKE1("AuthFormMimetype", set_cookie_form_mimetype, NULL, OR_AUTHCFG, "The field of the login form carrying the original request mimetype."),
AP_INIT_TAKE1("AuthFormBody", set_cookie_form_body, NULL, OR_AUTHCFG, "The field of the login form carrying the urlencoded original request " "body."),
AP_INIT_TAKE1("AuthFormSize", set_cookie_form_size, NULL, ACCESS_CONF, "Maximum size of body parsed by the form parser"),
AP_INIT_TAKE1("AuthFormLoginRequiredLocation", set_login_required_location,
NULL, OR_AUTHCFG, "If set, redirect the browser to this URL rather than " "return 401 Not Authorized."),
AP_INIT_TAKE1("AuthFormLoginSuccessLocation", set_login_success_location,
NULL, OR_AUTHCFG, "If set, redirect the browser to this URL when a login " "processed by the login handler is successful."),
AP_INIT_TAKE1("AuthFormLogoutLocation", set_logout_location,
NULL, OR_AUTHCFG, "The URL of the logout successful page. An attempt to access an " "URL handled by the handler " FORM_LOGOUT_HANDLER " will result " "in an redirect to this page after logout."),
AP_INIT_TAKE1("AuthFormSitePassphrase", set_site_passphrase,
NULL, OR_AUTHCFG, "If set, use this passphrase to determine whether the user should " "be authenticated. Bypasses the user authentication check on " "every website hit, and is useful for high traffic sites."),
AP_INIT_FLAG("AuthFormAuthoritative", set_authoritative,
NULL, OR_AUTHCFG, "Set to 'Off' to allow access control to be passed along to " "lower modules if the UserID is not known to this module"),
AP_INIT_FLAG("AuthFormFakeBasicAuth", set_fake_basic_auth,
NULL, OR_AUTHCFG, "Set to 'On' to pass through authentication to the rest of the " "server as a basic authentication header."),
AP_INIT_FLAG("AuthFormDisableNoStore", set_disable_no_store,
NULL, OR_AUTHCFG, "Set to 'on' to stop the sending of a Cache-Control no-store header with " "the login screen. This allows the browser to cache the credentials, but " "at the risk of it being possible for the login form to be resubmitted " "and revealed to the backend server through XSS. Use at own risk."),
{NULL}
};
/* find the username and password in the form */
apr_array_header_t *pairs = NULL;
apr_off_t len;
apr_size_t size; int res; char *buffer;
/* have we isolated the user and pw before? */
get_notes_auth(r, sent_user, sent_pw, sent_method, sent_mimetype); if (sent_user && *sent_user && sent_pw && *sent_pw) { return OK;
}
/* These functions return 0 if client is OK, and proper error status *ifnot...eitherHTTP_UNAUTHORIZED,ifwemadeacheck,anditfailed,or *HTTP_INTERNAL_SERVER_ERROR,ifthingsaresototallyconfusedthatwe *couldn'tfigureouthowtotelliftheclientisauthorizedornot. * *IftheyreturnDECLINED,andallothermodulesalsodecline,that's *treatedbytheservercoreasaconfigurationerror,loggedand *reportedassuch.
*/
/* Are we configured to be Form auth? */
current_auth = ap_auth_type(r); if (!current_auth || ap_cstr_casecmp(current_auth, "form")) { return DECLINED;
}
/* *XSSsecuritywarning:usingcookiestostoreprivatedataonlyworks *whentheadministratorhasfullcontroloverthesourcewebsite.When *inforward-proxymode,websitesarepublicbydefinition,andsocan *neverbesecure.Aborttheauthattemptinthiscase.
*/ if (PROXYREQ_PROXY == r->proxyreq) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01809) "form auth cannot be used for proxy " "requests due to XSS risk, access denied: %s", r->uri); return HTTP_INTERNAL_SERVER_ERROR;
}
/* We need an authentication realm. */ if (!ap_auth_name(r)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01810) "need AuthName: %s", r->uri); return HTTP_INTERNAL_SERVER_ERROR;
}
r->ap_auth_type = (char *) current_auth;
/* try get the username and password from the notes, if present */
get_notes_auth(r, &sent_user, &sent_pw, &sent_method, &sent_mimetype); if (!sent_user || !sent_pw || !*sent_user || !*sent_pw) {
/* otherwise try get the username and password from a session, if present */
res = get_session_auth(r, &sent_user, &sent_pw, &sent_hash);
} else {
res = APR_SUCCESS;
}
/* first test whether the site passphrase matches */ if (APR_SUCCESS == res && sent_user && sent_hash && sent_pw) {
rv = check_site(r, conf->site, sent_user, sent_hash); if (OK == rv) {
fake_basic_authentication(r, conf, sent_user, sent_pw); return OK;
}
}
/* otherwise test for a normal password match */ if (APR_SUCCESS == res && sent_user && sent_pw) {
rv = check_authn(r, sent_user, sent_pw); if (OK == rv) {
fake_basic_authentication(r, conf, sent_user, sent_pw); return OK;
}
}
/* create a subrequest of our current uri */
rr = ap_sub_req_lookup_uri(r->uri, r, r->input_filters);
rr->headers_in = r->headers_in;
/* run the insert_filters hook on the subrequest to ensure a body read can *bedoneproperly.
*/
ap_run_insert_filter(rr);
/* parse the form by reading the subrequest */
rv = get_form_auth(rr, conf->username, conf->password, conf->location,
conf->method, conf->mimetype, conf->body,
&sent_user, &sent_pw, &sent_loc, &sent_method,
&sent_mimetype, &sent_body, conf);
/* make sure any user detected within the subrequest is saved back to *themainrequest.
*/
r->user = apr_pstrdup(r->pool, rr->user);
/* we cannot clean up rr at this point, as memory allocated to rr is *referencedfromthemainrequest.Itwillbecleanedupwhenthe *mainrequestiscleanedup.
*/
/* insert the kept_body filter on the main request to guarantee the *inputfilterstackcannotbereadasecondtime,optionallyinject *asavedbodyifonewasspecifiedintheloginform.
*/ if (sent_body && sent_mimetype) {
apr_table_set(r->headers_in, "Content-Type", sent_mimetype);
r->kept_body = sent_body;
} else {
r->kept_body = apr_brigade_create(r->pool, r->connection->bucket_alloc);
}
ap_request_insert_filter_fn(r);
/* did the form ask to change the method? if so, switch in the redirect handler *torelaunchthisrequestasthesubrequestwiththenewmethod.Ifthe *formdidn'tspecifyamethod,thedefaultvalueGETwillforcearedirect.
*/ if (sent_method && strcmp(r->method, sent_method)) {
r->handler = FORM_REDIRECT_HANDLER;
}
/* check the authn in the main request, based on the username found */ if (OK == rv) {
rv = check_authn(r, sent_user, sent_pw); if (OK == rv) {
fake_basic_authentication(r, conf, sent_user, sent_pw);
set_session_auth(r, sent_user, sent_pw, conf->site); if (sent_loc) {
apr_table_set(r->headers_out, "Location", sent_loc); return HTTP_MOVED_TEMPORARILY;
} if (conf->loginsuccess) { constchar *loginsuccess = ap_expr_str_exec(r,
conf->loginsuccess, &err); if (!err) {
apr_table_set(r->headers_out, "Location", loginsuccess); return HTTP_MOVED_TEMPORARILY;
} else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02339) "Can't evaluate login success expression: %s", err); return HTTP_INTERNAL_SERVER_ERROR;
}
}
}
}
/* did the user ask to be redirected on login success? */ if (sent_loc) {
apr_table_set(r->headers_out, "Location", sent_loc);
rv = HTTP_MOVED_TEMPORARILY;
}
if (strcmp(r->handler, FORM_LOGIN_HANDLER)) { return DECLINED;
}
if (r->method_number != M_POST) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01811) "the " FORM_LOGIN_HANDLER " only supports the POST method for %s",
r->uri); return HTTP_METHOD_NOT_ALLOWED;
}
if (strcmp(r->handler, FORM_REDIRECT_HANDLER)) { return DECLINED;
}
/* get the method and mimetype from the notes */
get_notes_auth(r, NULL, NULL, &sent_method, &sent_mimetype);
if (r->kept_body && sent_method && sent_mimetype) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01812) "internal redirect to method '%s' and body mimetype '%s' for the " "uri: %s", sent_method, sent_mimetype, r->uri);
} else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01813) "internal redirect requested but one or all of method, mimetype or " "body are NULL: %s", r->uri); return HTTP_INTERNAL_SERVER_ERROR;
}
/* return the underlying error, or OK on success */ return r->status == HTTP_OK || r->status == OK ? OK : r->status;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.