Apache HTTPD
mod_auth_form.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr_strings.h"
18#include "apr_lib.h" /* for apr_isspace */
19#include "apr_base64.h" /* for apr_base64_decode et al */
20#define APR_WANT_STRFUNC /* for strcasecmp */
21#include "apr_want.h"
22
23#include "ap_config.h"
24#include "httpd.h"
25#include "http_config.h"
26#include "http_core.h"
27#include "http_log.h"
28#include "http_protocol.h"
29#include "http_request.h"
30#include "ap_provider.h"
31#include "util_md5.h"
32#include "ap_expr.h"
33
34#include "mod_auth.h"
35#include "mod_session.h"
36#include "mod_request.h"
37
38#define FORM_LOGIN_HANDLER "form-login-handler"
39#define FORM_LOGOUT_HANDLER "form-logout-handler"
40#define FORM_REDIRECT_HANDLER "form-redirect-handler"
41#define MOD_AUTH_FORM_HASH "site"
42
46
49
82
84{
85 auth_form_config_rec *conf = apr_pcalloc(p, sizeof(*conf));
86
87 conf->dir = d;
88 /* Any failures are fatal. */
89 conf->authoritative = 1;
90
91 /* form size defaults to 8k */
93
94 /* default form field names */
95 conf->username = "httpd_username";
96 conf->password = "httpd_password";
97 conf->location = "httpd_location";
98 conf->method = "httpd_method";
99 conf->mimetype = "httpd_mimetype";
100 conf->body = "httpd_body";
101
102 return conf;
103}
104
105static void *merge_auth_form_dir_config(apr_pool_t * p, void *basev, void *addv)
106{
110
111 new->providers = !add->providers ? base->providers : add->providers;
112 new->authoritative = (add->authoritative_set == 0) ? base->authoritative : add->authoritative;
113 new->authoritative_set = add->authoritative_set || base->authoritative_set;
114 new->site = (add->site_set == 0) ? base->site : add->site;
115 new->site_set = add->site_set || base->site_set;
116 new->username = (add->username_set == 0) ? base->username : add->username;
117 new->username_set = add->username_set || base->username_set;
118 new->password = (add->password_set == 0) ? base->password : add->password;
119 new->password_set = add->password_set || base->password_set;
120 new->location = (add->location_set == 0) ? base->location : add->location;
121 new->location_set = add->location_set || base->location_set;
122 new->form_size = (add->form_size_set == 0) ? base->form_size : add->form_size;
123 new->form_size_set = add->form_size_set || base->form_size_set;
124 new->fakebasicauth = (add->fakebasicauth_set == 0) ? base->fakebasicauth : add->fakebasicauth;
125 new->fakebasicauth_set = add->fakebasicauth_set || base->fakebasicauth_set;
126 new->method = (add->method_set == 0) ? base->method : add->method;
127 new->method_set = add->method_set || base->method_set;
128 new->mimetype = (add->mimetype_set == 0) ? base->mimetype : add->mimetype;
129 new->mimetype_set = add->mimetype_set || base->mimetype_set;
130 new->body = (add->body_set == 0) ? base->body : add->body;
131 new->body_set = add->body_set || base->body_set;
132 new->disable_no_store = (add->disable_no_store_set == 0) ? base->disable_no_store : add->disable_no_store;
133 new->disable_no_store_set = add->disable_no_store_set || base->disable_no_store_set;
134 new->loginsuccess = (add->loginsuccess_set == 0) ? base->loginsuccess : add->loginsuccess;
135 new->loginsuccess_set = add->loginsuccess_set || base->loginsuccess_set;
136 new->loginrequired = (add->loginrequired_set == 0) ? base->loginrequired : add->loginrequired;
137 new->loginrequired_set = add->loginrequired_set || base->loginrequired_set;
138 new->logout = (add->logout_set == 0) ? base->logout : add->logout;
139 new->logout_set = add->logout_set || base->logout_set;
140
141 return new;
142}
143
144static const char *add_authn_provider(cmd_parms * cmd, void *config,
145 const char *arg)
146{
149
150 newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list));
151 newp->provider_name = arg;
152
153 /* lookup and cache the actual provider now */
155 newp->provider_name,
157
158 if (newp->provider == NULL) {
159 /*
160 * by the time they use it, the provider should be loaded and
161 * registered with us.
162 */
163 return apr_psprintf(cmd->pool,
164 "Unknown Authn provider: %s",
165 newp->provider_name);
166 }
167
168 if (!newp->provider->check_password) {
169 /* if it doesn't provide the appropriate function, reject it */
170 return apr_psprintf(cmd->pool,
171 "The '%s' Authn provider doesn't support "
172 "Form Authentication", newp->provider_name);
173 }
174
175 /* Add it to the list now. */
176 if (!conf->providers) {
177 conf->providers = newp;
178 }
179 else {
181
182 while (last->next) {
183 last = last->next;
184 }
185 last->next = newp;
186 }
187
188 return NULL;
189}
190
195static const char *check_string(cmd_parms * cmd, const char *string)
196{
197 if (!string || !*string || ap_strchr_c(string, '=') || ap_strchr_c(string, '&')) {
198 return apr_pstrcat(cmd->pool, cmd->directive->directive,
199 " cannot be empty, or contain '=' or '&'.",
200 NULL);
201 }
202 return NULL;
203}
204
205static const char *set_cookie_form_location(cmd_parms * cmd, void *config, const char *location)
206{
208 conf->location = location;
209 conf->location_set = 1;
210 return check_string(cmd, location);
211}
212
213static const char *set_cookie_form_username(cmd_parms * cmd, void *config, const char *username)
214{
216 conf->username = username;
217 conf->username_set = 1;
218 return check_string(cmd, username);
219}
220
221static const char *set_cookie_form_password(cmd_parms * cmd, void *config, const char *password)
222{
224 conf->password = password;
225 conf->password_set = 1;
226 return check_string(cmd, password);
227}
228
229static const char *set_cookie_form_method(cmd_parms * cmd, void *config, const char *method)
230{
232 conf->method = method;
233 conf->method_set = 1;
234 return check_string(cmd, method);
235}
236
237static const char *set_cookie_form_mimetype(cmd_parms * cmd, void *config, const char *mimetype)
238{
240 conf->mimetype = mimetype;
241 conf->mimetype_set = 1;
242 return check_string(cmd, mimetype);
243}
244
245static const char *set_cookie_form_body(cmd_parms * cmd, void *config, const char *body)
246{
248 conf->body = body;
249 conf->body_set = 1;
250 return check_string(cmd, body);
251}
252
253static const char *set_cookie_form_size(cmd_parms * cmd, void *config,
254 const char *arg)
255{
256 auth_form_config_rec *conf = config;
257 apr_off_t size;
258
259 if (APR_SUCCESS != apr_strtoff(&size, arg, NULL, 10)
261 return "AuthCookieFormSize must be a size in bytes, or zero.";
262 }
263 conf->form_size = (apr_size_t)size;
264 conf->form_size_set = 1;
265
266 return NULL;
267}
268
269static const char *set_login_required_location(cmd_parms * cmd, void *config, const char *loginrequired)
270{
272 const char *err;
273
275 &err, NULL);
276 if (err) {
277 return apr_psprintf(cmd->pool,
278 "Could not parse login required expression '%s': %s",
279 loginrequired, err);
280 }
281 conf->loginrequired_set = 1;
282
283 return NULL;
284}
285
286static const char *set_login_success_location(cmd_parms * cmd, void *config, const char *loginsuccess)
287{
289 const char *err;
290
292 &err, NULL);
293 if (err) {
294 return apr_psprintf(cmd->pool,
295 "Could not parse login success expression '%s': %s",
296 loginsuccess, err);
297 }
298 conf->loginsuccess_set = 1;
299
300 return NULL;
301}
302
303static const char *set_logout_location(cmd_parms * cmd, void *config, const char *logout)
304{
306 const char *err;
307
309 &err, NULL);
310 if (err) {
311 return apr_psprintf(cmd->pool,
312 "Could not parse logout required expression '%s': %s",
313 logout, err);
314 }
315 conf->logout_set = 1;
316
317 return NULL;
318}
319
320static const char *set_site_passphrase(cmd_parms * cmd, void *config, const char *site)
321{
323 conf->site = site;
324 conf->site_set = 1;
325 return NULL;
326}
327
328static const char *set_authoritative(cmd_parms * cmd, void *config, int flag)
329{
331 conf->authoritative = flag;
332 conf->authoritative_set = 1;
333 return NULL;
334}
335
336static const char *set_fake_basic_auth(cmd_parms * cmd, void *config, int flag)
337{
339 conf->fakebasicauth = flag;
340 conf->fakebasicauth_set = 1;
341 return NULL;
342}
343
344static const char *set_disable_no_store(cmd_parms * cmd, void *config, int flag)
345{
347 conf->disable_no_store = flag;
348 conf->disable_no_store_set = 1;
349 return NULL;
350}
351
353{
355 "specify the auth providers for a directory or location"),
357 "The field of the login form carrying the username"),
359 "The field of the login form carrying the password"),
361 "The field of the login form carrying the URL to redirect on "
362 "successful login."),
364 "The field of the login form carrying the original request method."),
366 "The field of the login form carrying the original request mimetype."),
368 "The field of the login form carrying the urlencoded original request "
369 "body."),
371 "Maximum size of body parsed by the form parser"),
372 AP_INIT_TAKE1("AuthFormLoginRequiredLocation", set_login_required_location,
374 "If set, redirect the browser to this URL rather than "
375 "return 401 Not Authorized."),
376 AP_INIT_TAKE1("AuthFormLoginSuccessLocation", set_login_success_location,
378 "If set, redirect the browser to this URL when a login "
379 "processed by the login handler is successful."),
380 AP_INIT_TAKE1("AuthFormLogoutLocation", set_logout_location,
382 "The URL of the logout successful page. An attempt to access an "
383 "URL handled by the handler " FORM_LOGOUT_HANDLER " will result "
384 "in an redirect to this page after logout."),
385 AP_INIT_TAKE1("AuthFormSitePassphrase", set_site_passphrase,
387 "If set, use this passphrase to determine whether the user should "
388 "be authenticated. Bypasses the user authentication check on "
389 "every website hit, and is useful for high traffic sites."),
390 AP_INIT_FLAG("AuthFormAuthoritative", set_authoritative,
392 "Set to 'Off' to allow access control to be passed along to "
393 "lower modules if the UserID is not known to this module"),
394 AP_INIT_FLAG("AuthFormFakeBasicAuth", set_fake_basic_auth,
396 "Set to 'On' to pass through authentication to the rest of the "
397 "server as a basic authentication header."),
398 AP_INIT_FLAG("AuthFormDisableNoStore", set_disable_no_store,
400 "Set to 'on' to stop the sending of a Cache-Control no-store header with "
401 "the login screen. This allows the browser to cache the credentials, but "
402 "at the risk of it being possible for the login form to be resubmitted "
403 "and revealed to the backend server through XSS. Use at own risk."),
404 {NULL}
405};
406
407module AP_MODULE_DECLARE_DATA auth_form_module;
408
410{
412 &auth_form_module);
413
414 if (conf->location && ap_strchr_c(conf->location, ':')) {
415 apr_table_setn(r->err_headers_out, "Location", conf->location);
416 }
417}
418
420 const char *auth_type)
421{
422 if (ap_cstr_casecmp(auth_type, "form"))
423 return DECLINED;
424
426 return OK;
427}
428
434 const char *user, const char *pw,
435 const char *method, const char *mimetype)
436{
437 apr_table_t *notes = NULL;
438 const char *authname;
439
440 /* find the main request */
441 while (r->main) {
442 r = r->main;
443 }
444 /* find the first redirect */
445 while (r->prev) {
446 r = r->prev;
447 }
448 notes = r->notes;
449
450 /* have we isolated the user and pw before? */
452 if (user) {
453 apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-user", NULL), user);
454 }
455 if (pw) {
456 apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-pw", NULL), pw);
457 }
458 if (method) {
459 apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-method", NULL), method);
460 }
461 if (mimetype) {
462 apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-mimetype", NULL), mimetype);
463 }
464
465}
466
472 const char **user, const char **pw,
473 const char **method, const char **mimetype)
474{
475 const char *authname;
476 request_rec *m = r;
477
478 /* find the main request */
479 while (m->main) {
480 m = m->main;
481 }
482 /* find the first redirect */
483 while (m->prev) {
484 m = m->prev;
485 }
486
487 /* have we isolated the user and pw before? */
489 if (user) {
490 *user = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-user", NULL));
491 }
492 if (pw) {
493 *pw = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-pw", NULL));
494 }
495 if (method) {
496 *method = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-method", NULL));
497 }
498 if (mimetype) {
499 *mimetype = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-mimetype", NULL));
500 }
501
502 /* set the user, even though the user is unauthenticated at this point */
503 if (user && *user) {
504 r->user = (char *) *user;
505 }
506
508 "from notes: user: %s, pw: %s, method: %s, mimetype: %s",
509 user ? *user : "<null>", pw ? *pw : "<null>",
510 method ? *method : "<null>", mimetype ? *mimetype : "<null>");
511
512}
513
521 const char *user, const char *pw, const char *site)
522{
523 const char *hash = NULL;
524 const char *authname = ap_auth_name(r);
525 session_rec *z = NULL;
526
527 if (site) {
528 hash = ap_md5(r->pool,
529 (unsigned char *) apr_pstrcat(r->pool, user, ":", site, NULL));
530 }
531
536
537 return APR_SUCCESS;
538
539}
540
546 const char **user, const char **pw, const char **hash)
547{
548 const char *authname = ap_auth_name(r);
549 session_rec *z = NULL;
550
552
553 if (user) {
555 }
556 if (pw) {
558 }
559 if (hash) {
561 }
562
563 /* set the user, even though the user is unauthenticated at this point */
564 if (user && *user) {
565 r->user = (char *) *user;
566 }
567
569 "from session: " MOD_SESSION_USER ": %s, " MOD_SESSION_PW
570 ": %s, " MOD_AUTH_FORM_HASH ": %s",
571 user ? *user : "<null>", pw ? *pw : "<null>",
572 hash ? *hash : "<null>");
573
574 return APR_SUCCESS;
575
576}
577
590 const char *username,
591 const char *password,
592 const char *location,
593 const char *method,
594 const char *mimetype,
595 const char *body,
596 const char **sent_user,
597 const char **sent_pw,
598 const char **sent_loc,
599 const char **sent_method,
600 const char **sent_mimetype,
603{
604 /* sanity check - are we a POST request? */
605
606 /* find the username and password in the form */
610 int res;
611 char *buffer;
612
613 /* have we isolated the user and pw before? */
615 if (sent_user && *sent_user && sent_pw && *sent_pw) {
616 return OK;
617 }
618
619 res = ap_parse_form_data(r, NULL, &pairs, -1, conf->form_size);
620 if (res != OK) {
621 return res;
622 }
623 while (pairs && !apr_is_empty_array(pairs)) {
625 if (username && !strcmp(pair->name, username) && sent_user) {
626 apr_brigade_length(pair->value, 1, &len);
627 size = (apr_size_t) len;
628 buffer = apr_palloc(r->pool, size + 1);
630 buffer[len] = 0;
631 *sent_user = buffer;
632 }
633 else if (password && !strcmp(pair->name, password) && sent_pw) {
634 apr_brigade_length(pair->value, 1, &len);
635 size = (apr_size_t) len;
636 buffer = apr_palloc(r->pool, size + 1);
638 buffer[len] = 0;
639 *sent_pw = buffer;
640 }
641 else if (location && !strcmp(pair->name, location) && sent_loc) {
642 apr_brigade_length(pair->value, 1, &len);
643 size = (apr_size_t) len;
644 buffer = apr_palloc(r->pool, size + 1);
646 buffer[len] = 0;
647 *sent_loc = buffer;
648 }
649 else if (method && !strcmp(pair->name, method) && sent_method) {
650 apr_brigade_length(pair->value, 1, &len);
651 size = (apr_size_t) len;
652 buffer = apr_palloc(r->pool, size + 1);
654 buffer[len] = 0;
656 }
657 else if (mimetype && !strcmp(pair->name, mimetype) && sent_mimetype) {
658 apr_brigade_length(pair->value, 1, &len);
659 size = (apr_size_t) len;
660 buffer = apr_palloc(r->pool, size + 1);
662 buffer[len] = 0;
664 }
665 else if (body && !strcmp(pair->name, body) && sent_body) {
666 *sent_body = pair->value;
667 }
668 }
669
671 "from form: user: %s, pw: %s, method: %s, mimetype: %s, location: %s",
672 sent_user ? *sent_user : "<null>", sent_pw ? *sent_pw : "<null>",
673 sent_method ? *sent_method : "<null>",
674 sent_mimetype ? *sent_mimetype : "<null>",
675 sent_loc ? *sent_loc : "<null>");
676
677 /* set the user, even though the user is unauthenticated at this point */
678 if (sent_user && *sent_user) {
679 r->user = (char *) *sent_user;
680 }
681
682 /* a missing username or missing password means auth denied */
683 if (!sent_user || !*sent_user) {
684
686 "form parsed, but username field '%s' was missing or empty, unauthorized",
687 username);
688
689 return HTTP_UNAUTHORIZED;
690 }
691 if (!sent_pw || !*sent_pw) {
692
694 "form parsed, but password field '%s' was missing or empty, unauthorized",
695 password);
696
697 return HTTP_UNAUTHORIZED;
698 }
699
700 /*
701 * save away the username, password, mimetype and method, so that they
702 * are available should the auth need to be run again.
703 */
706
707 return OK;
708}
709
710/* These functions return 0 if client is OK, and proper error status
711 * if not... either HTTP_UNAUTHORIZED, if we made a check, and it failed, or
712 * HTTP_INTERNAL_SERVER_ERROR, if things are so totally confused that we
713 * couldn't figure out how to tell if the client is authorized or not.
714 *
715 * If they return DECLINED, and all other modules also decline, that's
716 * treated by the server core as a configuration error, logged and
717 * reported as such.
718 */
719
720
733static int check_site(request_rec * r, const char *site, const char *sent_user, const char *sent_hash)
734{
735
736 if (site && sent_user && sent_hash) {
737 const char *hash = ap_md5(r->pool,
738 (unsigned char *) apr_pstrcat(r->pool, sent_user, ":", site, NULL));
739
740 if (!strcmp(sent_hash, hash)) {
741 return OK;
742 }
743 else {
744 return AUTH_USER_NOT_FOUND;
745 }
746 }
747
748 return DECLINED;
749
750}
751
758static int check_authn(request_rec * r, const char *sent_user, const char *sent_pw)
759{
763 &auth_form_module);
764
766 do {
767 const authn_provider *provider;
768
769 /*
770 * For now, if a provider isn't set, we'll be nice and use the file
771 * provider.
772 */
773 if (!current_provider) {
777
778 if (!provider || !provider->check_password) {
780 "no authn provider configured");
782 break;
783 }
785 }
786 else {
787 provider = current_provider->provider;
789 }
790
791 if (!sent_user || !sent_pw) {
793 break;
794 }
795
797
799
800 /* Something occurred. Stop checking. */
802 break;
803 }
804
805 /* If we're not really configured for providers, stop now. */
806 if (!conf->providers) {
807 break;
808 }
809
811 } while (current_provider);
812
813 if (auth_result != AUTH_GRANTED) {
814 int return_code;
815
816 /* If we're not authoritative, then any error is ignored. */
817 if (!(conf->authoritative) && auth_result != AUTH_DENIED) {
818 return DECLINED;
819 }
820
821 switch (auth_result) {
822 case AUTH_DENIED:
824 "user '%s': authentication failure for \"%s\": "
825 "password Mismatch",
826 sent_user, r->uri);
828 break;
831 "user '%s' not found: %s", sent_user, r->uri);
833 break;
835 default:
836 /*
837 * We'll assume that the module has already said what its error
838 * was in the logs.
839 */
841 break;
842 }
843
844 /* If we're returning 401, tell them to try again. */
847 }
848
849/* TODO: Flag the user somehow as to the reason for the failure */
850
851 return return_code;
852 }
853
854 return OK;
855
856}
857
858/* fake the basic authentication header if configured to do so */
860 const char *user, const char *pw)
861{
862 if (conf->fakebasicauth) {
863 char *basic = apr_pstrcat(r->pool, user, ":", pw, NULL);
864 apr_size_t size = (apr_size_t) strlen(basic);
865 char *base64 = apr_palloc(r->pool,
866 apr_base64_encode_len(size + 1) * sizeof(char));
868 apr_table_setn(r->headers_in, "Authorization",
869 apr_pstrcat(r->pool, "Basic ", base64, NULL));
870 }
871}
872
882{
884 &auth_form_module);
885 const char *sent_user = NULL, *sent_pw = NULL, *sent_hash = NULL;
886 const char *sent_loc = NULL, *sent_method = "GET", *sent_mimetype = NULL;
887 const char *current_auth = NULL;
888 const char *err;
890 int rv = HTTP_UNAUTHORIZED;
891
892 /* Are we configured to be Form auth? */
894 if (!current_auth || ap_cstr_casecmp(current_auth, "form")) {
895 return DECLINED;
896 }
897
898 /*
899 * XSS security warning: using cookies to store private data only works
900 * when the administrator has full control over the source website. When
901 * in forward-proxy mode, websites are public by definition, and so can
902 * never be secure. Abort the auth attempt in this case.
903 */
904 if (PROXYREQ_PROXY == r->proxyreq) {
906 "form auth cannot be used for proxy "
907 "requests due to XSS risk, access denied: %s", r->uri);
909 }
910
911 /* We need an authentication realm. */
912 if (!ap_auth_name(r)) {
914 "need AuthName: %s", r->uri);
916 }
917
918 r->ap_auth_type = (char *) current_auth;
919
920 /* try get the username and password from the notes, if present */
922 if (!sent_user || !sent_pw || !*sent_user || !*sent_pw) {
923
924 /* otherwise try get the username and password from a session, if present */
926
927 }
928 else {
930 }
931
932 /* first test whether the site passphrase matches */
933 if (APR_SUCCESS == res && sent_user && sent_hash && sent_pw) {
934 rv = check_site(r, conf->site, sent_user, sent_hash);
935 if (OK == rv) {
937 return OK;
938 }
939 }
940
941 /* otherwise test for a normal password match */
942 if (APR_SUCCESS == res && sent_user && sent_pw) {
944 if (OK == rv) {
946 return OK;
947 }
948 }
949
950 /*
951 * If we reach this point, the request should fail with access denied,
952 * except for one potential scenario:
953 *
954 * If the request is a POST, and the posted form contains user defined fields
955 * for a username and a password, and the username and password are correct,
956 * then return the response obtained by a GET to this URL.
957 *
958 * If an additional user defined location field is present in the form,
959 * instead of a GET of the current URL, redirect the browser to the new
960 * location.
961 *
962 * As a further option, if the user defined fields for the type of request,
963 * the mime type of the body of the request, and the body of the request
964 * itself are present, replace this request with a new request of the given
965 * type and with the given body.
966 *
967 * Otherwise access is denied.
968 *
969 * Reading the body requires some song and dance, because the input filters
970 * are not yet configured. To work around this problem, we create a
971 * subrequest and use that to create a sane filter stack we can read the
972 * form from.
973 *
974 * The main request is then capped with a kept_body input filter, which has
975 * the effect of guaranteeing the input stack can be safely read a second time.
976 *
977 */
981
982 /* create a subrequest of our current uri */
984 rr->headers_in = r->headers_in;
985
986 /* run the insert_filters hook on the subrequest to ensure a body read can
987 * be done properly.
988 */
990
991 /* parse the form by reading the subrequest */
992 rv = get_form_auth(rr, conf->username, conf->password, conf->location,
993 conf->method, conf->mimetype, conf->body,
995 &sent_mimetype, &sent_body, conf);
996
997 /* make sure any user detected within the subrequest is saved back to
998 * the main request.
999 */
1000 r->user = apr_pstrdup(r->pool, rr->user);
1001
1002 /* we cannot clean up rr at this point, as memory allocated to rr is
1003 * referenced from the main request. It will be cleaned up when the
1004 * main request is cleaned up.
1005 */
1006
1007 /* insert the kept_body filter on the main request to guarantee the
1008 * input filter stack cannot be read a second time, optionally inject
1009 * a saved body if one was specified in the login form.
1010 */
1011 if (sent_body && sent_mimetype) {
1012 apr_table_set(r->headers_in, "Content-Type", sent_mimetype);
1014 }
1015 else {
1017 }
1019
1020 /* did the form ask to change the method? if so, switch in the redirect handler
1021 * to relaunch this request as the subrequest with the new method. If the
1022 * form didn't specify a method, the default value GET will force a redirect.
1023 */
1026 }
1027
1028 /* check the authn in the main request, based on the username found */
1029 if (OK == rv) {
1031 if (OK == rv) {
1034 if (sent_loc) {
1035 apr_table_set(r->headers_out, "Location", sent_loc);
1037 }
1038 if (conf->loginsuccess) {
1039 const char *loginsuccess = ap_expr_str_exec(r,
1040 conf->loginsuccess, &err);
1041 if (!err) {
1042 apr_table_set(r->headers_out, "Location", loginsuccess);
1044 }
1045 else {
1047 "Can't evaluate login success expression: %s", err);
1049 }
1050 }
1051 }
1052 }
1053
1054 }
1055
1056 /*
1057 * did the admin prefer to be redirected to the login page on failure
1058 * instead?
1059 */
1060 if (HTTP_UNAUTHORIZED == rv && conf->loginrequired) {
1061 const char *loginrequired = ap_expr_str_exec(r,
1062 conf->loginrequired, &err);
1063 if (!err) {
1064 apr_table_set(r->headers_out, "Location", loginrequired);
1066 }
1067 else {
1069 "Can't evaluate login required expression: %s", err);
1071 }
1072 }
1073
1074 /* did the user ask to be redirected on login success? */
1075 if (sent_loc) {
1076 apr_table_set(r->headers_out, "Location", sent_loc);
1078 }
1079
1080
1081 /*
1082 * potential security issue: if we return a login to the browser, we must
1083 * send a no-store to make sure a well behaved browser will not try and
1084 * send the login details a second time if the back button is pressed.
1085 *
1086 * if the user has full control over the backend, the
1087 * AuthCookieDisableNoStore can be used to turn this off.
1088 */
1089 if (HTTP_UNAUTHORIZED == rv && !conf->disable_no_store) {
1090 apr_table_addn(r->headers_out, "Cache-Control", "no-store");
1091 apr_table_addn(r->err_headers_out, "Cache-Control", "no-store");
1092 }
1093
1094 return rv;
1095
1096}
1097
1113{
1115 const char *err;
1116
1117 const char *sent_user = NULL, *sent_pw = NULL, *sent_loc = NULL;
1118 int rv;
1119
1121 return DECLINED;
1122 }
1123
1124 if (r->method_number != M_POST) {
1126 "the " FORM_LOGIN_HANDLER " only supports the POST method for %s",
1127 r->uri);
1129 }
1130
1131 conf = ap_get_module_config(r->per_dir_config, &auth_form_module);
1132
1133 rv = get_form_auth(r, conf->username, conf->password, conf->location,
1134 NULL, NULL, NULL,
1136 NULL, NULL, NULL, conf);
1137 if (OK == rv) {
1139 if (OK == rv) {
1141 if (sent_loc) {
1142 apr_table_set(r->headers_out, "Location", sent_loc);
1144 }
1145 if (conf->loginsuccess) {
1146 const char *loginsuccess = ap_expr_str_exec(r,
1147 conf->loginsuccess, &err);
1148 if (!err) {
1149 apr_table_set(r->headers_out, "Location", loginsuccess);
1151 }
1152 else {
1154 "Can't evaluate login success expression: %s", err);
1156 }
1157 }
1158 return HTTP_OK;
1159 }
1160 }
1161
1162 /* did we prefer to be redirected to the login page on failure instead? */
1163 if (HTTP_UNAUTHORIZED == rv && conf->loginrequired) {
1164 const char *loginrequired = ap_expr_str_exec(r,
1165 conf->loginrequired, &err);
1166 if (!err) {
1167 apr_table_set(r->headers_out, "Location", loginrequired);
1169 }
1170 else {
1172 "Can't evaluate login required expression: %s", err);
1174 }
1175 }
1176
1177 return rv;
1178
1179}
1180
1193{
1195 const char *err;
1196
1198 return DECLINED;
1199 }
1200
1201 conf = ap_get_module_config(r->per_dir_config, &auth_form_module);
1202
1203 /* remove the username and password, effectively logging the user out */
1205
1206 /*
1207 * make sure the logout page is never cached - otherwise the logout won't
1208 * work!
1209 */
1210 apr_table_addn(r->headers_out, "Cache-Control", "no-store");
1211 apr_table_addn(r->err_headers_out, "Cache-Control", "no-store");
1212
1213 /* if set, internal redirect to the logout page */
1214 if (conf->logout) {
1215 const char *logout = ap_expr_str_exec(r,
1216 conf->logout, &err);
1217 if (!err) {
1218 apr_table_addn(r->headers_out, "Location", logout);
1220 }
1221 else {
1223 "Can't evaluate logout expression: %s", err);
1225 }
1226 }
1227
1228 return HTTP_OK;
1229
1230}
1231
1241{
1242
1243 request_rec *rr = NULL;
1244 const char *sent_method = NULL, *sent_mimetype = NULL;
1245
1247 return DECLINED;
1248 }
1249
1250 /* get the method and mimetype from the notes */
1252
1253 if (r->kept_body && sent_method && sent_mimetype) {
1254
1256 "internal redirect to method '%s' and body mimetype '%s' for the "
1257 "uri: %s", sent_method, sent_mimetype, r->uri);
1258
1261
1262 }
1263 else {
1265 "internal redirect requested but one or all of method, mimetype or "
1266 "body are NULL: %s", r->uri);
1268 }
1269
1270 /* return the underlying error, or OK on success */
1271 return r->status == HTTP_OK || r->status == OK ? OK : r->status;
1272
1273}
1274
1276 apr_pool_t *ptemp, server_rec *s)
1277{
1278
1285 "You must load mod_session to enable the mod_auth_form "
1286 "functions");
1287 return !OK;
1288 }
1289 }
1290
1296 "You must load mod_request to enable the mod_auth_form "
1297 "functions");
1298 return !OK;
1299 }
1300 }
1301
1302 return OK;
1303}
1304
1322
1324{
1326 create_auth_form_dir_config, /* dir config creater */
1327 merge_auth_form_dir_config, /* dir merger --- default is to override */
1328 NULL, /* server config */
1329 NULL, /* merge server config */
1330 auth_form_cmds, /* command apr_table_t */
1331 register_hooks /* register hooks */
1332};
Symbol export macros and hook functions.
Expression parser.
Apache Provider API.
const char apr_size_t len
Definition ap_regex.h:187
APR-UTIL Base64 Encoding.
static const char base64[]
Definition apr_encode.c:198
APR general purpose library routines.
#define hash(h, r, b, n)
Definition apr_random.c:51
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
APR Standard Headers Support.
static apr_pool_t * pconf
Definition event.c:441
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_FLAG(directive, func, mconfig, where, help)
ap_conf_vector_t * base
#define AP_INIT_ITERATE(directive, func, mconfig, where, help)
void ap_hook_handler(ap_HOOK_handler_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:170
request_rec * r
#define HUGE_STRING_LEN
Definition httpd.h:303
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
const char * ap_auth_name(request_rec *r)
Definition core.c:807
const char * ap_auth_type(request_rec *r)
Definition core.c:793
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_TRACE1
Definition http_log.h:72
#define APLOG_DEBUG
Definition http_log.h:71
void ap_hook_note_auth_failure(ap_HOOK_note_auth_failure_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition protocol.c:2594
void * ap_lookup_provider(const char *provider_group, const char *provider_name, const char *provider_version)
Definition provider.c:99
#define AP_AUTH_INTERNAL_PER_CONF
void ap_hook_check_user_id(ap_HOOK_check_user_id_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition request.c:85
request_rec * ap_sub_req_lookup_uri(const char *new_uri, const request_rec *r, ap_filter_t *next_filter)
Definition request.c:2297
int ap_run_sub_req(request_rec *r)
Definition request.c:2528
int ap_is_initial_req(request_rec *r)
Definition request.c:2567
request_rec * ap_sub_req_method_uri(const char *method, const char *new_uri, const request_rec *r, ap_filter_t *next_filter)
Definition request.c:2242
void ap_hook_check_authn(ap_HOOK_check_user_id_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder, int type)
Definition request.c:2218
void ap_run_insert_filter(request_rec *r)
Definition request.c:96
void const char * arg
Definition http_vhost.h:63
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_RETRIEVE_OPTIONAL_FN(name)
#define APR_OPTIONAL_FN_TYPE(name)
#define AP_EXPR_FLAG_STRING_RESULT
Definition ap_expr.h:68
#define ap_expr_parse_cmd(cmd, expr, flags, err, lookup_fn)
Definition ap_expr.h:340
const char * ap_expr_str_exec(request_rec *r, const ap_expr_info_t *expr, const char **err)
#define ACCESS_CONF
#define OR_AUTHCFG
#define HTTP_OK
Definition httpd.h:490
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define HTTP_MOVED_TEMPORARILY
Definition httpd.h:502
#define HTTP_METHOD_NOT_ALLOWED
Definition httpd.h:513
#define HTTP_UNAUTHORIZED
Definition httpd.h:509
#define HTTP_TEMPORARY_REDIRECT
Definition httpd.h:506
#define MOD_SESSION_USER
Definition mod_session.h:67
#define MOD_SESSION_PW
Definition mod_session.h:73
#define M_POST
Definition httpd.h:594
#define STANDARD20_MODULE_STUFF
int ap_cstr_casecmp(const char *s1, const char *s2)
Definition util.c:3542
#define ap_strchr_c(s, c)
Definition httpd.h:2353
int ap_parse_form_data(request_rec *r, struct ap_filter_t *f, apr_array_header_t **ptr, apr_size_t num, apr_size_t size)
Definition util.c:2787
#define PROXYREQ_PROXY
Definition httpd.h:1134
apr_size_t size
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char apr_int32_t flag
char * buffer
apr_uint32_t apr_pool_t apr_uint32_t apr_pollset_method_e method
Definition apr_poll.h:195
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char char ** last
const char * s
Definition apr_strings.h:95
const void * m
const char const char * password
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
const char * username
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
Authentication and Authorization Extension for Apache.
#define AUTHN_PROVIDER_NAME_NOTE
Definition mod_auth.h:45
#define AUTHN_PROVIDER_VERSION
Definition mod_auth.h:41
#define AUTHN_PROVIDER_GROUP
Definition mod_auth.h:39
#define AUTHN_DEFAULT_PROVIDER
Definition mod_auth.h:43
authn_status
Definition mod_auth.h:64
@ AUTH_GRANTED
Definition mod_auth.h:66
@ AUTH_DENIED
Definition mod_auth.h:65
@ AUTH_GENERAL_ERROR
Definition mod_auth.h:69
@ AUTH_USER_NOT_FOUND
Definition mod_auth.h:68
static apr_OFN_ap_session_set_t * ap_session_set_fn
static int authenticate_form_login_handler(request_rec *r)
static int authenticate_form_authn(request_rec *r)
static int authenticate_form_redirect_handler(request_rec *r)
static void get_notes_auth(request_rec *r, const char **user, const char **pw, const char **method, const char **mimetype)
static const char * set_login_required_location(cmd_parms *cmd, void *config, const char *loginrequired)
#define FORM_LOGOUT_HANDLER
static const char * set_disable_no_store(cmd_parms *cmd, void *config, int flag)
static apr_OFN_ap_session_get_t * ap_session_get_fn
static void note_cookie_auth_failure(request_rec *r)
static int hook_note_cookie_auth_failure(request_rec *r, const char *auth_type)
static void * merge_auth_form_dir_config(apr_pool_t *p, void *basev, void *addv)
static const command_rec auth_form_cmds[]
static apr_status_t set_session_auth(request_rec *r, const char *user, const char *pw, const char *site)
static void(* ap_request_insert_filter_fn)(request_rec *r)
#define FORM_REDIRECT_HANDLER
static const char * set_cookie_form_mimetype(cmd_parms *cmd, void *config, const char *mimetype)
static const char * set_fake_basic_auth(cmd_parms *cmd, void *config, int flag)
static const char * add_authn_provider(cmd_parms *cmd, void *config, const char *arg)
#define FORM_LOGIN_HANDLER
static const char * set_cookie_form_username(cmd_parms *cmd, void *config, const char *username)
static apr_OFN_ap_session_load_t * ap_session_load_fn
static void register_hooks(apr_pool_t *p)
static void fake_basic_authentication(request_rec *r, auth_form_config_rec *conf, const char *user, const char *pw)
static void * create_auth_form_dir_config(apr_pool_t *p, char *d)
static int authenticate_form_logout_handler(request_rec *r)
static const char * set_login_success_location(cmd_parms *cmd, void *config, const char *loginsuccess)
static const char * set_site_passphrase(cmd_parms *cmd, void *config, const char *site)
static const char * set_logout_location(cmd_parms *cmd, void *config, const char *logout)
static int authenticate_form_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
static const char * set_cookie_form_body(cmd_parms *cmd, void *config, const char *body)
static const char * set_cookie_form_password(cmd_parms *cmd, void *config, const char *password)
static void set_notes_auth(request_rec *r, const char *user, const char *pw, const char *method, const char *mimetype)
static const char * set_authoritative(cmd_parms *cmd, void *config, int flag)
static int check_site(request_rec *r, const char *site, const char *sent_user, const char *sent_hash)
static const char * set_cookie_form_method(cmd_parms *cmd, void *config, const char *method)
static const char * set_cookie_form_size(cmd_parms *cmd, void *config, const char *arg)
static void(* ap_request_remove_filter_fn)(request_rec *r)
static int get_form_auth(request_rec *r, const char *username, const char *password, const char *location, const char *method, const char *mimetype, const char *body, const char **sent_user, const char **sent_pw, const char **sent_loc, const char **sent_method, const char **sent_mimetype, apr_bucket_brigade **sent_body, auth_form_config_rec *conf)
#define MOD_AUTH_FORM_HASH
static const char * check_string(cmd_parms *cmd, const char *string)
static apr_status_t get_session_auth(request_rec *r, const char **user, const char **pw, const char **hash)
static const char * set_cookie_form_location(cmd_parms *cmd, void *config, const char *location)
static int check_authn(request_rec *r, const char *sent_user, const char *sent_pw)
static void ap_request_insert_filter(request_rec *r)
static void ap_request_remove_filter(request_rec *r)
mod_request private header file
static apr_status_t ap_session_load(request_rec *r, session_rec **z)
Definition mod_session.c:91
static apr_status_t ap_session_get(request_rec *r, session_rec *z, const char *key, const char **value)
static apr_status_t ap_session_set(request_rec *r, session_rec *z, const char *key, const char *value)
Session Module for Apache.
return NULL
Definition mod_so.c:359
const char * username
const char * location
const char * password
ap_expr_info_t * loginrequired
ap_expr_info_t * loginsuccess
authn_provider_list * providers
const char * mimetype
ap_expr_info_t * logout
authn_provider_list * next
Definition mod_auth.h:100
const authn_provider * provider
Definition mod_auth.h:99
const char * provider_name
Definition mod_auth.h:98
authn_status(* check_password)(request_rec *r, const char *user, const char *password)
Definition mod_auth.h:84
struct apr_bucket_alloc_t * bucket_alloc
Definition httpd.h:1201
A structure that represents the current request.
Definition httpd.h:845
char * user
Definition httpd.h:1005
int status
Definition httpd.h:891
char * uri
Definition httpd.h:1016
struct ap_filter_t * output_filters
Definition httpd.h:1070
request_rec * prev
Definition httpd.h:856
const char * handler
Definition httpd.h:994
apr_table_t * notes
Definition httpd.h:985
int method_number
Definition httpd.h:898
apr_pool_t * pool
Definition httpd.h:847
int proxyreq
Definition httpd.h:873
conn_rec * connection
Definition httpd.h:849
apr_bucket_brigade * kept_body
Definition httpd.h:953
apr_table_t * err_headers_out
Definition httpd.h:981
struct ap_filter_t * input_filters
Definition httpd.h:1072
apr_table_t * headers_in
Definition httpd.h:976
request_rec * main
Definition httpd.h:860
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
const char * method
Definition httpd.h:900
char * ap_auth_type
Definition httpd.h:1007
apr_table_t * headers_out
Definition httpd.h:978
A structure to store information for each virtual server.
Definition httpd.h:1322
char * ap_md5(apr_pool_t *p, const unsigned char *string)
Definition util_md5.c:75
Apache MD5 library.