1
votes

I have a mod_perl PerlAuthzHandler authorizing access to directories served by Apache2. In terms of controlling access it is working well.

A side effect, though, is that it seems to be preventing POST form variables from being available to PHP apps in the protected locations. At least when I comment out the PerlAuthzHandler and reload Apache the PHP app functions again. I think either the full environment is not being inherited by Perl or Perl is sending a cleansed environment on.

Is it possible to ensure that all POST variables are available to the PHP application after authorization?


Details

User authentication is managed by simplesamlphp on this box, the SP, and ADFS, the IdP. The addition to the simplesamlphp installation is the use of PerlAuthzHandler.

Apache configuration

The Apache configuration for the location in question looks like this:

<Location /activity>

   ErrorDocument 401 "/simplesaml/authmemcookie.php"
   AuthName "MCLAnet"
   AuthType Cookie
   Require valid-user

   PerlSetvar Auth_memCookie_SessionTableSize "40"
   PerlAuthzHandler My::simple
   PerlSetVar VALID_GROUP_EXPR "status-acad or staff-g"

</Location>

Authorization handler

The authorization handler retrieves group memberships recorded in setting up the session and compared to a VALID_GROUP_EXPRESSION in the PerlSetVar:

#! /usr/bin/perl

package My::simple;

# Version 1.0  MCLA CSS

use Apache2::Access ();
use Apache2::RequestUtil ();

# load modules that are going to be used
use Data::Dumper;
use CGI qw(:standard);
use CGI::Cookie;
use Cache::Memcached;
use PHP::Serialization qw(serialize unserialize);

# compile (or import) constants
use Apache2::Const -compile => qw(OK FORBIDDEN);

$debug=0;
$debug_file="/tmp/xxx";

dmp('prerun',('test'));

sub handler {

      my $r = shift;

      my $user = $r->user;
      dmp('0 user',$user);

      # ------------------------ get valid group(s) for this session

      my $valid_group_expr=$r->dir_config("VALID_GROUP_EXPR");
      dmp('1 valid group list',$valid_group_expr);

      # -- get the session cooke to retrieve the session <ID>

      $query = new CGI;
      # fetch existing cookies
      my %cookies = CGI::Cookie->fetch;
      # dmp('Cookies',%cookies);

      my $ID = $cookies{'SimpleSAMLSessionID'}->value;
      dmp('2 SimpleSAMLSessionID value',$ID);

      my $SessionID='simpleSAMLphp.session.' . $ID;

      # -- use the session ID to look up the value of memcached key simpleSAMLphp.session.<ID>

      my $cache =  new Cache::Memcached {
         'servers' => ['127.0.0.1:11211'],
         'compress_threshold' => 10_000,
       };

      # Get the value from cache:
      my $value = $cache->get($SessionID);

      # dmp('mamcache value',($value));

      # -- use the value data to find the groups

      my $hashref = unserialize($value);
      # dmp('mamcache unserialized',($hashref));

      my %hash = %{ $hashref };
      %hash = % { $hash {'data'}{chr(0) . 'SimpleSAML_Session' . chr(0) . 'authData'}{'default-sp'}{'Attributes'} };
      my @groups = @ { $hash{'groups'} };

      dmp("3 Comparing $valid_group_expr to", \@groups);
      my $result=evaluate($valid_group_expr,@groups);
      if ($result) {
             dmp("this guy oK",$result);
             return Apache2::Const::HTTP_OK;
      }

     dmp("blowing this guy off",$result);
     $r->log_reason("Not a member of group " . $valid_group_expr);
      return Apache2::Const::FORBIDDEN;

    # return Apache2::Const::HTTP_FORBIDDEN;
    # return Apache2::Const::HTTP_OK;
    # return Apache2::Const::DECLINED;
}

# ======================= utility functions

# evaluate returns the boolean value of the expression $expr
#          after substituting membership information in @groups
#
# valid operators are
#
#    &&, and, AND             logical AND
#    ||, or, OR               logical OR
#    !, NOT, not              logical NOT
#
# expression must be infix and precidence can be indicated by ()

sub evaluate {

   my ($expr,@groups)=@_;
   # print "$expr\n";
   # print Dumper(\%group_hash);

   # operator tokens
   my %token_hash = (
       '(' => '(',
       ')' => ')',
       'AND' => '&&',
       'and' => '&&',
       'or' => '||',
       'OR' => '||',
       '!' => '!',
       'not' => '!',
       'NOT' => '!',
   ) ;

   # add the group array into the token hash as TRUEs
   foreach $v (@groups) {
      $v=~s/ /_/g;
      $token_hash{$v} = 1;
   }
   dmp('merged hash',\%token_hash);

   # merge the two hashes into %token_hash
   # foreach my $tkey ( keys %group_hash) { $token_hash{$tkey} = $group_hash{$tkey}; }
   # print Dumper(\%token_hash);

   $expr=~s/\(/ ( /g;
   $expr=~s/\)/ ) /g;
   $expr=~s/\!/ ! /g;

   # print "$expr\n";
   my @expr_hash=split (/ /,$expr);

   $expr='';
   foreach my $t (@expr_hash) {
       if ($t ne '') {
          if (exists ($token_hash{$t})) { $t = $token_hash{$t} } else {$t = 0;}
          $expr = $expr . "$t ";
       }
   }
   dmp("expression",$expr);
   my $result=0;
   my $assignment="\$result = $expr;";
   dmp("assignment",$assignment);
   eval($assignment);
   dmp("result",$result);
   return $result;

}

# debug dump structure funcion
sub dmp {

   if ($debug == 1) {

     my ($label,@value) = @_;
     my $temp = Dumper(@value);
     open (T, ">>$debug_file"); #   || die "Can't open $debug_file: $!\n";
     print T "$label: $temp\n";
     close (T);

   }

}

1;

Failing PHP script

The simple PHP form below displays no value when the Perl authorization is enabled. If I comment out the PerlAuthzHandler line both $_POST'[submit'] and $_POST['in1'] are set.

<?php

   if (isset($_POST['submit'])) { print_r($_POST); }

   $form=<<<EOT
      <form name="test" action="y.php" method="post">
         <input name="in1">
         <input type="submit" name="submit">
      </form>
EOT;

   print $form;

?>

Again, authentication (simplesamlphp/ADFS) and authorization both work as expected. The exception is that when authorization is used no $_POST variables are available.

1
Please show your Apache configuration, the contents of your PerlAuthzHandler, and a simple, reproducible example of a PHP script that fails. - ThisSuitIsBlackNot
Hi pha, I've edited your question to fix the formatting issues you were having, plus a few other minor tweaks. Including a code block in a numbered list is tricky (you need to use an empty HTML comment, e.g. <!-- -->, between the list item and the code block, with a blank line before and after the comment); needless to say, this isn't described in the Markdown help, so don't worry about not knowing. If you ever have questions about how to do things on SO, you can search meta.stackoverflow.com and ask a question if there isn't one already. - ThisSuitIsBlackNot
Also, this is a very well-written question. Welcome to Stack Overflow and good luck! - ThisSuitIsBlackNot
Thank you for your help and welcome! - pha

1 Answers

1
votes

RESOLUTION

As often happens the problem was of my own making. One of the kind monks at perlmonks.org pointed out that the Perl handler contained the line:

$query = new CGI;

Removing that did it. Since I was in fact only accessing but not changing anything there was no point to it and in fact $query was never used.