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:
Maxime Besson 2022-05-19 15:00:44 +00:00
commit 694fb4e440
27 changed files with 362 additions and 79 deletions

View File

@ -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::

View File

@ -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``

View File

@ -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

View File

@ -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)';

View File

@ -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'

View File

@ -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 => {

View File

@ -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',
]
},

View File

@ -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

View File

@ -161,6 +161,7 @@
"casSrvMetaDataOptionsIcon":"مسارالأيقونة",
"casSrvMetaDataOptionsProxiedServices":"خدمات البروكسي",
"casSrvMetaDataOptionsRenew":"تجديد إثبات الهوية",
"casSrvMetaDataOptionsResolutionRule":"حل القاعدة",
"casSrvMetaDataOptionsSortNumber":"Order",
"casSrvMetaDataOptionsUrl":" يو أر ل الخادم",
"casSrvName":"اسم خادم كاس",
@ -652,6 +653,7 @@
"oidcOPMetaDataOptionsMaxAge":"الحد الأقصى للعمر",
"oidcOPMetaDataOptionsPrompt":"عاجل",
"oidcOPMetaDataOptionsProtocol":"بروتوكول",
"oidcOPMetaDataOptionsResolutionRule":"حل القاعدة",
"oidcOPMetaDataOptionsScope":"نطاق",
"oidcOPMetaDataOptionsSortNumber":"Order",
"oidcOPMetaDataOptionsStoreIDToken":"مخزن تعريف التوكن",

View File

@ -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",

View File

@ -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",

View File

@ -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é",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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 權杖",

View File

@ -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 權杖",

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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"}',
}
}
}
);
}