From b1f2ac6a738eae2cf515a1ca897da72e47b1ca8c Mon Sep 17 00:00:00 2001 From: Xavier Guimard Date: Tue, 22 Nov 2016 12:34:09 +0000 Subject: [PATCH] SAML in progress (#595) --- .../lib/Lemonldap/NG/Portal/Auth/SAML.pm | 2 + .../lib/Lemonldap/NG/Portal/Main/Process.pm | 2 +- .../lib/Lemonldap/NG/Portal/Main/Request.pm | 17 ++- .../lib/Lemonldap/NG/Portal/Main/Run.pm | 117 ++++++++++++++++++ 4 files changed, 133 insertions(+), 5 deletions(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SAML.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SAML.pm index d8bc0aa29..e3ca2b8fc 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SAML.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SAML.pm @@ -725,6 +725,7 @@ sub extractFormInfo { # TODO: verify this $req->steps( ['autoPost'] ); + $req->continue(1); return PE_OK; } @@ -1059,6 +1060,7 @@ sub extractFormInfo { # TODO: verify this $req->steps( ['autoPost'] ); + $req->continue(1); return PE_OK; } diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Process.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Process.pm index 319bafe66..05a526992 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Process.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Process.pm @@ -220,7 +220,7 @@ sub checkXSSAttack { sub extractFormInfo { my ( $self, $req ) = @_; my $ret = $self->_authentication->extractFormInfo($req); - if ( $ret == PE_OK and not $req->user ) { + if ( $ret == PE_OK and not ($req->user or $req->continue) ) { $self->lmLog( 'Authentication module succeed but has not set $req->user', 'error' ); diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Request.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Request.pm index 9be9737d0..c7d3cfdcd 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Request.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Request.pm @@ -51,8 +51,13 @@ has customParameters => ( is => 'rw' ); has mustRedirect => ( is => 'rw' ); # Store URL for redirections -has urldc => ( is => 'rw' ); -has postUrl => ( is => 'rw' ); +has urldc => ( is => 'rw' ); +has postUrl => ( is => 'rw' ); +has postFields => ( is => 'rw' ); +has portalHiddenFormValues => ( is => 'rw' ); + +# Flag that permit to a auth module to return PE_OK without setting $user +has continue => ( is => 'rw' ); # "check logins "flag" has checkLogins => ( is => 'rw' ); @@ -114,11 +119,15 @@ sub init { } sub errorString { - - #TODO + print STDERR "TODO Request::errorString()\n"; } sub loginInfo { + print STDERR "TODO Request::loginInfo()\n"; +} + +sub info { + print STDERR "TODO Request::info()\n"; } # TODO: oldpassword diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm index 85086141c..7865e52c2 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm @@ -468,4 +468,121 @@ sub stamp { return $self->conf->{cipher} ? $self->conf->{cipher}->encrypt( time() ) : 1; } +# Transfer POST data with auto submit +# @return void +sub autoPost { + my ( $self, $req ) = @_; + + # Get URL and Form fields + $req->{urldc} = $req->postUrl; + my $formFields = $req->postFields; + + $self->clearHiddenFormValue($req); + foreach ( keys %$formFields ) { + $self->setHiddenFormValue( $req, $_, $formFields->{$_}, "", 0 ); + } + + # Display info before redirecting + if ( $req->info() ) { + $req->{infoFormMethod} = $req->param('method') || "post"; + return PE_INFO; + } + + $self->{redirectFormMethod} = "post"; + return PE_REDIRECT; +} + +# Add element into $self->{portalHiddenFormValues}, those values could be +# used to hide values into HTML form. +# @param fieldname The field name which will contain the correponding value +# @param value The associated value +# @param prefix Prefix of the field key +# @param base64 Encode value in base64 +# @return nothing +sub setHiddenFormValue { + my ( $self, $req, $key, $val, $prefix, $base64 ) = @_; + + # Default values + $prefix = "lmhidden_" unless defined $prefix; + $base64 = 1 unless defined $base64; + + # Store value + if ($val) { + $key = $prefix . $key; + $val = encode_base64($val) if $base64; + $req->{portalHiddenFormValues}->{$key} = $val; + $self->lmLog( "Store $val in hidden key $key", 'debug' ); + } +} + +## @method public void getHiddenFormValue(string fieldname, string prefix, boolean base64) +# Get value into $self->{portalHiddenFormValues}. +# @param fieldname The existing field name which contains a value +# @param prefix Prefix of the field key +# @param base64 Decode value from base64 +# @return string The associated value +sub getHiddenFormValue { + my ( $self, $req, $key, $prefix, $base64 ) = @_; + + # Default values + $prefix = "lmhidden_" unless defined $prefix; + $base64 = 1 unless defined $base64; + + $key = $prefix . $key; + + # Get value + if ( my $val = $req->param($key) ) { + $val = decode_base64($val) if $base64; + return $val; + $self->lmLog( "Hidden value $val found for key $key", 'debug' ); + } + + # No value found + return undef; +} + +## @method protected void clearHiddenFormValue(arrayref keys) +# Clear values form stored hidden fields +# Delete all keys if no keys provided +# @param keys Array reference of keys +# @return nothing +sub clearHiddenFormValue { + my ( $self, $req, $keys ) = @_; + + unless ( defined $keys ) { + delete $req->{portalHiddenFormValues}; + $self->lmLog( "Delete all hidden values", 'debug' ); + } + else { + foreach (@$keys) { + delete $req->{portalHiddenFormValues}->{$_}; + $self->lmLog( "Delete hidden value for key $_", 'debug' ); + } + } + + return; +} + +##@method public string buildHiddenForm() +# Return an HTML representation of hidden values. +# @return HTML code +sub buildHiddenForm { + my ( $self, $req ) = @_; + my @keys = keys %{ $req->{portalHiddenFormValues} // {} }; + my $val = ''; + + foreach (@keys) { + + # Check XSS attacks + next + if $self->checkXSSAttack( $_, $req->{portalHiddenFormValues}->{$_} ); + + # Build hidden input HTML code + $val .= qq{'; + } + + return $val; +} + 1;