#!/usr/bin/perl
#
#
use strict;
use Carp;
use CGI::Simple;
use IPC::Open3;
use JSON;

my $configfile = $ENV{rest_auth_configfile} || '/etc/benno-auth-modules/restauth.conf';
my $DEBUG = $ENV{DEBUG};

my $accept_type = 'application/json';

my $q = CGI::Simple->new;
$q->charset('UTF-8');

my $request_type  = $q->content_type();
my $accept_header = $q->http('Accept');

my $config;
eval {
    $config = read_config($configfile);
    $DEBUG = $DEBUG || $config->{DEBUG};
};
if ($@) {
    print STDERR "[REST_AUTH:0] configuration error: $@";
    return_error($q,'500 Internal Server Error',$accept_type);
}

if ($config->{REST_AUTH_APIKEY}) {
    my ($auth_scheme,$auth_key)  = split(/\s/, $q->http('HTTP_AUTHORIZATION'),2);
    return_error($q,'403 Forbidden', $accept_type) unless $auth_key;
    if ($auth_scheme eq 'ApiKey') {
        return_error($q,'401 Unauthorized', $accept_type, 'API KEY mismatch') if ($auth_key ne $config->{REST_AUTH_APIKEY});
    }
    else {
        return_error($q,'401 Unauthorized', $accept_type, 'Authentication scheme incorrect');
    }
}


my ($credentials);
if ($request_type eq 'application/json') {
    eval {
        $credentials = decode_json($q->param('POSTDATA'));
    };
    if ($@) {
        my $errmsg = $@;
        $errmsg =~ s/\sat \/.+$//;
        return_error($q,'400 Bad Request', $accept_type, "JSON ERROR: $errmsg");
    }
}
else {
    $credentials->{username} = $q->param('username');
    $credentials->{password} = $q->param('password');
}


# OK
print $q->header(
    -type   => 'application/json',
    -status => 200,
);

my($wtr, $rdr, $err);
use Symbol 'gensym'; $err = gensym;
my $pid = open3($wtr, $rdr, $err, $config->{REST_AUTH_PROGRAM});
print $wtr $credentials->{username}."\n";
print $wtr $credentials->{password}."\n";
close $wtr;
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;

my $ret = { ROLE    => 'USER',
            MAIL    => [],
};
foreach my $line (<$rdr>) {
    chomp $line;
    print STDERR "[REST_AUTH:4] RETURN $line\n" if $DEBUG >= 2;
    my ($keyword,$value) = split(/\s/,$line,2);
    $keyword = uc $keyword;
    if ($keyword =~ /^ARCHIVE$/ &! $ret->{ARCHIVE}) {
        $ret->{ARCHIVE} = [];
    }
    if ((ref $ret->{$keyword}) eq 'ARRAY') {
        push @{$ret->{$keyword}}, $value;
    }
    else {
        $ret->{$keyword} = $value;
    }
}

$ret->{ROLE} = 'USER' unless $ret->{ROLE};
 
foreach my $errline (<$err>) {
    print STDERR "AUTH ERROR: $errline";
}

my $json = JSON->new->allow_nonref;
print $json->encode($ret);


### SUBS ###

# return_error
sub return_error
{
    my ($q,$status,$type,$errmsg) = @_;

    print $q->header(
        -type   => $accept_type,
        -status => $status,
    );
    print STDERR "[REST_AUTH:0] $status";
    print STDERR ": $errmsg" if $errmsg;
    print STDERR "\n";
    print "{ \"error\": \"$errmsg\" }\n";
    exit;
}

# read_config
sub read_config
{
    my $configfile = shift;
    my $config = {};
    open my $ch, $configfile or croak "Cannot open config file $configfile. $!\n";
    foreach my $line (<$ch>) {
        next if $line =~ /^$/;
        next if$line  =~ /^#/;
        chomp $line;
        my ($param,$value) = split(/\s*=\s*/,$line,2);
        $config->{$param} = $value;
    }
    close $ch;

    $config->{REST_AUTH_PROGRAM} = '/usr/sbin/benno_auth.d' unless $config->{REST_AUTH_PROGRAM};

    return $config;
}

1; ### EOP ###

