mercoledì, Febbraio 5, 2025
nerd

Apache mod auth form with OTP support as separated field

In questi giorni ho avuto la necessità di modificare il modulo di autenticazione mod_auth_form di apache per aggiungere il supporto dell’OTP come campo separato e non per forza accodato alla password (questo perchè ho la necessità di salvare separatamente i due campi per successivi utilizzi in backend).

Con questa piccola patch si ottengono due nuovi parametri di configurazione inerenti a mod_auth_form, ovvero:

AuthFormOtp = Permette di impostare il nome del campo form che cotiene il campo OTP (come per AuthFormPassword) [default httpd_otp]
AuthFormOtpReuse = se impostato ad On rimanda il token otp accodato alla password al provider di autenticazione scelto anche quando tutte le credenziali arrivano dalla sessione (cookie nel nostro caso) [default off]

La logica di funzionamento è molto semplice; se nella POST il campo httpd_otp NON esiste il modulo funziona in maniera tradizionale, invece se questo campo è presente allora la password e l’otp vengono uniti in una unica stringa ed inviati al sottostante provider autenticazione scelto.
Il salvataggio dei dati nella sessione avviene mantendendo separati user password e otp.

Attenzione, l’otp e la password vengono uniti SOLO nel caso di una autenticazione proveniente da form (quindi una post http), se la ri-autenticazione sta avvenendo mediante la sessione (es: cookie) l’otp viene ignorato perchè, verosimilmente, sarà scaduto… questo comportamento però modificabile tramite l’apposita riga di configurazione AuthFormOtpReuse.

Ecco la patch:

--- mod_auth_form.c.orig	2014-06-03 14:14:22.000000000 +0200
+++ mod_auth_form.c	2018-02-09 10:11:56.274877918 +0100
@@ -40,6 +40,8 @@
#define FORM_REDIRECT_HANDLER "form-redirect-handler"
#define MOD_AUTH_FORM_HASH "site"
+#define MOD_SESSION_OTP "otp"
+
static int (*ap_session_load_fn) (request_rec * r, session_rec ** z) = NULL;
static apr_status_t (*ap_session_get_fn)(request_rec * r, session_rec * z,
const char *key, const char **value) = NULL;
@@ -59,10 +61,14 @@
int username_set;
const char *password;
int password_set;
+    const char *otp;
+    int otp_set;
apr_size_t form_size;
int form_size_set;
int fakebasicauth;
int fakebasicauth_set;
+    int otpreuse;
+    int otpreuse_set;
const char *location;
int location_set;
const char *method;
@@ -95,6 +101,7 @@
/* default form field names */
conf->username = "httpd_username";
conf->password = "httpd_password";
+    conf->otp = "httpd_otp";
conf->location = "httpd_location";
conf->method = "httpd_method";
conf->mimetype = "httpd_mimetype";
@@ -118,12 +125,16 @@
new->username_set = add->username_set || base->username_set;
new->password = (add->password_set == 0) ? base->password : add->password;
new->password_set = add->password_set || base->password_set;
+    new->otp = (add->otp_set == 0) ? base->otp : add->otp;
+    new->otp_set = add->otp_set || base->otp_set;
new->location = (add->location_set == 0) ? base->location : add->location;
new->location_set = add->location_set || base->location_set;
new->form_size = (add->form_size_set == 0) ? base->form_size : add->form_size;
new->form_size_set = add->form_size_set || base->form_size_set;
new->fakebasicauth = (add->fakebasicauth_set == 0) ? base->fakebasicauth : add->fakebasicauth;
new->fakebasicauth_set = add->fakebasicauth_set || base->fakebasicauth_set;
+    new->otpreuse = (add->otpreuse_set == 0) ? base->otpreuse : add->otpreuse;
+    new->otpreuse_set = add->otpreuse_set || base->otpreuse_set;
new->method = (add->method_set == 0) ? base->method : add->method;
new->method_set = add->method_set || base->method_set;
new->mimetype = (add->mimetype_set == 0) ? base->mimetype : add->mimetype;
@@ -227,6 +238,14 @@
return check_string(cmd, password);
}
+static const char *set_cookie_form_otp(cmd_parms * cmd, void *config, const char *otp)
+{
+    auth_form_config_rec *conf = (auth_form_config_rec *) config;
+    conf->otp = otp;
+    conf->otp_set = 1;
+    return check_string(cmd, otp);
+}
+
static const char *set_cookie_form_method(cmd_parms * cmd, void *config, const char *method)
{
auth_form_config_rec *conf = (auth_form_config_rec *) config;
@@ -342,6 +361,14 @@
return NULL;
}
+static const char *set_disable_otp_reuse(cmd_parms * cmd, void *config, int flag)
+{
+    auth_form_config_rec *conf = (auth_form_config_rec *) config;
+    conf->otpreuse = flag;
+    conf->otpreuse_set = 1;
+    return NULL;
+}
+
static const char *set_disable_no_store(cmd_parms * cmd, void *config, int flag)
{
auth_form_config_rec *conf = (auth_form_config_rec *) config;
@@ -358,6 +385,8 @@
"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("AuthFormOtp", set_cookie_form_otp, NULL, OR_AUTHCFG,
+                  "The field of the login form carrying the OTP"),
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."),
@@ -396,6 +425,10 @@
NULL, OR_AUTHCFG,
"Set to 'On' to pass through authentication to the rest of the "
"server as a basic authentication header."),
+    AP_INIT_FLAG("AuthFormOtpReuse", set_disable_otp_reuse,
+                 NULL, OR_AUTHCFG,
+                 "Set to 'On' for reuse OTP number from cookie and send'it to "
+                 "to authentication provider."),
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 "
@@ -432,7 +465,7 @@
* notes table.
*/
static void set_notes_auth(request_rec * r,
-                                const char *user, const char *pw,
+                                const char *user, const char *pw, const char *otp,
const char *method, const char *mimetype)
{
apr_table_t *notes = NULL;
@@ -456,6 +489,9 @@
if (pw) {
apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-pw", NULL), pw);
}
+    if (otp) {
+        apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-otp", NULL), otp);
+    }
if (method) {
apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-method", NULL), method);
}
@@ -471,7 +507,7 @@
*/
static void get_notes_auth(request_rec *r,
const char **user, const char **pw,
-                           const char **method, const char **mimetype)
+                           const char **method, const char **mimetype, const char **otp)
{
const char *authname;
request_rec *m = r;
@@ -493,6 +529,9 @@
if (pw) {
*pw = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-pw", NULL));
}
+    if (otp) {
+        *otp = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-otp", NULL));
+    }
if (method) {
*method = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-method", NULL));
}
@@ -506,9 +545,9 @@
}
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
-                  "from notes: user: %s, pw: %s, method: %s, mimetype: %s",
-                  user ? *user : "", pw ? *pw : "",
-                  method ? *method : "", mimetype ? *mimetype : "");
+                  "from notes: user: %s, pw: %s, method: %s, mimetype: %s, otp: %s",
+                  user ? *user : "", pw ? *pw : "", 
+                  method ? *method : "", mimetype ? *mimetype : "",otp ? *otp : "");
}
@@ -519,7 +558,7 @@
* and/or password will be removed from the session.
*/
static apr_status_t set_session_auth(request_rec * r,
-                                     const char *user, const char *pw, const char *site)
+                                     const char *user, const char *pw, const char *site, const char *otp)
{
const char *hash = NULL;
const char *authname = ap_auth_name(r);
@@ -533,6 +572,7 @@
ap_session_load_fn(r, &z);
ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_USER, NULL), user);
ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_PW, NULL), pw);
+    ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_OTP, NULL), otp);
ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_AUTH_FORM_HASH, NULL), hash);
return APR_SUCCESS;
@@ -544,10 +584,12 @@
* notes table, if present.
*/
static apr_status_t get_session_auth(request_rec * r,
-                                     const char **user, const char **pw, const char **hash)
+                                     const char **user, const char **pw, const char **hash, const char **otp)
{
const char *authname = ap_auth_name(r);
session_rec *z = NULL;
+    auth_form_config_rec *conf = ap_get_module_config(r->per_dir_config,
+                                                      &auth_form_module);
ap_session_load_fn(r, &z);
@@ -557,6 +599,11 @@
if (pw) {
ap_session_get_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_PW, NULL), pw);
}
+    if (conf->otpreuse) {
+	    if (otp) {
+	        ap_session_get_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_OTP, NULL), otp);
+	    }
+    }
if (hash) {
ap_session_get_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_AUTH_FORM_HASH, NULL), hash);
}
@@ -568,9 +615,10 @@
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
"from session: " MOD_SESSION_USER ": %s, " MOD_SESSION_PW
-                  ": %s, " MOD_AUTH_FORM_HASH ": %s",
+                  ": %s, " MOD_AUTH_FORM_HASH ": %s, " MOD_SESSION_OTP ": %s (reuse %s)" ,
user ? *user : "", pw ? *pw : "",
-                  hash ? *hash : "");
+                  hash ? *hash : "", otp ? *otp : "",
+                  conf->otpreuse ? "On" : "Off");
return APR_SUCCESS;
@@ -590,12 +638,14 @@
static int get_form_auth(request_rec * r,
const char *username,
const char *password,
+                             const char *otp,
const char *location,
const char *method,
const char *mimetype,
const char *body,
const char **sent_user,
const char **sent_pw,
+                             const char **sent_otp,
const char **sent_loc,
const char **sent_method,
const char **sent_mimetype,
@@ -612,7 +662,7 @@
char *buffer;
/* have we isolated the user and pw before? */
-    get_notes_auth(r, sent_user, sent_pw, sent_method, sent_mimetype);
+    get_notes_auth(r, sent_user, sent_pw, sent_method, sent_mimetype, sent_otp);
if (*sent_user && *sent_pw) {
return OK;
}
@@ -639,6 +689,14 @@
buffer[len] = 0;
*sent_pw = buffer;
}
+        else if (otp && !strcmp(pair->name, otp) && sent_otp) {
+            apr_brigade_length(pair->value, 1, &len);
+            size = (apr_size_t) len;
+            buffer = apr_palloc(r->pool, size + 1);
+            apr_brigade_flatten(pair->value, buffer, &size);
+            buffer[len] = 0;
+            *sent_otp = buffer;
+        }
else if (location && !strcmp(pair->name, location) && sent_loc) {
apr_brigade_length(pair->value, 1, &len);
size = (apr_size_t) len;
@@ -669,11 +727,12 @@
}
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
-                  "from form: user: %s, pw: %s, method: %s, mimetype: %s, location: %s",
+                  "from form: user: %s, pw: %s, method: %s, mimetype: %s, location: %s, otp: %s",
sent_user ? *sent_user : "", sent_pw ? *sent_pw : "",
sent_method ? *sent_method : "",
sent_mimetype ? *sent_mimetype : "",
-                  sent_loc ? *sent_loc : "");
+                  sent_loc ? *sent_loc : "",
+		  sent_otp ? *sent_otp : "");
/* set the user, even though the user is unauthenticated at this point */
if (sent_user && *sent_user) {
@@ -702,7 +761,7 @@
* save away the username, password, mimetype and method, so that they
* are available should the auth need to be run again.
*/
-    set_notes_auth(r, *sent_user, *sent_pw, sent_method ? *sent_method : NULL,
+    set_notes_auth(r, *sent_user, *sent_pw, *sent_otp ? *sent_otp : NULL, sent_method ? *sent_method : NULL,
sent_mimetype ? *sent_mimetype : NULL);
return OK;
@@ -756,12 +815,20 @@
*
* Return an HTTP code.
*/
-static int check_authn(request_rec * r, const char *sent_user, const char *sent_pw)
+static int check_authn(request_rec * r, const char *sent_user, const char *sent_pw, const char *sent_otp)
{
authn_status auth_result;
authn_provider_list *current_provider;
auth_form_config_rec *conf = ap_get_module_config(r->per_dir_config,
&auth_form_module);
+    char *sent_secret = NULL;
+
+    // -lm
+    if (sent_otp) {
+	sent_secret = apr_pstrcat(r->pool, sent_pw, sent_otp, NULL);
+    } else {
+	sent_secret = apr_pstrcat(r->pool, sent_pw, NULL);
+    }
current_provider = conf->providers;
do {
@@ -794,7 +861,12 @@
break;
}
-        auth_result = provider->check_password(r, sent_user, sent_pw);
+	ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+                  "provider->check_password - sent_user : %s, sent_secret: %s (pw: %s - otp: %s)", 
+		  sent_user, sent_secret, sent_pw, sent_otp);
+
+        auth_result = provider->check_password(r, sent_user, sent_secret);
+        //auth_result = provider->check_password(r, sent_user, sent_pw);
apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);
@@ -883,7 +955,7 @@
{
auth_form_config_rec *conf = ap_get_module_config(r->per_dir_config,
&auth_form_module);
-    const char *sent_user = NULL, *sent_pw = NULL, *sent_hash = NULL;
+    const char *sent_user = NULL, *sent_pw = NULL, *sent_hash = NULL, *sent_otp = NULL;
const char *sent_loc = NULL, *sent_method = "GET", *sent_mimetype = NULL;
const char *current_auth = NULL;
const char *err;
@@ -919,11 +991,11 @@
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);
+    get_notes_auth(r, &sent_user, &sent_pw, &sent_method, &sent_mimetype, &sent_otp);
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);
+        res = get_session_auth(r, &sent_user, &sent_pw, &sent_hash, &sent_otp);
}
else {
@@ -941,7 +1013,7 @@
/* otherwise test for a normal password match */
if (APR_SUCCESS == res && sent_user && sent_pw) {
-        rv = check_authn(r, sent_user, sent_pw);
+        rv = check_authn(r, sent_user, sent_pw, sent_otp);
if (OK == rv) {
fake_basic_authentication(r, conf, sent_user, sent_pw);
return OK;
@@ -990,9 +1062,9 @@
ap_run_insert_filter(rr);
/* parse the form by reading the subrequest */
-        rv = get_form_auth(rr, conf->username, conf->password, conf->location,
+        rv = get_form_auth(rr, conf->username, conf->password, conf->otp, conf->location,
conf->method, conf->mimetype, conf->body,
-                           &sent_user, &sent_pw, &sent_loc, &sent_method,
+                           &sent_user, &sent_pw, &sent_otp, &sent_loc, &sent_method,
&sent_mimetype, &sent_body, conf);
/* make sure any user detected within the subrequest is saved back to
@@ -1028,10 +1100,10 @@
/* check the authn in the main request, based on the username found */
if (OK == rv) {
-            rv = check_authn(r, sent_user, sent_pw);
+            rv = check_authn(r, sent_user, sent_pw, sent_otp);
if (OK == rv) {
fake_basic_authentication(r, conf, sent_user, sent_pw);
-                set_session_auth(r, sent_user, sent_pw, conf->site);
+                set_session_auth(r, sent_user, sent_pw, conf->site, sent_otp);
if (sent_loc) {
apr_table_set(r->headers_out, "Location", sent_loc);
return HTTP_MOVED_TEMPORARILY;
@@ -1115,7 +1187,7 @@
auth_form_config_rec *conf;
const char *err;
-    const char *sent_user = NULL, *sent_pw = NULL, *sent_loc = NULL;
+    const char *sent_user = NULL, *sent_pw = NULL, *sent_otp = NULL, *sent_loc = NULL;
int rv;
if (strcmp(r->handler, FORM_LOGIN_HANDLER)) {
@@ -1131,14 +1203,14 @@
conf = ap_get_module_config(r->per_dir_config, &auth_form_module);
-    rv = get_form_auth(r, conf->username, conf->password, conf->location,
+    rv = get_form_auth(r, conf->username, conf->password, conf->otp, conf->location,
NULL, NULL, NULL,
-                       &sent_user, &sent_pw, &sent_loc,
+                       &sent_user, &sent_pw, &sent_otp, &sent_loc,
NULL, NULL, NULL, conf);
if (OK == rv) {
-        rv = check_authn(r, sent_user, sent_pw);
+        rv = check_authn(r, sent_user, sent_pw, sent_otp);
if (OK == rv) {
-            set_session_auth(r, sent_user, sent_pw, conf->site);
+            set_session_auth(r, sent_user, sent_pw, conf->site, sent_otp);
if (sent_loc) {
apr_table_set(r->headers_out, "Location", sent_loc);
return HTTP_MOVED_TEMPORARILY;
@@ -1202,7 +1274,7 @@
conf = ap_get_module_config(r->per_dir_config, &auth_form_module);
/* remove the username and password, effectively logging the user out */
-    set_session_auth(r, NULL, NULL, NULL);
+    set_session_auth(r, NULL, NULL, NULL, NULL);
/*
* make sure the logout page is never cached - otherwise the logout won't
@@ -1249,7 +1321,7 @@
}
/* get the method and mimetype from the notes */
-    get_notes_auth(r, NULL, NULL, &sent_method, &sent_mimetype);
+    get_notes_auth(r, NULL, NULL, &sent_method, &sent_mimetype, NULL);
if (r->kept_body && sent_method && sent_mimetype) {

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *