292 lines
8.9 KiB
Perl
292 lines
8.9 KiB
Perl
package Lemonldap::NG::Portal::Plugins::CheckDevOps;
|
|
|
|
use strict;
|
|
use Mouse;
|
|
use JSON qw(from_json);
|
|
use Lemonldap::NG::Common::UserAgent;
|
|
use Lemonldap::NG::Portal::Main::Constants qw(
|
|
URIRE
|
|
PE_OK
|
|
PE_ERROR
|
|
PE_BADURL
|
|
PE_NOTOKEN
|
|
PE_TOKENEXPIRED
|
|
PE_FILENOTFOUND
|
|
PE_BAD_DEVOPS_FILE
|
|
PE_REGISTERFORMEMPTY
|
|
);
|
|
|
|
our $VERSION = '2.0.14';
|
|
|
|
extends qw(
|
|
Lemonldap::NG::Portal::Main::Plugin
|
|
Lemonldap::NG::Portal::Lib::_tokenRule
|
|
);
|
|
|
|
# INITIALIZATION
|
|
|
|
has ott => (
|
|
is => 'rw',
|
|
lazy => 1,
|
|
default => sub {
|
|
my $ott =
|
|
$_[0]->{p}->loadModule('Lemonldap::NG::Portal::Lib::OneTimeToken');
|
|
$ott->timeout( $_[0]->{conf}->{formTimeout} );
|
|
return $ott;
|
|
}
|
|
);
|
|
|
|
has ua => (
|
|
is => 'rw',
|
|
lazy => 1,
|
|
builder => sub {
|
|
my $ua = Lemonldap::NG::Common::UserAgent->new( $_[0]->{conf} );
|
|
$ua->env_proxy();
|
|
return $ua;
|
|
}
|
|
);
|
|
|
|
sub init {
|
|
my ($self) = @_;
|
|
$self->addAuthRoute( checkdevops => 'parse', ['POST'] )
|
|
->addAuthRouteWithRedirect( checkdevops => 'display', ['GET'] );
|
|
|
|
unless ( $self->conf->{useSafeJail} ) {
|
|
$self->logger->warn('"CheckDevOps" plugin enabled WITHOUT SafeJail');
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
# RUNNING METHOD
|
|
|
|
sub display {
|
|
my ( $self, $req ) = @_;
|
|
|
|
# Display form
|
|
my $params = {
|
|
PORTAL => $self->conf->{portal},
|
|
MAIN_LOGO => $self->conf->{portalMainLogo},
|
|
SKIN => $self->p->getSkin($req),
|
|
LANGS => $self->conf->{showLanguages},
|
|
DOWNLOAD => $self->conf->{checkDevOpsDownload},
|
|
MSG => 'checkDevOps',
|
|
ALERTE => 'alert-info',
|
|
TOKEN => (
|
|
$self->ottRule->( $req, {} )
|
|
? $self->ott->createToken()
|
|
: ''
|
|
)
|
|
};
|
|
return $self->sendJSONresponse( $req, $params ) if $req->wantJSON;
|
|
|
|
# Display form
|
|
return $self->p->sendHtml( $req, 'checkdevops', params => $params, );
|
|
}
|
|
|
|
sub parse {
|
|
my ( $self, $req ) = @_;
|
|
my ( $headers, $rules ) = ( [], [] );
|
|
my ( $msg, $json, $url );
|
|
my $alert = 'alert-danger';
|
|
|
|
# Check token
|
|
if ( $self->ottRule->( $req, {} ) ) {
|
|
my $token;
|
|
$msg = PE_OK;
|
|
if ( $token = $req->param('token') ) {
|
|
unless ( $self->ott->getToken($token) ) {
|
|
$self->userLogger->warn(
|
|
'CheckDevOps called with an expired/bad token');
|
|
$msg = PE_TOKENEXPIRED;
|
|
$token = $self->ott->createToken();
|
|
}
|
|
}
|
|
else {
|
|
$self->userLogger->warn('CheckDevOps called without token');
|
|
$msg = PE_NOTOKEN;
|
|
$token = $self->ott->createToken();
|
|
}
|
|
|
|
# Prepare form
|
|
my $params = {
|
|
PORTAL => $self->conf->{portal},
|
|
MAIN_LOGO => $self->conf->{portalMainLogo},
|
|
SKIN => $self->p->getSkin($req),
|
|
LANGS => $self->conf->{showLanguages},
|
|
DOWNLOAD => $self->conf->{checkDevOpsDownload},
|
|
MSG => "PE$msg",
|
|
ALERTE => 'alert-warning',
|
|
TOKEN => $token
|
|
};
|
|
return $self->p->sendJSONresponse( $req, $params )
|
|
if ( $req->wantJSON && $msg );
|
|
|
|
# Display form
|
|
return $self->p->sendHtml( $req, 'checkdevops', params => $params )
|
|
if $msg;
|
|
}
|
|
|
|
$msg = 'PE' . PE_REGISTERFORMEMPTY
|
|
unless ( $req->param('url') || $req->param('checkDevOpsFile') );
|
|
|
|
# Check URL if allowed and exists
|
|
if ( $self->conf->{checkDevOpsDownload} and $url = $req->param('url') ) {
|
|
undef $url if $self->p->checkXSSAttack( 'CheckDevOps URL', $url );
|
|
if ( $url && $url =~ URIRE ) {
|
|
|
|
# Reformat url
|
|
my ( $proto, $vhost, $appuri ) = ( $2, $3, $5 );
|
|
$url = "$proto://$vhost/rules.json";
|
|
my $resp = $self->ua->get( $url, 'Accept' => 'application/json' );
|
|
$self->logger->debug( "Code/Message from $url: "
|
|
. $resp->code . '/'
|
|
. $resp->message );
|
|
my $content = $resp->decoded_content;
|
|
$self->logger->debug("Content received from $url: $content")
|
|
if $content;
|
|
|
|
if ( $resp->is_success ) {
|
|
$json = eval { from_json( $content, { allow_nonref => 1 } ) };
|
|
if ($@) {
|
|
|
|
# Prepare form params
|
|
undef $json;
|
|
$msg = 'PE' . PE_BAD_DEVOPS_FILE;
|
|
$self->userLogger->error(
|
|
"CheckDevOps: bad 'rules.json' file retrieved from $url ($@)"
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
|
|
# Prepare form params
|
|
$msg = 'PE' . PE_FILENOTFOUND;
|
|
$self->userLogger->error(
|
|
"CheckDevOps: Unable to download 'rules.json' file from $url"
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
|
|
# Prepare form params
|
|
$msg = 'PE' . PE_BADURL;
|
|
$self->userLogger->error('CheckDevOps: bad URL provided');
|
|
}
|
|
}
|
|
unless ( $json || $msg ) {
|
|
$json = eval {
|
|
from_json( $req->param('checkDevOpsFile'), { allow_nonref => 1 } );
|
|
} if $req->param('checkDevOpsFile');
|
|
if ($@) {
|
|
|
|
# Prepare form params
|
|
undef $json;
|
|
$msg = 'PE' . PE_BAD_DEVOPS_FILE;
|
|
$alert = 'alert-danger';
|
|
$self->userLogger->error(
|
|
"CheckDevOps: bad provided 'rules.json' file ($@)");
|
|
}
|
|
}
|
|
|
|
# Parse JSON
|
|
if ($json) {
|
|
my $handler = $self->p->HANDLER;
|
|
my $vhost = $handler->resolveAlias($req);
|
|
|
|
# Removed hidden session attributes
|
|
foreach my $v ( split /[,\s]+/, $self->conf->{hiddenAttributes} ) {
|
|
foreach ( keys %{ $json->{headers} } ) {
|
|
if ( $json->{headers}->{$_} =~ /\$$v/ ) {
|
|
delete $json->{headers}->{$_};
|
|
my $user = $req->userData->{ $self->conf->{whatToTrace} };
|
|
$self->userLogger->warn(
|
|
"CheckDevOps: $user tried to retrieve hidden attribute '$v'"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
# Compile headers
|
|
$handler->headersInit( undef, { $vhost => $json->{headers} } );
|
|
$headers = $handler->checkHeaders( $req, $req->userData );
|
|
|
|
if ( $handler->tsv->{maintenance}->{$vhost} ) {
|
|
|
|
# Prepare form params
|
|
undef $json;
|
|
$headers = [];
|
|
$alert = 'alert-danger';
|
|
$msg = 'PE' . PE_BAD_DEVOPS_FILE;
|
|
$self->userLogger->error(
|
|
"CheckDevOps: bad 'rules.json' file (headers)");
|
|
$handler->tsv->{maintenance}->{$vhost} = 0;
|
|
}
|
|
else {
|
|
|
|
# Normalize headers name if required
|
|
if ( $self->conf->{checkDevOpsDisplayNormalizedHeaders} ) {
|
|
$self->logger->debug("Normalize headers...");
|
|
@$headers = map {
|
|
; # Prevent compilation error with old Perl versions
|
|
no strict 'refs';
|
|
{
|
|
key => &{ $handler . '::cgiName' }( $_->{key} ),
|
|
value => $_->{value}
|
|
}
|
|
} @$headers;
|
|
}
|
|
|
|
my $headers_list = join ', ', map "$_->{key}:$_->{value}",
|
|
@$headers;
|
|
$self->logger->debug("CheckDevOps compiled headers: $headers_list");
|
|
|
|
# Compile rules
|
|
@$rules = map {
|
|
my ( $sub, $flag ) =
|
|
$handler->conditionSub( $json->{rules}->{$_} );
|
|
{
|
|
uri => $_,
|
|
access => $sub->( $req, $req->userData )
|
|
? 'allowed'
|
|
: 'forbidden'
|
|
}
|
|
} sort keys %{ $json->{rules} };
|
|
my $rules_list = join ', ', map "$_->{uri}:$_->{access}", @$rules;
|
|
$self->logger->debug("CheckDevOps compiled rules: $rules_list");
|
|
|
|
# Prepare form params
|
|
$msg = 'checkDevOps';
|
|
$alert = 'alert-info';
|
|
$json = JSON->new->ascii->pretty->encode($json); # Pretty print
|
|
}
|
|
}
|
|
|
|
# Prepare form
|
|
my $params = {
|
|
PORTAL => $self->conf->{portal},
|
|
MAIN_LOGO => $self->conf->{portalMainLogo},
|
|
SKIN => $self->p->getSkin($req),
|
|
LANGS => $self->conf->{showLanguages},
|
|
DOWNLOAD => $self->conf->{checkDevOpsDownload},
|
|
MSG => $msg,
|
|
ALERTE => $alert,
|
|
FILE => $json,
|
|
HEADERS => $headers,
|
|
RULES => $rules,
|
|
URL => $url,
|
|
TOKEN => (
|
|
$self->ottRule->( $req, {} )
|
|
? $self->ott->createToken()
|
|
: ''
|
|
)
|
|
};
|
|
return $self->p->sendJSONresponse( $req, $params ) if $req->wantJSON;
|
|
|
|
# Display form
|
|
return $self->p->sendHtml( $req, 'checkdevops', params => $params );
|
|
}
|
|
|
|
1;
|