How do I implement cookie based auth for a Perl website on shared hosting? - perl

I'm very new to Perl, and I have absolutely no idea how to approach this. We have an old Perl application which previously used Apache auth; we'd like to replace this with a cookie based form-style authentication. I understand that this is very case-specific, and there is no one answer as such, but some general tips would be much appreciated.
Will I need to edit all .pl files in the website? Or is there a "golden hammer" solution I can use? Is there something on CPAN I can use? We're using Perl v5.8.8 if it matters, and we're using Apache 2 shared hosting. I am happy to provide additional information as is necessary.

For the authentication to be recognized/required, it will need to be checked by the .pl file that initially receives the user's request. So the answer to whether all .pl files will need to be changed depends on how your application is structured:
If the user goes to http://myserver.com/one.pl to do the first thing and http://myserver.com/two.pl to do the second thing, then, yes, you'll need to change them all because they're all receiving requests individually.
If the user goes to http://myserver.com/dispatch.pl?mode=one for the first thing and http://myserver.com/dispatch.pl?mode=two for the second thing and dispatch.pl calls either one.pl or two.pl behind the scenes based on the mode parameter, then you only need to change dispatch.pl, since it's the only one directly receiving requests from the user.
Edited to add: If you're dealing with the first model, then I'd strongly recommend setting up an external module (.pm file) with the cookie-handling code and calling that from each of your individual .pl files instead of duplicating that code all over the place. Ideally, this would let you get by with only a few lines of added code in each .pl:
use MyCookieHandlingModule qw(verify_cookie redirect_to_login);
my $q = CGI->new; # ...unless you're already using CGI in object-oriented mode
redirect_to_login unless verify_cookie($q);

You could do it at a level outside the Perl program.

Thanks for your answers guys, but I eventually decided on CGI::Session::Auth::DBI which works well on shared hosting.

Related

Creating a custom powershell module without exposing code

I want to create a custom powershell module that I can distribute without exposing the code. The script includes API calls with app specific private keys that I don't want to compromise. I've seen a lot of discussions about this over the years, but nothing that really solves my problem.
Is there a good way to create a custom powershell module without exposing the underlying code? I want to be able to distribute the powershell module, for others to import or install.
this may be what you are looking for : https://www.powershellgallery.com/packages/ps2exe/1.0.11
but be careful, the API key will still be in the compiled file at someplace. You can try and cipher it, but if it's needed for your script, it will be in your file no matter how you try to hide it. the question is why do you need to ship it inside your script in the first place ? I mean that any of your script's user will be using your private key which is likely not what you want to do

Modern core method of uploading file in Perl

I'm looking to write a script that lets a user upload an image from a webpage, for later use on that website. As per usual, all I can find is examples involving CGI.pm. Are there any core modules that I can use as a replacement?
The Perl core distribution contains no modules for writing web applications. I think you probably want something based on Plack::Request and Plack::Request::Upload (for example Dancer2::Core::Request::Upload).
The solution I ended up going with may not be the best, but it's functioning, and simple.
Using cgi-lib.pl I can simply use
open(VAR, ">output/file.png");
binmode VAR;
print VAR $in{input};
close(VAR);
and it gets the job done.
If there are any notable problems with this, please let me know.

Do away with SOAP::Lite->service() call

I have a fully functional perl script which talks to our SOAP webservice. Today it does that via the SOAP::Lite->service('.../name?WSDL') and then a call to execute() against the returned value. They're now locking down the WSDL so when I hit that I get a 403 error back.
I'm looking for pointers on how to change my script so that it no longer uses the WSDL to figure things out. I do have access to the WSDL itself to look at anything I need to know, but the perl script no longer will.
Since you have the WSDL file, you can use the local copy of it to drop right in with no other changes to your code:
my $soap = SOAP::Lite->service("file:localcopy.wsdl");
If you don't mind switching to SOAP::WSDL, it includes wsdl2perl.pl which will generate all of the perl packages for you:
wsdl2perl.pl file:localcopy.wsdl

How can I get the path info of a top level url using Perl?

What I'm Trying To Achieve
Given a top level URL such as http://www.myapp.com/
If somebody requests:
http://www.myapp.com/questions/id/1
I want to get the "questions/id/1" part and pass it to the appropriate Perl script to retrieve the required resource.
What I've Achieved
Currently I know how to do it if there's an extra level in the url, like so:
http://www.myapp.com/model/questions/id/1
Where "model" is simply a typical Perl CGI script except it has with no ".pl" extension and the Apache perl handler is configured to handle this and the "questions/id/1" part is interpreted as as the path info (via CGI->path_info()) passed to "model".
I go this idea from Andrew Hanenkamp's article on the subject on onlamp.com:
Developing RESTful Web Services in Perl
What's Still Wrong
This approach, however, doesn't work for top level url since there's no place to put "model" or whatever the handler is called. I tried to set default documents settings in the config so that http://www.myapp.com/ to defaults to http://www.myapp.com/modle.
So that typing http://www.myapp.com/questions/id/1 is handled as http://www.myapp.com/model/questions/id/1
However, Apache thinks this is a 404 error.
How can I accomplish this? Is this even a job for Perl or better handled at the Apache config level or maybe tapping into some Apache API to catch 404 errors and extract the "/questions/id/1" part from there? I don't know. Maybe someone here knows. ;-)
Note: Apologies for the long worded and roundabout way of asking this question. I'm not quite sure what's the terminology required to elicit an on-topic answer. Mentioning a four letter word starting with R and ending with T while asking this question previously here and elsewhere has resulted heated discussions on the nature of the said for letter word and also well meaning but unhelpful suggestions to use some framework or another. I'm just curious to know how these frameworks implement this feature and I want to implement one in Perl to learn how to to do it.
Update:
One of the suggested answers has led me to try mod_rewrite. Works. However, it's rather impractical to set Apache's conf manually for each mapping. Further searching has let me to the O'Reilly book, "Practical mod_perl". In it, Bekman and Cholet wrote about accessing mod_rewrite programmatically via the Apache CPAN package to set the rewrite. Appendix 10 : "mod_rewrite in Perl" Writing some code now to test this book's idea. In the mean time, if there are better ways to accomplish this, please do share.
Conclusion
After prototyping two uri routing / dispatcher (or Whatchamacallit) scripts, one relying on mod_rewrite to call it and the other on ErrorDocument; I've come to the conclusion that mod_rewrite is the correct way to implement this.
The ErrorDocument method is wrong as it does not preserve POST data from the redirected page.
A no go as sending a POST request to http://www.myapp.com/questions to create a new resource is impossible as the POST data is unavailable to the custom error handler script called by ErrorDocument. Furthermore as each request by definition will not access a physical file, thus the Apache's error log will be full of spurios 404 file not found errors. This can be a huge problem is the transaction volume of the server is high. Thanks to everyone for pointing me in the right direction. Now my curiosity is satiated.
You can define rewrite rules in .htaccess file or in Apache configuration file.
See mod_rewrite for details.
In your case .htaccess file might looks like:
AddHandler cgi-script .cgi
Options +ExecCGI
RewriteEngine on
RewriteRule ^(questions/id/.*)$ model.cgi/$1 [L]
This should work if you need handle only /question/id/ requests. But you may want to handle all requests via your Perl application. So actually pass all requests to your app could be good idea. Something like:
RewriteRule ^(.*)$ app.cgi/$1 [L]
And let your application dispatch request than.
Except... there's always some exception. You need to let Apache to serve static files for you. And you need Apache not to serve your application files (executables and configs) as static files. So, most modern Perl frameworks stores static in separate dir, 'public' for example. So you put all your images, css, js, etc in /public and configure Apache in following way:
RewriteCond %{DOCUMENT_ROOT}/public/%{REQUEST_URI} -f
RewriteRule ^(.*) public/$1 [L]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f
RewriteRule ^(.*) myapp.cgi [L]
This example taken from Mojolicious documentation.
Now Apache sends static files to user if user requested something that exists in 'public' and redirects all other requests to your app.
In your app you need to dispatch some requests to some actions. Actually, you need a module that would do this job for you. Routes::Tiny (also available on CPAN) written by Viacheslav Tykhanovskyi is a nice choice.
After all, if you want to know how does frameworks work, why don't you dive into one of them? Mojolicious and Dancer too big, but you may look into something smaller, like Lamework that works over PSGI protocol that becomes standard nowadays.
I strongly advise using a web development framework. This will require a bit of learning but, by the time you have finished, you will realise that your current approach is far from ideal. There are many simple frameworks out there that will let you get up and running quickly. I suggest using Dancer (www.perldancer.org). In Dancer, setting routes is as simple as the example below.
get '/' => sub { 'Hello world!' }
As an aside, it is very unlikely that you want to be using CGI. CGI typically has very poor performance and is basically defunct. I suggest you look into FastCGI and PSGI, both of which are available in Apache.
You can catch the 404 error and handle it with a cgi script. In your top-level .htaccess file (docroot/.htaccess):
ErrorDocument 404 /cgi/my-script.sh
Then in your handler script (my-script.sh) the original path will be passed as the enviromnent variable REDIRECT_URL. But make sure your handler script sets the HTTP status correctly by adding in a Status: 200 OK header. Here's a sample cgi script (/cgi/my-script.sh):
#!/bin/sh
echo Status: 200 OK
echo Content-type: text/plain
echo
echo Your url was $REDIRECT_URL
(I'm not recommending using bourne shell for writing cgi scripts, but it illustrates the method).
You can put the ErrorDocument setting in your httpd.conf file also, but any change then requires a server restart; putting it in .htaccess makes it much easier to tweak at runtime.
Apache reference on custom error handling: http://httpd.apache.org/docs/2.1/custom-error.html
If you are using mod_perl, it's easier and cleaner (not to mention better performing) to set it up as a perl handler; again in the top-level .htaccess file (or httpd.conf):
SetHandler perl-script
PerlHandler MyThing::HandlerPackage
where MyThing::HandlerPackage is the perl module that defines an appropriate handler sub.

zend framework under document root in subdir

I developed a application with Zend Framework and now I want to be able to place the app in an subdirectory of a Documentroot.
e.g. http://www.example.com/myapp/
I read quite a lot of Docu how this could work, but all in all these solutions don´t fit my needs. Is there a trivial way to do the subdir thing, without adding the concrete path to any file which generates the pages.
There are some examples in the net, where a basePath is set in the application enviroment and so there is a method call bevor each "form" creation which prepends the path before the link.
$form->setAction($this->_request->getBaseUrl() . $this->_helper->url('sign'));
This was from: http://johnmee.com/2008/11/zend-framework-quickstart-tutorial-deploy-to-a-subdirectory-instead-of-web-root/
But this is only works for small examples, I have tons of forms, tons of views and tons of scripts. I can´t belive this (lets call it hack :) ) is the only solution to do this.
Any ideas?
You don't have to do anything special. See my tutorial at http://akrabat.com/Zend-framework-tutorial which is developed entirely within a sub-directory.
As they say on the web page:
I’m told this last issue has been
lodged has a defect and not necessary
from releases “1.7″ and beyond. The
helper->url will henceforth prepend
the baseUrl to its result.
So you should be fine. Do you actually use the $form->setAction() method on every form already? Because if you use it in combination with the url helper, the baseUrl will already be included.