diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/tr.json b/lemonldap-ng-manager/site/htdocs/static/languages/tr.json index ef99fbd2d..59b7e6d4d 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/tr.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/tr.json @@ -118,6 +118,7 @@ "casAppMetaDataOptions":"Seçenekler", "casAppMetaDataOptionsService":"Servis URL'si", "casAppMetaDataOptionsRule":"Kural", +"casAppMetaDataMacros":"Makrolar", "casAppMetaDataOptionsUserAttribute":"Kullanıcı niteliği", "casAppName":"CAS Uygulama Adı", "casAttr":"CAS girişi", diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/CAS.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/CAS.pm index 8384ea8c4..d0fd85656 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/CAS.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/CAS.pm @@ -801,9 +801,21 @@ sub _validate2 { } foreach my $casAttribute ( keys %$ev ) { - my $localSessionValue = $localSession->data->{ $ev->{$casAttribute} }; - $attributes->{$casAttribute} = $localSessionValue - if defined $localSessionValue; + my $sessionAttr = $ev->{$casAttribute}; + my $value; + + # Lookup per-service macros first, and then local sessions + # + if ( $app and $self->spMacros->{$app}->{$sessionAttr} ) { + $value = $self->spMacros->{$app}->{$sessionAttr} + ->( $req, $localSession->data ); + } + else { + $value = $localSession->data->{$sessionAttr}; + } + + $attributes->{$casAttribute} = $value + if defined $value; } # Return success message diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/CAS.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/CAS.pm index c3eae9000..0fda78c76 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/CAS.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/CAS.pm @@ -26,6 +26,7 @@ has ua => ( has casSrvList => ( is => 'rw', default => sub { {} }, ); has casAppList => ( is => 'rw', default => sub { {} }, ); has spRules => ( is => 'rw', default => sub { {} }, ); +has spMacros => ( is => 'rw', default => sub { {} }, ); # RUNNING METHODS @@ -67,6 +68,22 @@ sub loadApp { } $self->spRules->{$_} = $rule; } + + # Load per-application macros + my $macros = $self->conf->{casAppMetaDataMacros}->{$_}; + for my $macroAttr ( keys %{$macros} ) { + my $macroRule = $macros->{$macroAttr}; + if ( length $macroRule ) { + $macroRule = $self->p->HANDLER->substitute($macroRule); + unless ( $macroRule = $self->p->HANDLER->buildSub($macroRule) ) + { + $self->error( 'SAML SP macro error: ' + . $self->p->HANDLER->tsv->{jail}->error ); + return 0; + } + $self->spMacros->{$_}->{$macroAttr} = $macroRule; + } + } } return 1; } diff --git a/lemonldap-ng-portal/t/32-CAS-Macros.t b/lemonldap-ng-portal/t/32-CAS-Macros.t new file mode 100644 index 000000000..a6f09b440 --- /dev/null +++ b/lemonldap-ng-portal/t/32-CAS-Macros.t @@ -0,0 +1,115 @@ +use lib 'inc'; +use Test::More; # skip_all => 'CAS is in rebuild'; +use strict; +use IO::String; +use LWP::UserAgent; +use LWP::Protocol::PSGI; +use MIME::Base64; + +BEGIN { + require 't/test-lib.pm'; +} + +my $debug = 'error'; +my ( $issuer, $res ); + +eval { require XML::Simple }; +plan skip_all => "Missing dependencies: $@" if ($@); + +ok( $issuer = issuer(), 'Issuer portal' ); +count(1); + +ok( + $res = $issuer->_get( + '/cas/login', + query => 'service=http://auth.sp.com/', + accept => 'text/html' + ), + 'Query CAS server' +); +count(1); +expectOK($res); +my $pdata = 'lemonldappdata=' . expectCookie( $res, 'lemonldappdata' ); + +# Try to authenticate to IdP +my $body = $res->[2]->[0]; +$body =~ s/^.*?//s; +$body =~ s#.*$##s; +my %fields = + ( $body =~ /new( { + ini => { + logLevel => $debug, + domain => 'idp.com', + portal => 'http://auth.idp.com', + authentication => 'Demo', + userDB => 'Same', + issuerDBCASActivation => 1, + casAttr => 'uid', + casAppMetaDataOptions => { + sp => { + casAppMetaDataOptionsService => 'http://auth.sp.com/', + }, + }, + casAppMetaDataExportedVars => { + sp => { + cn => 'cn', + sn => 'extracted_sn', + mail => 'mail', + uid => 'uid', + }, + }, + casAppMetaDataMacros => { + sp => { + extracted_sn => '(split(/\s/, $cn))[1]', + } + }, + casAccessControlPolicy => 'error', + multiValuesSeparator => ';', + } + } + ); +}