Apache2-AuthenRadius

 view release on metacpan or  search on metacpan

AuthenRadius.pm  view on Meta::CPAN

use Apache2::RequestRec;
use Apache2::Access;
use Apache2::RequestUtil;
use Apache2::Log;
use APR::SockAddr;
use Authen::Radius;

$VERSION = '0.9';

# Create my own method to check a password
# The Authen::Radius->check_pwd method was too restrictive
# to use. We needed a function that returned all possible
# values.
sub chk_passwd {
  my ($rad, $uname, $upwd, $nas) = @_;

  $rad->clear_attributes;
  $rad->add_attributes (
			{Name => 1, Value => $uname, Type => 'string' },
			{Name => 2, Value => $upwd, Type => 'string' },
			{Name => 4, Value => $nas, Type => 'ipaddr' }
		       );

  $rad->send_packet(ACCESS_REQUEST);
  my $rcv = $rad->recv_packet();

  return($rcv);
}


sub handler {
  my $r = shift;
  
  # Continue only if the first request.
  return OK unless $r->is_initial_req();
  
  my $reqs_arr = $r->requires;
  return OK unless $reqs_arr;
  
  # Grab the password, or return if HTTP_UNAUTHORIZED
  my($res,$pass) = $r->get_basic_auth_pw;
  return $res if $res;
  
  # Get the user name.
  my $user = $r->user;
  
  # Primary Radius Server and port.
  my $host1    = $r->dir_config("Auth_Radius_host1") or return DECLINED;
  my $port1    = $r->dir_config("Auth_Radius_port1") || 1647;
  
  # Shared secret for the primary host we are running on.
  my $secret1  = $r->dir_config("Auth_Radius_secret1") or return DECLINED;
  
  # Secondary Radius Server and port.
  my $host2   = $r->dir_config("Auth_Radius_host2");
  my $port2    = $r->dir_config("Auth_Radius_port2") || 1647;
  
  # Shared secret for the secondary host we are running on.
  my $secret2  = $r->dir_config("Auth_Radius_secret2");
  
  # Timeout to wait for a response from the radius server.
  my $timeout = $r->dir_config("Auth_Radius_timeout") || 5;
  
  # Sanity for usernames and passwords.
  if (length $user > 64 or $user =~ /[^A-Za-z0-9\@\.\-\_\#\:]/) {
    $r->log_reason("Apache2::AuthenRadius username too long or"
		   ."contains illegal characters. URI:", $r->uri);
    $r->note_basic_auth_failure;
    return HTTP_UNAUTHORIZED;
  }

  # Prepend realm if set
  if ($r->dir_config("Auth_Radius_prependToUsername")) {
    $user = $r->dir_config("Auth_Radius_prependToUsername") . $user;
  }

  # Postfix realm if set
  if ($r->dir_config("Auth_Radius_postfixToUsername")) {
    $user .= $r->dir_config("Auth_Radius_postfixToUsername");
  }

  if (length $pass > 256) {
    $r->log_reason("Apache2::AuthenRadius password too long. URI:",$r->uri);
    $r->note_basic_auth_failure;
    return HTTP_UNAUTHORIZED;
  }
  
  # Create the object for the primary RADIUS query
  my $radius = Authen::Radius->new(
				   Host => "$host1:$port1",
				   Secret => $secret1,
				   TimeOut => $timeout
				  );

  # Fail if we can't create object for primary 
  # RADIUS server  
  if (!defined $radius) {
    $r->log_reason("Apache2::AuthenRadius failed to"
		   ."create object for $host1:$port1. URI:",$r->uri);	  
    return HTTP_INTERNAL_SERVER_ERROR;
  }
  
  # Get my IP address to pass as the
  # NAS IP Address
  my $c = $r->connection;
  my $sockaddr = $c->local_addr;
  my $nas_ip_address = $sockaddr->ip_get;
  
  # Check with the primary RADIUS server.
  my $access = chk_passwd($radius,$user,$pass,$nas_ip_address);
  if ($access == ACCESS_ACCEPT) {
    # Good ... we're in
    return OK;
  } elsif ($access == ACCESS_REJECT) {
    # Sorry, you can't get in
    $r->log_reason("Apache2::AuthenRadius failed for user $user. URI:",
		   $r->uri);
    $r->note_basic_auth_failure;
    return HTTP_UNAUTHORIZED;
  } elsif (!defined($access)) {
    # We didn't get a response from the primary



( run in 0.928 second using v1.01-cache-2.11-cpan-39bf76dae61 )