Merge branch 'v2.0'

This commit is contained in:
Christophe Maudoux 2020-11-01 00:00:52 +01:00
commit ac98c223d3
108 changed files with 1109 additions and 472 deletions

1
debian/control vendored
View File

@ -285,6 +285,7 @@ Recommends: libcrypt-openssl-bignum-perl,
libgd-securityimage-perl,
libmime-tools-perl,
libnet-ldap-perl,
libio-socket-timeout-perl,
libunicode-string-perl
Suggests: gpg,
libcrypt-u2f-server-perl,

View File

@ -714,6 +714,28 @@
"$ref" : "#/components/schemas/casOptions"
}
}
};
defs.CasAppReplace = {
"type" : "object",
"properties" : {
"macros" : {
"type" : "object",
"example" : {
"myMacroName" : "$macro(rule)"
}
},
"exportedVars" : {
"type" : "object",
"default" : {
"cn" : "cn",
"mail" : "mail",
"uid" : "uid"
}
},
"options" : {
"$ref" : "#/components/schemas/casOptions"
}
}
};
defs.CasAppUpdate = {
"type" : "object",
@ -976,6 +998,38 @@
"$ref" : "#/components/schemas/OidcOptions"
}
}
};
defs.OidcRpReplace = {
"required" : [ "clientId", "redirectUris" ],
"type" : "object",
"properties" : {
"clientId" : {
"type" : "string"
},
"exportedVars" : {
"type" : "object",
"example" : {
"email" : "mail",
"family_name" : "sn",
"name" : "cn"
}
},
"extraClaims" : {
"type" : "object",
"example" : {
"myscope" : "myattr1 myattr2 myattr3"
}
},
"macros" : {
"type" : "object",
"example" : {
"myMacroName" : "$macro(rule)"
}
},
"options" : {
"$ref" : "#/components/schemas/OidcOptions"
}
}
};
defs.OidcRpUpdate = {
"type" : "object",
@ -1111,6 +1165,31 @@
"$ref" : "#/components/schemas/samlOptions"
}
}
};
defs.SamlSpReplace = {
"required" : [ "metadata" ],
"type" : "object",
"properties" : {
"metadata" : {
"type" : "string",
"example" : "<?xml version=\"1.0\"?><EntityDescriptor..."
},
"macros" : {
"type" : "object",
"example" : {
"myMacroName" : "$macro(rule)"
}
},
"exportedAttributes" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/samlAttribute"
}
},
"options" : {
"$ref" : "#/components/schemas/samlOptions"
}
}
};
defs.SamlSpUpdate = {
"type" : "object",
@ -3233,7 +3312,7 @@ public class CasappApiExample {
CasappApi apiInstance = new CasappApi();
confKey confKey = ; // confKey | Configuration key of CAS Application that needs to be replaced
CasApp body = ; // CasApp |
CasAppReplace body = ; // CasAppReplace |
try {
apiInstance.replaceCasApp(confKey, body);
} catch (ApiException e) {
@ -3252,7 +3331,7 @@ public class CasappApiExample {
public static void main(String[] args) {
CasappApi apiInstance = new CasappApi();
confKey confKey = ; // confKey | Configuration key of CAS Application that needs to be replaced
CasApp body = ; // CasApp |
CasAppReplace body = ; // CasAppReplace |
try {
apiInstance.replaceCasApp(confKey, body);
} catch (ApiException e) {
@ -3268,7 +3347,7 @@ public class CasappApiExample {
</div> -->
<div class="tab-pane" id="examples-Casapp-replaceCasApp-0-objc">
<pre class="prettyprint"><code class="language-cpp">confKey *confKey = ; // Configuration key of CAS Application that needs to be replaced
CasApp *body = ; // (optional)
CasAppReplace *body = ; // (optional)
CasappApi *apiInstance = [[CasappApi alloc] init];
@ -3289,7 +3368,7 @@ CasappApi *apiInstance = [[CasappApi alloc] init];
var api = new LemonLdapngManagerApi.CasappApi()
var confKey = ; // {{confKey}} Configuration key of CAS Application that needs to be replaced
var opts = {
'body': // {{CasApp}}
'body': // {{CasAppReplace}}
};
var callback = function(error, data, response) {
if (error) {
@ -3321,7 +3400,7 @@ namespace Example
var apiInstance = new CasappApi();
var confKey = new confKey(); // confKey | Configuration key of CAS Application that needs to be replaced
var body = new CasApp(); // CasApp | (optional)
var body = new CasAppReplace(); // CasAppReplace | (optional)
try
{
@ -3344,7 +3423,7 @@ require_once(__DIR__ . '/vendor/autoload.php');
$api_instance = new Swagger\Client\ApiCasappApi();
$confKey = ; // confKey | Configuration key of CAS Application that needs to be replaced
$body = ; // CasApp |
$body = ; // CasAppReplace |
try {
$api_instance->replaceCasApp($confKey, $body);
@ -3361,7 +3440,7 @@ use WWW::SwaggerClient::CasappApi;
my $api_instance = WWW::SwaggerClient::CasappApi->new();
my $confKey = ; # confKey | Configuration key of CAS Application that needs to be replaced
my $body = WWW::SwaggerClient::Object::CasApp->new(); # CasApp |
my $body = WWW::SwaggerClient::Object::CasAppReplace->new(); # CasAppReplace |
eval {
$api_instance->replaceCasApp(confKey => $confKey, body => $body);
@ -3381,7 +3460,7 @@ from pprint import pprint
# create an instance of the API class
api_instance = swagger_client.CasappApi()
confKey = # confKey | Configuration key of CAS Application that needs to be replaced
body = # CasApp | (optional)
body = # CasAppReplace | (optional)
try:
# Replaces a CAS Application
@ -3440,7 +3519,7 @@ except ApiException as e:
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/CasApp"
"$ref" : "#/components/schemas/CasAppReplace"
}
}
}
@ -13528,7 +13607,7 @@ public class OidcrpApiExample {
OidcrpApi apiInstance = new OidcrpApi();
confKey confKey = ; // confKey | Configuration key of OpenID Connect Relaying Party that needs to be replaced
OidcRp body = ; // OidcRp |
OidcRpReplace body = ; // OidcRpReplace |
try {
apiInstance.replaceOidcRp(confKey, body);
} catch (ApiException e) {
@ -13547,7 +13626,7 @@ public class OidcrpApiExample {
public static void main(String[] args) {
OidcrpApi apiInstance = new OidcrpApi();
confKey confKey = ; // confKey | Configuration key of OpenID Connect Relaying Party that needs to be replaced
OidcRp body = ; // OidcRp |
OidcRpReplace body = ; // OidcRpReplace |
try {
apiInstance.replaceOidcRp(confKey, body);
} catch (ApiException e) {
@ -13563,7 +13642,7 @@ public class OidcrpApiExample {
</div> -->
<div class="tab-pane" id="examples-Oidcrp-replaceOidcRp-0-objc">
<pre class="prettyprint"><code class="language-cpp">confKey *confKey = ; // Configuration key of OpenID Connect Relaying Party that needs to be replaced
OidcRp *body = ; // (optional)
OidcRpReplace *body = ; // (optional)
OidcrpApi *apiInstance = [[OidcrpApi alloc] init];
@ -13584,7 +13663,7 @@ OidcrpApi *apiInstance = [[OidcrpApi alloc] init];
var api = new LemonLdapngManagerApi.OidcrpApi()
var confKey = ; // {{confKey}} Configuration key of OpenID Connect Relaying Party that needs to be replaced
var opts = {
'body': // {{OidcRp}}
'body': // {{OidcRpReplace}}
};
var callback = function(error, data, response) {
if (error) {
@ -13616,7 +13695,7 @@ namespace Example
var apiInstance = new OidcrpApi();
var confKey = new confKey(); // confKey | Configuration key of OpenID Connect Relaying Party that needs to be replaced
var body = new OidcRp(); // OidcRp | (optional)
var body = new OidcRpReplace(); // OidcRpReplace | (optional)
try
{
@ -13639,7 +13718,7 @@ require_once(__DIR__ . '/vendor/autoload.php');
$api_instance = new Swagger\Client\ApiOidcrpApi();
$confKey = ; // confKey | Configuration key of OpenID Connect Relaying Party that needs to be replaced
$body = ; // OidcRp |
$body = ; // OidcRpReplace |
try {
$api_instance->replaceOidcRp($confKey, $body);
@ -13656,7 +13735,7 @@ use WWW::SwaggerClient::OidcrpApi;
my $api_instance = WWW::SwaggerClient::OidcrpApi->new();
my $confKey = ; # confKey | Configuration key of OpenID Connect Relaying Party that needs to be replaced
my $body = WWW::SwaggerClient::Object::OidcRp->new(); # OidcRp |
my $body = WWW::SwaggerClient::Object::OidcRpReplace->new(); # OidcRpReplace |
eval {
$api_instance->replaceOidcRp(confKey => $confKey, body => $body);
@ -13676,7 +13755,7 @@ from pprint import pprint
# create an instance of the API class
api_instance = swagger_client.OidcrpApi()
confKey = # confKey | Configuration key of OpenID Connect Relaying Party that needs to be replaced
body = # OidcRp | (optional)
body = # OidcRpReplace | (optional)
try:
# Replaces an OpenID Connect Relaying Party
@ -13735,7 +13814,7 @@ except ApiException as e:
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/OidcRp"
"$ref" : "#/components/schemas/OidcRpReplace"
}
}
}
@ -16236,7 +16315,7 @@ public class SamlspApiExample {
SamlspApi apiInstance = new SamlspApi();
confKey confKey = ; // confKey | Configuration key of SAML Service Provider that needs to be replaced
SamlSp body = ; // SamlSp |
SamlSpReplace body = ; // SamlSpReplace |
try {
apiInstance.replaceSamlSp(confKey, body);
} catch (ApiException e) {
@ -16255,7 +16334,7 @@ public class SamlspApiExample {
public static void main(String[] args) {
SamlspApi apiInstance = new SamlspApi();
confKey confKey = ; // confKey | Configuration key of SAML Service Provider that needs to be replaced
SamlSp body = ; // SamlSp |
SamlSpReplace body = ; // SamlSpReplace |
try {
apiInstance.replaceSamlSp(confKey, body);
} catch (ApiException e) {
@ -16271,7 +16350,7 @@ public class SamlspApiExample {
</div> -->
<div class="tab-pane" id="examples-Samlsp-replaceSamlSp-0-objc">
<pre class="prettyprint"><code class="language-cpp">confKey *confKey = ; // Configuration key of SAML Service Provider that needs to be replaced
SamlSp *body = ; // (optional)
SamlSpReplace *body = ; // (optional)
SamlspApi *apiInstance = [[SamlspApi alloc] init];
@ -16292,7 +16371,7 @@ SamlspApi *apiInstance = [[SamlspApi alloc] init];
var api = new LemonLdapngManagerApi.SamlspApi()
var confKey = ; // {{confKey}} Configuration key of SAML Service Provider that needs to be replaced
var opts = {
'body': // {{SamlSp}}
'body': // {{SamlSpReplace}}
};
var callback = function(error, data, response) {
if (error) {
@ -16324,7 +16403,7 @@ namespace Example
var apiInstance = new SamlspApi();
var confKey = new confKey(); // confKey | Configuration key of SAML Service Provider that needs to be replaced
var body = new SamlSp(); // SamlSp | (optional)
var body = new SamlSpReplace(); // SamlSpReplace | (optional)
try
{
@ -16347,7 +16426,7 @@ require_once(__DIR__ . '/vendor/autoload.php');
$api_instance = new Swagger\Client\ApiSamlspApi();
$confKey = ; // confKey | Configuration key of SAML Service Provider that needs to be replaced
$body = ; // SamlSp |
$body = ; // SamlSpReplace |
try {
$api_instance->replaceSamlSp($confKey, $body);
@ -16364,7 +16443,7 @@ use WWW::SwaggerClient::SamlspApi;
my $api_instance = WWW::SwaggerClient::SamlspApi->new();
my $confKey = ; # confKey | Configuration key of SAML Service Provider that needs to be replaced
my $body = WWW::SwaggerClient::Object::SamlSp->new(); # SamlSp |
my $body = WWW::SwaggerClient::Object::SamlSpReplace->new(); # SamlSpReplace |
eval {
$api_instance->replaceSamlSp(confKey => $confKey, body => $body);
@ -16384,7 +16463,7 @@ from pprint import pprint
# create an instance of the API class
api_instance = swagger_client.SamlspApi()
confKey = # confKey | Configuration key of SAML Service Provider that needs to be replaced
body = # SamlSp | (optional)
body = # SamlSpReplace | (optional)
try:
# Replaces a SAML Service
@ -16443,7 +16522,7 @@ except ApiException as e:
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/SamlSp"
"$ref" : "#/components/schemas/SamlSpReplace"
}
}
}

View File

@ -34,10 +34,46 @@ authentication:
</tomcat-users>
LL::NG provides a valve, available on :doc:`download page</download>`.
This valve will check an HTTP header to set the authenticated user on
LL::NG provides a valve that will check an HTTP header to set the authenticated user on
the J2EE container.
Compilation
-----------
The sources are available at `<https://github.com/LemonLDAPNG/lemonldap-valve-tomcat>`__
Required :
- ant
- jre > 1.4
- tomcat >= 5.5
Configure your tomcat home in ``build.properties`` files.
.. attention::
Be careful for Windows user, path must contains "/".
Example:
::
c:/my hardisk/tomcat/
Next run ant command:
::
ant
``ValveLemonLDAPNG.jar`` is created under ``/dist`` directory.
.. |image0| image:: /applications/tomcat_logo.png
:class: align-center
Installation
------------
@ -85,40 +121,3 @@ Configure attributes:
in debug level. See `how configure logging in
Tomcat <http://tomcat.apache.org/tomcat-5.5-doc/logging.html>`__ .
Compilation
-----------
The sources are available on :doc:`download page</download>`.
Required :
- ant
- jre > 1.4
- tomcat >= 5.5
Configure your tomcat home in ``build.properties`` files.
.. attention::
Be careful for Windows user, path must contains "/".
Example:
::
c:/my hardisk/tomcat/
Next run ant command:
::
ant
``ValveLemonLDAPNG.jar`` is created under ``/dist`` directory.
.. |image0| image:: /applications/tomcat_logo.png
:class: align-center

View File

@ -92,7 +92,8 @@ Connection
bind is used.
- **Password**: password to used to connect to LDAP server. By default,
anonymous bind is used.
- **Timeout**: server idle timeout.
- **Connection timeout**: applies only when initiating the connection
- **Operation timeout**: applies to all LDAP operations
- **Version**: LDAP protocol version.
- **Binary attributes**: regular expression matching binary attributes
(see

View File

@ -506,12 +506,13 @@ Some options are available:
- Type: handler type (normal,
:doc:`ServiceToken Handler<servertoserver>`,
:doc:`DevOps Handler<devopshandler>`,...)
- Authentication level required: this option avoids to reject user with
a rule based on ``$_authenticationLevel``. When user hasn't got the
- Required authentication level: this option avoids to reject user with
a rule based on ``$_authenticationLevel``. When user has not got the
required level, he is redirected to an upgrade page in the portal.
This level is applied to ALL VirtualHost locations.
- ServiceToken timeout: The Service Token is only available during 30
seconds by default. This TTL can be customized for each virtual host.
This default level is required for ALL locations relative to this virtual host.
It can be overrided for each locations.
- ServiceToken timeout: by default, ServiceToken is just valid during 30
seconds. This TTL can be customized for each virtual host.
.. danger::

View File

@ -22,6 +22,8 @@ can be forbidden to assume.
identities like CEO, administrators or anonymous/protected users.
- **Unrestricted users rule**: Rule to define which users can switch
context of ALL users. ``Identities use rule`` is bypassed.
- **Allow 2FA modifications**: This option must be enabled to append,
verify or delete a second factor during context switching.
- **Stop by logout**: Stop context switching by sending a logout
request.

View File

@ -241,6 +241,7 @@ ldapSearchDeref "deref" param of Net::LD
ldapServer LDAP server (host or URI) ✔
ldapSetPassword ✔
ldapTimeout LDAP connection timeout ✔
ldapIOTimeout LDAP operation timeout ✔
ldapUsePasswordResetAttribute LDAP store reset flag in an attribute ✔
ldapVerify Whether to validate LDAP certificates ✔
ldapVersion LDAP protocol version ✔

View File

@ -308,7 +308,7 @@ Buttons
This node allows one to enable/disable buttons on the login page:
- **Check last logins**: displays a checkbox on login form, allowing
- **Check last logins**: display a checkbox on login form, allowing
user to check his login history right after opening session
- **Reset password**: display a link to
:doc:`reset your password page<resetpassword>` (for password based
@ -316,6 +316,8 @@ This node allows one to enable/disable buttons on the login page:
times by default)
- **Register**: display a link to :doc:`register page<register>` (for
password based authentication backends)
- **Reset certificate**: display a link to :doc:`reset certificate page<resetcertificate>` (for
password based authentication backends)
Password management
-------------------

View File

@ -48,9 +48,9 @@ rule.
Self-care on Portal
-------------------
User may register second facrots themselves on the Portal by using the 2FA Manager.
User may register second factors themselves on the Portal by using the 2FA Manager.
The link will be displayed if at least a SFA module is enabled. You can set a
The link will be displayed if at least one SFA module is enabled. You can set a
rule to display or not the link.
Session upgrade through 2FA

View File

@ -10,6 +10,7 @@ To configure sessions, go in Manager, ``General Parameters`` »
- **Store user password in session data**: see
:doc:`password store documentation<passwordstore>`.
- **Display session identifier**: Should the session ID be displayed in the manager's session explorer. The session ID is a sensitive information that should only be shown to highly trusted administrators.
- **Sessions timeout**: Maximum lifetime of a session. Old sessions are
deleted by a cron script.
- **Sessions activity timeout**: Maximum inactivity duration.

View File

@ -86,13 +86,13 @@ current URL.
Rules can also be used to intercept logout URL:
================================================================================================================= =================== ====
================================================================================================================= =================== =====================================
Goal Regular expression Rule
================================================================================================================= =================== ====
Logout user from Lemonldap::NG and redirect it to http://intranet/ ^/index.php\?logout
Logout user from current application and redirect it to the menu **(Apache only)** ^/index.php\?logout
Logout user from current application and from Lemonldap::NG and redirect it to http://intranet/ **(Apache only)** ^/index.php\?logout
================================================================================================================= =================== ====
================================================================================================================= =================== =====================================
Logout user from Lemonldap::NG and redirect it to http://intranet/ ^/index.php\?logout logout_sso http://intranet/
Logout user from current application and redirect it to the menu **(Apache only)** ^/index.php\?logout logout_app https://auth.example.com/
Logout user from current application and from Lemonldap::NG and redirect it to http://intranet/ **(Apache only)** ^/index.php\?logout logout_app_sso http://intranet/
================================================================================================================= =================== =====================================
.. danger::

View File

@ -135,7 +135,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/SamlSp'
$ref: '#/components/schemas/SamlSpReplace'
responses:
204:
$ref: '#/components/responses/NoContent'
@ -327,7 +327,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/OidcRp'
$ref: '#/components/schemas/OidcRpReplace'
responses:
204:
$ref: '#/components/responses/NoContent'
@ -469,7 +469,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/CasApp'
$ref: '#/components/schemas/CasAppReplace'
responses:
204:
$ref: '#/components/responses/NoContent'
@ -1067,6 +1067,24 @@ components:
$ref: '#/components/schemas/samlAttribute'
options:
$ref: '#/components/schemas/samlOptions'
SamlSpReplace:
type: object
required:
- metadata
properties:
metadata:
type: string
example: '<?xml version="1.0"?><EntityDescriptor...'
macros:
type: object
example:
myMacroName: "$macro(rule)"
exportedAttributes:
type: object
items:
$ref: '#/components/schemas/samlAttribute'
options:
$ref: '#/components/schemas/samlOptions'
samlOptions:
type: object
properties:
@ -1257,6 +1275,30 @@ components:
myMacroName: "$macro(rule)"
options:
$ref: '#/components/schemas/OidcOptions'
OidcRpReplace:
type: object
required:
- clientId
- redirectUris
properties:
clientId:
type: string
exportedVars:
type: object
example:
email: mail
family_name: sn
name: cn
extraClaims:
type: object
example:
myscope: "myattr1 myattr2 myattr3"
macros:
type: object
example:
myMacroName: "$macro(rule)"
options:
$ref: '#/components/schemas/OidcOptions'
CasApp:
required:
@ -1292,6 +1334,21 @@ components:
uid: uid
options:
$ref: '#/components/schemas/casOptions'
CasAppReplace:
type: object
properties:
macros:
type: object
example:
myMacroName: "$macro(rule)"
exportedVars:
type: object
default:
cn: cn
mail: mail
uid: uid
options:
$ref: '#/components/schemas/casOptions'
casOptions:
required:
- service

View File

@ -30,7 +30,7 @@ use constant DEFAULTCONFBACKENDOPTIONS => (
dirName => '/usr/local/lemonldap-ng/data/conf',
);
our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|(?:(?:d(?:emo|bi)|facebook|webID)ExportedVa|exported(?:Heade|Va)|issuerDBGetParamete)r|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|macro)s|o(?:idc(?:S(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar|Macro)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option|Macro)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars|fExtra)|c(?:as(?:A(?:ppMetaData(?:(?:ExportedVar|Option|Macro)s|Node)|ttributes)|S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions))|(?:ustom(?:Plugins|Add)Param|ombModule)s)|a(?:(?:daptativeAuthenticationLevelR|ut(?:hChoiceMod|oSigninR))ules|pplicationList)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|v(?:hostOptions|irtualHost)|S(?:MTPTLSOpts|SLVarIf))$/;
our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|f(?:RemovedUseNotif|OnlyUpgrade)|kip(?:Upgrade|Renew)Confirmation|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:Allow(?:PasswordGrant|Offline)|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|ErrorOn(?:ExpiredSession|MailNotFound)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxyUseSoap)|c(?:o(?:ntextSwitching(?:Allowed2fModifications|StopWithLogout)|mpactConf|rsEnabled)|a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:State|User|XSS)|da)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|re(?:st(?:(?:Password|Session|Config|Auth)Server|ExportSecretKeys)|freshSessions)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|d(?:isablePersistentStorage|biDynamicHashEnabled)|g(?:roupsBeforeMacros|lobalLogoutTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|(?:activeTim|wsdlServ)er|krb(?:RemoveDomain|ByJs))$/;
our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|f(?:RemovedUseNotif|OnlyUpgrade)|kip(?:Upgrade|Renew)Confirmation|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:Allow(?:PasswordGrant|Offline)|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|ErrorOn(?:ExpiredSession|MailNotFound)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxyUseSoap)|c(?:o(?:ntextSwitching(?:Allowed2fModifications|StopWithLogout)|mpactConf|rsEnabled)|a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:State|User|XSS)|da)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|re(?:st(?:(?:Password|Session|Config|Auth)Server|ExportSecretKeys)|freshSessions)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|d(?:is(?:ablePersistentStorage|playSessionId)|biDynamicHashEnabled)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|g(?:roupsBeforeMacros|lobalLogoutTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|(?:activeTim|wsdlServ)er|krb(?:RemoveDomain|ByJs))$/;
our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' );

View File

@ -72,8 +72,9 @@ sub defaultValues {
'mail' => 'mail',
'uid' => 'uid'
},
'domain' => 'example.com',
'exportedVars' => {
'displaySessionId' => 1,
'domain' => 'example.com',
'exportedVars' => {
'UA' => 'HTTP_USER_AGENT'
},
'ext2fActivation' => 0,
@ -139,12 +140,13 @@ sub defaultValues {
'ldapGroupAttributeNameSearch' => 'cn',
'ldapGroupAttributeNameUser' => 'dn',
'ldapGroupObjectClass' => 'groupOfNames',
'ldapIOTimeout' => 10,
'ldapPasswordResetAttribute' => 'pwdReset',
'ldapPasswordResetAttributeValue' => 'TRUE',
'ldapPwdEnc' => 'utf-8',
'ldapSearchDeref' => 'find',
'ldapServer' => 'ldap://localhost',
'ldapTimeout' => 120,
'ldapTimeout' => 10,
'ldapUsePasswordResetAttribute' => 1,
'ldapVerify' => 'require',
'ldapVersion' => 3,

View File

@ -45,7 +45,7 @@ our $authParameters = {
githubParams => [qw(githubAuthnLevel githubClientID githubClientSecret githubUserField githubScope)],
gpgParams => [qw(gpgAuthnLevel gpgDb)],
kerberosParams => [qw(krbAuthnLevel krbKeytab krbByJs krbRemoveDomain)],
ldapParams => [qw(ldapAuthnLevel ldapExportedVars ldapServer ldapPort ldapVerify ldapBase managerDn managerPassword ldapTimeout ldapVersion ldapRaw ldapCAFile ldapCAPath LDAPFilter AuthLDAPFilter mailLDAPFilter ldapSearchDeref ldapGroupBase ldapGroupObjectClass ldapGroupAttributeName ldapGroupAttributeNameUser ldapGroupAttributeNameSearch ldapGroupDecodeSearchedValue ldapGroupRecursive ldapGroupAttributeNameGroup ldapPpolicyControl ldapSetPassword ldapChangePasswordAsUser ldapPwdEnc ldapUsePasswordResetAttribute ldapPasswordResetAttribute ldapPasswordResetAttributeValue ldapAllowResetExpiredPassword ldapITDS)],
ldapParams => [qw(ldapAuthnLevel ldapExportedVars ldapServer ldapPort ldapVerify ldapBase managerDn managerPassword ldapTimeout ldapIOTimeout ldapVersion ldapRaw ldapCAFile ldapCAPath LDAPFilter AuthLDAPFilter mailLDAPFilter ldapSearchDeref ldapGroupBase ldapGroupObjectClass ldapGroupAttributeName ldapGroupAttributeNameUser ldapGroupAttributeNameSearch ldapGroupDecodeSearchedValue ldapGroupRecursive ldapGroupAttributeNameGroup ldapPpolicyControl ldapSetPassword ldapChangePasswordAsUser ldapPwdEnc ldapUsePasswordResetAttribute ldapPasswordResetAttribute ldapPasswordResetAttributeValue ldapAllowResetExpiredPassword ldapITDS)],
linkedinParams => [qw(linkedInAuthnLevel linkedInClientID linkedInClientSecret linkedInFields linkedInUserField linkedInScope)],
nullParams => [qw(nullAuthnLevel)],
oidcParams => [qw(oidcAuthnLevel oidcRPCallbackGetParam oidcRPStateTimeout)],

View File

@ -1,6 +1,8 @@
package Lemonldap::NG::Handler::Lib::CDA;
use strict;
use URI;
use URI::QueryParam;
our $VERSION = '2.1.0';
@ -9,7 +11,7 @@ sub run {
my $uri = $req->{env}->{REQUEST_URI};
my $cn = $class->tsv->{cookieName};
my ( $id, $session );
if ( $uri =~ s/[\?&;]${cn}cda=(\w+)$//oi ) {
if ( $uri =~ m/[\?&;]${cn}cda=(\w+)/oi ) {
if ( $id = $class->fetchId($req)
and $session = $class->retrieveSession( $req, $id ) )
{
@ -17,7 +19,13 @@ sub run {
'CDA asked for an already available session, skipping');
}
else {
my $cdaid = $1;
# Extract CDA code from URI
my $u = URI->new( $req->uri );
my $cdaid = $u->query_param("${cn}cda");
# Remove CDA param from URI
$u->query_param_delete("${cn}cda");
$class->logger->debug("CDA request with id $cdaid");
my $cdaInfos = $class->getCDAInfos( $req, $cdaid );
@ -26,7 +34,7 @@ sub run {
return $class->FORBIDDEN;
}
my $redirectUrl = $class->_buildUrl( $req, $uri );
my $redirectUrl = $class->_buildUrl( $req, $u->path_query );
my $redirectHttps = ( $redirectUrl =~ m/^https/ );
$class->set_header_out(
$req,

View File

@ -57,6 +57,8 @@ sub checkConf {
$class->logger->debug($Lemonldap::NG::Common::Conf::msg);
}
}
$Lemonldap::NG::Common::Conf::msg = '';
if ( $force or !$class->cfgNum or $class->cfgNum != $conf->{cfgNum} ) {
$class->logger->debug("Get configuration $conf->{cfgNum}");
unless ( $class->cfgNum( $conf->{cfgNum} ) ) {

View File

@ -45,6 +45,8 @@ sub init {
$self->setTypes($conf);
$self->{multiValuesSeparator} ||= '; ';
$self->{hiddenAttributes} //= "_password";
$self->{hiddenAttributes} .= ' _session_id'
unless $conf->{displaySessionId};
$self->{TOTPCheck} = $self->{U2FCheck} = $self->{UBKCheck} = '1';
return 1;
}

View File

@ -11,7 +11,6 @@ use Lemonldap::NG::Manager::Conf::Parser;
extends 'Lemonldap::NG::Manager::Api::Common';
sub getCasAppByConfKey {
my ( $self, $req ) = @_;
@ -26,8 +25,7 @@ sub getCasAppByConfKey {
my $casApp = $self->_getCasAppByConfKey( $conf, $confKey );
# Return 404 if not found
return $self->sendError( $req,
"CAS application '$confKey' not found", 404 )
return $self->sendError( $req, "CAS application '$confKey' not found", 404 )
unless ( defined $casApp );
return $self->sendJSONresponse( $req, $casApp );
@ -77,7 +75,8 @@ sub findCasAppsByServiceUrl {
return $self->sendError( $req, 'Invalid input: serviceUrl is missing', 400 )
unless ( defined $serviceUrl );
$self->logger->debug("[API] Find CAS Apps by service URL $serviceUrl requested");
$self->logger->debug(
"[API] Find CAS Apps by service URL $serviceUrl requested");
# Get latest configuration
my $conf = $self->_confAcc->getConf;
@ -104,6 +103,9 @@ sub addCasApp {
400 )
if ( ref $add->{confKey} );
return $self->sendError( $req, 'Invalid input: confKey is empty', 400 )
unless ( $add->{confKey} );
return $self->sendError( $req, 'Invalid input: service is missing', 400 )
unless ( defined $add->{options}->{service} );
@ -112,8 +114,7 @@ sub addCasApp {
if ( ref $add->{options}->{service} );
$self->logger->debug(
"[API] Add CAS App with confKey $add->{confKey} requested"
);
"[API] Add CAS App with confKey $add->{confKey} requested");
# Get latest configuration
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
@ -167,8 +168,7 @@ sub updateCasApp {
# Return 404 if not found
return $self->sendError( $req,
"CAS application '$confKey' not found", 404 )
return $self->sendError( $req, "CAS application '$confKey' not found", 404 )
unless ( defined $current );
# check if new clientID exists already
@ -195,13 +195,6 @@ sub replaceCasApp {
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
unless ($replace);
return $self->sendError( $req, 'Invalid input: confKey is missing', 400 )
unless ( defined $replace->{confKey} );
return $self->sendError( $req, 'Invalid input: confKey is not a string',
400 )
if ( ref $replace->{confKey} );
$self->logger->debug(
"[API] CAS App $confKey configuration replace requested");
@ -210,8 +203,7 @@ sub replaceCasApp {
# Return 404 if not found
return $self->sendError( $req,
"CAS application '$confKey' not found", 404 )
return $self->sendError( $req, "CAS application '$confKey' not found", 404 )
unless ( defined $self->_getCasAppByConfKey( $conf, $confKey ) );
# check if new clientID exists already
@ -241,8 +233,7 @@ sub deleteCasApp {
# Return 404 if not found
return $self->sendError( $req,
"CAS application '$confKey' not found", 404 )
return $self->sendError( $req, "CAS application '$confKey' not found", 404 )
unless ( defined $delete );
delete $conf->{casAppMetaDataOptions}->{$confKey};
@ -255,7 +246,6 @@ sub deleteCasApp {
return $self->sendJSONresponse( $req, undef, code => 204 );
}
sub _getCasAppByConfKey {
my ( $self, $conf, $confKey ) = @_;
@ -277,7 +267,7 @@ sub _getCasAppByConfKey {
my $configOption ( keys %{ $conf->{casAppMetaDataOptions}->{$confKey} } )
{
$options->{ $self->_translateOptionConfToApi($configOption) } =
$conf->{casAppMetaDataOptions}->{$confKey}->{$configOption};
$conf->{casAppMetaDataOptions}->{$confKey}->{$configOption};
}
return {
@ -307,7 +297,8 @@ sub _getCasAppByServiceUrl {
sub _isNewCasAppServiceUrlUnique {
my ( $self, $conf, $confKey, $casApp ) = @_;
my $curServiceUrl = $self->_getCasAppByConfKey( $conf, $confKey )->{options}->{service};
my $curServiceUrl =
$self->_getCasAppByConfKey( $conf, $confKey )->{options}->{service};
my $newServiceUrl = $casApp->{options}->{service} || "";
if ( $newServiceUrl ne '' && $newServiceUrl ne $curServiceUrl ) {
return {
@ -326,9 +317,9 @@ sub _pushCasApp {
my $translatedOptions = {};
if ($replace) {
$conf->{casAppMetaDataOptions}->{$confKey} = {};
$conf->{casAppMetaDataExportedVars}->{$confKey} = {};
$conf->{casAppMetaDataMacros}->{$confKey} = {};
$conf->{casAppMetaDataOptions}->{$confKey} = {};
$conf->{casAppMetaDataExportedVars}->{$confKey} = {};
$conf->{casAppMetaDataMacros}->{$confKey} = {};
$translatedOptions = $self->_getDefaultValues('casAppMetaDataNodes');
}

View File

@ -103,6 +103,9 @@ sub addOidcRp {
400 )
if ( ref $add->{confKey} );
return $self->sendError( $req, 'Invalid input: confKey is empty', 400 )
unless ( $add->{confKey} );
return $self->sendError( $req, 'Invalid input: clientId is missing', 400 )
unless ( defined $add->{clientId} );
@ -201,13 +204,6 @@ sub replaceOidcRp {
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
unless ($replace);
return $self->sendError( $req, 'Invalid input: confKey is missing', 400 )
unless ( defined $replace->{confKey} );
return $self->sendError( $req, 'Invalid input: confKey is not a string',
400 )
if ( ref $replace->{confKey} );
return $self->sendError( $req, 'Invalid input: clientId is missing', 400 )
unless ( defined $replace->{clientId} );
@ -297,6 +293,9 @@ sub _getOidcRpByConfKey {
# Get macros
my $macros = $conf->{oidcRPMetaDataMacros}->{$confKey} || {};
# Redirect URIs, filled later
my $redirectUris;
# Get options
my $options = {};
for
@ -304,12 +303,15 @@ sub _getOidcRpByConfKey {
{
# redirectUris is handled as an array
if ( $configOption eq "oidcRPMetaDataOptionsRedirectUris" ) {
$options->{ $self->_translateOptionConfToApi($configOption) } = [
$redirectUris = [
split(
/\s+/,
$conf->{oidcRPMetaDataOptions}->{$confKey}->{$configOption}
)
];
$options->{ $self->_translateOptionConfToApi($configOption) } =
$redirectUris;
}
else {
$options->{ $self->_translateOptionConfToApi($configOption) } =
@ -320,6 +322,7 @@ sub _getOidcRpByConfKey {
return {
confKey => $confKey,
clientId => $clientId,
redirectUris => $redirectUris,
exportedVars => $exportedVars,
extraClaims => $extraClaims,
macros => $macros,

View File

@ -96,6 +96,9 @@ sub addSamlSp {
return $self->sendError( $req, 'Invalid input: metadata is missing', 400 )
unless ( defined $add->{metadata} );
return $self->sendError( $req, 'Invalid input: confKey is empty', 400 )
unless ( $add->{confKey} );
my $entityId = $self->_readSamlSpEntityId( $add->{metadata} );
return $self->sendError( $req,

View File

@ -22,7 +22,10 @@ sub perlExpr {
grep( { $_ =~ /(?:Undefined subroutine|Devel::StackTrace)/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( -1, "__badExpression__: $err" ) : 1;
return -1, "__badExpression__: $err" if $err;
return $val =~ qr/(?<=[^=<!>\|\?])=(?![=~])/
? ( -1, '__badExpressionAssignment__' )
: 1;
}
sub types {
@ -1253,6 +1256,10 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'default' => 0,
'type' => 'bool'
},
'displaySessionId' => {
'default' => 1,
'type' => 'bool'
},
'domain' => {
'default' => 'example.com',
'msgFail' => '__badDomainName__',
@ -1667,6 +1674,10 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
'default' => 0,
'type' => 'bool'
},
'ldapIOTimeout' => {
'default' => 10,
'type' => 'int'
},
'ldapITDS' => {
'default' => 0,
'type' => 'bool'
@ -1735,7 +1746,7 @@ m[^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
'type' => 'bool'
},
'ldapTimeout' => {
'default' => 120,
'default' => 10,
'type' => 'int'
},
'ldapUsePasswordResetAttribute' => {

View File

@ -27,7 +27,10 @@ sub perlExpr {
my $err = join( '',
grep { $_ =~ /(?:Undefined subroutine|Devel::StackTrace)/ ? () : $_ }
split( /\n/, $@ ) );
return $err ? ( -1, "__badExpression__: $err" ) : (1);
return ( -1, "__badExpression__: $err" ) if $err;
return $val =~ qr/(?<=[^=<!>\|\?])=(?![=~])/
? ( -1, "__badExpressionAssignment__" )
: 1;
}
my $url_re = $RE{URI}{HTTP}{ -scheme => "https?" };
@ -879,6 +882,11 @@ sub attributes {
default => '_password _2fDevices',
documentation => 'Name of attributes to hide in logs',
},
displaySessionId => {
type => 'bool',
default => 1,
documentation => 'Display _session_id with sessions explorer',
},
persistentSessionAttributes => {
type => 'text',
default => '_loginHistory _2fDevices notification_',
@ -1097,9 +1105,10 @@ sub attributes {
documentation => 'Display logout tab in portal',
},
portalDisplayCertificateResetByMail => {
type => 'bool',
default => 0,
documentation => 'Display certificate reset by mail button in portal',
type => 'bool',
default => 0,
documentation =>
'Display certificate reset by mail button in portal',
},
portalDisplayRegister => {
default => 1,
@ -1130,7 +1139,7 @@ sub attributes {
portalDisplayRefreshMyRights => {
default => 1,
type => 'bool',
documentation => 'Displays the link to refresh the user session',
documentation => 'Display link to refresh the user session',
},
# Cookies
@ -2125,14 +2134,14 @@ sub attributes {
documentation => 'List of auto signin rules',
},
# Adaptative Authentication Level plugin
# Adaptative Authentication Level plugin
adaptativeAuthenticationLevelRules => {
type => 'keyTextContainer',
keyTest => sub {
eval { qr/$_[0]/ };
return $@ ? 0 : 1;
},
keyMsgFail => '__badRegexp__',
type => 'keyTextContainer',
keyTest => sub {
eval { qr/$_[0]/ };
return $@ ? 0 : 1;
},
keyMsgFail => '__badRegexp__',
documentation => 'Adaptative authentication level rules',
flags => 'p',
},
@ -3318,9 +3327,14 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
},
ldapTimeout => {
type => 'int',
default => 120,
default => 10,
documentation => 'LDAP connection timeout',
},
ldapIOTimeout => {
type => 'int',
default => 10,
documentation => 'LDAP operation timeout',
},
ldapVersion => {
type => 'int',
default => 3,

View File

@ -268,9 +268,9 @@ sub tree {
'ldapServer', 'ldapPort',
'ldapVerify', 'ldapBase',
'managerDn', 'managerPassword',
'ldapTimeout', 'ldapVersion',
'ldapRaw', 'ldapCAFile',
'ldapCAPath',
'ldapTimeout', 'ldapIOTimeout',
'ldapVersion', 'ldapRaw',
'ldapCAFile', 'ldapCAPath',
]
},
{
@ -552,8 +552,10 @@ sub tree {
title => 'logParams',
help => 'logs.html',
form => 'simpleInputContainer',
nodes =>
[ 'whatToTrace', 'customToTrace', 'hiddenAttributes' ]
nodes => [
'whatToTrace', 'customToTrace',
'hiddenAttributes'
]
},
{
title => 'cookieParams',
@ -571,6 +573,7 @@ sub tree {
help => 'sessions.html',
nodes => [
'storePassword',
'displaySessionId',
'timeout',
'timeoutActivity',
'timeoutActivityInterval',
@ -615,9 +618,9 @@ sub tree {
nodes => [
'stayConnected',
'portalStatus',
'adaptativeAuthenticationLevelRules',
'upgradeSession',
'refreshSessions',
'adaptativeAuthenticationLevelRules',
{
title => 'portalServers',
help => 'portalservers.html',

View File

@ -301,6 +301,28 @@ sub tests {
);
},
# Test support of timeouts for LDAPS connections
ldapsNoTimeout => sub {
# Skip test if no SMTP configuration
return (1) unless ( $conf->{ldapServer} );
if ( $conf->{ldapServer} =~ /ldaps:/ ) {
if ( eval "require IO::Socket::SSL; require IO::Socket::IP;" ) {
if ( IO::Socket::SSL->isa('IO::Socket::IP') ) {
unless ( eval { IO::Socket::IP->VERSION(0.31) } ) {
return ( 1,
"Your version of IO::Socket::IP is too old to enforce "
. "connection timeouts on ldaps:// URLs. Use ldap+tls:// instead"
);
}
}
}
}
return (1);
},
# Test SMTP connection and authentication (warning only)
smtpConfiguration => sub {
@ -380,7 +402,7 @@ sub tests {
&& $conf->{samlServicePublicKeySig} );
return 1;
},
samlSignatureOverrideNeedsCertificate => sub {
return 1 if $conf->{samlServicePublicKeySig} =~ /CERTIFICATE/;

View File

@ -5,6 +5,7 @@ use utf8;
use Mouse;
use JSON qw(from_json to_json);
use POSIX qw(strftime);
use MIME::Base64 qw(decode_base64);
use Lemonldap::NG::Common::Conf::Constants;
use Lemonldap::NG::Common::PSGI::Constants;
@ -243,40 +244,56 @@ sub notifications {
}
sub notification {
my ( $self, $req, $id, $type, $uid, $ref ) = @_;
my ( $self, $req, $id, $type ) = @_;
my $backend = $self->{notificationStorage};
$self->logger->debug("Notification storage: $backend");
if ( $type eq 'actives' ) {
( $uid, $ref ) = ( $id =~ /([^_]+?)_(.+)/ );
my ( $uid, $ref ) = ( $id =~ /([^_]+?)_(.+)/ );
my $n = $self->notifAccess->get( $uid, $ref );
unless ($n) {
$self->userLogger->notice(
"Notification $ref not found for user $uid");
"Active notification $ref not found for user $uid");
return $self->sendJSONresponse(
$req,
{
result => 0,
error => "Notification $ref not found for user $uid"
error => "Active otification $ref not found for user $uid"
}
);
}
$self->logger->debug("Active notification $ref found for user $uid");
return $self->sendJSONresponse( $req,
{ result => 1, count => 1, notifications => [ values %$n ] } );
}
else {
my ( $date, $uid, $ref ) =
$backend eq 'File'
? ( $id =~ /([^_]+?)_(.+?)_(.+?)\.done/ )
: ( $id =~ /([^_]+?)_(.+?)_(.+)/ );
$ref = decode_base64($ref) if ( $backend eq 'File' );
my $n = $self->notifAccess->getAccepted( $uid, $ref );
unless ($n) {
$self->userLogger->notice(
"Notification $ref not found for user $uid");
"Done notification $ref not found for user $uid");
return $self->sendJSONresponse(
$req,
{
result => 0,
error => "Notification $ref not found for user $uid"
error => "Done notification $ref not found for user $uid"
}
);
}
return $self->sendJSONresponse( $req,
{ result => 1, count => 1, done => $id, notifications => [ values %$n ] } );
$self->logger->debug("Done notification $ref found for user $uid");
return $self->sendJSONresponse(
$req,
{
result => 1,
count => 1,
done => $id,
notifications => [ values %$n ]
}
);
}
}

View File

@ -55,7 +55,9 @@ sub init {
$self->{ipField} ||= 'ipAddr';
$self->{multiValuesSeparator} ||= '; ';
$self->{impersonationPrefix} = $conf->{impersonationPrefix} || 'real_';
$self->{hiddenAttributes} //= "_password";
$self->{hiddenAttributes} //= '_password';
$self->{hiddenAttributes} .= ' _session_id'
unless $conf->{displaySessionId};
return 1;
}
@ -65,7 +67,7 @@ sub init {
sub delOIDCConsent {
my ( $self, $req, $session, $skey ) = @_;
my ( $self, $req ) = @_;
my $mod = $self->getMod($req)
or return $self->sendError( $req, undef, 400 );
@ -74,10 +76,15 @@ sub delOIDCConsent {
my $epoch = $params->{epoch};
my $rp = $params->{rp};
my $id = $req->params('sessionId')
or return $self->sendError( $req, 'sessionId is missing', 400 );
$req->parameters->set('sessionId', $self->_maybeDecryptSessionId($id));
if ( $rp =~ /\b[\w-]+\b/ and defined $epoch ) {
$self->logger->debug(
"Call procedure deleteOIDCConsent with RP=$rp and epoch=$epoch");
return $self->deleteOIDCConsent( $req, $session, $skey );
return $self->deleteOIDCConsent( $req );
}
else {
return $self->sendError( $req, undef, 400 );
@ -241,8 +248,9 @@ sub sessions {
count => scalar( @{ $r->{$uid} } ),
sessions => [
map { {
session => $_->{_sessionId},
date => $_->{_utime}
session =>
$self->_maybeEncryptSessionId( $_->{_sessionId} ),
date => $_->{_utime}
}
} @{ $r->{$uid} }
]
@ -349,7 +357,7 @@ qq{Use of an uninitialized attribute "$group" to group sessions},
elsif ( my $f = $req->params('orderBy') ) {
my @fields = split /,/, $f;
my @r = map {
my $tmp = { session => $_ };
my $tmp = { session => $self->_maybeEncryptSessionId($_) };
foreach my $f (@fields) {
my $s = $f;
$s =~ s/^net(?:4|6|)\(([\w:]+)\)$/$1/;
@ -390,7 +398,11 @@ qq{Use of an uninitialized attribute "$group" to group sessions},
else {
$res = [
sort { $a->{date} <=> $b->{date} }
map { { session => $_, date => $res->{$_}->{_utime} } }
map { {
session => $self->_maybeEncryptSessionId($_),
date => $res->{$_}->{_utime}
}
}
keys %$res
];
}
@ -406,6 +418,45 @@ qq{Use of an uninitialized attribute "$group" to group sessions},
);
}
sub session {
my ( $self, $req, $session, $skey ) = @_;
$session = $self->_maybeDecryptSessionId($session);
return $self->SUPER::session( $req, $session, $skey );
}
sub _maybeDecryptSessionId {
my ( $self, $session ) = @_;
if ( $self->{hiddenAttributes} =~ /\b_session_id\b/ ) {
$session =
Lemonldap::NG::Handler::Main->tsv->{cipher}->decryptHex($session);
}
return $session;
}
sub _maybeEncryptSessionId {
my ( $self, $session ) = @_;
if ( $self->{hiddenAttributes} =~ /\b_session_id\b/ ) {
$session =
Lemonldap::NG::Handler::Main->tsv->{cipher}->encryptHex($session);
}
return $session;
}
sub delSession {
my ( $self, $req ) = @_;
my $id = $req->params('sessionId')
or return $self->sendError( $req, 'sessionId is missing', 400 );
$req->parameters->set('sessionId', $self->_maybeDecryptSessionId($id));
return $self->SUPER::delSession( $req );
}
sub cmpIPv4 {
my @a = split /\./, $_[0];
my @b = split /\./, $_[1];

View File

@ -108,7 +108,6 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
# Delete 2FA device
$scope.delete2FA = (type, epoch) ->
#item = angular.element(".data-#{epoch}")
items = document.querySelectorAll(".data-#{epoch}")
for e in items
e.remove()

View File

@ -206,12 +206,10 @@ llapp.controller 'NotificationsExplorerCtrl', [ '$scope', '$translator', '$locat
$scope.currentScope = scope
node = scope.$modelValue
notificationId = node.notification
query = ''
if $scope.type == 'actives'
notificationId = "#{node.uid}_#{node.reference}"
if $scope.type == 'done'
query = "?uid=#{node.uid}&reference=#{node.reference}"
$http.get("#{scriptname}notifications/#{$scope.type}/#{notificationId}#{query}").then (response) ->
node.reference.replace(/#/, '_')
notificationId = "#{node.uid}_" + node.reference.replace(/#/, '_')
$http.get("#{scriptname}notifications/#{$scope.type}/#{notificationId}").then (response) ->
$scope.currentNotification =
uid: node.uid
reference: node.reference

View File

@ -176,8 +176,9 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
# Delete RP Consent
$scope.deleteOIDCConsent = (rp, epoch) ->
item = angular.element(".data-#{epoch}")
item.remove()
items = document.querySelectorAll(".data-#{epoch}")
for e in items
e.remove()
$scope.waiting = true
$http['delete']("#{scriptname}sessions/OIDCConsent/#{sessionType}/#{$scope.currentSession.id}?rp=#{rp}&epoch=#{epoch}").then (response) ->
$scope.waiting = false
@ -225,7 +226,6 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
title: title
nodes: tmp
time = session._utime
id = session._session_id
# 1. Replace values if needed
for key, value of session
@ -272,7 +272,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
delete session[attr]
else if session[attr].toString().match(/"rp":\s*"[\w-]+"/)
subres.push
title: "rp"
title: "RP"
value: "scope"
epoch: "date"
td: "0"
@ -375,7 +375,6 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
nodes: tmp
return {
_utime: time
id: id
nodes: res
}
@ -383,6 +382,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
sessionId = scope.$modelValue.session
$http.get("#{scriptname}sessions/#{sessionType}/#{sessionId}").then (response) ->
$scope.currentSession = transformSession response.data
$scope.currentSession.id = sessionId
$scope.showT = false
$scope.localeDate = (s) ->

View File

@ -243,19 +243,16 @@
}
};
$scope.displayNotification = function(scope) {
var node, notificationId, query;
var node, notificationId;
$scope.waiting = true;
$scope.currentScope = scope;
node = scope.$modelValue;
notificationId = node.notification;
query = '';
if ($scope.type === 'actives') {
notificationId = node.uid + "_" + node.reference;
node.reference.replace(/#/, '_');
notificationId = (node.uid + "_") + node.reference.replace(/#/, '_');
}
if ($scope.type === 'done') {
query = "?uid=" + node.uid + "&reference=" + node.reference;
}
$http.get(scriptname + "notifications/" + $scope.type + "/" + notificationId + query).then(function(response) {
$http.get(scriptname + "notifications/" + $scope.type + "/" + notificationId).then(function(response) {
var e, notif;
$scope.currentNotification = {
uid: node.uid,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -194,9 +194,12 @@
return $scope.showM = false;
};
$scope.deleteOIDCConsent = function(rp, epoch) {
var item;
item = angular.element(".data-" + epoch);
item.remove();
var e, i, items, len;
items = document.querySelectorAll(".data-" + epoch);
for (i = 0, len = items.length; i < len; i++) {
e = items[i];
e.remove();
}
$scope.waiting = true;
$http['delete'](scriptname + "sessions/OIDCConsent/" + sessionType + "/" + $scope.currentSession.id + "?rp=" + rp + "&epoch=" + epoch).then(function(response) {
return $scope.waiting = false;
@ -228,7 +231,7 @@
$scope.displaySession = function(scope) {
var sessionId, transformSession;
transformSession = function(session) {
var _insert, array, attr, attrs, category, cv, element, epoch, i, id, j, k, key, l, len, len1, len2, len3, len4, len5, m, name, o, oidcConsent, p, real, ref, ref1, res, sfDevice, spoof, subres, tab, time, title, tmp, value;
var _insert, array, attr, attrs, category, cv, element, epoch, i, j, k, key, l, len, len1, len2, len3, len4, len5, m, name, o, oidcConsent, p, real, ref, ref1, res, sfDevice, spoof, subres, tab, time, title, tmp, value;
_insert = function(re, title) {
var key, reg, tmp, value;
tmp = [];
@ -251,7 +254,6 @@
}
};
time = session._utime;
id = session._session_id;
for (key in session) {
value = session[key];
if (!value) {
@ -310,7 +312,7 @@
delete session[attr];
} else if (session[attr].toString().match(/"rp":\s*"[\w-]+"/)) {
subres.push({
title: "rp",
title: "RP",
value: "scope",
epoch: "date",
td: "0"
@ -449,14 +451,14 @@
});
return {
_utime: time,
id: id,
nodes: res
};
};
$scope.currentScope = scope;
sessionId = scope.$modelValue.session;
$http.get(scriptname + "sessions/" + sessionType + "/" + sessionId).then(function(response) {
return $scope.currentSession = transformSession(response.data);
$scope.currentSession = transformSession(response.data);
return $scope.currentSession.id = sessionId;
});
return $scope.showT = false;
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -79,6 +79,7 @@
"badDomainName":"اسم النطاق سيئ",
"badEncoding":"تشفير خاطئ",
"badExpression":"تعبير خاطئ",
"badExpressionAssignment":"Expression containing an assignment",
"badHeaderName":" حقل الهيدر خاطئ",
"badHostname":"اسم الخادم خاطئ",
"badLdapUri":"\n URI LDAP خاطئ",
@ -279,6 +280,7 @@
"diffViewer":"المشاهد المختلف",
"diffWithPrevious":"الفرق مع السابق",
"disabled":"معطلة",
"displaySessionId":"Display session identifier",
"done":"تم",
"dones":"تم",
"down":"Move down",
@ -447,7 +449,8 @@
"ldapSearchDeref":"الاسم المستعار",
"ldapServer":"مضيف الخادم",
"ldapSetPassword":"تعديل كلمة المرور مع عملية موسعة",
"ldapTimeout":"مهلة",
"ldapTimeout":"Connection timeout",
"ldapIOTimeout": "Operation timeout",
"ldapUsePasswordResetAttribute":"استخدام سمة إعادة الضبط",
"ldapVerify":"Verify LDAP server certificate",
"ldapVersion":"الإصدار",
@ -552,7 +555,7 @@
"notificationServerSentAttributes":"Notification parameters to send",
"serverNotification":"Server",
"notificationCreated":"تم إنشاء إشعار",
"notificationDeleted":"تم حذف الإشعار",
"notificationDeleted":"Notification has been marked as done",
"notificationDone":"انتهى الإشعار",
"notificationsDone":"انتهت الإشعارات",
"notificationsExplorer":"Explorer",

View File

@ -79,6 +79,7 @@
"badDomainName":"Ungültiger Domainname",
"badEncoding":"Ungültige Codierung",
"badExpression":"Bad expression",
"badExpressionAssignment":"Expression containing an assignment",
"badHeaderName":"Bad header name",
"badHostname":"Ungültiger Hostname",
"badLdapUri":"Bad LDAP URI",
@ -278,6 +279,7 @@
"diffViewer":"Difference viewer",
"diffWithPrevious":"difference with previous",
"disabled":"Disabled",
"displaySessionId":"Display session identifier",
"done":"done",
"dones":"Done",
"down":"Move down",
@ -446,7 +448,8 @@
"ldapSearchDeref":"Alias dereference",
"ldapServer":"Server host",
"ldapSetPassword":"Password modify extended operation",
"ldapTimeout":"Timeout",
"ldapTimeout":"Connection timeout",
"ldapIOTimeout": "Operation timeout",
"ldapUsePasswordResetAttribute":"Use reset attribute",
"ldapVerify":"Verify LDAP server certificate",
"ldapVersion":"Version",
@ -551,7 +554,7 @@
"notificationServerSentAttributes":"Notification parameters to send",
"serverNotification":"Server",
"notificationCreated":"Notification has been created",
"notificationDeleted":"Notification deleted",
"notificationDeleted":"Notification has been marked as done",
"notificationDone":"Notification done",
"notificationsDone":"Notifications done",
"notificationsExplorer":"Explorer",

View File

@ -79,6 +79,7 @@
"badDomainName":"Bad domain name",
"badEncoding":"Bad encoding",
"badExpression":"Bad expression",
"badExpressionAssignment":"Expression containing an assignment",
"badHeaderName":"Bad header name",
"badHostname":"Bad hostname",
"badLdapUri":"Bad LDAP URI",
@ -278,6 +279,7 @@
"diffViewer":"Difference viewer",
"diffWithPrevious":"difference with previous",
"disabled":"Disabled",
"displaySessionId":"Display session identifier",
"done":"done",
"dones":"Done",
"down":"Move down",
@ -446,7 +448,8 @@
"ldapSearchDeref":"Alias dereference",
"ldapServer":"Server host",
"ldapSetPassword":"Password modify extended operation",
"ldapTimeout":"Timeout",
"ldapTimeout":"Connection timeout",
"ldapIOTimeout": "Operation timeout",
"ldapUsePasswordResetAttribute":"Use reset attribute",
"ldapVerify":"Verify LDAP server certificate",
"ldapVersion":"Version",
@ -551,7 +554,7 @@
"notificationServerSentAttributes":"Notification parameters to send",
"serverNotification":"Server",
"notificationCreated":"Notification has been created",
"notificationDeleted":"Notification deleted",
"notificationDeleted":"Notification has been marked as done",
"notificationDone":"Notification done",
"notificationsDone":"Notifications done",
"notificationsExplorer":"Explorer",

View File

@ -79,6 +79,7 @@
"badDomainName":"Mauvais nom de domaine",
"badEncoding":"Mauvais encodage",
"badExpression":"Mauvaise expression",
"badExpressionAssignment":"Expression contenant une affectation",
"badHeaderName":"Mauvais nom d'en-tête",
"badHostname":"Mauvais nom d'hôte",
"badLdapUri":"Mauvaise URI LDAP",
@ -278,6 +279,7 @@
"diffViewer":"Visualisateur de différence",
"diffWithPrevious":"différence avec la précédente",
"disabled":"Désactivé",
"displaySessionId":"Afficher l'identifiant de session",
"done":"validée",
"dones":"Validées",
"down":"Descendre",
@ -446,7 +448,8 @@
"ldapSearchDeref":"Déréférence des alias",
"ldapServer":"Hôte",
"ldapSetPassword":"Opération étendue password modify",
"ldapTimeout":"Temps maximum d'inactivité",
"ldapTimeout":"Délai maximum de connexion",
"ldapIOTimeout": "Délai maximum d'opération",
"ldapUsePasswordResetAttribute":"Utiliser l'attribut de réinitialisation",
"ldapVerify":"Vérifier le certificat du serveur LDAP",
"ldapVersion":"Version",

View File

@ -79,6 +79,7 @@
"badDomainName":"Nome di dominio errato",
"badEncoding":"Codifica errata",
"badExpression":"Espressione errata",
"badExpressionAssignment":"Expression containing an assignment",
"badHeaderName":"Nome intestazione errato",
"badHostname":"Hostname errato",
"badLdapUri":"LDAP URI errata",
@ -278,6 +279,7 @@
"diffViewer":"Visualizzatore di differenza",
"diffWithPrevious":"differenza con il precedente",
"disabled":"Disabilitato",
"displaySessionId":"Display session identifier",
"done":"fatto",
"dones":"Fatto",
"down":"Move down",
@ -446,7 +448,8 @@
"ldapSearchDeref":"Alias dereference",
"ldapServer":"Host del server",
"ldapSetPassword":"Operazione prolungata di modifica password",
"ldapTimeout":"Timeout",
"ldapTimeout":"Connection timeout",
"ldapIOTimeout": "Operation timeout",
"ldapUsePasswordResetAttribute":"Utilizza l'attributo di ripristino",
"ldapVerify":"Verify LDAP server certificate",
"ldapVersion":"Versione",
@ -551,7 +554,7 @@
"notificationServerSentAttributes":"Notification parameters to send",
"serverNotification":"Server",
"notificationCreated":"La notifica è stata creata",
"notificationDeleted":"La notifica è stata cancellata",
"notificationDeleted":"Notification has been marked as done",
"notificationDone":"La notifica è stata effettuata",
"notificationsDone":"Notifiche effettuate",
"notificationsExplorer":"Explorer",

View File

@ -79,6 +79,7 @@
"badDomainName":"Błędna nazwa domeny",
"badEncoding":"Błędne kodowanie",
"badExpression":"Błędne wyrażenie",
"badExpressionAssignment":"Expression containing an assignment",
"badHeaderName":"Błędna nazwa nagłówka",
"badHostname":"Błędna nazwa hosta",
"badLdapUri":"Błędny identyfikator URI LDAP",
@ -278,6 +279,7 @@
"diffViewer":"Przeglądarka różnic",
"diffWithPrevious":"różnica w stosunku do poprzednich",
"disabled":"Wyłączone",
"displaySessionId":"Display session identifier",
"done":"wykonane",
"dones":"Wykonane",
"down":"Move down",
@ -446,7 +448,8 @@
"ldapSearchDeref":"Dereferencja aliasu",
"ldapServer":"Host serwera",
"ldapSetPassword":"Rozszerzona operacja modyfikacji hasła",
"ldapTimeout":"Limit czasu",
"ldapTimeout":"Connection timeout",
"ldapIOTimeout": "Operation timeout",
"ldapUsePasswordResetAttribute":"Użyj atrybutu reset",
"ldapVerify":"Verify LDAP server certificate",
"ldapVersion":"Wersja",
@ -551,7 +554,7 @@
"notificationServerSentAttributes":"Parametry powiadomienia do wysłania",
"serverNotification":"Serwer",
"notificationCreated":"Powiadomienie zostało utworzone",
"notificationDeleted":"Powiadomienie zostało usunięte",
"notificationDeleted":"Notification has been marked as done",
"notificationDone":"Powiadomienie wykonane",
"notificationsDone":"Powiadomienia wykonane",
"notificationsExplorer":"Explorer",

View File

@ -28,7 +28,7 @@
"2ndFA":"İki Faktörlü Kimlik Doğrulama",
"actives":"Etkin",
"activeTimer":"Otomatik kabul süresi",
"adaptativeAuthenticationLevelRules":"Adaptative authentication rules",
"adaptativeAuthenticationLevelRules":"Uyarlanabilir doğrulama kuralları",
"addAppCasPartner":"CAS uygulaması ekle",
"addIDPSamlPartner":"SAML IDP ekle",
"addOidcOp":"OpenID Connect Sağlayıcısı Ekle",
@ -79,6 +79,7 @@
"badDomainName":"Hatalı etki alanı adı",
"badEncoding":"Hatalı kodlama",
"badExpression":"Hatalı ifade",
"badExpressionAssignment":"Expression containing an assignment",
"badHeaderName":"Hatalı başlık adı",
"badHostname":"Hatalı konak adı",
"badLdapUri":"Hatalı LDAP URI",
@ -161,7 +162,7 @@
"certificateResetByMailValidityDelay":"Sona ermeden önceki minimum süre",
"contentSecurityPolicy":"İçerik güvenlik ilkesi",
"contextSwitching":"İçeriği başka bir kullanıcıyla değiştir",
"contextSwitchingAllowed2fModifications":"Allow 2FA modifications",
"contextSwitchingAllowed2fModifications":"2FA modifikasyonlarına izin ver",
"contextSwitchingHiddenAttributes":"Gizli nitelikler",
"contextSwitchingIdRule":"Kimlik kullanım kuralı",
"contextSwitchingRule":"Kuralı kullan",
@ -195,8 +196,8 @@
"checkUserIdRule":"Kimlik kullanım kuralı",
"checkUserHiddenAttributes":"Gizli nitelikler",
"checkUserUnrestrictedUsersRule":"Kısıtlamasız kullanıcı kuralı",
"checkUserDisplayComputedSession":"Display computed sessions",
"checkUserDisplayPersistentInfo":"Display persistent session data",
"checkUserDisplayComputedSession":"Hesaplanan oturumu görüntüle",
"checkUserDisplayPersistentInfo":"Kalıcı oturum verisini görüntüle",
"checkUserDisplayEmptyHeaders":"Boş başlıkları görüntüle",
"checkUserDisplayEmptyValues":"Boş değerleri görüntüle",
"checkUserSearchAttributes":"Arama oturumlarında kullanılan nitelikler",
@ -274,10 +275,11 @@
"demoExportedVars":"Dışa aktarılan değişkenler",
"demoParams":"Gösterim parametreleri",
"description":"Açıklama",
"dest":"Recipient",
"dest":"Alıcı",
"diffViewer":"Fark görüntüleyici",
"diffWithPrevious":"önceki ile farkı",
"disabled":"Devre dışı",
"displaySessionId":"Display session identifier",
"done":"tamam",
"dones":"Tamam",
"down":"Aşağı taşı",
@ -446,7 +448,8 @@
"ldapSearchDeref":"Takma ad yönlendirmeleri",
"ldapServer":"Konak sunucu",
"ldapSetPassword":"Parola değiştirme işlemi genişletilmiş",
"ldapTimeout":"Zaman aşımı",
"ldapTimeout":"Connection timeout",
"ldapIOTimeout": "Operation timeout",
"ldapUsePasswordResetAttribute":"Sıfırlama niteliklerini kullan",
"ldapVerify":"LDAP sunucu sertifikasını doğrulayın",
"ldapVersion":"Sürüm",
@ -518,7 +521,7 @@
"newApp":"Yeni uygulama",
"newChain":"Yeni zincir",
"newCat":"Yeni kategori",
"newCertificate":"New certificate",
"newCertificate":"Yeni sertifika",
"newCfgAvailable":"Yeni bir yapılandırma mevcut",
"newCmbMod":"Yeni modül",
"newCmbOver":"Yeni parametre",
@ -551,7 +554,7 @@
"notificationServerSentAttributes":"Gönderilecek bildirim parametreleri",
"serverNotification":"Sunucu",
"notificationCreated":"Bildirim oluşturuldu",
"notificationDeleted":"Bildirim silindi",
"notificationDeleted":"Bildirim tamamlandı olarak işaretlendi",
"notificationDone":"Bildirim tamamlandı",
"notificationsDone":"Bildirimler tamamlandı",
"notificationsExplorer":"Explorer",
@ -847,8 +850,8 @@
"secondFactors":"İki faktörlü kimlik doğrulama",
"securedCookie":"Güvenli Çerez (SSL)",
"security":"Güvenlik",
"sendTestMail":"Send test email",
"sendTestMailSuccess":"Test email successfully sent",
"sendTestMail":"Test e-postası gönder",
"sendTestMailSuccess":"Test e-postası başarıyla gönderildi",
"serverError":"Sunucu hatası",
"session":"oturum",
"sessions":"Oturumlar",

View File

@ -79,6 +79,7 @@
"badDomainName":"Tên miền không hợp lệ",
"badEncoding":"Mã hoá không hợp lệ",
"badExpression":"Biểu thức không hợp lệ",
"badExpressionAssignment":"Expression containing an assignment",
"badHeaderName":"Tên tiêu đề không hợp lệ",
"badHostname":"Tên máy chủ không hợp lệ",
"badLdapUri":"URI LDAP không đúng",
@ -278,6 +279,7 @@
"diffViewer":"Người xem khác ",
"diffWithPrevious":"khác biệt với cái trước",
"disabled":"Tắt",
"displaySessionId":"Display session identifier",
"done":"Hoàn thành",
"dones":"Hoàn thành",
"down":"Move down",
@ -446,7 +448,8 @@
"ldapSearchDeref":"Bí danh ngoại tham chiếu ",
"ldapServer":"Máy chủ lưu trữ",
"ldapSetPassword":"Mật khẩu sửa đổi hoạt động mở rộng",
"ldapTimeout":"Thời gian chờ",
"ldapTimeout":"Connection timeout",
"ldapIOTimeout": "Operation timeout",
"ldapUsePasswordResetAttribute":"Sử dụng thuộc tính đặt lại",
"ldapVerify":"Verify LDAP server certificate",
"ldapVersion":"Phiên bản",
@ -551,7 +554,7 @@
"notificationServerSentAttributes":"Notification parameters to send",
"serverNotification":"Server",
"notificationCreated":"Thông báo đã được tạo ra",
"notificationDeleted":"Thông báo đã xoá",
"notificationDeleted":"Notification has been marked as done",
"notificationDone":"Thông báo được thực hiện",
"notificationsDone":"Thông báo đã hoàn tất",
"notificationsExplorer":"Explorer",

View File

@ -79,6 +79,7 @@
"badDomainName":"无效的域名",
"badEncoding":"无效的编码",
"badExpression":"无效的表达式",
"badExpressionAssignment":"Expression containing an assignment",
"badHeaderName":"无效的头部名称",
"badHostname":"无效的主机名",
"badLdapUri":"无效的 LDAP URI ",
@ -278,6 +279,7 @@
"diffViewer":"Difference viewer",
"diffWithPrevious":"difference with previous",
"disabled":"Disabled",
"displaySessionId":"Display session identifier",
"done":"完成",
"dones":"完成",
"down":"Move down",
@ -446,7 +448,8 @@
"ldapSearchDeref":"Alias dereference",
"ldapServer":"Server host",
"ldapSetPassword":"Password modify extended operation",
"ldapTimeout":"Timeout",
"ldapTimeout":"Connection timeout",
"ldapIOTimeout": "Operation timeout",
"ldapUsePasswordResetAttribute":"Use reset attribute",
"ldapVerify":"Verify LDAP server certificate",
"ldapVersion":"版本",
@ -551,7 +554,7 @@
"notificationServerSentAttributes":"Notification parameters to send",
"serverNotification":"Server",
"notificationCreated":"Notification has been created",
"notificationDeleted":"Notification deleted",
"notificationDeleted":"Notification has been marked as done",
"notificationDone":"Notification done",
"notificationsDone":"Notifications done",
"notificationsExplorer":"Explorer",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -43,16 +43,9 @@ foreach my $i ( 0 .. 2 ) {
}
count(4);
ok(
@{ $resBody->{details}->{__needConfirmation__} } == 1,
'JSON response contains 1 needConfirmation'
@{ $resBody->{details}->{__needConfirmation__} } == 2,
'JSON response contains 2 needConfirmation'
) or print STDERR Dumper($resBody);
ok(
$resBody->{details}->{__needConfirmation__}->[0]->{message} =~
/\bplugin is enabled without CSRF Token neither Captcha required\b/,
"Warning with confirmation needed found"
) or print STDERR Dumper($resBody);
ok(
@{ $resBody->{details}->{__changes__} } == 23,
'JSON response contains 23 changes'
@ -65,9 +58,9 @@ ok(
),
"Request succeed"
);
ok( -f $confFiles->[1], 'File is created' );
count(5);
count(4);
my @changes = @{&changes};
my @cmsg = @{ $resBody->{details}->{__changes__} };
my $bug;

View File

@ -66,6 +66,12 @@ SKIP: {
$notif =
'{"date":"2099-12-31","uid":"dwho","reference":"Test","xml":"{\"title\":\"Test\"}"}';
$res =
$client->jsonPostResponse( 'notifications/actives', '',
IO::String->new($notif),
'application/json', length($notif) );
$notif =
'{"date":"2099-12-31","uid":"dwho","reference":"Test2","xml":"{\"title\":\"Test\"}"}';
$res =
$client->jsonPostResponse( 'notifications/actives', '',
IO::String->new($notif),
@ -89,20 +95,17 @@ SKIP: {
$res =
$client->jsonResponse( 'notifications/actives', 'groupBy=substr(uid,1)' );
ok( $res->{result} == 1, 'Result = 1' );
ok( $res->{count} == 0, 'Count = 0' );
ok( $res->{count} == 1, 'Count = 1' );
# Test "done" notifications display
displayTests('done');
# Delete notification
$res =
$client->_del('notifications/done/dwho_Test_20991231_dwho_VGVzdA==.done');
$res = $client->_del('notifications/done/dwho_Test_20991231');
$res =
$client->jsonResponse( 'notifications/done', 'groupBy=substr(uid,1)' );
ok( $res->{result} == 1, 'Result = 1' );
ok( $res->{count} == 0, 'Count = 0' ) or diag Dumper($res);
#print STDERR Dumper($res);
}
eval { unlink $file };
@ -110,35 +113,37 @@ count($maintests);
done_testing( count() );
sub displayTests {
my $type = shift;
my $type = shift;
my $count = $type eq 'actives' ? 2 : 1;
$res =
$client->jsonResponse( "notifications/$type", 'groupBy=substr(uid,1)' );
ok( $res->{result} == 1, 'Result = 1' );
ok( $res->{count} == 1, 'Count = 1' );
ok( $res->{count} == $count, "Count = $count" );
ok( $res->{values}->[0]->{value} eq 'd', 'Value is "d"' );
count(3);
$res = $client->jsonResponse( "notifications/$type", 'groupBy=uid' );
ok( $res->{result} == 1, 'Result = 1' );
ok( $res->{count} == 1, 'Count = 1' );
ok( $res->{count} == $count, "Count = $count" );
ok( $res->{values}->[0]->{value} eq 'dwho', 'Value is "dwho"' );
count(3);
$res = $client->jsonResponse( "notifications/$type", 'uid=d*&groupBy=uid' );
ok( $res->{result} == 1, 'Result = 1' );
ok( $res->{count} == 1, 'Count = 1' );
ok( $res->{count} == $count, "Count = $count" );
ok( $res->{values}->[0]->{value} eq 'dwho', 'Value is "dwho"' );
count(3);
$res = $client->jsonResponse( "notifications/$type", 'uid=d*' );
ok( $res->{result} == 1, 'Result = 1' );
ok( $res->{count} == 1, 'Count = 1' );
ok( $res->{count} == $count, "Count = $count" );
ok( $res->{values}->[0]->{uid} eq 'dwho', 'Value is "dwho"' );
count(3);
$res = $client->jsonResponse( "notifications/$type", 'uid=dwho' );
ok( $res->{result} == 1, 'Result = 1' );
ok( $res->{count} == 1, 'Count = 1' );
ok( $res->{count} == $count, "Count = $count" );
ok( $res->{values}->[0]->{uid} eq 'dwho', 'Value is "dwho"' );
count(3);
@ -161,8 +166,8 @@ sub displayTests {
) or diag Dumper($res);
my $internal_ref = $res->{values}->[0]->{notification};
my $ref = $res->{values}->[0]->{reference};
$res = $client->jsonResponse( "notifications/$type/$internal_ref",
"uid=dwho&reference=$ref" )
$internal_ref =~ s/#/_/g; # Fix 2353
$res = $client->jsonResponse("notifications/$type/$internal_ref")
or diag Dumper($res);
ok( $res = eval { from_json( $res->{notifications}->[0] ) },
'Response is JSON' )
@ -175,12 +180,6 @@ sub displayTests {
or diag Dumper($res);
ok( $res->{uid} eq 'dwho', 'uid found' )
or diag Dumper($res);
$res = $client->jsonResponse( "notifications/$type/$internal_ref",
"uid=davros&reference=$ref" )
or diag Dumper($res);
ok( $res->{error} eq 'Notification Test not found for user davros',
'error found' )
or diag Dumper($res);
count(7);
count(6);
}
}

View File

@ -137,8 +137,7 @@ sub displayTests {
) or diag Dumper($res);
my $internal_ref = $res->{values}->[0]->{notification};
my $ref = $res->{values}->[0]->{reference};
$res = &client->jsonResponse( "notifications/$type/$internal_ref",
"uid=dwho&reference=$ref" );
$res = &client->jsonResponse( "notifications/$type/$internal_ref" );
ok( $res->{done} eq $internal_ref, 'Internal reference found' )
or diag Dumper($res);
ok( $res = eval { from_json( $res->{notifications}->[0] ) },

View File

@ -1859,7 +1859,7 @@
"data": "logout_sso",
"re": "^/logout"
}, {
"data": "accept",
"data": "$uid = 1",
"re": "default",
"title": "default",
"comment": "",

View File

@ -11,12 +11,13 @@ package Lemonldap::NG::Portal::2F::Engines::Default;
use strict;
use Mouse;
use MIME::Base64 qw(encode_base64);
use JSON qw(from_json to_json);
use POSIX qw(strftime);
use Lemonldap::NG::Portal::Main::Constants qw(
PE_OK
PE_ERROR
PE_NOTOKEN
PE_OK
PE_SENDRESPONSE
PE_TOKENEXPIRED
PE_NO_SECOND_FACTORS
@ -192,8 +193,9 @@ sub init {
# run() is called at each authentication, just after sessionInfo populated
sub run {
my ( $self, $req ) = @_;
my $checkLogins = $req->param('checkLogins');
my $spoofId = $req->param('spoofId') || '';
my $checkLogins = $req->param('checkLogins');
my $stayconnected = $req->param('stayconnected');
my $spoofId = $req->param('spoofId') || '';
$self->logger->debug("2F checkLogins set") if ($checkLogins);
# Skip 2F unless a module has been registered
@ -358,11 +360,15 @@ sub run {
$req,
'2fchoice',
params => {
MAIN_LOGO => $self->conf->{portalMainLogo},
SKIN => $self->p->getSkin($req),
LANGS => $self->conf->{showLanguages},
TOKEN => $token,
MODULES => [
MAIN_LOGO => $self->conf->{portalMainLogo},
SKIN => $self->p->getSkin($req),
LANGS => $self->conf->{showLanguages},
CHECKLOGINS => $checkLogins,
STAYCONNECTED => $stayconnected,
TOKEN => $token,
MSG => $self->canUpdateSfa($req) || 'choose2f',
ALERT => ( $self->canUpdateSfa($req) ? 'warning' : 'positive' ),
MODULES => [
map { {
CODE => $_->prefix,
LOGO => $_->logo,
@ -370,7 +376,6 @@ sub run {
}
} @am
],
CHECKLOGINS => $checkLogins
}
);
$req->response($tpl);
@ -457,6 +462,8 @@ sub _displayRegister {
params => {
MAIN_LOGO => $self->conf->{portalMainLogo},
LANGS => $self->conf->{showLanguages},
MSG => $self->canUpdateSfa($req) || $m->{m}->welcome,
ALERT => ( $self->canUpdateSfa($req) ? 'warning' : 'positive' ),
}
);
}
@ -485,7 +492,7 @@ sub _displayRegister {
# Retrieve user all second factors
my $_2fDevices = [];
if ( $self->allowedUpdateSfa($req) ) {
unless ( $self->canUpdateSfa($req) ) {
$_2fDevices = $req->userData->{_2fDevices}
? eval {
from_json( $req->userData->{_2fDevices}, { allow_nonref => 1 } );
@ -500,8 +507,9 @@ sub _displayRegister {
$self->userLogger->warn("Do not diplay 2F Devices!");
}
# Parse second factors to display delete button if allowed
my $action = '';
# Parse second factors to display delete button if allowed and upgrade button
my $displayUpgBtn = 0;
my $action = '';
foreach
my $type ( split /,\s*/, $self->conf->{available2FSelfRegistration} )
{
@ -511,15 +519,22 @@ sub _displayRegister {
my $t = lc($type);
$t =~ s/2f$//i;
# Display delete button
$_->{delAllowed} =
$self->conf->{ $t . '2fActivation' }
&& $self->conf->{ $t . '2fUserCanRemoveKey' }
&& $self->conf->{ $t . '2fSelfRegistration' };
# Display upgrade button
$displayUpgBtn ||= $self->conf->{ $t . '2fAuthnLevel' }
&& $self->conf->{ $t . '2fAuthnLevel' } >
$req->userData->{authenticationLevel};
}
$action ||= $_->{delAllowed};
$_->{type} =~ s/^Yubikey$/UBK/;
}
}
$displayUpgBtn = 0 unless $self->conf->{upgradeSession};
# Display template
return $self->p->sendHtml(
@ -533,6 +548,11 @@ sub _displayRegister {
SFDEVICES => $_2fDevices,
ACTION => $action,
REG_REQUIRED => $req->data->{sfRegRequired},
DISPLAY_UPG => $displayUpgBtn,
MSG => $self->canUpdateSfa($req) || 'choose2f',
ALERT => ( $self->canUpdateSfa($req) ? 'warning' : 'positive' ),
SFREGISTERS_URL =>
encode_base64( "$self->{conf}->{portal}2fregisters", '' )
}
);
}

View File

@ -3,10 +3,10 @@ package Lemonldap::NG::Portal::2F::Ext2F;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADOTP
PE_ERROR
PE_FORMEMPTY
PE_OK
PE_ERROR
PE_BADOTP
PE_FORMEMPTY
PE_SENDRESPONSE
);
@ -51,7 +51,10 @@ sub run {
my ( $self, $req, $token ) = @_;
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("Ext2F checkLogins set") if ($checkLogins);
$self->logger->debug("Ext2F: checkLogins set") if $checkLogins;
my $stayconnected = $req->param('stayconnected');
$self->logger->debug("Ext2F: stayconnected set") if $stayconnected;
# Generate Code to send
my $code;
@ -87,7 +90,8 @@ sub run {
. $self->prefix
. '2fcheck?skin='
. $self->p->getSkin($req),
CHECKLOGINS => $checkLogins
CHECKLOGINS => $checkLogins,
STAYCONNECTED => $stayconnected
}
);
$self->logger->debug("Prepare external 2F verification");

View File

@ -3,18 +3,20 @@ package Lemonldap::NG::Portal::2F::Mail2F;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADOTP
PE_ERROR
PE_FORMEMPTY
PE_OK
PE_ERROR
PE_BADOTP
PE_FORMEMPTY
PE_SENDRESPONSE
PE_MUSTHAVEMAIL
);
our $VERSION = '2.1.0';
extends 'Lemonldap::NG::Portal::Main::SecondFactor',
'Lemonldap::NG::Portal::Lib::SMTP';
extends qw(
Lemonldap::NG::Portal::Main::SecondFactor
Lemonldap::NG::Portal::Lib::SMTP
);
# INITIALIZATION
@ -54,6 +56,10 @@ sub run {
my ( $self, $req, $token ) = @_;
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("Mail2F: checkLogins set") if $checkLogins;
my $stayconnected = $req->param('stayconnected');
$self->logger->debug("Mail2F: stayconnected set") if $stayconnected;
my $code = $self->random->randregex( $self->conf->{mail2fCodeRegex} );
$self->logger->debug("Generated two-factor code: $code");
@ -117,8 +123,9 @@ sub run {
. $self->prefix
. '2fcheck?skin='
. $self->p->getSkin($req),
LEGEND => 'enterMail2fCode',
CHECKLOGINS => $checkLogins
LEGEND => 'enterMail2fCode',
CHECKLOGINS => $checkLogins,
STAYCONNECTED => $stayconnected
}
);
$req->response($tmp);

View File

@ -12,15 +12,15 @@ use Lemonldap::NG::Portal::Main::Constants qw(
our $VERSION = '2.1.0';
extends 'Lemonldap::NG::Portal::Main::SecondFactor',
'Lemonldap::NG::Portal::Lib::REST';
extends qw(
Lemonldap::NG::Portal::Main::SecondFactor
Lemonldap::NG::Portal::Lib::REST
);
# INITIALIZATION
has prefix => ( is => 'rw', default => 'rest' );
has prefix => ( is => 'rw', default => 'rest' );
has initAttrs => ( is => 'rw', default => sub { {} } );
has vrfyAttrs => ( is => 'rw', default => sub { {} } );
sub init {
@ -58,7 +58,10 @@ sub run {
my ( $self, $req, $token ) = @_;
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("REST2F checkLogins set") if ($checkLogins);
$self->logger->debug("REST2F: checkLogins set") if $checkLogins;
my $stayconnected = $req->param('stayconnected');
$self->logger->debug("REST2F: stayconnected set") if $stayconnected;
if ( $self->conf->{rest2fInitUrl} ) {
@ -98,8 +101,9 @@ sub run {
. $self->prefix
. '2fcheck?skin='
. $self->p->getSkin($req),
LEGEND => 'enterRest2fCode',
CHECKLOGINS => $checkLogins
LEGEND => 'enterRest2fCode',
CHECKLOGINS => $checkLogins,
STAYCONNECTED => $stayconnected
}
);
$self->logger->debug("Prepare external REST verification");

View File

@ -17,7 +17,6 @@ extends 'Lemonldap::NG::Portal::Main::SecondFactor';
# INITIALIZATION
has prefix => ( is => 'rw', default => 'radius' );
has radius => ( is => 'rw' );
sub init {
@ -56,7 +55,10 @@ sub run {
my ( $self, $req, $token ) = @_;
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("Radius2F checkLogins set") if ($checkLogins);
$self->logger->debug("Radius2F: checkLogins set") if $checkLogins;
my $stayconnected = $req->param('stayconnected');
$self->logger->debug("Radius2F: stayconnected set") if $stayconnected;
# Prepare form
my $tmp = $self->p->sendHtml(
@ -71,8 +73,9 @@ sub run {
. $self->prefix
. '2fcheck?skin='
. $self->p->getSkin($req),
LEGEND => 'enterRadius2fCode',
CHECKLOGINS => $checkLogins
LEGEND => 'enterRadius2fCode',
CHECKLOGINS => $checkLogins,
STAYCONNECTED => $stayconnected
}
);
$self->logger->debug("Prepare Radius 2F verification");

View File

@ -7,12 +7,16 @@ use JSON qw(from_json to_json);
our $VERSION = '2.1.0';
extends 'Lemonldap::NG::Portal::Main::Plugin', 'Lemonldap::NG::Common::TOTP';
extends qw(
Lemonldap::NG::Portal::Main::Plugin
Lemonldap::NG::Common::TOTP
);
# INITIALIZATION
has prefix => ( is => 'rw', default => 'totp' );
has template => ( is => 'ro', default => 'totp2fregister' );
has welcome => ( is => 'ro', default => 'yourNewTotpKey' );
has logo => ( is => 'rw', default => 'totp.png' );
has ott => (
is => 'rw',
@ -37,8 +41,8 @@ sub run {
unless $user;
# Check if TOTP can be updated
return $self->p->sendError( $req, 'notAuthorized', 400 )
unless $self->allowedUpdateSfa( $req, $action );
my $msg = $self->canUpdateSfa( $req, $action );
return $self->p->sendError( $req, $msg, 400 ) if $msg;
# Verification that user has a valid TOTP app
if ( $action eq 'verify' ) {

View File

@ -7,13 +7,16 @@ use JSON qw(from_json to_json);
our $VERSION = '2.1.0';
extends 'Lemonldap::NG::Portal::Main::Plugin',
'Lemonldap::NG::Portal::Lib::U2F';
extends qw(
Lemonldap::NG::Portal::Main::Plugin
Lemonldap::NG::Portal::Lib::U2F
);
# INITIALIZATION
has prefix => ( is => 'rw', default => 'u' );
has template => ( is => 'ro', default => 'u2fregister' );
has welcome => ( is => 'ro', default => 'u2fWelcome' );
has logo => ( is => 'rw', default => 'u2f.png' );
sub init {
@ -34,8 +37,8 @@ sub run {
unless $user;
# Check if U2F key can be updated
return $self->p->sendError( $req, 'notAuthorized', 400 )
unless $self->allowedUpdateSfa( $req, $action );
my $msg = $self->canUpdateSfa( $req, $action );
return $self->p->sendError( $req, $msg, 400 ) if $msg;
if ( $action eq 'register' ) {

View File

@ -17,6 +17,7 @@ extends 'Lemonldap::NG::Portal::Main::Plugin';
has prefix => ( is => 'rw', default => 'yubikey' );
has template => ( is => 'ro', default => 'yubikey2fregister' );
has welcome => ( is => 'ro', default => 'clickOnYubikey' );
has logo => ( is => 'rw', default => 'yubikey.png' );
sub init {
@ -35,14 +36,15 @@ sub run {
unless $user;
# Check if UBK key can be updated
my $msg = $self->canUpdateSfa( $req, $action );
return $self->p->sendHtml(
$req, 'error',
params => {
MAIN_LOGO => $self->conf->{portalMainLogo},
RAW_ERROR => 'notAuthorized',
RAW_ERROR => 'notAuthorizedAuthLevel',
AUTH_ERROR_TYPE => 'warning',
}
) unless $self->allowedUpdateSfa( $req, $action );
) if $msg;
if ( $action eq 'register' ) {
my $otp = $req->param('otp');

View File

@ -8,22 +8,24 @@ use strict;
use Mouse;
use JSON qw(from_json to_json);
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADOTP
PE_ERROR
PE_FORMEMPTY
PE_OK
PE_ERROR
PE_BADOTP
PE_FORMEMPTY
PE_SENDRESPONSE
);
our $VERSION = '2.1.0';
extends 'Lemonldap::NG::Portal::Main::SecondFactor',
'Lemonldap::NG::Common::TOTP';
extends qw(
Lemonldap::NG::Portal::Main::SecondFactor
Lemonldap::NG::Common::TOTP
);
# INITIALIZATION
has prefix => ( is => 'ro', default => 'totp' );
has logo => ( is => 'rw', default => 'totp.png' );
has logo => ( is => 'rw', default => 'totp.png' );
sub init {
my ($self) = @_;
@ -46,17 +48,21 @@ sub run {
$self->logger->debug('Generate TOTP form');
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("TOTP checkLogins set") if ($checkLogins);
$self->logger->debug("TOTP: checkLogins set") if $checkLogins;
my $stayconnected = $req->param('stayconnected');
$self->logger->debug("TOTP: stayconnected set") if $stayconnected;
# Prepare form
my $tmp = $self->p->sendHtml(
$req,
'totp2fcheck',
params => {
MAIN_LOGO => $self->conf->{portalMainLogo},
SKIN => $self->p->getSkin($req),
TOKEN => $token,
CHECKLOGINS => $checkLogins
MAIN_LOGO => $self->conf->{portalMainLogo},
SKIN => $self->p->getSkin($req),
TOKEN => $token,
CHECKLOGINS => $checkLogins,
STAYCONNECTED => $stayconnected
}
);
$self->logger->debug("Prepare TOTP 2F verification");

View File

@ -4,28 +4,29 @@
# have registered their U2F key
package Lemonldap::NG::Portal::2F::U2F;
#use 5.16.0;
use strict;
use Mouse;
use JSON qw(from_json to_json);
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADCREDENTIALS
PE_ERROR
PE_OK
PE_SENDRESPONSE
PE_ERROR
PE_U2FFAILED
PE_SENDRESPONSE
PE_BADCREDENTIALS
);
our $VERSION = '2.1.0';
extends 'Lemonldap::NG::Portal::Main::SecondFactor',
'Lemonldap::NG::Portal::Lib::U2F';
extends qw(
Lemonldap::NG::Portal::Main::SecondFactor
Lemonldap::NG::Portal::Lib::U2F
);
# INITIALIZATION
has rule => ( is => 'rw' );
has rule => ( is => 'rw' );
has prefix => ( is => 'ro', default => 'u' );
has logo => ( is => 'rw', default => 'u2f.png' );
has logo => ( is => 'rw', default => 'u2f.png' );
sub init {
my ($self) = @_;
@ -52,7 +53,10 @@ sub run {
my ( $self, $req, $token ) = @_;
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("U2F checkLogins set") if ($checkLogins);
$self->logger->debug("U2F: checkLogins set") if $checkLogins;
my $stayconnected = $req->param('stayconnected');
$self->logger->debug("U2F: stayconnected set") if $stayconnected;
# Check if user is registered
if ( my $res = $self->loadUser( $req, $req->sessionInfo ) ) {
@ -91,11 +95,12 @@ sub run {
$req,
'u2fcheck',
params => {
MAIN_LOGO => $self->conf->{portalMainLogo},
SKIN => $self->p->getSkin($req),
DATA => $data,
TOKEN => $token,
CHECKLOGINS => $checkLogins
MAIN_LOGO => $self->conf->{portalMainLogo},
SKIN => $self->p->getSkin($req),
DATA => $data,
TOKEN => $token,
CHECKLOGINS => $checkLogins,
STAYCONNECTED => $stayconnected
}
);

View File

@ -13,17 +13,14 @@ extends 'Lemonldap::NG::Portal::Main::SecondFactor';
# INITIALIZATION
has prefix => ( is => 'ro', default => 'utotp' );
has logo => ( is => 'rw', default => 'utotp.png' );
has u2f => ( is => 'rw' );
has totp => ( is => 'rw' );
has logo => ( is => 'rw', default => 'utotp.png' );
has u2f => ( is => 'rw' );
has totp => ( is => 'rw' );
use Lemonldap::NG::Portal::Main::Constants qw(
PE_OK
PE_ERROR
PE_FORMEMPTY
PE_OK
PE_SENDRESPONSE
);
@ -61,13 +58,17 @@ sub run {
$self->logger->debug('Generate TOTP form');
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("UTOTP checkLogins set") if ($checkLogins);
$self->logger->debug("UTOTP: checkLogins set") if $checkLogins;
my $stayconnected = $req->param('stayconnected');
$self->logger->debug("UTOTP: stayconnected set") if $stayconnected;
my %tplPrms = (
MAIN_LOGO => $self->conf->{portalMainLogo},
SKIN => $self->p->getSkin($req),
TOKEN => $token,
CHECKLOGINS => $checkLogins
MAIN_LOGO => $self->conf->{portalMainLogo},
SKIN => $self->p->getSkin($req),
TOKEN => $token,
CHECKLOGINS => $checkLogins,
STAYCONNECTED => $stayconnected
);
if ( my $res = $self->u2f->loadUser( $req, $req->sessionInfo ) ) {

View File

@ -8,10 +8,10 @@ use strict;
use Mouse;
use JSON qw(from_json to_json);
use Lemonldap::NG::Portal::Main::Constants qw(
PE_OK
PE_ERROR
PE_BADOTP
PE_FORMEMPTY
PE_OK
PE_SENDRESPONSE
);
@ -121,7 +121,10 @@ sub run {
my ( $self, $req, $token, $_2fDevices ) = @_;
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("Yubikey checkLogins set") if ($checkLogins);
$self->logger->debug("Yubikey; checkLogins set") if ($checkLogins);
my $stayconnected = $req->param('stayconnected');
$self->logger->debug("Yubikey: stayconnected set") if $stayconnected;
my $yubikey = $self->_findYubikey( $req, $req->sessionInfo );
@ -144,7 +147,8 @@ sub run {
TARGET => '/yubikey2fcheck?skin=' . $self->p->getSkin($req),
INPUTLOGO => 'yubikey.png',
LEGEND => 'clickOnYubikey',
CHECKLOGINS => $checkLogins
CHECKLOGINS => $checkLogins,
STAYCONNECTED => $stayconnected
}
);
$self->logger->debug("Display Yubikey form");

View File

@ -5,14 +5,14 @@ use JSON qw(from_json to_json);
use Mouse;
use Lemonldap::NG::Common::FormEncode;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADURL
PE_BADCREDENTIALS
PE_CONFIRM
PE_ERROR
PE_LOGOUT_OK
PE_REDIRECT
PE_OK
PE_ERROR
PE_BADURL
PE_CONFIRM
PE_REDIRECT
PE_LOGOUT_OK
PE_PASSWORD_OK
PE_BADCREDENTIALS
PE_UNAUTHORIZEDPARTNER
PE_OIDC_SERVICE_NOT_ALLOWED
);
@ -988,7 +988,12 @@ sub run {
return PE_CONFIRM;
}
}
$self->logger->error("Unknown OIDC endpoint $path, skipping");
$self->logger->error(
$path
? "Unknown OIDC endpoint: $path, skipping"
: 'No OIDC endpoint found, aborting'
);
return PE_ERROR;
}
@ -998,10 +1003,7 @@ sub token {
$self->logger->debug("URL detected as an OpenID Connect TOKEN URL");
my $rp = $self->checkEndPointAuthenticationCredentials($req);
unless ($rp) {
return $self->p->sendError( $req, 'invalid_request', 400 );
}
return $self->p->sendError( $req, 'invalid_request', 400 ) unless ($rp);
my $grant_type = $req->param('grant_type');
@ -1032,8 +1034,8 @@ sub token {
else {
$self->userLogger->error(
$grant_type
? "Missing grant_type parameter"
: "Unknown grant type: $grant_type"
? "Unknown grant type: $grant_type"
: "Missing grant_type parameter"
);
return $self->p->sendError( $req, 'unsupported_grant_type', 400 );
}
@ -1042,12 +1044,10 @@ sub token {
sub _handlePasswordGrant {
my ( $self, $req, $rp ) = @_;
my $client_id = $self->oidcRPList->{$rp}->{oidcRPMetaDataOptionsClientID};
my $scope = $req->param('scope') || 'openid';
my $username = $req->param('username');
my $password = $req->param('password');
my $username = $req->param('username');
my $password = $req->param('password');
unless ( $username and $password ) {
$self->logger->error("Missing username or password");
@ -1080,9 +1080,8 @@ sub _handlePasswordGrant {
if $result;
## Make sure we returned successfuly from the process AND we were able to create a session
unless ( $result == PE_OK and $req->id and $req->user ) {
return $self->p->sendError( $req, 'invalid_grant', 400 );
}
return $self->p->sendError( $req, 'invalid_grant', 400 )
unless ( $result == PE_OK and $req->id and $req->user );
## Make sure the current user is allowed to use this RP
if ( my $rule = $self->spRules->{$rp} ) {
@ -1169,10 +1168,8 @@ sub _handlePasswordGrant {
sub _handleAuthorizationCodeGrant {
my ( $self, $req, $rp ) = @_;
my $client_id = $self->oidcRPList->{$rp}->{oidcRPMetaDataOptionsClientID};
my $code = $req->param('code');
my $code = $req->param('code');
unless ($code) {
$self->logger->error("No code found on token endpoint");
@ -1180,7 +1177,6 @@ sub _handleAuthorizationCodeGrant {
}
my $codeSession = $self->getAuthorizationCode($code);
unless ($codeSession) {
$self->logger->error("Unable to find OIDC session $code");
return $self->p->sendError( $req, 'invalid_request', 400 );
@ -1402,9 +1398,7 @@ sub _handleAuthorizationCodeGrant {
}
sub _handleRefreshTokenGrant {
my ( $self, $req, $rp ) = @_;
my $client_id = $self->oidcRPList->{$rp}->{oidcRPMetaDataOptionsClientID};
my $refresh_token = $req->param('refresh_token');
@ -1660,10 +1654,8 @@ sub userInfo {
my $userinfo_response =
$self->buildUserInfoResponse( $req, $scope, $rp, $session );
unless ($userinfo_response) {
return $self->returnBearerError( 'invalid_request',
'Invalid request', 401 );
}
return $self->returnBearerError( 'invalid_request', 'Invalid request', 401 )
unless ($userinfo_response);
my $userinfo_sign_alg = $self->conf->{oidcRPMetaDataOptions}->{$rp}
->{oidcRPMetaDataOptionsUserInfoSignAlg};
@ -1695,18 +1687,14 @@ sub _getSessionFromAccessTokenData {
# Get user identifier
$session = $self->p->getApacheSession( $tokenData->{user_session_id} );
unless ($session) {
$self->logger->error("Unable to find user session");
}
$self->logger->error("Unable to find user session") unless ($session);
}
else {
my $offline_session_id = $tokenData->{offline_session_id};
if ($offline_session_id) {
$session = $self->getRefreshToken($offline_session_id);
unless ($session) {
$self->logger->error("Unable to find refresh session");
}
$self->logger->error("Unable to find refresh session")
unless ($session);
}
}
return $session;
@ -1717,10 +1705,7 @@ sub introspection {
$self->logger->debug("URL detected as an OpenID Connect INTROSPECTION URL");
my $rp = $self->checkEndPointAuthenticationCredentials($req);
unless ($rp) {
return $self->p->sendError( $req, 'invalid_client', 401 );
}
return $self->p->sendError( $req, 'invalid_client', 401 ) unless ($rp);
if ( $self->conf->{oidcRPMetaDataOptions}->{$rp}
->{oidcRPMetaDataOptionsPublic} )
@ -1732,9 +1717,7 @@ sub introspection {
}
my $token = $req->param('token');
unless ($token) {
return $self->p->sendError( $req, 'invalid_request', 400 );
}
return $self->p->sendError( $req, 'invalid_request', 400 ) unless ($token);
my $response = { active => JSON::false };
my $oidcSession = $self->getOpenIDConnectSession($token);
@ -1806,9 +1789,8 @@ sub registration {
# Get client metadata
my $client_metadata_json = $req->content;
unless ($client_metadata_json) {
return $self->p->sendError( $req, 'Missing POST data', 400 );
}
return $self->p->sendError( $req, 'Missing POST data', 400 )
unless ($client_metadata_json);
$self->logger->debug("Client metadata received: $client_metadata_json");

View File

@ -10,6 +10,7 @@ use Lemonldap::NG::Portal::Main::Constants ':all';
use Encode;
use Unicode::String qw(utf8);
use Scalar::Util 'weaken';
use IO::Socket::Timeout;
use utf8;
our $VERSION = '2.1.0';
@ -76,6 +77,13 @@ sub new {
}
}
bless $self, $class;
# Set socket timeouts
my $socket = $self->socket;
IO::Socket::Timeout->enable_timeouts_on($socket);
$socket->read_timeout( $conf->{ldapIOTimeout} );
$socket->write_timeout( $conf->{ldapIOTimeout} );
if ($useTls) {
my %h = split( /[&=]/, $tlsParam );
$h{cafile} ||= $conf->{ldapCAFile} if ( $conf->{ldapCAFile} );

View File

@ -124,8 +124,9 @@ sub display {
CHOICE_VALUE => $req->data->{_authChoice},
CHECK_LOGINS => $self->conf->{portalCheckLogins}
&& $req->data->{login},
ASK_LOGINS => $req->param('checkLogins') || 0,
CONFIRMKEY => $self->stamp(),
ASK_LOGINS => $req->param('checkLogins') || 0,
ASK_STAYCONNECTED => $req->param('stayconnected') || 0,
CONFIRMKEY => $self->stamp(),
(
$req->data->{customScript}
? ( CUSTOM_SCRIPT => $req->data->{customScript} )
@ -150,9 +151,10 @@ sub display {
CHOICE_VALUE => $req->data->{_authChoice},
CHECK_LOGINS => $self->conf->{portalCheckLogins}
&& $req->data->{login},
ASK_LOGINS => $req->param('checkLogins') || 0,
CONFIRMKEY => $self->stamp(),
LIST => $req->data->{list} || [],
ASK_LOGINS => $req->param('checkLogins') || 0,
ASK_STAYCONNECTED => $req->param('stayconnected') || 0,
CONFIRMKEY => $self->stamp(),
LIST => $req->data->{list} || [],
(
$req->data->{customScript}
? ( CUSTOM_SCRIPT => $req->data->{customScript} )
@ -382,6 +384,7 @@ sub display {
DONT_STORE_PASSWORD => $self->conf->{browsersDontStorePassword},
CHECK_LOGINS => $self->conf->{portalCheckLogins},
ASK_LOGINS => $req->param('checkLogins') || 0,
ASK_STAYCONNECTED => $req->param('stayconnected') || 0,
DISPLAY_RESETPASSWORD => $self->conf->{portalDisplayResetPassword},
DISPLAY_REGISTER => $self->conf->{portalDisplayRegister},
DISPLAY_UPDATECERTIF =>

View File

@ -104,10 +104,10 @@ sub createNotification {
}
}
sub allowedUpdateSfa {
sub canUpdateSfa {
my ( $self, $req, $action ) = @_;
my $user = $req->userData->{ $self->conf->{whatToTrace} };
my $res = 1;
my $msg = undef;
# Test action
if ( $action && $action eq 'delete' ) {
@ -125,12 +125,12 @@ sub allowedUpdateSfa {
$self->logger->debug(
"authLevel: $req->{userData}->{authenticationLevel} < requiredLevel: "
. $self->{conf}->{"${module}2fAuthnLevel"} );
undef $res;
$msg = 'notAuthorizedAuthLevel';
}
}
# Test if impersonation is in progress
if ( $res && $self->conf->{impersonationRule} ) {
if ( !$msg && $self->conf->{impersonationRule} ) {
$self->logger->debug('Impersonation plugin is enabled');
if ( $req->userData->{"$self->{conf}->{impersonationPrefix}_user"}
&& $req->userData->{"$self->{conf}->{impersonationPrefix}_user"} ne
@ -139,12 +139,12 @@ sub allowedUpdateSfa {
$self->userLogger->warn(
"Impersonation in progress! $user is not allowed to update 2FA."
);
undef $res;
$msg = 'notAuthorized';
}
}
# Test if contextSwitching is in progress
if ( $res && $self->conf->{contextSwitchingRule} ) {
if ( !$msg && $self->conf->{contextSwitchingRule} ) {
$self->logger->debug('ContextSwitching plugin is enabled');
if (
$req->userData->{
@ -154,11 +154,11 @@ sub allowedUpdateSfa {
$self->userLogger->warn(
"ContextSwitching in progress! $user is not allowed to update 2FA."
);
undef $res;
$msg = 'notAuthorized';
}
}
$self->userLogger->info("$user is allowed to update 2FA") if $res;
return $res;
$self->userLogger->info("$user is allowed to update 2FA") unless $msg;
return $msg;
}
1;

View File

@ -19,8 +19,8 @@ our @pList = (
portalStatus => '::Plugins::Status',
cda => '::Plugins::CDA',
notification => '::Plugins::Notifications',
portalCheckLogins => '::Plugins::History',
stayConnected => '::Plugins::StayConnected',
portalCheckLogins => '::Plugins::History',
bruteForceProtection => '::Plugins::BruteForceProtection',
grantSessionRules => '::Plugins::GrantSession',
upgradeSession => '::Plugins::Upgrade',

View File

@ -56,9 +56,17 @@ sub init {
sub newDevice {
my ( $self, $req ) = @_;
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("StayConnected: checkLogins set") if $checkLogins;
if ( $req->param('stayconnected') ) {
my $token = $self->ott->createToken( {
name => $req->sessionInfo->{ $self->conf->{whatToTrace} }
name => $req->sessionInfo->{ $self->conf->{whatToTrace} },
(
$checkLogins
? ( history => $req->sessionInfo->{_loginHistory} )
: ()
)
}
);
$req->response(
@ -66,9 +74,10 @@ sub newDevice {
$req,
'../common/registerBrowser',
params => {
URL => $req->urldc,
TOKEN => $token,
ACTION => '/registerbrowser',
URL => $req->urldc,
TOKEN => $token,
ACTION => '/registerbrowser',
CHECKLOGINS => $checkLogins
}
)
);
@ -109,6 +118,7 @@ sub storeBrowser {
max_age => 2592000,
)
);
$req->sessionInfo->{_loginHistory} = $tmp->{history} if exists $tmp->{history};
}
else {
$self->logger->warn("Browser hasn't return fingerprint");
@ -128,8 +138,8 @@ sub storeBrowser {
$self->userLogger->error('StayConnected called without token');
}
# Deliver cookie llngbrowser
return $self->p->do( $req, [ sub { PE_OK } ] );
# Return cookie llngconnexion
return $self->p->do( $req, [ @{ $self->p->endAuth }, sub { PE_OK } ] );
}
# Check for:

View File

@ -65,14 +65,18 @@ sub confirmRenew {
# RUNNING METHOD
sub ask {
my ( $self, $req, $url, $message, $buttonlabel ) = @_;
my ( $self, $req, $form_action, $message, $buttonlabel ) = @_;
# Check if auth is already running
if ( $req->param('upgrading') or $req->param('kerberos') ) {
# and verify token
return $self->confirm($req)
if ( $req->param('upgrading') or $req->param('kerberos') );
# verify token
return $self->confirm($req);
}
my $url = $req->param('url') || '';
my $action = ( $message =~ /^askTo(\w+)$/ )[0];
$self->logger->debug(" -> $action required");
$self->logger->debug(" -> Skip confirmation is enabled")
if $self->conf->{"skip${action}Confirmation"};
# Display form
return $self->p->sendHtml(
@ -81,13 +85,20 @@ sub ask {
params => {
MAIN_LOGO => $self->conf->{portalMainLogo},
LANGS => $self->conf->{showLanguages},
FORMACTION => $url,
FORMACTION => $form_action,
PORTALBUTTON => 1,
MSG => $message,
BUTTON => $buttonlabel,
CONFIRMKEY => $self->p->stamp,
PORTAL => $self->conf->{portal},
URL => $req->param('url'),
URL => $url,
(
$self->conf->{"skip${action}Confirmation"}
? ( CUSTOM_SCRIPT =>
qq'<script type="text/javascript" src="$self->{p}->{staticPrefix}/common/js/autoRenew.min.js"></script>'
)
: ()
)
}
);
}

View File

@ -174,4 +174,10 @@ input.key {
/*font-style: normal;*/
/*font-weight: 400;*/
src: url(/static/common/fonts/password.ttf);
}
}
.info.table caption {
color: black;
text-align: center;
caption-side: bottom;
}

View File

@ -1 +1 @@
html,body{height:100%;background:radial-gradient(circle at 50% 0,#fff 0,#ddd 100%) no-repeat scroll 0 0 #ddd}#wrap{min-height:100%;height:auto;margin:0 auto -80px;padding:20px 0 80px}#footer{height:80px;background-color:#fff;background-color:rgba(255,255,255,0.9);text-align:center;padding-top:10px;overflow:hidden}#header img{background-color:#fff;background-color:rgba(255,255,255,0.8);margin-bottom:20px}.card,.navbar-light{background-color:#fff;background-color:rgba(255,255,255,0.9);background-image:none}.login,.password{text-align:center;padding:20px}div.form{margin:0 auto;max-width:330px}div.actions{margin:10px 0 0 0}div.actions a{margin-top:10px}.buttons{text-align:center;margin:10px 0 0 0;cursor:pointer}.btn{white-space:normal}.btn span.fa{padding-right:8px}li.ui-state-active{background-color:#fafafa;background-color:rgba(250,250,250,0.9)}#appslist,#password,#loginHistory,#logout,#oidcConsents{margin-top:20px}div.category{margin:10px 0;cursor:grab}div.application{margin:5px 0;overflow:hidden}div.application a,div.application a:hover{text-decoration:none}p.notifCheck label{margin-left:5px;margin-top:3px;display:inline-block}img.langicon{cursor:pointer}button.idploop{max-width:300px}button.idploop img{max-height:30px}div.oidc_consent_message>ul{text-align:left;list-style:circle}@media(min-width:768px){div.application{height:80px}div.application h4.appname{margin:0}#wrap{margin:0 auto -60px}#footer{height:60px}}.hiddenFrame{border:0;display:hidden;margin:0}.noborder{border:0}.max{width:100%}.link{cursor:pointer}.nodecor:hover,.nodecor:active.nodecor:focus{text-decoration:none}.fa.icon-blue{color:blue}.progress-bar-animated{width:100%}input.key{font-family:'password';width:100px}@font-face{font-family:'password';src:url(/static/common/fonts/password.ttf)}
html,body{height:100%;background:radial-gradient(circle at 50% 0,#fff 0,#ddd 100%) no-repeat scroll 0 0 #ddd}#wrap{min-height:100%;height:auto;margin:0 auto -80px;padding:20px 0 80px}#footer{height:80px;background-color:#fff;background-color:rgba(255,255,255,0.9);text-align:center;padding-top:10px;overflow:hidden}#header img{background-color:#fff;background-color:rgba(255,255,255,0.8);margin-bottom:20px}.card,.navbar-light{background-color:#fff;background-color:rgba(255,255,255,0.9);background-image:none}.login,.password{text-align:center;padding:20px}div.form{margin:0 auto;max-width:330px}div.actions{margin:10px 0 0 0}div.actions a{margin-top:10px}.buttons{text-align:center;margin:10px 0 0 0;cursor:pointer}.btn{white-space:normal}.btn span.fa{padding-right:8px}li.ui-state-active{background-color:#fafafa;background-color:rgba(250,250,250,0.9)}#appslist,#password,#loginHistory,#logout,#oidcConsents{margin-top:20px}div.category{margin:10px 0;cursor:grab}div.application{margin:5px 0;overflow:hidden}div.application a,div.application a:hover{text-decoration:none}p.notifCheck label{margin-left:5px;margin-top:3px;display:inline-block}img.langicon{cursor:pointer}button.idploop{max-width:300px}button.idploop img{max-height:30px}div.oidc_consent_message>ul{text-align:left;list-style:circle}@media(min-width:768px){div.application{height:80px}div.application h4.appname{margin:0}#wrap{margin:0 auto -60px}#footer{height:60px}}.hiddenFrame{border:0;display:hidden;margin:0}.noborder{border:0}.max{width:100%}.link{cursor:pointer}.nodecor:hover,.nodecor:active.nodecor:focus{text-decoration:none}.fa.icon-blue{color:blue}.progress-bar-animated{width:100%}input.key{font-family:'password';width:100px}@font-face{font-family:'password';src:url(/static/common/fonts/password.ttf)}.info.table caption{color:black;text-align:center;caption-side:bottom}

View File

@ -1 +1 @@
(function(){var a=function(e,r){return $("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},r=function(e,r,t){var o;if(console.log("Error",t),(o=JSON.parse(e.responseText))&&o.error)return o=o.error.replace(/.* /,""),console.log("Returned error",o),a(o,"warning")},t="",e=function(e){return a("yourTotpKey","warning"),$.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",data:{newkey:e},error:r,success:function(e){var r;return e.error?(e.error.match(/totpExistingKey/)&&$("#divToHide").hide(),a(e.error,"warning")):e.portal&&e.user&&e.secret?($("#divToHide").show(),r="otpauth://totp/"+escape(e.portal)+":"+escape(e.user)+"?secret="+e.secret+"&issuer="+escape(e.portal),6!==e.digits&&(r+="&digits="+e.digits),30!==e.interval&&(r+="&period="+e.interval),new QRious({element:document.getElementById("qr"),value:r,size:150}),$("#serialized").text(r),e.newkey?a("yourNewTotpKey","warning"):a("yourTotpKey","success"),t=e.token):a("PE24","danger")}})},o=function(){var e=$("#code").val();return e?$.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:t,code:e,TOTPName:$("#TOTPName").val()},error:r,success:function(e){return e.error?e.error.match(/bad(Code|Name)/)?a(e.error,"warning"):a(e.error,"danger"):a("yourKeyIsRegistered","success")}}):a("fillTheForm","warning")};$(document).ready(function(){return e(0),$("#changekey").on("click",function(){return e(1)}),$("#verify").on("click",o)})}).call(this);
(function(){var r,e,n,t,o;n=function(e,r){return $("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},r=function(e,r,t){var o;if(console.log("Error",t),(o=JSON.parse(e.responseText))&&o.error)return o=o.error.replace(/.* /,""),console.log("Returned error",o),n(o,"warning")},t="",e=function(e){return n("yourTotpKey","warning"),$.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",data:{newkey:e},error:r,success:function(e){var r;return e.error?(e.error.match(/totpExistingKey/)&&$("#divToHide").hide(),n(e.error,"warning")):e.portal&&e.user&&e.secret?($("#divToHide").show(),r="otpauth://totp/"+escape(e.portal)+":"+escape(e.user)+"?secret="+e.secret+"&issuer="+escape(e.portal),6!==e.digits&&(r+="&digits="+e.digits),30!==e.interval&&(r+="&period="+e.interval),new QRious({element:document.getElementById("qr"),value:r,size:150}),$("#serialized").text(r),e.newkey?n("yourNewTotpKey","warning"):n("yourTotpKey","success"),t=e.token):n("PE24","danger")}})},o=function(){var e;return(e=$("#code").val())?$.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:t,code:e,TOTPName:$("#TOTPName").val()},error:r,success:function(e){return e.error?e.error.match(/bad(Code|Name)/)?n(e.error,"warning"):n(e.error,"danger"):n("yourKeyIsRegistered","success")}}):n("fillTheForm","warning")},$(document).ready(function(){return e(0),$("#changekey").on("click",function(){return e(1)}),$("#verify").on("click",function(){return o()})})}).call(this);

View File

@ -1 +1 @@
{"version":3,"sources":["totpregistration.js"],"names":["setMsg","msg","level","$","html","window","translate","removeClass","addClass","displayError","j","status","err","res","console","log","JSON","parse","responseText","error","replace","token","getKey","reset","ajax","type","url","portal","dataType","data","newkey","success","s","match","hide","user","secret","show","escape","digits","interval","QRious","element","document","getElementById","value","size","text","verify","val","code","TOTPName","ready","on","call","this"],"mappings":"CAMA,WACE,IAEAA,EAAS,SAASC,EAAKC,GAOrB,OANAC,EAAE,QAAQC,KAAKC,OAAOC,UAAUL,IAChCE,EAAE,UAAUI,YAAY,4FACxBJ,EAAE,UAAUK,SAAS,WAAaN,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUK,SAAS,SAAWN,IAGzCO,EAAe,SAASC,EAAGC,EAAQC,GACjC,IAAIC,EAGJ,GAFAC,QAAQC,IAAI,QAASH,IACrBC,EAAMG,KAAKC,MAAMP,EAAEQ,gBACRL,EAAIM,MAGb,OAFAN,EAAMA,EAAIM,MAAMC,QAAQ,MAAO,IAC/BN,QAAQC,IAAI,iBAAkBF,GACvBb,EAAOa,EAAK,YAIvBQ,EAAQ,GAERC,EAAS,SAASC,GAEhB,OADAvB,EAAO,cAAe,WACfG,EAAEqB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJC,OAAQP,GAEVJ,MAAOV,EACPsB,QAAS,SAASF,GAChB,IAAQG,EACR,OAAIH,EAAKV,OACHU,EAAKV,MAAMc,MAAM,oBACnB9B,EAAE,cAAc+B,OAEXlC,EAAO6B,EAAKV,MAAO,YAEtBU,EAAKF,QAAUE,EAAKM,MAAQN,EAAKO,QAGvCjC,EAAE,cAAckC,OAChBL,EAAI,kBAAqBM,OAAOT,EAAKF,QAAW,IAAOW,OAAOT,EAAKM,MAAS,WAAaN,EAAKO,OAAS,WAAcE,OAAOT,EAAKF,QAC7G,IAAhBE,EAAKU,SACPP,GAAK,WAAaH,EAAKU,QAEH,KAAlBV,EAAKW,WACPR,GAAK,WAAaH,EAAKW,UAEpB,IAAIC,OAAO,CACdC,QAASC,SAASC,eAAe,MACjCC,MAAOb,EACPc,KAAM,MAER3C,EAAE,eAAe4C,KAAKf,GAClBH,EAAKC,OACP9B,EAAO,iBAAkB,WAEzBA,EAAO,cAAe,WAEjBqB,EAAQQ,EAAKR,OArBXrB,EAAO,OAAQ,cA0B9BgD,EAAS,WACP,IACAC,EAAM9C,EAAE,SAAS8C,MACjB,OAAKA,EAGI9C,EAAEqB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJR,MAAOA,EACP6B,KAAMD,EACNE,SAAUhD,EAAE,aAAa8C,OAE3B9B,MAAOV,EACPsB,QAAS,SAASF,GAChB,OAAIA,EAAKV,MACHU,EAAKV,MAAMc,MAAM,kBACZjC,EAAO6B,EAAKV,MAAO,WAEnBnB,EAAO6B,EAAKV,MAAO,UAGrBnB,EAAO,sBAAuB,cApBpCA,EAAO,cAAe,YA2BjCG,EAAEwC,UAAUS,MAAM,WAKhB,OAJA9B,EAAO,GACPnB,EAAE,cAAckD,GAAG,QAAS,WAC1B,OAAO/B,EAAO,KAETnB,EAAE,WAAWkD,GAAG,QACdL,OAIVM,KAAKC"}
{"version":3,"sources":["totpregistration.js"],"names":["displayError","getKey","setMsg","token","verify","msg","level","$","html","window","translate","removeClass","addClass","j","status","err","res","console","log","JSON","parse","responseText","error","replace","reset","ajax","type","url","portal","dataType","data","newkey","success","s","match","hide","user","secret","show","escape","digits","interval","QRious","element","document","getElementById","value","size","text","val","code","TOTPName","ready","on","call","this"],"mappings":"CAMA,WACE,IAAIA,EAAcC,EAAQC,EAAQC,EAAOC,EAEzCF,EAAS,SAASG,EAAKC,GAOrB,OANAC,EAAE,QAAQC,KAAKC,OAAOC,UAAUL,IAChCE,EAAE,UAAUI,YAAY,4FACxBJ,EAAE,UAAUK,SAAS,WAAaN,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUK,SAAS,SAAWN,IAGzCN,EAAe,SAASa,EAAGC,EAAQC,GACjC,IAAIC,EAGJ,GAFAC,QAAQC,IAAI,QAASH,IACrBC,EAAMG,KAAKC,MAAMP,EAAEQ,gBACRL,EAAIM,MAGb,OAFAN,EAAMA,EAAIM,MAAMC,QAAQ,MAAO,IAC/BN,QAAQC,IAAI,iBAAkBF,GACvBd,EAAOc,EAAK,YAIvBb,EAAQ,GAERF,EAAS,SAASuB,GAEhB,OADAtB,EAAO,cAAe,WACfK,EAAEkB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJC,OAAQP,GAEVF,MAAOtB,EACPgC,QAAS,SAASF,GAChB,IAAQG,EACR,OAAIH,EAAKR,OACHQ,EAAKR,MAAMY,MAAM,oBACnB3B,EAAE,cAAc4B,OAEXjC,EAAO4B,EAAKR,MAAO,YAEtBQ,EAAKF,QAAUE,EAAKM,MAAQN,EAAKO,QAGvC9B,EAAE,cAAc+B,OAChBL,EAAI,kBAAqBM,OAAOT,EAAKF,QAAW,IAAOW,OAAOT,EAAKM,MAAS,WAAaN,EAAKO,OAAS,WAAcE,OAAOT,EAAKF,QAC7G,IAAhBE,EAAKU,SACPP,GAAK,WAAaH,EAAKU,QAEH,KAAlBV,EAAKW,WACPR,GAAK,WAAaH,EAAKW,UAEpB,IAAIC,OAAO,CACdC,QAASC,SAASC,eAAe,MACjCC,MAAOb,EACPc,KAAM,MAERxC,EAAE,eAAeyC,KAAKf,GAClBH,EAAKC,OACP7B,EAAO,iBAAkB,WAEzBA,EAAO,cAAe,WAEjBC,EAAQ2B,EAAK3B,OArBXD,EAAO,OAAQ,cA0B9BE,EAAS,WACP,IAAI6C,EAEJ,OADAA,EAAM1C,EAAE,SAAS0C,OAIR1C,EAAEkB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJ3B,MAAOA,EACP+C,KAAMD,EACNE,SAAU5C,EAAE,aAAa0C,OAE3B3B,MAAOtB,EACPgC,QAAS,SAASF,GAChB,OAAIA,EAAKR,MACHQ,EAAKR,MAAMY,MAAM,kBACZhC,EAAO4B,EAAKR,MAAO,WAEnBpB,EAAO4B,EAAKR,MAAO,UAGrBpB,EAAO,sBAAuB,cApBpCA,EAAO,cAAe,YA2BjCK,EAAEqC,UAAUQ,MAAM,WAKhB,OAJAnD,EAAO,GACPM,EAAE,cAAc8C,GAAG,QAAS,WAC1B,OAAOpD,EAAO,KAETM,EAAE,WAAW8C,GAAG,QAAS,WAC9B,OAAOjD,UAIVkD,KAAKC"}

View File

@ -181,7 +181,9 @@
"ipAddr":"عنوان الأي بي",
"key":"المفتاح",
"lastFailedLogins":"عمليات تسجيل الدخول الأخيرة الغير الناجحة",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"آخر تسجيلات دخول",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"اسم العائلة",
"linkValidUntil":"تحتوي هذه الرسالة على رابط لإعادة تعيين كلمة المرور، وهذا الرابط صالح حتى",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -208,6 +210,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"You're not authorized to do this",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"لم يتم العثور: محاولة الدخول إلى صفحة غير متوفرة",
"noTOTPFound":"No TOTP found",
"noU2FKeyFound":"No U2F key found",

View File

@ -180,7 +180,9 @@
"ipAddr":"IP address",
"key":"Key",
"lastFailedLogins":"Letzte fehlgeschlagene Anmeldungen",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Letzte Anmeldungen",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Nachname",
"linkValidUntil":"Diese Nachricht enthält einen Link zum Zurücksetzen deines Passworts. Dieser Link ist gültig bis",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"Du bist nicht dazu berechtigt",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"Nicht gefunden: Du versuchst, auf eine nicht verfügbare Seite zuzugreifen",
"noTOTPFound":"Kein TOTP gefunden",
"noU2FKeyFound":"Kein U2F Schlüssel gefunden",

View File

@ -180,7 +180,9 @@
"ipAddr":"IP address",
"key":"Key",
"lastFailedLogins":"Last failed logins",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Last logins",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Last name",
"linkValidUntil":"This message contains a link to reset your password, this link is valid until ",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"You're not authorized to do this",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"Not found: you try to access to an unavailable page",
"noTOTPFound":"No TOTP found",
"noU2FKeyFound":"No U2F key found",

View File

@ -180,7 +180,9 @@
"ipAddr":"Dirección IP",
"key":"Llave",
"lastFailedLogins":"Últimas conexiones fallidas",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Últimas conexiones",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Apellido(s)",
"linkValidUntil":"Este mensaje contiene un enlace para reiniciar su contraseña, este enlace es válido hasta",
"linkValidUntilCertif":"Este mensaje contiene un link para reiniciar su certificado. Este link is válido hasta",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"No es un valor encriptado",
"notAuthorized":"Usted no está autorizado a hacer esto",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"No encontrado: página no disponible",
"noTOTPFound":"TOTP no encontrado",
"noU2FKeyFound":"Llave U2F no encontrada",

View File

@ -180,7 +180,9 @@
"ipAddr":"IP-osoite",
"key":"Key",
"lastFailedLogins":"Viimeiset virheelliset kirjautumiset",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Viimeisimmät kirjautumiset",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Sukunimi",
"linkValidUntil":"Tämä viesti sisältää linkin salasanan nollaamiseen, linkki on voimassa",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"You're not authorized to do this",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"Not found: you try to access to an unavailable page",
"noTOTPFound":"No TOTP found",
"noU2FKeyFound":"No U2F key found",

View File

@ -180,7 +180,9 @@
"ipAddr":"Adresse IP",
"key":"Clef",
"lastFailedLogins":"Dernières connexions refusées",
"lastFailedLoginsCaptionLabel":"Dernières connexions refusées",
"lastLogins":"Dernières connexions",
"lastLoginsCaptionLabel":"Dernières connexions",
"lastName":"Nom",
"linkValidUntil":"Ce message contient un lien pour réinitialiser votre mot de passe, ce lien est valide jusqu'au ",
"linkValidUntilCertif":"Ce message contient un lien pour réinitialiser votre certificat, ce lien est valide jusqu'à ",
@ -207,6 +209,7 @@
"noNotification":"Aucune notification acceptée trouvée",
"notAnEncryptedValue":"Ce n'est pas une valeur cryptée",
"notAuthorized":"Vous n'êtes pas autorisé à faire cette requête",
"notAuthorizedAuthLevel":"Cette action requiert un niveau d'authentification supérieur",
"notFound": "Non trouvé : vous tentez d'accéder à une page non disponible",
"noTOTPFound":"Aucun secret TOTP trouvé",
"noU2FKeyFound": "Aucune clef U2F trouvée",

View File

@ -180,7 +180,9 @@
"ipAddr":"Indirizzo IP",
"key":"Chiave",
"lastFailedLogins":"Ultimi login non riusciti",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Ultimi accessi",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Cognome",
"linkValidUntil":"Questo messaggio contiene un link per reimpostare la password, questo link è valido fino al",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"Non sei autorizzato a farlo",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"Non trovato: si tenta di accedere ad una pagina non disponibile",
"noTOTPFound":"Nessun TOTP trovato",
"noU2FKeyFound":"Nessuna chiave U2F trovata",

View File

@ -180,7 +180,9 @@
"ipAddr":"IP address",
"key":"Key",
"lastFailedLogins":"Last failed logins",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Last logins",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Last name",
"linkValidUntil":"This message contains a link to reset your password, this link is valid until ",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"You're not authorized to do this",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"Not found: you try to access to an unavailable page",
"noTOTPFound":"No TOTP found",
"noU2FKeyFound":"No U2F key found",

View File

@ -180,7 +180,9 @@
"ipAddr":"Adres IP",
"key":"Klucz",
"lastFailedLogins":"Ostatnie nieudane logowania",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Ostatnie logowania",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Nazwisko",
"linkValidUntil":"Ta wiadomość zawiera link do zresetowania hasła, ten link jest ważny do ",
"linkValidUntilCertif":"Ta wiadomość zawiera link do zresetowania certyfikatu, ten link jest ważny do ",
@ -207,6 +209,7 @@
"noNotification":"Nie znaleziono zaakceptowanego powiadomienia",
"notAnEncryptedValue":"To nie jest zaszyfrowana wartość",
"notAuthorized":"Nie masz do tego uprawnień",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"Nie znaleziono: próbujesz uzyskać dostęp do niedostępnej strony",
"noTOTPFound":"Nie znaleziono TOTP",
"noU2FKeyFound":"Nie znaleziono klucza U2F",

View File

@ -180,7 +180,9 @@
"ipAddr":"IP address",
"key":"Key",
"lastFailedLogins":"Last failed logins",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Last logins",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Last name",
"linkValidUntil":"This message contains a link to reset your password, this link is valid until ",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"You're not authorized to do this",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"Not found: you try to access to an unavailable page",
"noTOTPFound":"No TOTP found",
"noU2FKeyFound":"No U2F key found",

View File

@ -180,7 +180,9 @@
"ipAddr":"IP address",
"key":"Key",
"lastFailedLogins":"Last failed logins",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Last logins",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Last name",
"linkValidUntil":"This message contains a link to reset your password, this link is valid until ",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"You're not authorized to do this",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"Not found: you try to access to an unavailable page",
"noTOTPFound":"No TOTP found",
"noU2FKeyFound":"No U2F key found",

View File

@ -93,7 +93,7 @@
"PE101":"Parola izin verilmeyen karakterler içeriyor",
"PE102":"Oturum yükseltilmeli",
"PE103":"Hesabınız için ikinci faktör kullanılabilir değil",
"2FDeviceNotFound":"2F device not found",
"2FDeviceNotFound":"2F cihazı bulunamadı",
"2fRegRequired":"Bu servis iki adımlı kimlik doğrulama gerektiriyor. Şimdi bir cihaz ekleyin ve ardından portala geri dönün",
"accept":"Kabul Et",
"accessDenied":"Bu uygulamaya erişim yetkiniz yok",
@ -124,7 +124,7 @@
"changePwd":"Parolanı değiştir",
"checkLastLogins":"Son girişlerimi kontrol et",
"checkUser":"Kullanıcı TOA profilini kontrol et",
"checkUserComputedSession":"No SSO session found. Computed data!",
"checkUserComputedSession":"TOA oturumu bulunamadı. Hesaplanan veri!",
"checkUserMerged":"Kullanıcı TOA profilini kontrol et. Bazı Gerçek ve Sahte TOA grupları birleştirildi!",
"checkUserComputeSession":"Hesaplanan oturum verisi!",
"certificateReset":"Reset my certificate",
@ -181,7 +181,9 @@
"ipAddr":"IP adresi",
"key":"Anahtar",
"lastFailedLogins":"Son başarısız giriş denemeleri",
"lastFailedLoginsCaptionLabel":"Son başarısız girişler",
"lastLogins":"Son girişler",
"lastLoginsCaptionLabel":"Son girişler",
"lastName":"Soyad",
"linkValidUntil":"Bu mesaj parolanızı sıfırlamak için bir bağlantı içerir, bu bağlantı şu zamana kadar geçerlidir",
"linkValidUntilCertif":"Bu mesaj sertifikanızı sıfırlamak için bir bağlantı içerir, bu bağlantı şu zamana kadar geçerlidir",
@ -208,6 +210,7 @@
"noNotification":"Kabul edilen bildirim bulunamadı",
"notAnEncryptedValue":"Bu şifrelenmiş bir değer değil",
"notAuthorized":"Bunu yapmak için yetkili değilsiniz",
"notAuthorizedAuthLevel":"Bu eylem daha yüksek bir doğrulama seviyesi gerektirir",
"notFound":"Bulunamadı: mevcut olmayan bir sayfaya erişmeyi deniyorsunuz",
"noTOTPFound":"TOTP bulunamadi",
"noU2FKeyFound":"U2F anahtarı bulunamadı",

View File

@ -180,7 +180,9 @@
"ipAddr":"Địa chỉ IP",
"key":"Khóa",
"lastFailedLogins":"Lần cuối đăng nhập thất bại",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"Đăng nhập lần cuối",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"Họ",
"linkValidUntil":"Thông báo này có chứa liên kết để đặt lại mật khẩu của bạn, liên kết này hợp lệ cho đến khi",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"You're not authorized to do this",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"Không tìm thấy: bạn cố gắng truy cập vào một trang không có sẵn",
"noTOTPFound":"Đăng xuất khỏi các ứng dụng khác",
"noU2FKeyFound":"No U2F key found",

View File

@ -180,7 +180,9 @@
"ipAddr":"IP 地址",
"key":"Key",
"lastFailedLogins":"上次失败的认证",
"lastFailedLoginsCaptionLabel":"Last failed logins",
"lastLogins":"上次登陆",
"lastLoginsCaptionLabel":"Last logins",
"lastName":"姓氏",
"linkValidUntil":"此消息包含重置您密码的链接,该链接有效期截至",
"linkValidUntilCertif":"This message contains a link to reset your certificate, this link is valid until ",
@ -207,6 +209,7 @@
"noNotification":"None accepted notification found",
"notAnEncryptedValue":"It is not an encrypted value",
"notAuthorized":"您没有权限进行该项操作",
"notAuthorizedAuthLevel":"This action requires a higher authentication level",
"notFound":"无法找到:您请求的网页不存在。",
"noTOTPFound":"No TOTP found",
"noU2FKeyFound":"No U2F key found",

View File

@ -1,11 +1,12 @@
<TMPL_INCLUDE NAME="header.tpl">
<div class="container">
<div class="message message-positive alert" trspan="choose2f"></div>
<div class="message message-<TMPL_VAR NAME="ALERT"> alert" trspan="<TMPL_VAR NAME="MSG">"></div>
<div class="buttons">
<form action="/2fchoice" method="POST">
<input type="hidden" id="token" name="token" value="<TMPL_VAR NAME="TOKEN">" />
<input type="hidden" id="checkLogins" name="checkLogins" value="<TMPL_VAR NAME="CHECKLOGINS">">
<input type="hidden" id="checkLogins" name="checkLogins" value="<TMPL_VAR NAME="CHECKLOGINS">" />
<input type="hidden" id="stayconnected" name="stayconnected" value="<TMPL_VAR NAME="STAYCONNECTED">" />
<input type="hidden" name="skin" value="<TMPL_VAR NAME="SKIN">" />
<TMPL_LOOP NAME="MODULES">
<button type="submit" name="sf" value="<TMPL_VAR NAME="CODE">" class="mx-3 btn btn-light" role="button">

View File

@ -1,11 +1,11 @@
<TMPL_INCLUDE NAME="header.tpl">
<div class="container">
<div id="color" class="message message-positive alert">
<div id="color" class="message message-<TMPL_VAR NAME="ALERT"> alert">
<TMPL_IF NAME="REG_REQUIRED">
<span trspan="2fRegRequired"></span>
<TMPL_ELSE>
<span id="msg" trspan="choose2f"></span>
<span id="msg" trspan="<TMPL_VAR NAME="MSG">"></span>
</TMPL_IF>
</div>
<TMPL_IF NAME="SFDEVICES">
@ -64,6 +64,12 @@
</div>
<div class="buttons">
<TMPL_IF NAME="DISPLAY_UPG">
<a href="<TMPL_VAR NAME="PORTAL_URL">upgradesession?url=<TMPL_VAR NAME="SFREGISTERS_URL">" class="btn btn-success" role="button">
<span class="fa fa-sign-in"></span>
<span trspan="upgradeSession">Upgrade session</span>
</a>
</TMPL_IF>
<a href="<TMPL_VAR NAME="PORTAL_URL">?cancel=1&skin=<TMPL_VAR NAME="SKIN">" class="btn btn-primary" role="button">
<span class="fa fa-home"></span>
<span trspan="goToPortal">Go to portal</span>

View File

@ -15,7 +15,7 @@
<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text">
<input type="checkbox" id="stayconnected" name="stayconnected" aria-describedby="stayConnectedLabel" />
<input type="checkbox" id="stayconnected" name="stayconnected" aria-describedby="stayConnectedLabel" <TMPL_IF NAME="ASK_STAYCONNECTED">checked</TMPL_IF> />
</div>
</div>
<p class="form-control">

View File

@ -10,6 +10,7 @@
<div class="form">
<input type="hidden" id="token" name="token" value="<TMPL_VAR NAME="TOKEN">" />
<input type="hidden" id="checkLogins" name="checkLogins" value="<TMPL_VAR NAME="CHECKLOGINS">" />
<input type="hidden" id="stayconnected" name="stayconnected" value="<TMPL_VAR NAME="STAYCONNECTED">" />
<input type="hidden" name="skin" value="<TMPL_VAR NAME="SKIN">" />
<div class="input-group mb-3">
<div class="input-group-prepend">

View File

@ -23,9 +23,9 @@
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><label for="mailfield" class="mb-0"><i class="fa fa-envelope"></i></label></span>
<span class="input-group-text"><label for="mail" class="mb-0"><i class="fa fa-envelope"></i></label></span>
</div>
<input id="mailfield" name="mail" type="text" value="<TMPL_VAR NAME="MAIL">" class="form-control" trplaceholder="mail" required />
<input id="mail" name="mail" type="text" value="<TMPL_VAR NAME="MAIL">" class="form-control" trplaceholder="mail" required />
</div>
<TMPL_IF NAME=CAPTCHA_SRC>
@ -118,16 +118,16 @@
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><label for="newpasswordfield" class="mb-0"><i class="fa fa-lock"></i></label></span>
<span class="input-group-text"><label for="newpassword" class="mb-0"><i class="fa fa-lock"></i></label></span>
</div>
<input id="newpasswordfield" name="newpassword" type="password" class="form-control" trplaceholder="newPassword" />
<input id="newpassword" name="newpassword" type="password" class="form-control" trplaceholder="newPassword" />
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><label for="confirmpasswordfield" class="mb-0"><i class="fa fa-lock"></i></label></span>
<span class="input-group-text"><label for="confirmpassword" class="mb-0"><i class="fa fa-lock"></i></label></span>
</div>
<input id="confirmpasswordfield" name="confirmpassword" type="password" class="form-control" trplaceholder="confirmPwd" />
<input id="confirmpassword" name="confirmpassword" type="password" class="form-control" trplaceholder="confirmPwd" />
</div>
<TMPL_IF NAME="DISPLAY_GENERATE_PASSWORD">

View File

@ -223,7 +223,7 @@
<div class="col-3">
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/apps/<TMPL_VAR NAME="applogo">"
class="applogo <TMPL_VAR NAME="appid"> img-fluid"
alt="<TMPL_VAR NAME="appname">" />
alt="" />
</div>
<div class="col-9">
<TMPL_ELSE>

View File

@ -2,6 +2,11 @@
<h3 trspan="<TMPL_VAR NAME="title">"></h3>
</TMPL_IF>
<table class="info">
<TMPL_IF NAME="displayError">
<caption trspan="lastFailedLoginsCaptionLabel">Last failed logins</caption>
<TMPL_ELSE>
<caption trspan="lastLoginsCaptionLabel">Last logins</caption>
</TMPL_IF>
<thead>
<tr>
<TMPL_IF NAME="displayUser">

View File

@ -10,6 +10,7 @@
<div class="form">
<input type="hidden" id="token" name="token" value="<TMPL_VAR NAME="TOKEN">" />
<input type="hidden" id="checkLogins" name="checkLogins" value="<TMPL_VAR NAME="CHECKLOGINS">" />
<input type="hidden" id="stayconnected" name="stayconnected" value="<TMPL_VAR NAME="STAYCONNECTED">" />
<input type="hidden" name="skin" value="<TMPL_VAR NAME="SKIN">" />
<div class="input-group mb-3">
<div class="input-group-prepend">

View File

@ -2,7 +2,7 @@
<main id="menucontent" class="container">
<div id="color" class="message message-positive alert"><span id="msg" trspan="yourNewTotpKey"></span></div>
<div id="color" class="message message-<TMPL_VAR NAME="ALERT"> alert"><span id="msg" trspan="<TMPL_VAR NAME="MSG">"></span></div>
<div class="card">
<div class="card-body">

View File

@ -8,10 +8,11 @@
<TMPL_IF NAME="DATA">
<div class="message message-positive alert"><span trspan="touchU2fDevice"></span></div>
<form id="verify-form" action="/u2fcheck" method="post">
<input type="hidden" id="verify-data" name="signature" value="">
<input type="hidden" id="verify-challenge" name="challenge" value="">
<input type="hidden" id="token" name="token" value="<TMPL_VAR NAME="TOKEN">">
<input type="hidden" id="checkLogins" name="checkLogins" value="<TMPL_VAR NAME="CHECKLOGINS">">
<input type="hidden" id="verify-data" name="signature" value="" />
<input type="hidden" id="verify-challenge" name="challenge" value="" />
<input type="hidden" id="token" name="token" value="<TMPL_VAR NAME="TOKEN">" />
<input type="hidden" id="checkLogins" name="checkLogins" value="<TMPL_VAR NAME="CHECKLOGINS">" />
<input type="hidden" id="stayconnected" name="stayconnected" value="<TMPL_VAR NAME="STAYCONNECTED">" />
<input type="hidden" name="skin" value="<TMPL_VAR NAME="SKIN">" />
</form>
<script type="application/init">

View File

@ -2,7 +2,7 @@
<main id="menucontent" class="container">
<div id="color" class="message message-positive alert"><span id="msg" trspan="u2fWelcome"></span></div>
<div id="color" class="message message-<TMPL_VAR NAME="ALERT"> alert"><span id="msg" trspan="<TMPL_VAR NAME="MSG">"></span></div>
<div class="card">
<div class="card-body">

View File

@ -21,14 +21,15 @@
</div>
<TMPL_ELSE>
<form id="verify-form" action="/utotp2fcheck" method="post">
<input type="hidden" id="token" name="token" value="<TMPL_VAR NAME="TOKEN">">
<input type="hidden" id="checkLogins" name="checkLogins" value="<TMPL_VAR NAME="CHECKLOGINS">">
<input type="hidden" id="token" name="token" value="<TMPL_VAR NAME="TOKEN">" />
<input type="hidden" id="checkLogins" name="checkLogins" value="<TMPL_VAR NAME="CHECKLOGINS">" />
<input type="hidden" id="stayconnected" name="stayconnected" value="<TMPL_VAR NAME="STAYCONNECTED">" />
<TMPL_IF NAME="DATA">
<div class="message message-positive alert">
<span trspan="touchU2fDeviceOrEnterTotp"></span>
</div>
<input type="hidden" id="verify-data" name="signature" value="">
<input type="hidden" id="verify-challenge" name="challenge" value="">
<input type="hidden" id="verify-data" name="signature" value="" />
<input type="hidden" id="verify-challenge" name="challenge" value="" />
<script type="application/init">
<TMPL_VAR NAME="DATA">
</script>

Some files were not shown because too many files have changed in this diff Show More