overworked has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I'm near completing my little module for our project, but have run into something I'm not sure how to handle.

Project specs.
Client comes to website\s the module authenticates by checking IP against a central Database. IF the IP is not allowed to access we redirect them to a login page. If the IP is cleared to view the site then they need to be allowed to see the site.

The issue I’m having

Where the client’s IP is cleared to see the website, if I use a redirect I fall into a endless loop but I can’t seem to find any other method to do this. I would also like them to go directly to the page they are trying to reference.


Here is the code I have

package Apache2::Authclients;
use strict;
use DBI;
use CGI qw(:standard);
use Apache2::Connection ();
use Apache2::RequestRec (); # for $r->content_type
use Apache2::RequestIO (); # for $r->puts
use Apache2::Const -compile => ':common';
sub handler {
my $r = shift;
my $product = $r->dir_config('product');# Grab Var From Dir on which site
my $uri = $r->uri(); #incoming URL
my $c = $r->connection();
my $time = scalar localtime();
my $remote_sa = $c->remote_ip(); # icoming IP
my $result = &check_ip($remote_sa, $product); # Call to check for access 0 = NO 1 =YES
if ($results == 1) {
$r->content_type('text/html');
$r->puts(<<END);
<HTML><HEAD><meta http-equiv="REFRESH" content="0";url=" . $uri . """></HEAD><BODY></BODY></HTML>
END
return Apache2::Const::OK;
}
else
{
$r->content_type('text/html');
$r->puts(<<END);
<HTML><HEAD><meta http-equiv="REFRESH" content="0;url=<some URL> "></HEAD><BODY></BODY></HTML>
END
return Apache2::Const::OK;
}
}
  • Comment on Apache2 Mod_perl 2 without a endless loop of redirect

Replies are listed 'Best First'.
Re: Apache2 Mod_perl 2 without a endless loop of redirect
by tachyon-II (Chaplain) on Apr 25, 2008 at 06:21 UTC

    Lots of useless code. Not clear where check_ip lives or the need for DBI or CGI. Basically all you need is:

    package Apache2::Authclients; use Apache2::RequestRec (); # for $r->content_type use Apache2::Connection (); # for $c->remote_ip use Apache2::SubRequest (); # for $r->internal_redirect use Apache2::Const -compile => ':common'; sub handler { my $r = shift; my $c = $r->connection(); if ( check_ip($c->remote_ip(), $r->dir_config('product')) ) { $r->internal_redirect($r->uri); } else { $r->internal_redirect('/path/to/login'); } }

    Note that this code has a serious bug. You seem to assume that the remote_ip will be unique. If I am (say) at a university going through a proxy server (just about all connections will go through a proxy somewhere) the remote_ip for many connections will be the same. Thus if several people on campus were accessing your site simultaneously they would all have the same remote ip (you don't see their real ip which will be 10.x.x.x or 192.168.x.x or similar. The usual/common way to handle this is to assign a session cookie following a successful login. The logic then becomes if valid_session do stuff else login. A successful login give you a valid session key.

    Session control and login is a common problem with multiple CPAN modular solutions. Have a look at Apache2::AuthCookie Apache2::AuthCookieDBI for example. No reason you can't roll your own session framework. No need to either as there are literally dozens of pre-rolled solutions, highly likely to work out of the box.

      Hello,

      Thank you to everyone who as reponsed very good pointers, Tachyon-II thank you for the advice, we authenicate through IP based,
      so lets say a University has access to the website which we see as one IP but many users are viewing the site this is acceptable.
      We will later add cookie's but we must first crawl before we can walk.

      I also took note of your code you posted and again thank you.
      How ever I'm still having the same issue, I have tried a number of differant
      options based on your example and did some googling on some leads but nothing seems to work for me.

      So to make it easilier I have added pretty much everything and converted to your example so your not guessing on what I'm trying to do.

      package Apache2::Authclients;
      use strict;
      use DBI;
      use CGI qw(:standard);
      use Apache2::RequestRec (); # for $r->content_type
      use Apache2::Connection (); # for $c->remote_ip
      use Apache2::SubRequest (); # for $r->internal_redirect
      use Apache2::Const -compile => ':common';


      sub handler
      {
      my $r = shift;
      my $c = $r->connection();


      if ( check_ip($c->remote_ip(), $r->dir_config('product')) )
      {
      $r->internal_redirect($r->uri);
      }
      else {
      $r->internal_redirect('/path/to/login');
      }


      sub check_ip
      {
      my ($ip, $product) = @_;
      my $user;
      my $conn = DBI->connect("DBI:Sybase:<NAME-DATABASE-SERVER>", "<USERNAME>", "<PASSWORD>") || die DBI->errstr;
      $conn->do("<NAME-DATABASE>") || die DBI->errstr;
      my $qry = "exec <STORED-PROCEDURE> '" . $ip . "','" . $product . "'";
      my $smt = $conn->prepare($qry) || die DBI->errstr;
      $smt->execute() || die DBI->errstr;
      while(my $var = $smt->fetchrow_arrayref)
      {
      $user = $var->[0];
      }


      $smt = undef;
      $conn->disconnect;
      return $user;
      }
      }
      1;

      I have also included my apache Dir.

      <VirtualHost *>
      DocumentRoot /var/www/html/<product>
      ServerName <product_DNS_Name>


      <Directory "/var/www/html/<product>">
      SetHandler modperl
      PerlSetVar product <product>
      PerlResponseHandler Apache2::Authclients


      allow from all
      Options +Indexes
      </Directory>


      ScriptAlias /cgi-bin/ /var/www/cgi-bin/
      <Directory "/var/www/cgi-bin">
      AllowOverride None
      Options None
      Order allow,deny
      Allow from all
      </Directory>
      </VirtualHost>

      Apache/2.0.55
      mod_perl/2.0.2
      Perl/v5.8.7


      I'm not totally sure on if the apache Dir is correctly done so I have included this as well.


      The DBI is used to make a connection to the database which checks for IP and product access, it returns a 0 or 1.
      For the CGI I need because of the dir_config.

      Again thank you all for taking the time to look at my issues.
      this is the first time I have really asked issues like this on a forum and I must say I am impressed with everyones enthusiasm to help with quick response times.

      cheers
      overworked

        Please do not roll this yourself. It is extremely broken. The whole reason mod_perl is fast is persistence. You have a non persistent DB connection which is just totally wrong. Connecting to a database is slow. In mod_perl you connect once, use lots (and handle unexpected disconnections). Compiling scripts is slow. In mod_perl you don't use anything in cgi-bin. You need proper session control. Saying you want to build it broken and fix it later is just plain stupid.

        Lot's of people have spent lots of time on this task. Please use 1 of the many session control modules to do your sessioning properly. Please use one of the persistent database connection modules ie Apache2::DBI to handle this. Please use CPAN!!!!! Do it right the first time.

        Have a read of this to get an idea of some basic design concepts. Have a look at this and this online mod_perl book and the sample chapter on authentication available free online out of The mod_perl Developer's cookbook

Re: Apache2 Mod_perl 2 without a endless loop of redirect
by TOD (Friar) on Apr 25, 2008 at 03:12 UTC
    to actually recognize where the redirect loops come from i should have to take a look at the /etc/apache2/sites-available/xxx.conf file. i assume that there you define your Apache2::AuthClients module to be the content handler for your site. thus every request to the location described in that config file will be answered by your module.
    however, there are two ways for solving your problem: 1) use the $r->internal_redirect_handler method. you'll find an explanation of it in the docs on Apache2::SubRequest. 2.) why do you return an OK when actually you want a redirect? there is a http response code indicating a redirect: 301 (permanent redirect, probably not what you need), and 302 (temporary redirect). i don't know for the moment what the Apache2::Const denotations are, but a quick glance at the docs on Apache2::Response revealed a method called $r->custom_response which might be of a help.
    --------------------------------
    masses are the opiate for religion.
      The return codes from apache handlers are not the same as HTTP codes. Some of them are for historical reasons, but it can't be counted on. HTTP codes are used in the headers and apache constants are used as handler return values.