Better URL parsing (#2477)

This commit is contained in:
Yadd 2021-03-02 08:46:59 +01:00
parent 8a18543f55
commit 3732cdcc19
11 changed files with 47 additions and 30 deletions

View File

@ -9,6 +9,7 @@ use Lemonldap::NG::Manager::Build::CTrees;
use Lemonldap::NG::Manager::Build::PortalConstants; use Lemonldap::NG::Manager::Build::PortalConstants;
use Lemonldap::NG::Manager::Conf::Zero; use Lemonldap::NG::Manager::Conf::Zero;
use Data::Dumper; use Data::Dumper;
use Regexp::Common 'URI';
use Regexp::Assemble; use Regexp::Assemble;
use JSON; use JSON;
use Getopt::Std; use Getopt::Std;
@ -466,6 +467,7 @@ sub buildPortalConstants() {
printf STDERR $format, $self->portalConstantsFile; printf STDERR $format, $self->portalConstantsFile;
open( F, '>', $self->portalConstantsFile ) or die($!); open( F, '>', $self->portalConstantsFile ) or die($!);
my $urire = $RE{URI}{HTTP}{ -scheme=>qr/https?/ }{-keep};
my $content = <<EOF; my $content = <<EOF;
# This file is generated by $module. Don't modify it by hand # This file is generated by $module. Don't modify it by hand
package Lemonldap::NG::Portal::Main::Constants; package Lemonldap::NG::Portal::Main::Constants;
@ -476,6 +478,7 @@ use Exporter 'import';
our \$VERSION = '$Lemonldap::NG::Manager::Build::Attributes::VERSION'; our \$VERSION = '$Lemonldap::NG::Manager::Build::Attributes::VERSION';
use constant HANDLER => 'Lemonldap::NG::Handler::PSGI::Main'; use constant HANDLER => 'Lemonldap::NG::Handler::PSGI::Main';
use constant URIRE => qr{$urire};
use constant { use constant {
EOF EOF
for my $pe ( for my $pe (
@ -499,7 +502,7 @@ $portalConstsStr
} }
# EXPORTER PARAMETERS # EXPORTER PARAMETERS
our \@EXPORT_OK = ( 'portalConsts', 'HANDLER', $exports ); our \@EXPORT_OK = ( 'portalConsts', 'HANDLER', 'URIRE', $exports );
our %EXPORT_TAGS = ( 'all' => [ \@EXPORT_OK, 'import' ], ); our %EXPORT_TAGS = ( 'all' => [ \@EXPORT_OK, 'import' ], );
our \@EXPORT = qw(import PE_OK); our \@EXPORT = qw(import PE_OK);

View File

@ -12,9 +12,10 @@ use Lemonldap::NG::Portal::Main::Constants qw(
PE_OK PE_OK
PE_BADURL PE_BADURL
PE_SENDRESPONSE PE_SENDRESPONSE
URIRE
); );
our $VERSION = '2.0.9'; our $VERSION = '2.0.12';
extends 'Lemonldap::NG::Portal::Main::Issuer', extends 'Lemonldap::NG::Portal::Main::Issuer',
'Lemonldap::NG::Portal::Lib::CAS'; 'Lemonldap::NG::Portal::Lib::CAS';
@ -93,8 +94,7 @@ sub storeEnvAndCheckGateway {
return PE_SENDRESPONSE; return PE_SENDRESPONSE;
} }
if ( $service and $service =~ m#^(https?://[^/]+)(/.*)?$# ) { if ( $service and $service =~ URIRE ) {
my ( $host, $uri ) = ( $1, $2 );
my $app = $self->getCasApp($service); my $app = $self->getCasApp($service);
if ($app) { if ($app) {

View File

@ -5,9 +5,9 @@ use Mouse;
use URI::Escape; use URI::Escape;
use Lemonldap::NG::Common::FormEncode; use Lemonldap::NG::Common::FormEncode;
use Lemonldap::NG::Portal::Main::Constants use Lemonldap::NG::Portal::Main::Constants
qw(PE_OK PE_BADURL PE_GET_SERVICE_NOT_ALLOWED); qw(PE_OK PE_BADURL PE_GET_SERVICE_NOT_ALLOWED URIRE);
our $VERSION = '2.0.9'; our $VERSION = '2.0.12';
extends 'Lemonldap::NG::Portal::Main::Issuer'; extends 'Lemonldap::NG::Portal::Main::Issuer';
@ -82,11 +82,11 @@ sub computeGetParams {
# Additional GET variables # Additional GET variables
my %getPrms; my %getPrms;
if ( exists $self->conf->{issuerDBGetParameters} ) { if ( exists $self->conf->{issuerDBGetParameters} ) {
unless ( $req->urldc =~ m#^https?://([^/]+)# ) { unless ( $req->urldc =~ URIRE ) {
$self->logger->error("Malformed url $req->urldc"); $self->logger->error("Malformed url $req->urldc");
return; return;
} }
my $vhost = $1; my $vhost = $3 . ( $4 ? ":$4" : '' );
my $prms = $self->conf->{issuerDBGetParameters}->{$vhost}; my $prms = $self->conf->{issuerDBGetParameters}->{$vhost};
unless ($prms) { unless ($prms) {
$self->logger->warn("IssuerGet: $vhost has no configuration"); $self->logger->warn("IssuerGet: $vhost has no configuration");

View File

@ -9,10 +9,10 @@ with 'Lemonldap::NG::Portal::Lib::OverConf';
our $VERSION = '2.0.11'; our $VERSION = '2.0.11';
has modules => ( is => 'rw', default => sub { {} } ); has modules => ( is => 'rw', default => sub { {} } );
has rules => ( is => 'rw', default => sub { {} } ); has rules => ( is => 'rw', default => sub { {} } );
has type => ( is => 'rw' ); has type => ( is => 'rw' );
has catch => ( is => 'rw', default => sub { {} } ); has catch => ( is => 'rw', default => sub { {} } );
has sessionKey => ( is => 'ro', default => '_choice' ); has sessionKey => ( is => 'ro', default => '_choice' );
my $_choiceRules; my $_choiceRules;

View File

@ -7,6 +7,8 @@ use Exporter 'import';
our $VERSION = '2.0.12'; our $VERSION = '2.0.12';
use constant HANDLER => 'Lemonldap::NG::Handler::PSGI::Main'; use constant HANDLER => 'Lemonldap::NG::Handler::PSGI::Main';
use constant URIRE =>
qr{(((?^:https?))://((?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-9]*[a-zA-Z0-9]|[a-zA-Z])[.]?)|(?:[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+)))(?::((?:[0-9]*)))?(/(((?:(?:(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*)(?:;(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*))*)(?:/(?:(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*)(?:;(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*))*))*))(?:[?]((?:(?:[;/?:@&=+$,a-zA-Z0-9\-_.!~*'()]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*)))?))?)};
use constant { use constant {
PE_IDPCHOICE => -5, PE_IDPCHOICE => -5,
PE_SENDRESPONSE => -4, PE_SENDRESPONSE => -4,
@ -224,6 +226,7 @@ sub portalConsts {
our @EXPORT_OK = ( our @EXPORT_OK = (
'portalConsts', 'portalConsts',
'HANDLER', 'HANDLER',
'URIRE',
'PE_IDPCHOICE', 'PE_IDPCHOICE',
'PE_SENDRESPONSE', 'PE_SENDRESPONSE',
'PE_INFO', 'PE_INFO',

View File

@ -5,8 +5,9 @@ package Lemonldap::NG::Portal::Main::Menu;
use strict; use strict;
use Mouse; use Mouse;
use Clone 'clone'; use Clone 'clone';
use Lemonldap::NG::Portal::Main::Constants 'URIRE';
our $VERSION = '2.0.8'; our $VERSION = '2.0.12';
extends 'Lemonldap::NG::Common::Module'; extends 'Lemonldap::NG::Common::Module';
@ -293,11 +294,11 @@ sub _buildApplicationHash {
my $applications; my $applications;
# Get application items # Get application items
my $appname = $apphash->{options}->{name} || $appid; my $appname = $apphash->{options}->{name} || $appid;
my $appuri = $apphash->{options}->{uri} || ""; my $appuri = $apphash->{options}->{uri} || "";
my $appdesc = $apphash->{options}->{description}; my $appdesc = $apphash->{options}->{description};
my $applogo = $apphash->{options}->{logo}; my $applogo = $apphash->{options}->{logo};
my $apptip = $apphash->{options}->{tooltip} || $appname; my $apptip = $apphash->{options}->{tooltip} || $appname;
# Detect sub applications # Detect sub applications
my $subapphash; my $subapphash;
@ -393,9 +394,8 @@ sub _filterHash {
# Check rights # Check rights
my $appdisplay = $apphash->{$key}->{options}->{display} my $appdisplay = $apphash->{$key}->{options}->{display}
|| "auto"; || "auto";
my ( $vhost, $appuri ) = $apphash->{$key}->{options}->{uri} =~ URIRE;
$apphash->{$key}->{options}->{uri} =~ m#^https?://([^/]*)(.*)#; my ( $vhost, $appuri ) = ( $3, $5 );
$vhost =~ s/:\d+$//;
$vhost = $self->p->HANDLER->resolveAlias($vhost); $vhost = $self->p->HANDLER->resolveAlias($vhost);
$appuri ||= '/'; $appuri ||= '/';

View File

@ -156,12 +156,16 @@ sub controlUrl {
} }
# Unprotected hosts # Unprotected hosts
my ( $proto, $vhost, $appuri ) = $tmp =~ m{^(https?://)([^/#?]*)(.*)}; unless ( $tmp =~ URIRE ) {
$vhost =~ s/:\d+$//; $self->userLogger->error("Bad URL $tmp");
delete $req->{urldc};
return PE_BADURL;
}
my ( $proto, $vhost, $appuri ) = ( $2, $3, $5 );
# Try to resolve alias # Try to resolve alias
my $originalVhost = $self->HANDLER->resolveAlias($vhost); my $originalVhost = $self->HANDLER->resolveAlias($vhost);
$vhost = $proto . $originalVhost; $vhost = $proto . '://' . $originalVhost;
$self->logger->debug( "Required URL (param: " $self->logger->debug( "Required URL (param: "
. ( $req->param('logout') ? 'HTTP Referer' : 'urldc' ) . ( $req->param('logout') ? 'HTTP Referer' : 'urldc' )
. " | value: $tmp | alias: $vhost)" ); . " | value: $tmp | alias: $vhost)" );

View File

@ -9,7 +9,7 @@
# #
package Lemonldap::NG::Portal::Main::Run; package Lemonldap::NG::Portal::Main::Run;
our $VERSION = '2.0.10'; our $VERSION = '2.0.12';
package Lemonldap::NG::Portal::Main; package Lemonldap::NG::Portal::Main;
@ -886,14 +886,16 @@ sub sendHtml {
my $csp = $self->csp . "form-action " . $self->conf->{cspFormAction}; my $csp = $self->csp . "form-action " . $self->conf->{cspFormAction};
if ( my $url = $req->urldc ) { if ( my $url = $req->urldc ) {
$self->logger->debug("Required urldc : $url"); $self->logger->debug("Required urldc : $url");
$url =~ s#(https?://[^/]+).*#$1#; $url =~ URIRE;
$url = $2 . '://' . $3 . ( $4 ? ":$4" : '' );
$self->logger->debug("Set CSP form-action with urldc : $url"); $self->logger->debug("Set CSP form-action with urldc : $url");
$csp .= " $url"; $csp .= " $url";
} }
my $url = $args{params}->{URL}; my $url = $args{params}->{URL};
if ( defined $url ) { if ( defined $url ) {
$self->logger->debug("Required Params URL : $url"); $self->logger->debug("Required Params URL : $url");
if ( $url =~ s#(https?://[^/]+).*#$1# ) { if ( $url =~ URIRE ) {
$url = $2 . '://' . $3 . ( $4 ? ":$4" : '' );
$self->logger->debug("Set CSP form-action with Params URL : $url"); $self->logger->debug("Set CSP form-action with Params URL : $url");
$csp .= " $url"; $csp .= " $url";
} }

View File

@ -6,9 +6,10 @@ use Lemonldap::NG::Portal::Main::Constants qw(
PE_APACHESESSIONERROR PE_APACHESESSIONERROR
PE_ERROR PE_ERROR
PE_OK PE_OK
URIRE
); );
our $VERSION = '2.0.8'; our $VERSION = '2.0.12';
extends 'Lemonldap::NG::Common::Module'; extends 'Lemonldap::NG::Common::Module';
@ -25,7 +26,8 @@ sub changeUrldc {
my ( $self, $req ) = @_; my ( $self, $req ) = @_;
my $urldc = $req->{urldc} || ''; my $urldc = $req->{urldc} || '';
if ( $req->id if ( $req->id
and $urldc !~ m#^https?://[^/]*$self->{conf}->{domain}(:\d+)?/#oi and $urldc =~ URIRE
and $3 !~ m@\Q$self->{conf}->{domain}\E$@oi
and $self->p->isTrustedUrl($urldc) ) and $self->p->isTrustedUrl($urldc) )
{ {
my $ssl = $urldc =~ /^https/; my $ssl = $urldc =~ /^https/;

View File

@ -62,6 +62,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
PE_OK PE_OK
portalConsts portalConsts
PE_PASSWORD_OK PE_PASSWORD_OK
URIRE
); );
our $VERSION = '2.0.12'; our $VERSION = '2.0.12';
@ -247,7 +248,7 @@ sub init {
mysession => { ':sessionType' => 'updateMySession' }, mysession => { ':sessionType' => 'updateMySession' },
['PUT'] ['PUT']
); );
extends @parents if ($add); extends @parents if ($add);
$self->setTypes( $self->conf ) if ( $self->conf->{restSessionServer} ); $self->setTypes( $self->conf ) if ( $self->conf->{restSessionServer} );
return 1; return 1;
@ -406,7 +407,8 @@ sub mysession {
if ( $self->p->checkXSSAttack( 'authorizationfor', $req->urldc ) ); if ( $self->p->checkXSSAttack( 'authorizationfor', $req->urldc ) );
# Split URL # Split URL
my ( $host, $uri ) = ( $req->urldc =~ m#^https?://([^/]+)(/.*)?$# ); $req->urldc =~ URIRE;
my ( $host, $uri ) = ( $3 . ( $4 ? ":$4" : '' ), $5 );
$uri ||= '/'; $uri ||= '/';
return $self->p->sendError( $req, "Bad URL $req->{urldc}", 400 ) return $self->p->sendError( $req, "Bad URL $req->{urldc}", 400 )
unless ($host); unless ($host);

View File

@ -16,6 +16,7 @@ use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw( use Lemonldap::NG::Portal::Main::Constants qw(
PE_OK PE_OK
PE_FORMEMPTY PE_FORMEMPTY
URIRE
); );
our $VERSION = '2.0.12'; our $VERSION = '2.0.12';
@ -458,7 +459,7 @@ sub isAuthorizedURI {
my ( $self, $req, $id, $url ) = @_; my ( $self, $req, $id, $url ) = @_;
die 'id is required' unless ($id); die 'id is required' unless ($id);
die 'uri is required' unless ($url); die 'uri is required' unless ($url);
die 'Bad uri' unless ( $url =~ m#^https?://([^/]+)(/.*)?$# ); die 'Bad uri' unless ( $url =~ URIRE );
my ( $host, $uri ) = ( $1, $2 ); my ( $host, $uri ) = ( $1, $2 );
# Get user session. # Get user session.