package Catalyst::Authentication::Credential::RedmineCookie;
use Moose;
use IPC::Open2;
use JSON::MaybeXS qw(:legacy);
use POSIX ":sys_wait_h";
has cmd => ( is => 'ro', isa => 'Str|ArrayRef', required => 1 );
# /jails/logserver/usr/local/lib/ruby/gems/2.6/gems/rack-1.6.11/lib/rack/session/cookie.rb
# https://qiita.com/labocho/items/32efc5b7c73aba3500ff
my $pid;
my $in;
my $out;
sub BUILDARGS { $_[1] }
sub authenticate {
my ($self, $c, $realm, $info) = @_;
if (my $cookie = $c->req->cookies->{_redmine_session}) {
my $str = $cookie->value;
my $cmd = $self->cmd;
my $retry;
OPEN: $pid ||= open2($out, $in, ref($cmd) ? @$cmd : $cmd) or die "open2 error. \$?:$? \$!:$!";
if ( waitpid($pid, WNOHANG) ) {
$c->log->warn("child process has gone. retry pid:$pid");
if ($retry) {
die "failed to start child process. pid:$pid";
}
else {
$pid = undef;
$retry++;
goto OPEN;
}
}
$in->print($str."\n");
$in->flush;
my $line = <$out>;
if ( $line =~ /^{/ ) {
my $data = eval { decode_json($line) };
if ($@) {
$c->log->error("@{[ __PACKAGE__ ]} $@ line:$line");
}
else {
if (my $id = $data->{user_id}) {
my $authinfo = { id => $id, status => 1, _redmine_cookie => $data };
return $realm->find_user($authinfo, $c);
}
else {
$c->log->debug("@{[ __PACKAGE__ ]} header _redmine_session has not user_id");
}
}
}
else {
$c->log->error("@{[ __PACKAGE__ ]} invalid input. line:$line");
}
}
else {
$c->log->debug("@{[ __PACKAGE__ ]} header _redmine_session missing");
}
}
no Moose;
__PACKAGE__->meta->make_immutable;
1;