.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.42) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "ReverseProxy::FormFiller 3pm" .TH ReverseProxy::FormFiller 3pm "2022-06-17" "perl v5.34.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" ReverseProxy::FormFiller \- Let Apache fill and submit any html form in place of the user .SH "VERSION" .IX Header "VERSION" Version 0.5 .SH "SYNOPSIS" .IX Header "SYNOPSIS" ReverseProxy::FormFiller makes an Apache server, positioned as a frontal server or as a reverse-proxy, fill and submit html forms in place of users. .PP This is particularly intended for authentication forms, if you want users to be authenticated with some account, but you don't want them to know and type any password. But it also works with any html \s-1POST\s0 form. .PP ReverseProxy::FormFiller is based on Apache2 mod_perl filters. So, you have to enable mod_perl. .SS "Basic Example" .IX Subsection "Basic Example" Assume you want all users requesting some web app to be authenticated as \*(L"jdoe\*(R", but you don't want to publish jdoe's password. If the app's authentication form is located at http://auth.example.com/login.php and looks like .PP .Vb 5 \&
\&
login:
\&
password:
\&
\&
.Ve .PP create an Apache virtualhost called myauth.example.com, looking like : .PP .Vb 2 \& \& ServerName myauth.example.com \& \& PerlModule ReverseProxy::FormFiller \& PerlSetVar FormFillerParamFile "/etc/apache2/FormFiller/example" \& \& ProxyPass / http://auth.example.com/ \& ProxyPassReverse / http://auth.example.com/ \& \& \& RequestHeader unset Accept\-Encoding \& Header unset Content\-Length \& PerlOutputFilterHandler ReverseProxy::FormFiller::output \& \& \& \& PerlInputFilterHandler ReverseProxy::FormFiller::input \& \& .Ve .PP and create a ReverseProxy::FormFiller config file at /etc/apache2/FormFiller/example, looking like .PP .Vb 9 \& form => \*(Aq"#authForm"\*(Aq, \& submit => "true", \& publicFormData => { \& login => \*(Aq"jdoe"\*(Aq, \& password => \*(Aq"fake"\*(Aq, \& }, \& secretFormData => { \& password => \*(Aq"secret"\*(Aq, \& }, .Ve .PP Quotes around strings are necessary for some parameters that are interpreted as perl expressions. Look at \fIReverseProxy::FormFiller config parameters\fR for more details. .SS "Elaborate example" .IX Subsection "Elaborate example" Assume you want some people to be authenticated as \*(L"user\*(R", and some other as \*(L"admin\*(R". .PP Besides, assume just submit form does not work, but it is necessary to click on the button, since it will execute a javascript function. .PP Finally, assume jQuery is not loaded by the web page displaying the form. .PP /etc/apache2/FormFiller/example will look like .PP .Vb 10 \& jQueryUrl => \*(Aqhttp://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js\*(Aq, \& form => \*(Aq"#authForm"\*(Aq, \& submit => \*(Aq"button[type=submit]"\*(Aq, \& publicFormData => { \& login => \*(Aq$ENV{REMOTE_USER} =~ /(rtyler|msmith)/ ? "admin" : "user"\*(Aq, \& password => \*(Aq"fake"\*(Aq, \& }, \& secretFormData => { \& password => \*(Aq$ENV{REMOTE_USER} =~ /(rtyler|msmith)/ ? "admin\-secret" : "user\-secret"\*(Aq, \& }, .Ve .SS "Screwy example" .IX Subsection "Screwy example" Assume you have two authentication forms in the same page, one for the morning and another one for the afternoon : .PP /etc/apache2/FormFiller/example will look like .PP .Vb 11 \& form => \*(Aq(localtime)[2] >= 12 ? "#morningForm" : "#afternoonForm"\*(Aq, \& submit => "false", \& publicFormData => { \& login => \*(Aq"jdoe"\*(Aq, # so, user believe he\*(Aqll be authenticated as "jdoe" \& password => \*(Aq"fake"\*(Aq, \& }, \& secretFormData => { \& # but actually, he\*(Aqll be authenticated as "admin" if he uses Firefox, as "user" else \& login => \*(Aq$ENV{HTTP_USER_AGENT} =~ /Firefox/ ? "admin" : "user"\*(Aq, \& password => \*(Aq$ENV{HTTP_USER_AGENT} =~ /Firefox/ ? "admin\-secret" : "user\-secret"\*(Aq, \& }, .Ve .SS "Framework example" .IX Subsection "Framework example" Some applications based on frameworks either use \s-1HTTP\s0 without \s-1HTML\s0 (e.g Flash), or they send \s-1POST\s0 data out of any \s-1HTML\s0 form. .PP This module allows one to fill any \s-1HTML\s0 field from its jQuery selectors, thanks to the \fIpublicFilledData\fR parameter. .PP On the other hand, you can apply any substitution on \s-1POST\s0 datas, thanks to the \fIpostDataSub\fR parameter \- but it may require some tuning to get the right substitution \s-1PCRE.\s0 .PP Here is an example from a real-life \s-1GWT\s0 application : .PP .Vb 10 \& jQueryUrl => \*(Aq//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js\*(Aq, \& form => \*(Aq"body"\*(Aq, \& submit => \*(Aq"button.genericButton"\*(Aq, \& publicFilledData => { \& \*(Aqinput.gwt\-TextBox\*(Aq => \*(Aq"jdoe"\*(Aq, \& \*(Aqinput.gwt\-PasswordTextBox\*(Aq => \*(Aq"fake"\*(Aq, \& }, \& postDataSub => [ \& \*(Aqs/jdoe\e|fake/jdoe\e|secret/\*(Aq \& ] .Ve .SH "Details of Apache config" .IX Header "Details of Apache config" .SS "Load Module" .IX Subsection "Load Module" This is done by .PP .Vb 1 \& PerlModule ReverseProxy::FormFiller .Ve .PP This directive has to appear once in Apache config. It can be set in server config or in a \f(CW\*(C`\*(C'\fR container. .SS "Set config parameters" .IX Subsection "Set config parameters" This is done by .PP .Vb 1 \& PerlSetVar FormFillerParamFile "/etc/apache2/FormFiller/example" .Ve .PP This directive can be set in server config or in a any container directive (as a \f(CW\*(C`\*(C'\fR container, a \f(CW\*(C`\*(C'\fR container or a \f(CW\*(C`\*(C'\fR container). It is applied only to requests matching the corresponding container directive. .PP This directive can be set several times, so a single server can manage several forms (typically, on different virtualhosts, but you can also manage several forms in the same virtualhost). .SS "Filter response body" .IX Subsection "Filter response body" When Apache has received the response from the remote server (if Apache is used as a reverse-proxy) or from the backend server (if used as a frontend), it rewrites html so as to fill the form and possibly submitting it or clicking on a button. .PP Actually, this is done not by directly overwriting the form, but by including some javascript filling and submitting the form. .PP This is done by the directive .PP .Vb 1 \& PerlOutputFilterHandler ReverseProxy::FormFiller::output .Ve .PP Besides, ReverseProxy::FormFiller::output can not (or not yet) read zipped contents, so \s-1HTTP\s0 request headers \*(L"Content-encoding\*(R" have to be removed. This is done by the directive .PP .Vb 1 \& RequestHeader unset Accept\-Encoding .Ve .PP And ReverseProxy::FormFiller::output can not (or not yet) set Content-Length response header to the modified response body's length. So, remove Content-Length response header to avoid some bugs: .PP .Vb 1 \& Header unset Content\-Length .Ve .PP For performances, it is better to handle only html pages containing the aimed form. So, you should place these directives in a container directive matching the form \s-1URL\s0 (as a \f(CW\*(C`\*(C'\fR directive), so as not to filter any html content. .SS "Filter request body" .IX Subsection "Filter request body" When Apache receives a \s-1POST\s0 request from a client, it rewrites request \s-1POST\s0 body, replacing empty or fake data with secret data. This is done by the directive .PP .Vb 1 \& PerlInputFilterHandler ReverseProxy::FormFiller::input .Ve .PP For performances, it is better to handle only requests to the form \*(L"action\*(R" \s-1URL.\s0 So, you should place this directive in a container directive matching this \s-1URL\s0 (as a \f(CW\*(C`\*(C'\fR directive), so as not to filter any request. .SH "ReverseProxy::FormFiller config parameters" .IX Header "ReverseProxy::FormFiller config parameters" .SS "Config file" .IX Subsection "Config file" ReverseProxy::FormFiller config file looks similar to a .ini file, but it is not. Actually it is simply a hash content. So, don't forget commas ! In case of syntax error, you'll have a message \*(L" content doesn't seem to be a valid perl hash\*(R" in Apache error logs. .SS "Parameters" .IX Subsection "Parameters" Most of config parameters are interpreted as perl expressions, not just as strings. So, they can rely on standard perl functions and request env vars (look at the examples below). These parameters are: .IP "\(bu" 4 form .IP "\(bu" 4 submit .IP "\(bu" 4 publicFormData values .IP "\(bu" 4 publicFilledData values .IP "\(bu" 4 secretFormData values .IP "\(bu" 4 javascript .PP That's why these parameters, if they are set to strings, need quotes around. For example, .PP .Vb 2 \& form => \*(Aq#authForm\*(Aq, # bad ! \& form => \*(Aq"#authForm"\*(Aq, # good ! .Ve .PP Indeed, these parameters are \fIeval\fRed in a piece of code looking like .PP .Vb 1 \& eval "\e$x = $form"; .Ve .PP Well, in some cases quotes are unnecessary, because Perl in laxist enough to work with not-quoted strings: .PP .Vb 4 \& $x = "foo"; # this is right syntax \& $x = foo; # this is lazy syntax, but it works \& $x = "39foo"; # this is right syntax \& $x = 39foo; # this does not work, an error is thrown "Bareword found where operator expected" .Ve .IP "\fBjQueryUrl\fR" 4 .IX Item "jQueryUrl" \&\s-1URL\s0 to load jQuery, since ReverseProxy::FormFiller response filter relies on jQuery (any version >= 1.0) .Sp Optional: if empty or not defined, jQuery is supposed to be already loaded in the web page .IP "\fBform\fR" 4 .IX Item "form" jQuery selector to the form to fill. .Sp Optional: if empty or not defined, first form in web page will be filled. That is, default value is \*(L"form:first\*(R" .Sp Here are few examples : .Sp .Vb 1 \& form => \*(Aq"form#authForm"\*(Aq, \& \& form => \*(Aq"form:last"\*(Aq, \& \& form => \*(Aq(localtime)[2] >= 12 ? "#morningForm" : "#afternoonForm"\*(Aq, \& \& form => \*(Aq$ENV{REMOTE_USER} =~ /(rtyler|msmith)/ ? "#adminForm" : "#userForm"\*(Aq, .Ve .IP "\fBsubmit\fR" 4 .IX Item "submit" To enable form autosubmit, or to automatically click on a button. .Sp It may be \*(L"true\*(R" (autosubmit enabled), \*(L"false\*(R" (autosubmit disabled), or a jQuery selector to the button to click on (this is sometimes useful, when clicking runs a javasript function). .Sp Optional: if empty or not defined, autosubmit is disabled \- that is, default value is \*(L"false\*(R". .Sp For example, .Sp .Vb 1 \& submit => \*(Aqtrue\*(Aq, \& \& submit => \*(Aq"button#login"\*(Aq, .Ve .IP "\fBpublicFormData\fR" 4 .IX Item "publicFormData" Form fields to fill in html form : these data will be seen by user. .Sp Additionnaly, these fields will be controled in \s-1POST\s0 request when the form will be submitted, to prevent malicious users to change any value. .Sp For example, .Sp .Vb 5 \& publicFormData => { \& company => \*(Aq"SnakeOilsInc"\*(Aq, \& user => \*(Aq$ENV{REMOTE_USER} =~ /(rtyler|msmith)/ ? "admin" : "user"\*(Aq, \& password => \*(Aq"hidden"\*(Aq \& }, .Ve .Sp Note that these data are filled through jQuery method '.\fBval()\fR', so it works only with text inputs, password inputs, select tags and textarea, but not with checkboxes and radio buttons. In order to select on radio buttons or check on checkboxes, look at the \fIjavascript\fR parameter. .IP "\fBpublicFilledData\fR" 4 .IX Item "publicFilledData" Input fields to fill, defined by jQuery selectors instead of their name attribute. This is useful if an input field has no name attribute. .Sp .Vb 5 \& publicFilledData => { \& \*(Aqtextarea.company\*(Aq => \*(Aq"SnakeOilsInc"\*(Aq, \& \*(Aqinput#user\*(Aq => \*(Aq$ENV{REMOTE_USER} =~ /(rtyler|msmith)/ ? "user" : $ENV{REMOTE_USER} =~ /dwho/ ? "admin" : "nobody"\*(Aq, \& \*(Aqinput[type=password]\*(Aq => \*(Aq"hidden"\*(Aq \& } .Ve .Sp As same as \fIpublicFormData\fR, these data will be seen by users, and it works only with text inputs, password inputs, select tags and textarea. .Sp Unlike to \fIpublicFormData\fR, these fields are not controled in \s-1POST\s0 request against malicious tampering of values. .Sp Parameters \fIpublicFormData\fR and \fIpublicFilledData\fR can be used together. .IP "\fBsecretFormData\fR" 4 .IX Item "secretFormData" Form fields to fill in request body, in addition or in overload to \fIpublicFormData\fR. The main difference with \fIpublicFormData\fR is that these data will not be filled in the html form, so users can't see them. .Sp .Vb 3 \& secretFormData => { \& password => \*(Aq$ENV{REMOTE_USER} =~ /(rtyler|msmith)/ ? "admin\-secret" : "user\-secret"\*(Aq, \& }, .Ve .IP "\fBpostDataSub\fR" 4 .IX Item "postDataSub" Substitutions to apply to \s-1POST\s0 datas. Substitutions are defined with \s-1PCRE\s0 and may use captures. They may rely on env vars, but not on perl functions. .Sp Parameter \fIpostDataSub\fR is an array ref and not a hash ref (unlike to \fIpublicFormData\fR, \fIpublicFilledData\fR and \fIsecretFormData\fR). Hence substitutions are applied in the order they are defined. .Sp Basic example: .Sp .Vb 3 \& postDataSub => [ \& \*(Aqs/foo/bar/gi\*(Aq, \& ] .Ve .Sp If \s-1POST\s0 data are made of colon-separated values and you want to change 5th value into \*(L"foo\*(R": .Sp .Vb 3 \& postDataSub => [ \& \*(Aqs/^((.+?:){4}).+?:/$1:foo:/\*(Aq # if POST data are made of :\-separated values and you want to change 5th value into "foo" \& ] .Ve .Sp In order to rewrite \s-1POST\s0 data so as to force jdoe's password to \*(L"jdoe-secret\*(R" and rtyler's to \*(L"rtyler-passwd\*(R", whereas these passwords are disclosed \- assume \s-1POST\s0 data is '[login]:[password]' .Sp .Vb 5 \& postDataSub => [ \& \*(Aqs/^.*$/$ENV{REMOTE_USER}:$ENV{REMOTE_USER}/\*(Aq, \& \*(Aqs/jdoe:jdoe/jdoe:jdoe\-secret/\*(Aq, \& \*(Aqs/rtyler:rtyler/rtyler:rtyler\-passwd/\*(Aq \& ] .Ve .IP "\fBjavascript\fR" 4 .IX Item "javascript" Arbitrary javascript code to run after fields are filled, but before posting the form. .Sp If you call jQuery through its shortcut '$', you have to escape it. Use single quotes and double quotes as in the example. .Sp .Vb 1 \& javascript => \*(Aqalert("Hello $ENV{REMOTE_USER}"); \e$(input.mycheckbox).prop("checked", true)\*(Aq .Ve .SH "AUTHOR" .IX Header "AUTHOR" \&\s-1FX\s0 Deltombe, \f(CW\*(C`\*(C'\fR .SH "BUGS" .IX Header "BUGS" Please report any bugs or feature requests to \f(CW\*(C`bug\-reverseproxy\-formfiller at rt.cpan.org\*(C'\fR, or through the web interface at . I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. .SH "SUPPORT" .IX Header "SUPPORT" You can find documentation for this module with the perldoc command. .PP .Vb 1 \& perldoc ReverseProxy::FormFiller .Ve .PP You can also look for information at: .IP "\(bu" 4 \&\s-1RT: CPAN\s0's request tracker .Sp .IP "\(bu" 4 AnnoCPAN: Annotated \s-1CPAN\s0 documentation .Sp .IP "\(bu" 4 \&\s-1CPAN\s0 Ratings .Sp .IP "\(bu" 4 Search \s-1CPAN\s0 .Sp .SH "ACKNOWLEDGEMENTS" .IX Header "ACKNOWLEDGEMENTS" .SH "LICENSE AND COPYRIGHT" .IX Header "LICENSE AND COPYRIGHT" Copyright 2013\-2014 \s-1FX\s0 Deltombe. .PP This program is free software; you can redistribute it and/or modify it under the terms of either: the \s-1GNU\s0 General Public License as published by the Free Software Foundation; or the Artistic License. .PP See http://dev.perl.org/licenses/ for more information.