New Issuer::CAS (#1183)
This commit is contained in:
parent
d1d57fae22
commit
b83374b274
|
@ -24,7 +24,7 @@ our $specialNodeHash = {
|
||||||
our $doubleHashKeys = 'issuerDBGetParameters';
|
our $doubleHashKeys = 'issuerDBGetParameters';
|
||||||
our $simpleHashKeys = '(?:(?:l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|c(?:as(?:StorageOption|Attribute)|ustomAddParam|ombModule)|(?:(?:d(?:emo|bi)|facebook|webID)E|e)xportedVar|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|re(?:moteGlobalStorageOption|loadUrl)|macro)s|o(?:idcS(?:erviceMetaDataAuthnContext|torageOptions)|penIdExportedVars)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember)|a(?:uthChoiceModules|pplicationList)|S(?:MTPTLSOpts|SLVarIf))';
|
our $simpleHashKeys = '(?:(?:l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|c(?:as(?:StorageOption|Attribute)|ustomAddParam|ombModule)|(?:(?:d(?:emo|bi)|facebook|webID)E|e)xportedVar|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|re(?:moteGlobalStorageOption|loadUrl)|macro)s|o(?:idcS(?:erviceMetaDataAuthnContext|torageOptions)|penIdExportedVars)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember)|a(?:uthChoiceModules|pplicationList)|S(?:MTPTLSOpts|SLVarIf))';
|
||||||
our $specialNodeKeys = '(?:(?:(?:saml(?:ID|S)|oidc[OR])P|cas(?:App|Srv))MetaDataNode|virtualHost)s';
|
our $specialNodeKeys = '(?:(?:(?:saml(?:ID|S)|oidc[OR])P|cas(?:App|Srv))MetaDataNode|virtualHost)s';
|
||||||
our $casAppMetaDataNodeKeys = 'casAppMetaData(?:OptionsService|ExportedVars)';
|
our $casAppMetaDataNodeKeys = 'casAppMetaData(?:Options(?:Servic|Rul)e|ExportedVars)';
|
||||||
our $casSrvMetaDataNodeKeys = 'casSrvMetaData(?:Options(?:ProxiedServices|DisplayName|Gateway|Renew|Icon|Url)|ExportedVars)';
|
our $casSrvMetaDataNodeKeys = 'casSrvMetaData(?:Options(?:ProxiedServices|DisplayName|Gateway|Renew|Icon|Url)|ExportedVars)';
|
||||||
our $oidcOPMetaDataNodeKeys = 'oidcOPMetaData(?:Options(?:C(?:lient(?:Secret|ID)|heckJWTSignature|onfigurationURI)|TokenEndpointAuthMethod|(?:JWKSTimeou|Promp)t|I(?:DTokenMaxAge|con)|S(?:toreIDToken|cope)|U(?:iLocales|seNonce)|Display(?:Name)?|AcrValues|MaxAge)|ExportedVars|J(?:SON|WKS))';
|
our $oidcOPMetaDataNodeKeys = 'oidcOPMetaData(?:Options(?:C(?:lient(?:Secret|ID)|heckJWTSignature|onfigurationURI)|TokenEndpointAuthMethod|(?:JWKSTimeou|Promp)t|I(?:DTokenMaxAge|con)|S(?:toreIDToken|cope)|U(?:iLocales|seNonce)|Display(?:Name)?|AcrValues|MaxAge)|ExportedVars|J(?:SON|WKS))';
|
||||||
our $oidcRPMetaDataNodeKeys = 'oidcRPMetaData(?:Options(?:I(?:DToken(?:Expiration|SignAlg)|con)|Logout(?:SessionRequired|Type|Url)|AccessTokenExpiration|R(?:edirectUris|ule)|Client(?:Secret|ID)|BypassConsent|DisplayName|ExtraClaims|UserIDAttr)|ExportedVars)';
|
our $oidcRPMetaDataNodeKeys = 'oidcRPMetaData(?:Options(?:I(?:DToken(?:Expiration|SignAlg)|con)|Logout(?:SessionRequired|Type|Url)|AccessTokenExpiration|R(?:edirectUris|ule)|Client(?:Secret|ID)|BypassConsent|DisplayName|ExtraClaims|UserIDAttr)|ExportedVars)';
|
||||||
|
@ -67,6 +67,5 @@ our $issuerParameters = {
|
||||||
};
|
};
|
||||||
our $samlServiceParameters = [qw(samlEntityID samlServicePrivateKeySig samlServicePrivateKeySigPwd samlServicePublicKeySig samlServicePrivateKeyEnc samlServicePrivateKeyEncPwd samlServicePublicKeyEnc samlServiceUseCertificateInResponse samlNameIDFormatMapEmail samlNameIDFormatMapX509 samlNameIDFormatMapWindows samlNameIDFormatMapKerberos samlAuthnContextMapPassword samlAuthnContextMapPasswordProtectedTransport samlAuthnContextMapTLSClient samlAuthnContextMapKerberos samlOrganizationDisplayName samlOrganizationName samlOrganizationURL samlSPSSODescriptorAuthnRequestsSigned samlSPSSODescriptorWantAssertionsSigned samlSPSSODescriptorSingleLogoutServiceHTTPRedirect samlSPSSODescriptorSingleLogoutServiceHTTPPost samlSPSSODescriptorSingleLogoutServiceSOAP samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact samlSPSSODescriptorAssertionConsumerServiceHTTPPost samlSPSSODescriptorArtifactResolutionServiceArtifact samlIDPSSODescriptorWantAuthnRequestsSigned samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect samlIDPSSODescriptorSingleSignOnServiceHTTPPost samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect samlIDPSSODescriptorSingleLogoutServiceHTTPPost samlIDPSSODescriptorSingleLogoutServiceSOAP samlIDPSSODescriptorArtifactResolutionServiceArtifact samlAttributeAuthorityDescriptorAttributeServiceSOAP samlIdPResolveCookie samlMetadataForceUTF8 samlStorage samlStorageOptions samlRelayStateTimeout samlUseQueryStringSpecific samlCommonDomainCookieActivation samlCommonDomainCookieDomain samlCommonDomainCookieReader samlCommonDomainCookieWriter)];
|
our $samlServiceParameters = [qw(samlEntityID samlServicePrivateKeySig samlServicePrivateKeySigPwd samlServicePublicKeySig samlServicePrivateKeyEnc samlServicePrivateKeyEncPwd samlServicePublicKeyEnc samlServiceUseCertificateInResponse samlNameIDFormatMapEmail samlNameIDFormatMapX509 samlNameIDFormatMapWindows samlNameIDFormatMapKerberos samlAuthnContextMapPassword samlAuthnContextMapPasswordProtectedTransport samlAuthnContextMapTLSClient samlAuthnContextMapKerberos samlOrganizationDisplayName samlOrganizationName samlOrganizationURL samlSPSSODescriptorAuthnRequestsSigned samlSPSSODescriptorWantAssertionsSigned samlSPSSODescriptorSingleLogoutServiceHTTPRedirect samlSPSSODescriptorSingleLogoutServiceHTTPPost samlSPSSODescriptorSingleLogoutServiceSOAP samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact samlSPSSODescriptorAssertionConsumerServiceHTTPPost samlSPSSODescriptorArtifactResolutionServiceArtifact samlIDPSSODescriptorWantAuthnRequestsSigned samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect samlIDPSSODescriptorSingleSignOnServiceHTTPPost samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect samlIDPSSODescriptorSingleLogoutServiceHTTPPost samlIDPSSODescriptorSingleLogoutServiceSOAP samlIDPSSODescriptorArtifactResolutionServiceArtifact samlAttributeAuthorityDescriptorAttributeServiceSOAP samlIdPResolveCookie samlMetadataForceUTF8 samlStorage samlStorageOptions samlRelayStateTimeout samlUseQueryStringSpecific samlCommonDomainCookieActivation samlCommonDomainCookieDomain samlCommonDomainCookieReader samlCommonDomainCookieWriter)];
|
||||||
our $oidcServiceParameters = [qw(oidcServiceMetaDataIssuer oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI oidcServiceMetaDataEndSessionURI oidcServiceMetaDataCheckSessionURI oidcServiceMetaDataFrontChannelURI oidcServiceMetaDataBackChannelURI oidcServiceMetaDataAuthnContext oidcServicePrivateKeySig oidcServicePublicKeySig oidcServiceKeyIdSig oidcServiceAllowDynamicRegistration oidcServiceAllowAuthorizationCodeFlow oidcServiceAllowImplicitFlow oidcServiceAllowHybridFlow oidcStorage oidcStorageOptions)];
|
our $oidcServiceParameters = [qw(oidcServiceMetaDataIssuer oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI oidcServiceMetaDataEndSessionURI oidcServiceMetaDataCheckSessionURI oidcServiceMetaDataFrontChannelURI oidcServiceMetaDataBackChannelURI oidcServiceMetaDataAuthnContext oidcServicePrivateKeySig oidcServicePublicKeySig oidcServiceKeyIdSig oidcServiceAllowDynamicRegistration oidcServiceAllowAuthorizationCodeFlow oidcServiceAllowImplicitFlow oidcServiceAllowHybridFlow oidcStorage oidcStorageOptions)];
|
||||||
our $casServiceParameters = [qw()];
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -640,6 +640,25 @@ sub attributes {
|
||||||
'casAppMetaDataOptions' => {
|
'casAppMetaDataOptions' => {
|
||||||
'type' => 'subContainer'
|
'type' => 'subContainer'
|
||||||
},
|
},
|
||||||
|
'casAppMetaDataOptionsRule' => {
|
||||||
|
'test' => sub {
|
||||||
|
my ( $val, $conf ) = @_;
|
||||||
|
my $s = '';
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
${^WARNING_BITS} =
|
||||||
|
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55";
|
||||||
|
}
|
||||||
|
eval "$s $val";
|
||||||
|
my $err = join(
|
||||||
|
'',
|
||||||
|
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
|
||||||
|
split( /\n/, $@, 0 ) )
|
||||||
|
);
|
||||||
|
return $err ? ( 1, "__badExpression__: $err" ) : 1;
|
||||||
|
},
|
||||||
|
'type' => 'text'
|
||||||
|
},
|
||||||
'casAppMetaDataOptionsService' => {
|
'casAppMetaDataOptionsService' => {
|
||||||
'type' => 'url'
|
'type' => 'url'
|
||||||
},
|
},
|
||||||
|
|
|
@ -214,7 +214,7 @@ EOF
|
||||||
}
|
}
|
||||||
print F "$tmp};\n";
|
print F "$tmp};\n";
|
||||||
}
|
}
|
||||||
foreach (qw(samlServiceParameters oidcServiceParameters casServiceParameters)) {
|
foreach (qw(samlServiceParameters oidcServiceParameters)) {
|
||||||
no strict 'refs';
|
no strict 'refs';
|
||||||
$tmp = "our \$$_ = [qw(" . join( ' ', @$$_ ) . ")];\n";
|
$tmp = "our \$$_ = [qw(" . join( ' ', @$$_ ) . ")];\n";
|
||||||
print F "$tmp";
|
print F "$tmp";
|
||||||
|
|
|
@ -1247,6 +1247,11 @@ sub attributes {
|
||||||
type => 'url',
|
type => 'url',
|
||||||
documentation => 'CAS App service',
|
documentation => 'CAS App service',
|
||||||
},
|
},
|
||||||
|
casAppMetaDataOptionsRule => {
|
||||||
|
type => 'text',
|
||||||
|
test => $perlExpr,
|
||||||
|
documentation => 'CAS App rule',
|
||||||
|
},
|
||||||
|
|
||||||
# Fake attribute: used by manager REST API to agglomerate all nodes
|
# Fake attribute: used by manager REST API to agglomerate all nodes
|
||||||
# related to a SAML SP partner
|
# related to a SAML SP partner
|
||||||
|
|
|
@ -231,7 +231,10 @@ sub cTrees {
|
||||||
casAppMetaDataNode => [
|
casAppMetaDataNode => [
|
||||||
{
|
{
|
||||||
title => 'casAppMetaDataOptions',
|
title => 'casAppMetaDataOptions',
|
||||||
nodes => ['casAppMetaDataOptionsService']
|
nodes => [
|
||||||
|
'casAppMetaDataOptionsService',
|
||||||
|
'casAppMetaDataOptionsRule'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
'casAppMetaDataExportedVars',
|
'casAppMetaDataExportedVars',
|
||||||
],
|
],
|
||||||
|
|
|
@ -16,6 +16,11 @@ function templates(tpl,key) {
|
||||||
"get" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsService",
|
"get" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsService",
|
||||||
"id" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsService",
|
"id" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsService",
|
||||||
"title" : "casAppMetaDataOptionsService"
|
"title" : "casAppMetaDataOptionsService"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"get" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsRule",
|
||||||
|
"id" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsRule",
|
||||||
|
"title" : "casAppMetaDataOptionsRule"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"id" : "casAppMetaDataOptions",
|
"id" : "casAppMetaDataOptions",
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -108,6 +108,7 @@
|
||||||
"casAppMetaDataNodes": "CAS Applications",
|
"casAppMetaDataNodes": "CAS Applications",
|
||||||
"casAppMetaDataOptions": "Options",
|
"casAppMetaDataOptions": "Options",
|
||||||
"casAppMetaDataOptionsService": "Service URL",
|
"casAppMetaDataOptionsService": "Service URL",
|
||||||
|
"casAppMetaDataOptionsRule": "Rule",
|
||||||
"casAppName": "CAS App Name",
|
"casAppName": "CAS App Name",
|
||||||
"casAttr": "CAS login",
|
"casAttr": "CAS login",
|
||||||
"casAttributes": "CAS exported attributes",
|
"casAttributes": "CAS exported attributes",
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
"casAppMetaDataNodes": "Applications CAS",
|
"casAppMetaDataNodes": "Applications CAS",
|
||||||
"casAppMetaDataOptions": "Options",
|
"casAppMetaDataOptions": "Options",
|
||||||
"casAppMetaDataOptionsService": "URL du service",
|
"casAppMetaDataOptionsService": "URL du service",
|
||||||
|
"casAppMetaDataOptionsRule": "Règle",
|
||||||
"casAppName": "Nom de l'application CAS",
|
"casAppName": "Nom de l'application CAS",
|
||||||
"casAttr": "Identifiant CAS",
|
"casAttr": "Identifiant CAS",
|
||||||
"casAttributes": "Attributs CAS",
|
"casAttributes": "Attributs CAS",
|
||||||
|
|
|
@ -27,6 +27,7 @@ sub init {
|
||||||
|
|
||||||
# Launch parents initialization subroutines, then launch IdP en SP lists
|
# Launch parents initialization subroutines, then launch IdP en SP lists
|
||||||
my $res = $self->Lemonldap::NG::Portal::Main::Issuer::init();
|
my $res = $self->Lemonldap::NG::Portal::Main::Issuer::init();
|
||||||
|
return 0 unless($self->loadApp);
|
||||||
$self->addUnauthRoute(
|
$self->addUnauthRoute(
|
||||||
( $self->path ) => {
|
( $self->path ) => {
|
||||||
serviceValidate => 'serviceValidate',
|
serviceValidate => 'serviceValidate',
|
||||||
|
@ -108,17 +109,18 @@ sub run {
|
||||||
"CAS access control requested on service $service");
|
"CAS access control requested on service $service");
|
||||||
|
|
||||||
## HERE
|
## HERE
|
||||||
unless ( $service =~ m#^https?://([^/]+)(/.*)?$# ) {
|
unless ( $service =~ m#^(https?://[^/]+)(/.*)?$# ) {
|
||||||
$self->logger->error("Bad service $service");
|
$self->logger->error("Bad service $service");
|
||||||
return PE_ERROR;
|
return PE_ERROR;
|
||||||
}
|
}
|
||||||
my ( $host, $uri ) = ( $1, $2 );
|
my ( $host, $uri ) = ( $1, $2 );
|
||||||
if (
|
my $app;
|
||||||
$self->p->HANDLER->grant(
|
unless($app = $self->casAppList->{$host} ) {
|
||||||
$req, $req->sessionInfo, $1, undef, $2
|
$self->userLogger->error('CAS service not configured');
|
||||||
)
|
return PE_CAS_SERVICE_NOT_ALLOWED;
|
||||||
)
|
}
|
||||||
{
|
if ( my $rule = $self->appRules->{$app} ) {
|
||||||
|
if($rule->($req, $req->sessionInfo ) ) {
|
||||||
$self->logger->debug("CAS service $service access allowed");
|
$self->logger->debug("CAS service $service access allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +130,7 @@ sub run {
|
||||||
|
|
||||||
if ( $casAccessControlPolicy =~ /^(error)$/i ) {
|
if ( $casAccessControlPolicy =~ /^(error)$/i ) {
|
||||||
$self->logger->debug(
|
$self->logger->debug(
|
||||||
"Return error instead of redirecting user on CAS service"
|
"Return error instead of redirecting user on CAS service"
|
||||||
);
|
);
|
||||||
return PE_CAS_SERVICE_NOT_ALLOWED;
|
return PE_CAS_SERVICE_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
|
@ -140,6 +142,7 @@ sub run {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unless ($casServiceTicket) {
|
unless ($casServiceTicket) {
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ has ua => (
|
||||||
|
|
||||||
has casSrvList => ( is => 'rw', default => sub { {} }, );
|
has casSrvList => ( is => 'rw', default => sub { {} }, );
|
||||||
has casAppList => ( is => 'rw', default => sub { {} }, );
|
has casAppList => ( is => 'rw', default => sub { {} }, );
|
||||||
|
has appRules => ( is => 'rw', default => sub { {} }, );
|
||||||
|
|
||||||
# RUNNING METHODS
|
# RUNNING METHODS
|
||||||
|
|
||||||
|
@ -50,9 +51,21 @@ sub loadApp {
|
||||||
}
|
}
|
||||||
foreach ( keys %{ $self->conf->{casAppMetaDataOptions} } ) {
|
foreach ( keys %{ $self->conf->{casAppMetaDataOptions} } ) {
|
||||||
my $tmp =
|
my $tmp =
|
||||||
$self->conf->{casAppMetaDataOptions}->{casAppMetaDataOptionsService};
|
$self->conf->{casAppMetaDataOptions}->{$_}
|
||||||
|
->{casAppMetaDataOptionsService};
|
||||||
$tmp =~ s#^(https?://[^/]+).*$#$1#;
|
$tmp =~ s#^(https?://[^/]+).*$#$1#;
|
||||||
$self->casAppList->{$tmp} = $_;
|
$self->casAppList->{$tmp} = $_;
|
||||||
|
my $rule = $self->conf->{casAppMetaDataOptions}->{$_}
|
||||||
|
->{casAppMetaDataOptionsRule};
|
||||||
|
if ( length $rule ) {
|
||||||
|
$rule = $self->p->HANDLER->substitute($rule);
|
||||||
|
unless ( $rule = $self->p->HANDLER->buildSub($rule) ) {
|
||||||
|
$self->error( 'OIDC RP rule error: '
|
||||||
|
. $self->p->HANDLER->tsv->{jail}->error );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$self->appRules->{$_} = $rule;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -315,7 +328,7 @@ sub validateST {
|
||||||
|
|
||||||
my $proxied = $srvConf->{casSrvMetaDataOptionsProxiedServices} || {};
|
my $proxied = $srvConf->{casSrvMetaDataOptionsProxiedServices} || {};
|
||||||
my $proxy_url;
|
my $proxy_url;
|
||||||
if(%$proxied) {
|
if (%$proxied) {
|
||||||
$proxy_url = $self->p->fullUrl($req) . '?casProxy=1';
|
$proxy_url = $self->p->fullUrl($req) . '?casProxy=1';
|
||||||
if ( $self->conf->{authChoiceParam}
|
if ( $self->conf->{authChoiceParam}
|
||||||
and my $tmp = $req->param( $self->conf->{authChoiceParam} ) )
|
and my $tmp = $req->param( $self->conf->{authChoiceParam} ) )
|
||||||
|
@ -327,7 +340,7 @@ sub validateST {
|
||||||
|
|
||||||
$req->datas->{casProxyUrl} = $proxy_url;
|
$req->datas->{casProxyUrl} = $proxy_url;
|
||||||
|
|
||||||
$serviceValidateUrl .= "&pgtUrl=" . uri_escape( $proxy_url );
|
$serviceValidateUrl .= "&pgtUrl=" . uri_escape($proxy_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $response = $self->ua->get($serviceValidateUrl);
|
my $response = $self->ua->get($serviceValidateUrl);
|
||||||
|
@ -348,7 +361,7 @@ sub validateST {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get proxy data and store pgtId
|
# Get proxy data and store pgtId
|
||||||
if ( $proxy_url ) {
|
if ($proxy_url) {
|
||||||
my $pgtIou =
|
my $pgtIou =
|
||||||
$xml->{'cas:authenticationSuccess'}->{'cas:proxyGrantingTicket'};
|
$xml->{'cas:authenticationSuccess'}->{'cas:proxyGrantingTicket'};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user