Merge branch 'fix-idprules-oidc-2753' into 'v2.0'
Add IDP resolution rules for CAS/OIDC (#2753) See merge request lemonldap-ng/lemonldap-ng!267
This commit is contained in:
commit
694fb4e440
|
@ -63,23 +63,48 @@ Then, go in ``CAS parameters``:
|
|||
|
||||
- **Authentication level**: authentication level for this module.
|
||||
|
||||
Then create the list of CAS servers in the manager. For each, set:
|
||||
Then create the list of CAS servers in the manager.
|
||||
|
||||
Options
|
||||
~~~~~~~
|
||||
|
||||
- **Server URL** *(required)*: CAS server URL (must use https://)
|
||||
- **Renew authentication** *(default: disabled)*: force authentication
|
||||
renewal on CAS server
|
||||
- **Gateways authentication** *(default: disabled)*: force transparent
|
||||
authentication on CAS server
|
||||
|
||||
Proxied services
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
In this section, set the list of services for which a proxy ticket is
|
||||
requested:
|
||||
|
||||
- **Key**: Service ID
|
||||
- **Value** Service URL (CAS service identifier)
|
||||
|
||||
Display
|
||||
~~~~~~~
|
||||
- **Display Name**: Name to display. Required if you have more than 1
|
||||
CAS server declared
|
||||
- **Icon**: Path to CAS Server icon. Used only if you have more than 1
|
||||
CAS server declared
|
||||
- **Order**: Number to sort CAS Servers display
|
||||
- **Proxied services**: list of services for which a proxy ticket is
|
||||
requested:
|
||||
- **Resolution Rule**: rule that will be applied to preselect a CAS server for
|
||||
a user. You have access to all environment variable *(like user IP address)*
|
||||
and all session keys.
|
||||
|
||||
- **Key**: Service ID
|
||||
- **Value** Service URL (CAS service identifier)
|
||||
For example, to preselect this server for users coming from 129.168.0.0/16
|
||||
network
|
||||
|
||||
::
|
||||
|
||||
$ENV{REMOTE_ADDR} =~ /^192\.168/
|
||||
|
||||
To preselect this server when the ``MY_SRV`` :doc:`choice <authchoice>` is selected ::
|
||||
|
||||
$_choice eq "MY_SRV"
|
||||
|
||||
- **Order**: Number to sort CAS Servers display
|
||||
|
||||
|
||||
.. tip::
|
||||
|
|
|
@ -210,42 +210,59 @@ So you can define by example:
|
|||
Options
|
||||
^^^^^^^
|
||||
|
||||
- **Configuration**:
|
||||
Configuration
|
||||
"""""""""""""
|
||||
|
||||
- **Configuration endpoint**: URL of OP configuration endpoint
|
||||
- **JWKS data timeout**: After this time, LL::NG will do a request
|
||||
to get a fresh version of JWKS data. Set to 0 to disable it.
|
||||
- **Client ID**: Client ID given by OP
|
||||
- **Client secret**: Client secret given by OP
|
||||
- **Store ID token**: Allows one to store the ID Token (JWT) inside
|
||||
user session. Do not enable it unless you need to replay this token
|
||||
on an application, or if you need the id_token_hint parameter when
|
||||
using logout.
|
||||
- **Configuration endpoint**: URL of OP configuration endpoint
|
||||
- **JWKS data timeout**: After this time, LL::NG will do a request
|
||||
to get a fresh version of JWKS data. Set to 0 to disable it.
|
||||
- **Client ID**: Client ID given by OP
|
||||
- **Client secret**: Client secret given by OP
|
||||
- **Store ID token**: Allows one to store the ID Token (JWT) inside
|
||||
user session. Do not enable it unless you need to replay this token
|
||||
on an application, or if you need the id_token_hint parameter when
|
||||
using logout.
|
||||
|
||||
- **Protocol**:
|
||||
Protocol
|
||||
""""""""
|
||||
- **Scope**: Value of scope parameter (example: openid profile). The
|
||||
``openid`` scope is mandatory.
|
||||
- **Display**: Value of display parameter (example: page)
|
||||
- **Prompt**: Value of prompt parameter (example: consent)
|
||||
- **Max age**: Value of max_age parameter (example: 3600)
|
||||
- **UI locales**: Value of ui_locales parameter (example: en-GB en
|
||||
fr-FR fr)
|
||||
- **ACR values**: Value acr_values parameters (example: loa-1)
|
||||
- **Token endpoint authentication method**: Choice between
|
||||
``client_secret_post`` and ``client_secret_basic``
|
||||
- **Check JWT signature**: Set to 0 to disable JWT signature
|
||||
checking
|
||||
- **ID Token max age**: If defined, LL::NG will check the ID Token
|
||||
date and reject it if too old
|
||||
- **Use Nonce**: If enabled, a nonce will be sent, and verified from
|
||||
the ID Token
|
||||
|
||||
- **Scope**: Value of scope parameter (example: openid profile). The
|
||||
``openid`` scope is mandatory.
|
||||
- **Display**: Value of display parameter (example: page)
|
||||
- **Prompt**: Value of prompt parameter (example: consent)
|
||||
- **Max age**: Value of max_age parameter (example: 3600)
|
||||
- **UI locales**: Value of ui_locales parameter (example: en-GB en
|
||||
fr-FR fr)
|
||||
- **ACR values**: Value acr_values parameters (example: loa-1)
|
||||
- **Token endpoint authentication method**: Choice between
|
||||
``client_secret_post`` and ``client_secret_basic``
|
||||
- **Check JWT signature**: Set to 0 to disable JWT signature
|
||||
checking
|
||||
- **ID Token max age**: If defined, LL::NG will check the ID Token
|
||||
date and reject it if too old
|
||||
- **Use Nonce**: If enabled, a nonce will be sent, and verified from
|
||||
the ID Token
|
||||
Display
|
||||
"""""""
|
||||
|
||||
- **Display**:
|
||||
- **Display name**: Name of the application
|
||||
- **Logo**: Logo of the application
|
||||
- **Resolution Rule**: rule that will be applied to preselect an OP
|
||||
for a user. You have access to all environment variable *(like user
|
||||
IP address)* and all session keys.
|
||||
|
||||
- **Display name**: Name of the application
|
||||
- **Logo**: Logo of the application
|
||||
- **Order**: Number to sort buttons
|
||||
For example, to preselect this OP for users coming from 129.168.0.0/16
|
||||
network
|
||||
|
||||
::
|
||||
|
||||
$ENV{REMOTE_ADDR} =~ /^192\.168/
|
||||
|
||||
To preselect this OP when the ``MY_OP`` :doc:`choice <authchoice>` is selected ::
|
||||
|
||||
$_choice eq "MY_OP"
|
||||
|
||||
- **Order**: Number to sort buttons
|
||||
|
||||
|
||||
.. attention::
|
||||
|
@ -254,4 +271,4 @@ Options
|
|||
with ``verify_hostname => 0`` and ``SSL_verify_mode => 0``.
|
||||
|
||||
|
||||
Go to: ``General Parameters > Advanced Parameters > Security > SSL options for server requests``
|
||||
Go to: ``General Parameters > Advanced Parameters > Security > SSL options for server requests``
|
||||
|
|
|
@ -111,20 +111,6 @@ For each attribute, you can set:
|
|||
Options
|
||||
^^^^^^^
|
||||
|
||||
General options
|
||||
'''''''''''''''
|
||||
|
||||
- **Resolution Rule**: rule that will be applied to preselect an IDP
|
||||
for a user. You have access to all environment variable *(like user
|
||||
IP address)* and all session keys.
|
||||
|
||||
For example, to preselect this IDP for users coming from 129.168.0.0/16
|
||||
network and member of "admin" group:
|
||||
|
||||
::
|
||||
|
||||
$ENV{REMOTE_ADDR} =~ /^192\.168/ and $groups =~ /\badmin\b/
|
||||
|
||||
Authentication request
|
||||
''''''''''''''''''''''
|
||||
|
||||
|
@ -212,8 +198,6 @@ Used only if at least 2 SAML Identity Providers are declared
|
|||
|
||||
- **Display name**: Name of the IDP
|
||||
- **Logo**: Logo of the IDP
|
||||
- **Order**: Number used for sorting IDP display
|
||||
|
||||
|
||||
.. tip::
|
||||
|
||||
|
@ -222,6 +206,23 @@ Used only if at least 2 SAML Identity Providers are declared
|
|||
icon file name directly in the field and copy the logo file in portal
|
||||
icons directory
|
||||
|
||||
- **Resolution Rule**: rule that will be applied to preselect an IDP
|
||||
for a user. You have access to all environment variable *(like user
|
||||
IP address)* and all session keys.
|
||||
|
||||
For example, to preselect this IDP for users coming from 129.168.0.0/16
|
||||
network
|
||||
|
||||
::
|
||||
|
||||
$ENV{REMOTE_ADDR} =~ /^192\.168/
|
||||
|
||||
To preselect this IDP when the ``MY_IDP`` :doc:`choice <authchoice>` is selected ::
|
||||
|
||||
$_choice eq "MY_IDP"
|
||||
|
||||
- **Order**: Number used for sorting IDP display
|
||||
|
||||
.. |image0| image:: /documentation/manager-saml-metadata.png
|
||||
:class: align-center
|
||||
.. |image1| image:: /documentation/manager-saml-attributes.png
|
||||
|
|
|
@ -25,8 +25,8 @@ our $doubleHashKeys = 'issuerDBGetParameters';
|
|||
our $simpleHashKeys = '(?:(?:c(?:as(?:StorageOption|Attribute)|ustom(?:Plugins|Add)Param|heckUserHiddenHeader|ombModule)|l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|f(?:indUser(?:Exclud|Search)ingAttribute|acebookExportedVar)|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|(?:(?:d(?:emo|bi)|webID)E|e)xportedVar|macro)s|o(?:idc(?:S(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|OPMetaDataJ(?:SON|WKS))|penIdExportedVars)|a(?:(?:daptativeAuthenticationLevelR|ut(?:hChoiceMod|oSigninR))ules|pplicationList)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember|fExtra)|S(?:MTPTLSOpts|SLVarIf))';
|
||||
our $specialNodeKeys = '(?:(?:(?:saml(?:ID|S)|oidc[OR])P|cas(?:App|Srv))MetaDataNode|virtualHost)s';
|
||||
our $casAppMetaDataNodeKeys = 'casAppMetaData(?:Options(?:(?:UserAttribut|Servic|Rul)e|AuthnLevel)|(?:ExportedVar|Macro)s)';
|
||||
our $casSrvMetaDataNodeKeys = 'casSrvMetaData(?:Options(?:ProxiedServices|DisplayName|SortNumber|Gateway|Renew|Icon|Url)|ExportedVars)';
|
||||
our $oidcOPMetaDataNodeKeys = 'oidcOPMetaData(?:Options(?:C(?:lient(?:Secret|ID)|heckJWTSignature|onfigurationURI)|S(?:toreIDToken|ortNumber|cope)|TokenEndpointAuthMethod|(?:JWKSTimeou|Promp)t|I(?:DTokenMaxAge|con)|U(?:iLocales|seNonce)|Display(?:Name)?|AcrValues|MaxAge)|ExportedVars|J(?:SON|WKS))';
|
||||
our $casSrvMetaDataNodeKeys = 'casSrvMetaData(?:Options(?:Re(?:solutionRule|new)|ProxiedServices|DisplayName|SortNumber|Gateway|Icon|Url)|ExportedVars)';
|
||||
our $oidcOPMetaDataNodeKeys = 'oidcOPMetaData(?:Options(?:C(?:lient(?:Secret|ID)|heckJWTSignature|onfigurationURI)|S(?:toreIDToken|ortNumber|cope)|(?:ResolutionRul|MaxAg)e|TokenEndpointAuthMethod|(?:JWKSTimeou|Promp)t|I(?:DTokenMaxAge|con)|U(?:iLocales|seNonce)|Display(?:Name)?|AcrValues)|ExportedVars|J(?:SON|WKS))';
|
||||
our $oidcRPMetaDataNodeKeys = 'oidcRPMetaData(?:Options(?:A(?:llow(?:(?:ClientCredentials|Password)Grant|Offline)|ccessToken(?:Expiration|SignAlg|Claims|JWT)|uth(?:orizationCodeExpiration|nLevel)|dditionalAudiences)|I(?:DToken(?:ForceClaims|Expiration|SignAlg)|con)|R(?:e(?:directUris|freshToken|quirePKCE)|ule)|Logout(?:SessionRequired|Type|Url)|P(?:ostLogoutRedirectUris|ublic)|UserI(?:nfoSignAlg|DAttr)|OfflineSessionExpiration|Client(?:Secret|ID)|BypassConsent|DisplayName|ExtraClaims)|(?:ExportedVar|ScopeRule|Macro)s)';
|
||||
our $samlIDPMetaDataNodeKeys = 'samlIDPMetaData(?:Options(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|EncryptionMod|UserAttribut|DisplayNam)e|S(?:ign(?:S[LS]OMessage|atureMethod)|toreSAMLToken|[LS]OBinding|ortNumber)|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Re(?:questedAuthnContext|solutionRule|layStateURL)|Force(?:Authn|UTF8)|I(?:sPassive|con)|NameIDFormat)|ExportedAttributes|XML)';
|
||||
our $samlSPMetaDataNodeKeys = 'samlSPMetaData(?:Options(?:S(?:ign(?:S[LS]OMessage|atureMethod)|essionNotOnOrAfterTimeout)|N(?:ameID(?:SessionKey|Format)|otOnOrAfterTimeout)|(?:CheckS[LS]OMessageSignatur|OneTimeUs|Rul)e|En(?:ableIDPInitiatedURL|cryptionMode)|AuthnLevel|ForceUTF8)|(?:ExportedAttribute|Macro)s|XML)';
|
||||
|
|
|
@ -797,6 +797,10 @@ sub attributes {
|
|||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'casSrvMetaDataOptionsResolutionRule' => {
|
||||
'default' => '',
|
||||
'type' => 'longtext'
|
||||
},
|
||||
'casSrvMetaDataOptionsSortNumber' => {
|
||||
'type' => 'int'
|
||||
},
|
||||
|
@ -2277,6 +2281,10 @@ m[^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
|||
'oidcOPMetaDataOptionsPrompt' => {
|
||||
'type' => 'text'
|
||||
},
|
||||
'oidcOPMetaDataOptionsResolutionRule' => {
|
||||
'default' => '',
|
||||
'type' => 'longtext'
|
||||
},
|
||||
'oidcOPMetaDataOptionsScope' => {
|
||||
'default' => 'openid profile',
|
||||
'type' => 'text'
|
||||
|
|
|
@ -3673,6 +3673,10 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
|||
type => 'int',
|
||||
documentation => 'Number to sort buttons',
|
||||
},
|
||||
casSrvMetaDataOptionsResolutionRule => {
|
||||
type => 'longtext',
|
||||
default => '',
|
||||
},
|
||||
|
||||
# Fake attribute: used by manager REST API to agglomerate all nodes
|
||||
# related to a CAS IDP partner
|
||||
|
@ -4372,6 +4376,10 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
|||
oidcOPMetaDataOptionsIcon => { type => 'text', },
|
||||
oidcOPMetaDataOptionsStoreIDToken => { type => 'bool', default => 0 },
|
||||
oidcOPMetaDataOptionsSortNumber => { type => 'int', },
|
||||
oidcOPMetaDataOptionsResolutionRule => {
|
||||
type => 'longtext',
|
||||
default => '',
|
||||
},
|
||||
|
||||
# OpenID Connect relying parties
|
||||
oidcRPMetaDataExportedVars => {
|
||||
|
|
|
@ -82,7 +82,6 @@ sub cTrees {
|
|||
help => 'authsaml.html#options',
|
||||
form => 'simpleInputContainer',
|
||||
nodes => [
|
||||
'samlIDPMetaDataOptionsResolutionRule',
|
||||
'samlIDPMetaDataOptionsNameIDFormat',
|
||||
'samlIDPMetaDataOptionsForceAuthn',
|
||||
'samlIDPMetaDataOptionsIsPassive',
|
||||
|
@ -98,6 +97,7 @@ sub cTrees {
|
|||
nodes => [
|
||||
"samlIDPMetaDataOptionsDisplayName",
|
||||
"samlIDPMetaDataOptionsIcon",
|
||||
'samlIDPMetaDataOptionsResolutionRule',
|
||||
"samlIDPMetaDataOptionsSortNumber"
|
||||
]
|
||||
}
|
||||
|
@ -186,6 +186,7 @@ sub cTrees {
|
|||
nodes => [
|
||||
'oidcOPMetaDataOptionsDisplayName',
|
||||
'oidcOPMetaDataOptionsIcon',
|
||||
'oidcOPMetaDataOptionsResolutionRule',
|
||||
'oidcOPMetaDataOptionsSortNumber'
|
||||
]
|
||||
},
|
||||
|
@ -285,6 +286,7 @@ sub cTrees {
|
|||
nodes => [
|
||||
'casSrvMetaDataOptionsDisplayName',
|
||||
'casSrvMetaDataOptionsIcon',
|
||||
'casSrvMetaDataOptionsResolutionRule',
|
||||
'casSrvMetaDataOptionsSortNumber',
|
||||
]
|
||||
},
|
||||
|
|
|
@ -146,6 +146,13 @@ function templates(tpl,key) {
|
|||
"id" : tpl+"s/"+key+"/"+"casSrvMetaDataOptionsIcon",
|
||||
"title" : "casSrvMetaDataOptionsIcon"
|
||||
},
|
||||
{
|
||||
"default" : "",
|
||||
"get" : tpl+"s/"+key+"/"+"casSrvMetaDataOptionsResolutionRule",
|
||||
"id" : tpl+"s/"+key+"/"+"casSrvMetaDataOptionsResolutionRule",
|
||||
"title" : "casSrvMetaDataOptionsResolutionRule",
|
||||
"type" : "longtext"
|
||||
},
|
||||
{
|
||||
"get" : tpl+"s/"+key+"/"+"casSrvMetaDataOptionsSortNumber",
|
||||
"id" : tpl+"s/"+key+"/"+"casSrvMetaDataOptionsSortNumber",
|
||||
|
@ -362,6 +369,13 @@ function templates(tpl,key) {
|
|||
"id" : tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsIcon",
|
||||
"title" : "oidcOPMetaDataOptionsIcon"
|
||||
},
|
||||
{
|
||||
"default" : "",
|
||||
"get" : tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsResolutionRule",
|
||||
"id" : tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsResolutionRule",
|
||||
"title" : "oidcOPMetaDataOptionsResolutionRule",
|
||||
"type" : "longtext"
|
||||
},
|
||||
{
|
||||
"get" : tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsSortNumber",
|
||||
"id" : tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsSortNumber",
|
||||
|
@ -976,13 +990,6 @@ function templates(tpl,key) {
|
|||
},
|
||||
{
|
||||
"_nodes" : [
|
||||
{
|
||||
"default" : "",
|
||||
"get" : tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsResolutionRule",
|
||||
"id" : tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsResolutionRule",
|
||||
"title" : "samlIDPMetaDataOptionsResolutionRule",
|
||||
"type" : "longtext"
|
||||
},
|
||||
{
|
||||
"default" : "",
|
||||
"get" : tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsNameIDFormat",
|
||||
|
@ -1114,6 +1121,13 @@ function templates(tpl,key) {
|
|||
"id" : tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsIcon",
|
||||
"title" : "samlIDPMetaDataOptionsIcon"
|
||||
},
|
||||
{
|
||||
"default" : "",
|
||||
"get" : tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsResolutionRule",
|
||||
"id" : tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsResolutionRule",
|
||||
"title" : "samlIDPMetaDataOptionsResolutionRule",
|
||||
"type" : "longtext"
|
||||
},
|
||||
{
|
||||
"get" : tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSortNumber",
|
||||
"id" : tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSortNumber",
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"مسارالأيقونة",
|
||||
"casSrvMetaDataOptionsProxiedServices":"خدمات البروكسي",
|
||||
"casSrvMetaDataOptionsRenew":"تجديد إثبات الهوية",
|
||||
"casSrvMetaDataOptionsResolutionRule":"حل القاعدة",
|
||||
"casSrvMetaDataOptionsSortNumber":"Order",
|
||||
"casSrvMetaDataOptionsUrl":" يو أر ل الخادم",
|
||||
"casSrvName":"اسم خادم كاس",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"الحد الأقصى للعمر",
|
||||
"oidcOPMetaDataOptionsPrompt":"عاجل",
|
||||
"oidcOPMetaDataOptionsProtocol":"بروتوكول",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"حل القاعدة",
|
||||
"oidcOPMetaDataOptionsScope":"نطاق",
|
||||
"oidcOPMetaDataOptionsSortNumber":"Order",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"مخزن تعريف التوكن",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"Icon path",
|
||||
"casSrvMetaDataOptionsProxiedServices":"Proxied services",
|
||||
"casSrvMetaDataOptionsRenew":"Renew authentication",
|
||||
"casSrvMetaDataOptionsResolutionRule":"Resolution rule",
|
||||
"casSrvMetaDataOptionsSortNumber":"Order",
|
||||
"casSrvMetaDataOptionsUrl":"Server URL",
|
||||
"casSrvName":"CAS Server Name",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"Max age",
|
||||
"oidcOPMetaDataOptionsPrompt":"Prompt",
|
||||
"oidcOPMetaDataOptionsProtocol":"Protocol",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"Resolution rule",
|
||||
"oidcOPMetaDataOptionsScope":"Scope",
|
||||
"oidcOPMetaDataOptionsSortNumber":"Order",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"Store ID Token",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"Icon path",
|
||||
"casSrvMetaDataOptionsProxiedServices":"Servicios proxificados",
|
||||
"casSrvMetaDataOptionsRenew":"Renovar autentificación",
|
||||
"casSrvMetaDataOptionsResolutionRule":"Resolution rule",
|
||||
"casSrvMetaDataOptionsSortNumber":"Orden",
|
||||
"casSrvMetaDataOptionsUrl":"URL de servicio",
|
||||
"casSrvName":"Nombre de servidor CAS",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"Max age",
|
||||
"oidcOPMetaDataOptionsPrompt":"Prompt",
|
||||
"oidcOPMetaDataOptionsProtocol":"Protocolo",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"Resolution rule",
|
||||
"oidcOPMetaDataOptionsScope":"Ámbito",
|
||||
"oidcOPMetaDataOptionsSortNumber":"Orden",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"Guardar token ID",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"Chemin de l'icône",
|
||||
"casSrvMetaDataOptionsProxiedServices":"Services mandatés",
|
||||
"casSrvMetaDataOptionsRenew":"Renouveler l'authentification",
|
||||
"casSrvMetaDataOptionsResolutionRule":"Règle de résolution",
|
||||
"casSrvMetaDataOptionsSortNumber":"Ordre",
|
||||
"casSrvMetaDataOptionsUrl":"URL du serveur",
|
||||
"casSrvName":"Nom du serveur CAS",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"Age maximum",
|
||||
"oidcOPMetaDataOptionsPrompt":"Interaction",
|
||||
"oidcOPMetaDataOptionsProtocol":"Protocole",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"Règle de résolution",
|
||||
"oidcOPMetaDataOptionsScope":"Scope",
|
||||
"oidcOPMetaDataOptionsSortNumber":"Ordre",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"Conserver le jeton d'identité",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"נתיב לסמל",
|
||||
"casSrvMetaDataOptionsProxiedServices":"שירותים מתווכים",
|
||||
"casSrvMetaDataOptionsRenew":"חידוש אימות",
|
||||
"casSrvMetaDataOptionsResolutionRule":"Resolution rule",
|
||||
"casSrvMetaDataOptionsSortNumber":"סדר",
|
||||
"casSrvMetaDataOptionsUrl":"כתובת שרת",
|
||||
"casSrvName":"CAS Server Name",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"גיל מרבי",
|
||||
"oidcOPMetaDataOptionsPrompt":"Prompt",
|
||||
"oidcOPMetaDataOptionsProtocol":"פרוטוקול",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"Resolution rule",
|
||||
"oidcOPMetaDataOptionsScope":"היקף",
|
||||
"oidcOPMetaDataOptionsSortNumber":"סדר",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"Store ID Token",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"Path icona",
|
||||
"casSrvMetaDataOptionsProxiedServices":"Servizi Proxied",
|
||||
"casSrvMetaDataOptionsRenew":"Rinnova l'autenticazione",
|
||||
"casSrvMetaDataOptionsResolutionRule":"Regola di risoluzione",
|
||||
"casSrvMetaDataOptionsSortNumber":"Ordine",
|
||||
"casSrvMetaDataOptionsUrl":"URL del server",
|
||||
"casSrvName":"NOme del Server CAS",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"Età massima",
|
||||
"oidcOPMetaDataOptionsPrompt":"Richiesta",
|
||||
"oidcOPMetaDataOptionsProtocol":"Protocollo",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"Regola di risoluzione",
|
||||
"oidcOPMetaDataOptionsScope":"Scopo",
|
||||
"oidcOPMetaDataOptionsSortNumber":"Ordine",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"Immagazzina ID Token",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"Ścieżka ikony",
|
||||
"casSrvMetaDataOptionsProxiedServices":"Usługi proxy",
|
||||
"casSrvMetaDataOptionsRenew":"Odnów uwierzytelnianie",
|
||||
"casSrvMetaDataOptionsResolutionRule":"Reguła rozstrzygania",
|
||||
"casSrvMetaDataOptionsSortNumber":"Kolejność",
|
||||
"casSrvMetaDataOptionsUrl":"URL serwera",
|
||||
"casSrvName":"Nazwa serwera CAS",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"Maksymalny czas ważności",
|
||||
"oidcOPMetaDataOptionsPrompt":"Prompt",
|
||||
"oidcOPMetaDataOptionsProtocol":"Protokół",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"Reguła rozstrzygania",
|
||||
"oidcOPMetaDataOptionsScope":"Zakres",
|
||||
"oidcOPMetaDataOptionsSortNumber":"Kolejność",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"Przechowuj token identyfikacyjny",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"İkon yolu",
|
||||
"casSrvMetaDataOptionsProxiedServices":"Vekil sunucu servisleri",
|
||||
"casSrvMetaDataOptionsRenew":"Kimlik doğrulamayı yenile",
|
||||
"casSrvMetaDataOptionsResolutionRule":"Çözünürlük kuralı",
|
||||
"casSrvMetaDataOptionsSortNumber":"Sıra",
|
||||
"casSrvMetaDataOptionsUrl":"Sunucu URL'si",
|
||||
"casSrvName":"CAS Sunucu Adı",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"Maksimum ömür",
|
||||
"oidcOPMetaDataOptionsPrompt":"İstem",
|
||||
"oidcOPMetaDataOptionsProtocol":"Protokol",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"Çözünürlük kuralı",
|
||||
"oidcOPMetaDataOptionsScope":"Kapsam",
|
||||
"oidcOPMetaDataOptionsSortNumber":"Sıra",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"ID Jetonu Sakla",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"Đường dẫn Icon",
|
||||
"casSrvMetaDataOptionsProxiedServices":"Dịch vụ proxy",
|
||||
"casSrvMetaDataOptionsRenew":"Gia hạn chứng thực",
|
||||
"casSrvMetaDataOptionsResolutionRule":"Quy tắc phân giải ",
|
||||
"casSrvMetaDataOptionsSortNumber":"Order",
|
||||
"casSrvMetaDataOptionsUrl":"URL máy chủ",
|
||||
"casSrvName":"Tên máy chủ CAS",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"Thời hạn tối đa",
|
||||
"oidcOPMetaDataOptionsPrompt":"Nhắc nhở",
|
||||
"oidcOPMetaDataOptionsProtocol":"Giao thức",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"Quy tắc phân giải ",
|
||||
"oidcOPMetaDataOptionsScope":"Phạm vi",
|
||||
"oidcOPMetaDataOptionsSortNumber":"Order",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"Mã thông báo Cửa hàng",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"图标路径",
|
||||
"casSrvMetaDataOptionsProxiedServices":"代理服务",
|
||||
"casSrvMetaDataOptionsRenew":"更新驗證",
|
||||
"casSrvMetaDataOptionsResolutionRule":"解析規則",
|
||||
"casSrvMetaDataOptionsSortNumber":"順序",
|
||||
"casSrvMetaDataOptionsUrl":"服务器 URL",
|
||||
"casSrvName":"CAS 服务器名称",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"最大時間",
|
||||
"oidcOPMetaDataOptionsPrompt":"提示",
|
||||
"oidcOPMetaDataOptionsProtocol":"協定",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"解析規則",
|
||||
"oidcOPMetaDataOptionsScope":"範圍",
|
||||
"oidcOPMetaDataOptionsSortNumber":"順序",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"儲存 ID 權杖",
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
"casSrvMetaDataOptionsIcon":"圖示路徑",
|
||||
"casSrvMetaDataOptionsProxiedServices":"已代理的服務",
|
||||
"casSrvMetaDataOptionsRenew":"更新驗證",
|
||||
"casSrvMetaDataOptionsResolutionRule":"解析規則",
|
||||
"casSrvMetaDataOptionsSortNumber":"順序",
|
||||
"casSrvMetaDataOptionsUrl":"伺服器 URL",
|
||||
"casSrvName":"CAS 伺服器名稱",
|
||||
|
@ -652,6 +653,7 @@
|
|||
"oidcOPMetaDataOptionsMaxAge":"最大時間",
|
||||
"oidcOPMetaDataOptionsPrompt":"提示",
|
||||
"oidcOPMetaDataOptionsProtocol":"協定",
|
||||
"oidcOPMetaDataOptionsResolutionRule":"解析規則",
|
||||
"oidcOPMetaDataOptionsScope":"範圍",
|
||||
"oidcOPMetaDataOptionsSortNumber":"順序",
|
||||
"oidcOPMetaDataOptionsStoreIDToken":"儲存 ID 權杖",
|
||||
|
|
|
@ -561,8 +561,9 @@ t/30-Auth-and-issuer-SAML-POST.t
|
|||
t/30-Auth-and-issuer-SAML-Redirect-IdP-initiated.t
|
||||
t/30-Auth-and-issuer-SAML-Redirect-MultipleSP-Missing-SLO.t
|
||||
t/30-Auth-and-issuer-SAML-Redirect-MultipleSP.t
|
||||
t/30-Auth-and-issuer-SAML-Redirect-With-Info.t
|
||||
t/30-Auth-and-issuer-SAML-Redirect.t
|
||||
t/30-Auth-and-issuer-SAML-Redirect-With-Info.t
|
||||
t/30-Auth-ResolutionRule.t
|
||||
t/30-Auth-SAML-with-choice.t
|
||||
t/30-CDC.t
|
||||
t/30-SAML-Head-to-Tail-POST.t
|
||||
|
|
|
@ -133,14 +133,24 @@ sub extractFormInfo {
|
|||
|
||||
else {
|
||||
|
||||
# Server list
|
||||
my $portalPath = $self->conf->{portal};
|
||||
$portalPath =~ s#^https?://[^/]+/?#/#;
|
||||
# Try to use server resolution ruls
|
||||
foreach ( keys %{ $self->srvRules } ) {
|
||||
my $cond = $self->srvRules->{$_} or next;
|
||||
if ( $cond->( $req, $req->sessionInfo ) ) {
|
||||
$self->logger->debug(
|
||||
"CAS Server $_ selected from resolution rule");
|
||||
$srv = $_;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
$req->data->{list} = $self->srvList;
|
||||
unless ($srv) {
|
||||
|
||||
$req->data->{login} = 1;
|
||||
return PE_IDPCHOICE;
|
||||
# Server list
|
||||
$req->data->{list} = $self->srvList;
|
||||
$req->data->{login} = 1;
|
||||
return PE_IDPCHOICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -249,14 +249,23 @@ sub extractFormInfo {
|
|||
|
||||
else {
|
||||
|
||||
# IDP list
|
||||
my $portalPath = $self->{conf}->{portal};
|
||||
$portalPath =~ s#^https?://[^/]+/?#/#;
|
||||
# Try to use OP resolution ruls
|
||||
foreach ( keys %{ $self->opRules } ) {
|
||||
my $cond = $self->opRules->{$_} or next;
|
||||
if ( $cond->( $req, $req->sessionInfo ) ) {
|
||||
$self->logger->debug("OP $_ selected from resolution rule");
|
||||
$op = $_;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
$req->data->{list} = $self->opList;
|
||||
unless ($op) {
|
||||
|
||||
$req->data->{login} = 1;
|
||||
return PE_IDPCHOICE;
|
||||
# display OP list
|
||||
$req->data->{list} = $self->opList;
|
||||
$req->data->{login} = 1;
|
||||
return PE_IDPCHOICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ has ua => (
|
|||
|
||||
has casSrvList => ( is => 'rw', default => sub { {} }, );
|
||||
has casAppList => ( is => 'rw', default => sub { {} }, );
|
||||
has srvRules => ( is => 'rw', default => sub { {} }, );
|
||||
has spRules => ( is => 'rw', default => sub { {} }, );
|
||||
has spMacros => ( is => 'rw', default => sub { {} }, );
|
||||
|
||||
|
@ -41,6 +42,18 @@ sub loadSrv {
|
|||
return 0;
|
||||
}
|
||||
$self->casSrvList( $self->conf->{casSrvMetaDataOptions} );
|
||||
|
||||
# Set rule
|
||||
foreach ( keys %{ $self->conf->{casSrvMetaDataOptions} } ) {
|
||||
my $cond = $self->conf->{casSrvMetaDataOptions}->{$_}
|
||||
->{casSrvMetaDataOptionsResolutionRule};
|
||||
if ( length $cond ) {
|
||||
my $rule_sub = $self->p->buildRule( $cond, "CAS server resolution" );
|
||||
if ($rule_sub) {
|
||||
$self->srvRules->{$_} = $rule_sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ use constant OIDC_SCOPES => [qw/openid profile email address phone/];
|
|||
has oidcOPList => ( is => 'rw', default => sub { {} }, );
|
||||
has oidcRPList => ( is => 'rw', default => sub { {} }, );
|
||||
has rpAttributes => ( is => 'rw', default => sub { {} }, );
|
||||
has opRules => ( is => 'rw', default => sub { {} } );
|
||||
has spRules => ( is => 'rw', default => sub { {} } );
|
||||
has spMacros => ( is => 'rw', default => sub { {} } );
|
||||
has spScopeRules => ( is => 'rw', default => sub { {} } );
|
||||
|
@ -90,6 +91,20 @@ sub loadOPs {
|
|||
$self->oidcOPList->{$_}->{jwks} =
|
||||
$self->decodeJSON( $self->conf->{oidcOPMetaDataJWKS}->{$_} );
|
||||
}
|
||||
|
||||
# Set rule
|
||||
foreach ( keys %{ $self->conf->{oidcOPMetaDataOptions} } ) {
|
||||
my $cond = $self->conf->{oidcOPMetaDataOptions}->{$_}
|
||||
->{oidcOPMetaDataOptionsResolutionRule};
|
||||
if ( length $cond ) {
|
||||
my $rule_sub =
|
||||
$self->p->buildRule( $cond, "OIDC provider resolution" );
|
||||
if ($rule_sub) {
|
||||
$self->opRules->{$_} = $rule_sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
use lib 'inc';
|
||||
use Test::More;
|
||||
use strict;
|
||||
use IO::String;
|
||||
use LWP::UserAgent;
|
||||
use LWP::Protocol::PSGI;
|
||||
use MIME::Base64;
|
||||
use XML::LibXML;
|
||||
|
||||
BEGIN {
|
||||
require 't/test-lib.pm';
|
||||
require 't/saml-lib.pm';
|
||||
}
|
||||
|
||||
my $debug = 'error';
|
||||
my ( $issuer, $res );
|
||||
my $maintests = 0;
|
||||
|
||||
sub testchoiceredirection {
|
||||
my ( $issuer, $choice, $url ) = @_;
|
||||
my $res;
|
||||
ok(
|
||||
$res = $issuer->_get(
|
||||
'/',
|
||||
query => 'lmAuth=' . $choice,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
);
|
||||
count(1);
|
||||
expectRedirection( $res, $url );
|
||||
}
|
||||
|
||||
SKIP: {
|
||||
eval "use Lasso";
|
||||
if ($@) {
|
||||
skip 'Lasso not found', $maintests;
|
||||
}
|
||||
|
||||
# Initialization
|
||||
ok( $issuer = issuer(), 'Issuer portal' );
|
||||
count(1);
|
||||
|
||||
testchoiceredirection( $issuer, 'SAML1',
|
||||
qr,http://auth.idp.com/saml/singleSignOn, );
|
||||
testchoiceredirection( $issuer, 'SAML2',
|
||||
qr,http://auth.idp2.com/saml/singleSignOn, );
|
||||
testchoiceredirection( $issuer, 'OIDC1',
|
||||
qr,http://auth.op.com/oauth2/authorize, );
|
||||
testchoiceredirection( $issuer, 'OIDC2',
|
||||
qr,http://auth.op2.com/oauth2/authorize, );
|
||||
testchoiceredirection( $issuer, 'CAS1', qr,http://auth.srv.com/cas/login, );
|
||||
testchoiceredirection( $issuer, 'CAS2',
|
||||
qr,http://auth.srv2.com/cas/login, );
|
||||
|
||||
clean_sessions();
|
||||
}
|
||||
|
||||
count($maintests);
|
||||
done_testing( count() );
|
||||
|
||||
sub issuer {
|
||||
return LLNG::Manager::Test->new( {
|
||||
ini => {
|
||||
logLevel => $debug,
|
||||
domain => 'example.com',
|
||||
portal => 'http://auth.example.com',
|
||||
authentication => 'Choice',
|
||||
userDB => 'Same',
|
||||
authChoiceModules => {
|
||||
'OIDC1' => 'OpenIDConnect;Null;Null',
|
||||
'OIDC2' => 'OpenIDConnect;Null;Null',
|
||||
'SAML1' => 'SAML;Null;Null',
|
||||
'SAML2' => 'SAML;Null;Null',
|
||||
'CAS1' => 'CAS;Null;Null',
|
||||
'CAS2' => 'CAS;Null;Null',
|
||||
},
|
||||
|
||||
samlIDPMetaDataOptions => {
|
||||
"idp.com" => {
|
||||
samlIDPMetaDataOptionsResolutionRule =>
|
||||
'$_choice eq "SAML1"',
|
||||
},
|
||||
"idp2.com" => {
|
||||
samlIDPMetaDataOptionsResolutionRule =>
|
||||
'$_choice eq "SAML2"',
|
||||
},
|
||||
},
|
||||
samlIDPMetaDataXML => {
|
||||
"idp.com" => {
|
||||
samlIDPMetaDataXML =>
|
||||
samlIDPMetaDataXML( 'idp', 'HTTP-Redirect' )
|
||||
},
|
||||
"idp2.com" => {
|
||||
samlIDPMetaDataXML =>
|
||||
samlIDPMetaDataXML( 'idp2', 'HTTP-Redirect' )
|
||||
},
|
||||
},
|
||||
samlServicePrivateKeyEnc => saml_key_idp_private_enc,
|
||||
samlServicePrivateKeySig => saml_key_idp_private_sig,
|
||||
samlServicePublicKeyEnc => saml_key_idp_public_enc,
|
||||
samlServicePublicKeySig => saml_key_idp_public_sig,
|
||||
|
||||
casSrvMetaDataOptions => {
|
||||
idp => {
|
||||
casSrvMetaDataOptionsUrl => 'http://auth.srv.com/cas',
|
||||
casSrvMetaDataOptionsResolutionRule =>
|
||||
'$_choice eq "CAS1"',
|
||||
},
|
||||
idp2 => {
|
||||
casSrvMetaDataOptionsUrl => 'http://auth.srv2.com/cas',
|
||||
casSrvMetaDataOptionsResolutionRule =>
|
||||
'$_choice eq "CAS2"',
|
||||
},
|
||||
},
|
||||
|
||||
oidcOPMetaDataOptions => {
|
||||
op => {
|
||||
oidcOPMetaDataOptionsClientSecret => "rpsecret",
|
||||
oidcOPMetaDataOptionsResolutionRule =>
|
||||
'$_choice eq "OIDC1"',
|
||||
},
|
||||
op2 => {
|
||||
oidcOPMetaDataOptionsResolutionRule =>
|
||||
'$_choice eq "OIDC2"',
|
||||
},
|
||||
},
|
||||
oidcOPMetaDataJSON => {
|
||||
op =>
|
||||
'{"authorization_endpoint":"http://auth.op.com/oauth2/authorize"}',
|
||||
op2 =>
|
||||
'{"authorization_endpoint":"http://auth.op2.com/oauth2/authorize"}',
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue