lemonldap-ng/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Main/Reload.pm

675 lines
22 KiB
Perl
Raw Normal View History

package Lemonldap::NG::Handler::Main::Reload;
2019-02-12 18:21:38 +01:00
our $VERSION = '2.1.0';
2017-02-08 23:18:52 +01:00
package Lemonldap::NG::Handler::Main;
use strict;
use Lemonldap::NG::Common::Conf::Constants; #inherits
use Lemonldap::NG::Common::Crypto;
use Lemonldap::NG::Common::Safelib; #link protected safe Safe object
use Lemonldap::NG::Handler::Main::Jail;
use Scalar::Util qw(weaken);
use constant UNPROTECT => 1;
use constant SKIP => 2;
2019-12-10 16:06:17 +01:00
use constant MAYSKIP => 3;
our @_onReload;
sub onReload {
my ( $class, $obj, $sub ) = @_;
weaken($obj);
push @_onReload, [ $obj, $sub ];
}
# CONFIGURATION UPDATE
## @rmethod protected int checkConf(boolean force)
# Check if configuration is up to date, and reload it if needed.
# If the optional boolean $force is set to true,
# * cached configuration is ignored
# * and checkConf returns false if it fails to load remote config
# @param $force boolean
# @return true if config is up to date or if reload config succeeded
sub checkConf {
my ( $class, $force ) = @_;
2018-06-12 14:02:32 +02:00
$class->logger->debug("Check configuration for $class");
2019-07-02 20:03:40 +02:00
my $prm = { local => !$force, localPrm => $class->localConfig };
2017-02-18 12:31:07 +01:00
my $conf = $class->confAcc->getConf($prm);
2018-06-15 19:00:14 +02:00
chomp $Lemonldap::NG::Common::Conf::msg;
unless ( ref($conf) ) {
2017-02-15 07:41:50 +01:00
$class->logger->error(
"$class: Unable to load configuration: $Lemonldap::NG::Common::Conf::msg"
);
return $force ? 0 : $class->cfgNum ? 1 : 0;
}
if ($Lemonldap::NG::Common::Conf::msg) {
if ( $Lemonldap::NG::Common::Conf::msg =~ /Error:/ ) {
$class->logger->error($Lemonldap::NG::Common::Conf::msg);
}
elsif ( $Lemonldap::NG::Common::Conf::msg =~ /Warn:/ ) {
$class->logger->warn($Lemonldap::NG::Common::Conf::msg);
}
else {
$class->logger->debug($Lemonldap::NG::Common::Conf::msg);
}
}
2020-10-17 19:46:05 +02:00
$Lemonldap::NG::Common::Conf::msg = '';
if ( $force
or !$class->cfgNum
or !$class->cfgDate
or $class->cfgNum != $conf->{cfgNum}
or $class->cfgDate != $conf->{cfgDate} )
{
$class->logger->debug("Get configuration $conf->{cfgNum}");
unless ( $class->cfgNum( $conf->{cfgNum} )
&& $class->cfgDate( $conf->{cfgDate} ) )
{
2017-02-15 07:41:50 +01:00
$class->logger->error('No configuration available');
return 0;
}
$class->configReload($conf);
foreach (@_onReload) {
my ( $obj, $sub ) = @$_;
if ($obj) {
$class->logger->debug(
'Launching ' . ref($obj) . "->$sub(conf)" );
unless ( $obj->$sub($conf) ) {
$class->logger->error( "Underlying object can't load conf ("
. ref($obj)
. "->$sub)" );
return 0;
}
}
}
}
$class->checkTime( $conf->{checkTime} ) if $conf->{checkTime};
2018-06-15 19:00:14 +02:00
$class->lastCheck( time() );
$class->logger->debug("$class: configuration is up to date");
return 1;
}
# RELOAD SYSTEM
## @rmethod int reload
# Launch checkConf() with $local=0, so remote configuration is tested.
# Then build a simple HTTP response that just returns "200 OK" or
# "500 Server Error".
# @return Apache constant ($class->OK or $class->SERVER_ERROR)
sub reload {
my $class = shift;
2017-02-15 07:41:50 +01:00
$class->logger->notice("Request for configuration reload");
return $class->checkConf(1) ? $class->DONE : $class->SERVER_ERROR;
}
*refresh = *reload;
# INTERNAL METHODS
## @imethod void configReload(hashRef conf, hashRef tsv)
# Given a Lemonldap::NG configuration $conf, computes values used to
# handle requests and store them in a thread shared object called $tsv
#
# methods called by configReload, and thread shared values computed, are:
# - jailInit():
# - jail
# - defaultValuesInit():
# (scalars for global options)
# - cookieExpiration # warning: absent from default Conf
# - cookieName
# - securedCookie,
# - httpOnly
# - whatToTrace
# - customFunctions
# - timeoutActivity
# - timeoutActivityInterval
# - useRedirectOnError
# - useRedirectOnForbidden
# - useSafeJail
# (objects)
# - cipher # Lemonldap::NG::Common::Crypto object
# (hashrefs for vhost options)
# - https
# - port
# - maintenance
# - portalInit():
# - portal (functions that returns portal URL)
# - locationRulesInit():
# - locationCount
# - defaultCondition
# - defaultProtection
# - locationCondition
# - locationProtection
# - locationRegexp
# - locationConditionText
# - sessionStorageInit():
# - sessionStorageModule
# - sessionStorageOptions
# - sessionCacheModule
# - sessionCacheOptions
# - headersInit():
# - headerList
# - forgeHeaders
# - postUrlInit():
2014-07-07 20:30:42 +02:00
# - inputPostData
# - outputPostData
# - aliasInit():
# - vhostAlias
#
# The *Init() methods can be run in any order,
# but jailInit must be run first because $tsv->{jail}
# is used by locationRulesInit, headersInit and postUrlInit.
# @param $conf reference to the configuration hash
# @param $tsv reference to the thread-shared parameters conf
sub configReload {
my ( $class, $conf ) = @_;
2017-02-15 07:41:50 +01:00
$class->logger->info(
"Loading configuration $conf->{cfgNum} for process $$");
foreach my $sub (
qw( defaultValuesInit jailInit portalInit locationRulesInit
sessionStorageInit headersInit postUrlInit aliasInit oauth2Init )
2014-07-24 17:48:32 +02:00
)
{
2017-02-15 07:41:50 +01:00
$class->logger->debug("Process $$ calls $sub");
$class->$sub($conf);
}
return 1;
}
## @imethod protected void jailInit(hashRef args)
# Set default values for non-customized variables
# @param $args reference to the configuration hash
sub jailInit {
my ( $class, $conf ) = @_;
2019-02-07 09:27:56 +01:00
$class->tsv->{jail} = Lemonldap::NG::Handler::Main::Jail->new( {
useSafeJail => $conf->{useSafeJail},
customFunctions => $conf->{customFunctions},
multiValuesSeparator => $conf->{multiValuesSeparator},
2017-02-09 22:36:23 +01:00
}
);
$class->tsv->{jail}
->build_jail( $class, $conf->{require}, $conf->{requireDontDie} );
}
## @imethod protected void defaultValuesInit(hashRef args)
# Set default values for non-customized variables
# @param $args reference to the configuration hash
sub defaultValuesInit {
my ( $class, $conf ) = @_;
2014-07-24 17:48:32 +02:00
2019-02-07 09:27:56 +01:00
$class->tsv->{$_} = $conf->{$_} foreach ( qw(
2017-02-16 11:42:22 +01:00
cookieExpiration cookieName customFunctions httpOnly
securedCookie timeout timeoutActivity
timeoutActivityInterval useRedirectOnError useRedirectOnForbidden
2018-11-26 14:40:21 +01:00
useSafeJail whatToTrace handlerInternalCache
2019-09-09 21:54:08 +02:00
handlerServiceTokenTTL customToTrace lwpOpts lwpSslOpts
authChoiceAuthBasic authChoiceParam hiddenAttributes
upgradeSession
2014-07-24 17:48:32 +02:00
)
);
$class->tsv->{cipher} = Lemonldap::NG::Common::Crypto->new( $conf->{key} );
foreach my $opt (qw(https port maintenance)) {
# Record default value in key '_'
$class->tsv->{$opt} = { _ => $conf->{$opt} };
# Override with vhost options
if ( $conf->{vhostOptions} ) {
my $name = 'vhost' . ucfirst($opt);
2020-01-08 23:05:43 +01:00
foreach my $vhost ( sort keys %{ $conf->{vhostOptions} } ) {
$conf->{vhostOptions}->{$vhost} ||= {};
my $val = $conf->{vhostOptions}->{$vhost}->{$name};
2017-01-12 07:05:06 +01:00
# Keep global value if $val is negative
2017-01-12 07:05:06 +01:00
if ( defined $val and $val >= 0 ) {
2017-02-15 07:41:50 +01:00
$class->logger->debug(
"Options $opt for vhost $vhost: $val");
2017-01-12 07:05:06 +01:00
$class->tsv->{$opt}->{$vhost} = $val;
}
}
}
}
2017-02-08 23:18:52 +01:00
if ( $conf->{vhostOptions} ) {
2020-01-08 23:05:43 +01:00
foreach my $vhost ( sort keys %{ $conf->{vhostOptions} } ) {
2017-02-08 23:18:52 +01:00
$class->tsv->{type}->{$vhost} =
$conf->{vhostOptions}->{$vhost}->{vhostType};
$class->tsv->{authnLevel}->{$vhost} =
$conf->{vhostOptions}->{$vhost}->{vhostAuthnLevel};
$class->tsv->{serviceTokenTTL}->{$vhost} =
$conf->{vhostOptions}->{$vhost}->{vhostServiceTokenTTL};
2020-11-12 13:43:41 +01:00
$class->tsv->{accessToTrace}->{$vhost} =
$conf->{vhostOptions}->{$vhost}->{vhostAccessToTrace};
2017-02-08 23:18:52 +01:00
}
}
return 1;
}
## @imethod protected void portalInit(hashRef args)
# Verify that portal variable exists. Die unless
# @param $args reference to the configuration hash
sub portalInit {
my ( $class, $conf ) = @_;
2016-01-05 12:06:13 +01:00
unless ( $conf->{portal} ) {
2017-02-15 07:41:50 +01:00
$class->logger->error("portal parameter required");
2016-01-05 12:06:13 +01:00
return 0;
}
if ( $conf->{portal} =~ /[\$\(&\|"']/ ) {
( $class->tsv->{portal} ) =
$class->conditionSub( $conf->{portal} );
}
else {
$class->tsv->{portal} = sub { return $conf->{portal} };
}
return 1;
}
## @imethod void locationRulesInit(hashRef args)
# Compile rules.
# Rules are stored in $args->{locationRules}->{<virtualhost>} that contains
# regexp=>test expressions where :
# - regexp is used to test URIs
# - test contains an expression used to grant the user
#
# This function creates 2 hashRef containing :
# - one list of the compiled regular expressions for each virtual host
# - one list of the compiled functions (compiled with conditionSub()) for each
# virtual host
# @param $args reference to the configuration hash
sub locationRulesInit {
2017-02-22 07:35:19 +01:00
my ( $class, $conf, $orules ) = @_;
$orules ||= $conf->{locationRules};
$class->tsv->{vhostReg} = [];
my @lastReg;
2017-02-22 07:35:19 +01:00
foreach my $vhost ( keys %$orules ) {
my $rules = $orules->{$vhost};
if ( $vhost =~ /[\%\*]/ ) {
my $expr = join '[^\.]*', map {
my $elt = $_;
join '.*', map { quotemeta $_ } split /\*/, $elt;
} split /\%/, $vhost;
if ($expr) {
push @{ $class->tsv->{vhostReg} }, [ qr/^$expr$/, $vhost ];
}
else {
push @lastReg, [ qr/.+/, $vhost ];
}
}
$class->tsv->{locationCount}->{$vhost} = 0;
$class->tsv->{locationCondition}->{$vhost} = [];
$class->tsv->{locationProtection}->{$vhost} = [];
$class->tsv->{locationRegexp}->{$vhost} = [];
$class->tsv->{locationConditionText}->{$vhost} = [];
2019-10-27 17:47:29 +01:00
$class->tsv->{locationAuthnLevel}->{$vhost} = [];
2014-07-24 17:48:32 +02:00
foreach my $url ( sort keys %{$rules} ) {
my ( $cond, $prot ) = $class->conditionSub( $rules->{$url} );
2016-03-08 19:00:10 +01:00
unless ($cond) {
$class->tsv->{maintenance}->{$vhost} = 1;
2017-02-15 07:41:50 +01:00
$class->logger->error(
2016-03-08 19:00:10 +01:00
"Unable to build rule '$rules->{$url}': "
2017-02-15 07:41:50 +01:00
. $class->tsv->{jail}->error );
2016-03-08 19:00:10 +01:00
next;
}
if ( $url eq 'default' ) {
$class->tsv->{defaultCondition}->{$vhost} = $cond;
$class->tsv->{defaultProtection}->{$vhost} = $prot;
}
else {
push @{ $class->tsv->{locationCondition}->{$vhost} }, $cond;
push @{ $class->tsv->{locationProtection}->{$vhost} }, $prot;
push @{ $class->tsv->{locationRegexp}->{$vhost} }, qr/$url/;
2019-10-27 17:47:29 +01:00
push @{ $class->tsv->{locationAuthnLevel}->{$vhost} },
$url =~ /\(\?#AuthnLevel=(-?\d+)\)/
? $1
: undef;
push @{ $class->tsv->{locationConditionText}->{$vhost} },
2019-10-26 22:37:56 +02:00
$url =~ /^\(\?#(.*?)\)/ ? $1
: $url =~ /^(.*?)##(.+)$/ ? $2
2019-10-27 17:47:29 +01:00
: $url;
$class->tsv->{locationCount}->{$vhost}++;
}
}
# Default policy set to 'accept'
unless ( $class->tsv->{defaultCondition}->{$vhost} ) {
2019-07-02 20:03:40 +02:00
$class->tsv->{defaultCondition}->{$vhost} = sub { 1 };
$class->tsv->{defaultProtection}->{$vhost} = 0;
}
}
@{ $class->tsv->{vhostReg} } = sort {
my $av = $a->[1];
my $bv = $b->[1];
2020-05-06 13:02:57 +02:00
return 1 if $av =~ /^\*/ and $bv !~ /^\*/;
return -1 if $bv =~ /^\*/ and $av !~ /^\*/;
return 1 if $av =~ /^\%/ and $bv !~ /^\%/;
return -1 if $bv =~ /^\%/ and $av !~ /^\%/;
return length($bv) <=> length($av) || $av cmp $bv;
2020-05-06 13:02:57 +02:00
} @{ $class->tsv->{vhostReg} } if @{ $class->tsv->{vhostReg} };
push @{ $class->tsv->{vhostReg} }, @lastReg if @lastReg;
return 1;
}
## @imethod protected void sessionStorageInit(hashRef args)
# Initialize the Apache::Session::* module choosed to share user's variables
2020-01-07 22:38:08 +01:00
# and the Cache::Cache module chosen to cache sessions
# @param $args reference to the configuration hash
sub sessionStorageInit {
my ( $class, $conf ) = @_;
2019-04-22 17:51:00 +02:00
# Global session storage
unless ( $class->tsv->{sessionStorageModule} = $conf->{globalStorage} ) {
2017-02-15 07:41:50 +01:00
$class->logger->error("globalStorage required");
2016-01-05 12:06:13 +01:00
return 0;
}
eval "use " . $class->tsv->{sessionStorageModule};
die($@) if ($@);
$class->tsv->{sessionStorageOptions} = $conf->{globalStorageOptions};
2019-04-22 17:51:00 +02:00
# OIDC session storage
if ( $conf->{oidcStorage} ) {
eval "use " . $conf->{oidcStorage};
2019-04-22 17:51:00 +02:00
die($@) if ($@);
$class->tsv->{oidcStorageModule} = $conf->{oidcStorage};
$class->tsv->{oidcStorageOptions} = $conf->{oidcStorageOptions};
}
else {
$class->tsv->{oidcStorageModule} = $conf->{globalStorage};
$class->tsv->{oidcStorageOptions} = $conf->{globalStorageOptions};
}
# Local session storage
2014-07-24 17:48:32 +02:00
if ( $conf->{localSessionStorage} ) {
$class->tsv->{sessionCacheModule} = $conf->{localSessionStorage};
$class->tsv->{sessionCacheOptions} =
$conf->{localSessionStorageOptions};
$class->tsv->{sessionCacheOptions}->{default_expires_in} ||= 600;
2014-07-24 17:48:32 +02:00
if ( $conf->{status} ) {
my $params = "";
if ( $class->tsv->{sessionCacheModule} ) {
$params = $class->tsv->{sessionCacheModule} . ',{' . join(
2019-08-27 10:10:11 +02:00
',',
map {
"$_ => '"
. $class->tsv->{sessionCacheOptions}->{$_} . "'"
}
keys %{ $class->tsv->{sessionCacheOptions} // {} }
) . '}';
}
2018-06-12 11:45:21 +02:00
$class->tsv->{statusPipe}->print("RELOADCACHE $params\n");
}
}
return 1;
}
## @imethod void headersInit(hashRef args)
# Create the subroutines used to insert headers into the HTTP request.
# @param $args reference to the configuration hash
sub headersInit {
2017-02-22 07:35:19 +01:00
my ( $class, $conf, $headers ) = @_;
$headers ||= $conf->{exportedHeaders};
# Creation of the subroutine which will generate headers
2017-03-03 18:25:03 +01:00
foreach my $vhost ( keys %{$headers} ) {
2018-06-01 16:32:23 +02:00
unless ($vhost) {
$class->logger->warn('Empty vhost in headers, skipping');
next;
}
$headers->{$vhost} ||= {};
2017-02-22 07:35:19 +01:00
my %headers = %{ $headers->{$vhost} };
$class->tsv->{headerList}->{$vhost} = [ keys %headers ];
2017-01-12 07:05:06 +01:00
my $sub = '';
foreach ( keys %headers ) {
$headers{$_} ||= "''";
my $val = $class->substitute( $headers{$_} ) . " // ''";
2019-05-10 17:20:59 +02:00
$sub .= "('$_' => $val),";
}
unless ( $class->tsv->{forgeHeaders}->{$vhost} =
2016-07-30 22:48:03 +02:00
$class->buildSub($sub) )
{
$class->tsv->{maintenance}->{$vhost} = 1;
2019-05-10 17:20:59 +02:00
$class->logger->error( "$class Unable to forge $vhost headers: "
2017-02-15 07:41:50 +01:00
. $class->tsv->{jail}->error );
}
}
return 1;
}
## @imethod protected void postUrlInit()
# Prepare methods to post form attributes
sub postUrlInit {
my ( $class, $conf ) = @_;
2014-07-07 20:30:42 +02:00
return unless ( $conf->{post} );
# Browse all vhost
2014-07-07 20:30:42 +02:00
foreach my $vhost ( keys %{ $conf->{post} } ) {
2014-07-24 17:48:32 +02:00
2014-07-07 20:30:42 +02:00
# Browse all POST URI
2018-06-01 17:15:13 +02:00
foreach my $url ( keys %{ $conf->{post}->{$vhost} || {} } ) {
my $d = $conf->{post}->{$vhost}->{$url};
2017-02-15 07:41:50 +01:00
$class->logger->debug("Compiling POST data for $url");
2014-07-07 20:30:42 +02:00
# Where to POST
2016-02-13 19:21:03 +01:00
$d->{target} ||= $url;
2014-07-07 20:30:42 +02:00
my $sub;
2016-02-13 19:21:03 +01:00
$d->{vars} ||= [];
foreach my $input ( @{ delete $d->{vars} } ) {
2016-02-14 08:13:05 +01:00
$sub .=
"'$input->[0]' => " . $class->substitute( $input->[1] ) . ",";
}
unless (
$class->tsv->{inputPostData}->{$vhost}->{ delete $d->{target} }
= $class->tsv->{outputPostData}->{$vhost}->{$url} =
2016-07-30 22:48:03 +02:00
$class->buildSub($sub) )
{
$class->tsv->{maintenance}->{$vhost} = 1;
2018-07-05 23:00:40 +02:00
$class->logger->error( "$class: Unable to build post data: "
2017-02-15 07:41:50 +01:00
. $class->tsv->{jail}->error );
}
$class->tsv->{postFormParams}->{$vhost}->{$url} = $d;
}
}
2014-07-07 20:30:42 +02:00
return 1;
}
## @imethod protected codeRef conditionSub(string cond)
# Returns a compiled function used to grant users (used by
# locationRulesInit(). The second value returned is a non null
# constant if URL is not protected (by "unprotect" or "skip"), 0 else.
# @param $cond The boolean expression to use
# @param $mainClass optional
# @return array (ref(sub), int)
sub conditionSub {
my ( $class, $cond ) = @_;
2019-10-26 13:02:04 +02:00
$cond =~ s/\(\?#(\d+)\)$//;
my ( $OK, $NOK ) = ( sub { 1 }, sub { 0 } );
# Simple cases : accept and deny
return ( $OK, 0 )
if ( $cond =~ /^accept$/i );
return ( $NOK, 0 )
if ( $cond =~ /^deny$/i );
# Cases unprotect and skip : 2nd value is 1 or 2
return ( $OK, UNPROTECT )
if ( $cond =~ /^unprotect$/i );
return ( $OK, SKIP )
if ( $cond =~ /^skip$/i );
# Case logout
if ( $cond =~ /^logout(?:_sso)?(?:\s+(.*))?$/i ) {
my $url = $1;
return (
$url
? (
sub {
$_[1]->{_logout} = $url;
return 0;
},
0
)
: (
sub {
$_[1]->{_logout} = $class->tsv->{portal}->();
return 0;
},
0
)
);
}
# Since filter exists only with Apache>=2, logout_app and logout_app_sso
# targets are available only for it.
# This error can also appear with Manager configured as CGI script
2016-04-27 08:20:32 +02:00
if ( $cond =~ /^logout_app/i
2017-02-09 22:36:23 +01:00
and not $class->isa('Lemonldap::NG::Handler::ApacheMP2::Main') )
2016-04-27 08:20:32 +02:00
{
2017-02-15 07:41:50 +01:00
$class->logger->info(
"Rules logout_app and logout_app_sso require Apache>=2");
return ( sub { 1 }, 0 );
}
# logout_app
if ( $cond =~ /^logout_app(?:\s+(.*))?$/i ) {
2017-07-17 14:54:22 +02:00
my $u = $1 || $class->tsv->{portal}->();
eval 'use Apache2::Filter' unless ( $INC{"Apache2/Filter.pm"} );
return (
sub {
2017-03-29 13:26:04 +02:00
$_[0]->{env}->{'psgi.r'}->add_output_filter(
sub {
2016-04-21 22:19:22 +02:00
return $class->redirectFilter( $u, @_ );
}
);
1;
},
0
);
}
elsif ( $cond =~ /^logout_app_sso(?:\s+(.*))?$/i ) {
2017-07-17 14:54:22 +02:00
my $u = $1 || $class->tsv->{portal}->();
2016-04-25 09:39:58 +02:00
eval 'use Apache2::Filter' unless ( $INC{"Apache2/Filter.pm"} );
return (
sub {
my ($req) = @_;
2020-07-17 17:22:07 +02:00
$class->localUnlog( $req, @_ );
$req->{env}->{'psgi.r'}->add_output_filter(
sub {
2016-04-21 22:19:22 +02:00
my $r = $_[0]->r;
return $class->redirectFilter(
&{ $class->tsv->{portal} }() . "?url="
. $class->encodeUrl( $req, $u )
. "&logout=1",
@_
);
}
);
1;
},
0
);
}
2019-12-10 16:06:17 +01:00
my $mayskip = 0;
$mayskip = MAYSKIP if $cond =~ /\bskip\b/;
# Replace some strings in condition
$cond = $class->substitute($cond);
my $sub;
2016-07-30 22:48:03 +02:00
unless ( $sub = $class->buildSub($cond) ) {
2017-02-15 07:41:50 +01:00
$class->logger->error( "$class: Unable to build condition ($cond): "
. $class->tsv->{jail}->error );
}
# Return sub and protected flag
2019-12-10 16:06:17 +01:00
return ( $sub, $mayskip );
}
## @method arrayref aliasInit
# @param options vhostOptions configuration item
# @return arrayref of vhost and aliases
sub aliasInit {
my ( $class, $conf ) = @_;
foreach my $vhost ( keys %{ $conf->{vhostOptions} || {} } ) {
2016-02-19 09:50:38 +01:00
if ( my $aliases = $conf->{vhostOptions}->{$vhost}->{vhostAliases} ) {
foreach ( split /\s+/, $aliases ) {
$class->tsv->{vhostAlias}->{$_} = $vhost;
2017-02-15 07:41:50 +01:00
$class->logger->debug("Registering $_ as alias of $vhost");
}
}
}
return 1;
}
2014-07-24 17:48:32 +02:00
# TODO: support wildcards in aliases
## @method arrayref oauth2Init
# @param options vhostOptions configuration item
# @return arrayref of vhost and aliases
sub oauth2Init {
my ( $class, $conf ) = @_;
foreach my $rp ( keys %{ $conf->{oidcRPMetaDataOptions} || {} } ) {
if ( $conf->{oidcRPMetaDataOptions}->{$rp}
and $conf->{oidcRPMetaDataOptions}->{$rp}
->{oidcRPMetaDataOptionsClientID} )
{
$class->tsv->{oauth2Options}->{$rp}->{clientId} =
$conf->{oidcRPMetaDataOptions}->{$rp}
->{oidcRPMetaDataOptionsClientID};
}
}
return 1;
}
sub substitute {
my ( $class, $expr ) = @_;
# substitute special vars, just for retro-compatibility
2016-02-14 08:13:05 +01:00
$expr =~ s/\$date\b/&date/sg;
$expr =~ s/\$vhost\b/\$ENV{HTTP_HOST}/sg;
$expr =~ s/\$ip\b/\$ENV{REMOTE_ADDR}/sg;
# substitute vars with session data, excepts special vars $_ and $\d+
$expr =~ s/\$(?!(?:ENV|env|_rulematch)\b)(_\w+|[a-zA-Z]\w*)/\$s->{$1}/sg;
$expr =~ s/\$ENV\{/\$r->{env}->\{/g;
2018-09-04 16:03:53 +02:00
$expr =~ s/\$env->\{/\$r->{env}->\{/g;
$expr =~ s/\$_rulematch\[/\$m->\[/g;
2019-12-10 16:06:17 +01:00
$expr =~ s/\bskip\b/q\{999_SKIP\}/g;
# handle inGroup
2020-11-11 13:27:43 +01:00
$expr =~ s/\binGroup\(([^)]*)\)/listMatch(\$s->{'hGroups'},$1,1)/g;
2020-11-18 00:53:07 +01:00
# handle has2f
$expr =~ s/\bhas2f\(([^),]*)\)/has2f(\$s,$1)/g;
return $expr;
}
2016-07-30 22:48:03 +02:00
sub buildSub {
my ( $class, $val ) = @_;
2017-02-21 18:39:55 +01:00
my $res =
$class->tsv->{jail}->jail_reval("sub{my (\$r,\$s,\$m)=\@_;return($val)}");
2017-02-21 18:39:55 +01:00
unless ($res) {
$class->logger->error( $class->tsv->{jail}->error );
}
return $res;
2016-07-30 22:48:03 +02:00
}
1;