Attributes.pm 137 KB
Newer Older
Christophe Maudoux's avatar
Christophe Maudoux committed
1
#  This file contains the description of all configuration parameters
2 3 4
# It may be included only by batch files, never in portal or handler chain
# for performances reasons

Xavier Guimard's avatar
Xavier Guimard committed
5
# DON'T FORGET TO RUN "make json" AFTER EACH CHANGE
6 7 8

package Lemonldap::NG::Manager::Build::Attributes;

Xavier Guimard's avatar
Xavier Guimard committed
9
our $VERSION = '2.1.0';
10 11 12
use strict;
use Regexp::Common qw/URI/;

13
sub perlExpr {
14
    my ( $val, $conf ) = @_;
15 16
    my $cpt = new Safe;
    $cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
17 18 19 20 21 22 23
    $cpt->share_from(
        'Lemonldap::NG::Handler::Main::Jail',
        [
            '&encrypt', '&token',
            @Lemonldap::NG::Handler::Main::Jail::builtCustomFunctions
        ]
    );
24 25
    $cpt->share_from( 'Lemonldap::NG::Common::Safelib',
        $Lemonldap::NG::Common::Safelib::functions );
26
    $cpt->reval("BEGIN { 'warnings'->unimport; } $val");
27 28 29
    my $err = join( '',
        grep { $_ =~ /Undefined subroutine/ ? () : $_ } split( /\n/, $@ ) );
    return $err ? ( 1, "__badExpression__: $err" ) : (1);
30
}
31

Xavier Guimard's avatar
Xavier Guimard committed
32
my $url = $RE{URI}{HTTP}{ -scheme => "https?" };
Xavier Guimard's avatar
Xavier Guimard committed
33 34 35
$url =~ s/(?<=[^\\])\$/\\\$/g;
$url = qr/$url/;

36 37 38 39 40
sub types {
    return {

        # Simple text types
        text => {
41
            test    => sub { 1 },
42 43 44
            msgFail => '__malformedValue__',
        },
        password => {
45
            test    => sub { 1 },
46 47 48
            msgFail => '__malformedValue__',
        },
        longtext => {
49
            test => sub { 1 }
50 51 52
        },
        url => {
            form    => 'text',
Xavier Guimard's avatar
Xavier Guimard committed
53
            test    => $url,
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
            msgFail => '__badUrl__',
        },
        PerlModule => {
            form    => 'text',
            test    => qr/^[a-zA-Z][a-zA-Z0-9]*(?:::[a-zA-Z][a-zA-Z0-9]*)*$/,
            msgFail => '__badPerlPackageName__',
        },
        hostname => {
            form    => 'text',
            test    => qr/^(?:$Regexp::Common::URI::RFC2396::host)?$/,
            msgFail => '__badHostname__',
        },
        pcre => {
            form => 'text',
            test => sub {
69
                eval { qr/$_[0]/ };
70 71 72 73 74
                return $@ ? ( 0, "__badRegexp__: $@" ) : (1);
            },
        },
        lmAttrOrMacro => {
            form => 'text',
Xavier Guimard's avatar
Xavier Guimard committed
75 76
            test => sub {
                my ( $val, $conf ) = @_;
77
                return 1
78
                  if ( defined $conf->{macros}->{$val}
79
                    or $val eq '_timezone' );
80 81
                foreach ( keys %$conf ) {
                    return 1
82
                      if ( $_ =~ /exportedvars$/i
83
                        and defined $conf->{$_}->{$val} );
Xavier Guimard's avatar
Xavier Guimard committed
84
                }
85
                return ( 1, "__unknownAttrOrMacro__: $val" );
Xavier Guimard's avatar
Xavier Guimard committed
86
            },
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
        },

        # Other types
        int => {
            test    => qr/^\-?\d+$/,
            msgFail => '__notAnInteger__',
        },
        bool => {
            test    => qr/^[01]$/,
            msgFail => '__notABoolean__',
        },
        trool => {
            test    => qr/^(?:-1|0|1)$/,
            msgFail => '__authorizedValues__: -1, 0, 1',
        },
        boolOrExpr => {
103
            test    => sub { return perlExpr(@_) },
104 105
            msgFail => '__notAValidPerlExpression__',
        },
Xavier Guimard's avatar
Xavier Guimard committed
106 107
        keyTextContainer => {
            test       => qr/./,
Xavier Guimard's avatar
Xavier Guimard committed
108
            msgFail    => '__emptyValueNotAllowed__',
Xavier Guimard's avatar
Xavier Guimard committed
109
            keyTest    => qr/^\w[\w\.\-]*$/,
Xavier Guimard's avatar
Xavier Guimard committed
110
            keyMsgFail => '__badKeyName__',
Xavier Guimard's avatar
Xavier Guimard committed
111 112 113
        },
        subContainer => {
            keyTest => qr/\w/,
114
            test    => sub { 1 },
Xavier Guimard's avatar
Xavier Guimard committed
115
        },
Xavier Guimard's avatar
Xavier Guimard committed
116 117
        select => {
            test => sub {
118
                my $test = grep ( { $_ eq $_[0] }
Xavier Guimard's avatar
Xavier Guimard committed
119
                    map ( { $_->{k} } @{ $_[2]->{select} } ) );
Xavier Guimard's avatar
Xavier Guimard committed
120
                return $test
121 122
                  ? 1
                  : ( 1, "Invalid value '$_[0]' for this select" );
Xavier Guimard's avatar
Xavier Guimard committed
123 124
            },
        },
125 126 127

        # Files type (long text)
        file => {
128
            test => sub { 1 }
129 130
        },
        RSAPublicKey => {
131
            test => sub {
132
                return (
133 134
                    $_[0] =~
/^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9\/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+PUBLIC\s+KEY\s*\-+)?[\r\n]*)?$/s
135
                    ? (1)
136 137
                    : ( 1, '__badPemEncoding__' )
                );
138
            },
139
        },
140
        'RSAPublicKeyOrCertificate' => {
141
            'test' => sub {
142
                return (
143 144
                    $_[0] =~
/^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9\/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+)?[\r\n]*)?$/s
145
                    ? (1)
146 147
                    : ( 1, '__badPemEncoding__' )
                );
148
            },
149
        },
150
        RSAPrivateKey => {
151
            test => sub {
152
                return (
153
                    $_[0] =~
Maxime Besson's avatar
Maxime Besson committed
154
/^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?(?:Proc-Type:.*\r?\nDEK-Info:.*\r?\n[\r\n]*)?[a-zA-Z0-9\/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+)?[\r\n]*)?$/s
155
                    ? (1)
156 157
                    : ( 1, '__badPemEncoding__' )
                );
158
            },
159 160 161
        },

        authParamsText => {
162
            test => sub { 1 }
163 164
        },
        blackWhiteList => {
165
            test => sub { 1 }
166 167
        },
        catAndAppList => {
168
            test => sub { 1 }
169 170 171
        },
        keyText => {
            keyTest => qr/^[a-zA-Z0-9_]+$/,
Xavier Guimard's avatar
Xavier Guimard committed
172
            test    => qr/^.*$/,
173 174 175
            msgFail => '__badValue__',
        },
        menuApp => {
176
            test => sub { 1 }
177 178
        },
        menuCat => {
179
            test => sub { 1 }
180 181
        },
        oidcOPMetaDataNode => {
182
            test => sub { 1 }
183 184
        },
        oidcRPMetaDataNode => {
185
            test => sub { 1 }
186 187
        },
        oidcmetadatajson => {
188
            test => sub { 1 }
189 190
        },
        oidcmetadatajwks => {
191
            test => sub { 1 }
192 193
        },
        portalskin => {
194
            test => sub { 1 }
195 196
        },
        portalskinbackground => {
197
            test => sub { 1 }
198 199
        },
        post => {
200
            test => sub { 1 }
201 202
        },
        rule => {
203
            test => sub { 1 }
204 205
        },
        samlAssertion => {
206
            test => sub { 1 }
207 208
        },
        samlAttribute => {
209
            test => sub { 1 }
210 211
        },
        samlIDPMetaDataNode => {
212
            test => sub { 1 }
213 214
        },
        samlSPMetaDataNode => {
215
            test => sub { 1 }
216 217
        },
        samlService => {
218
            test => sub { 1 }
219
        },
220
        array => {
221
            test => sub { 1 }
222
        },
223 224 225 226 227 228 229
    };
}

sub attributes {
    return {

        # Other
230 231 232
        checkTime => {
            type => 'int',
            documentation =>
233
              'Timeout to check new configuration in local cache',
234
            default => 600,
235 236 237 238 239 240
            flags   => 'hp',
        },
        mySessionAuthorizedRWKeys => {
            type          => 'array',
            documentation => 'Alterable session keys by user itself',
            default =>
241
              [ '_appsListOrder', '_oidcConnectedRP', '_oidcConsents' ],
242
        },
Xavier Guimard's avatar
Xavier Guimard committed
243 244 245 246 247 248 249 250 251 252 253 254
        configStorage => {
            type          => 'text',
            documentation => 'Configuration storage',
            flags         => 'hmp',
        },
        localStorage => {
            type          => 'text',
            documentation => 'Local cache',
            flags         => 'hmp',
        },
        localStorageOptions => {
            type          => 'keyTextContainer',
Xavier Guimard's avatar
Xavier Guimard committed
255
            documentation => 'Local cache parameters',
Xavier Guimard's avatar
Xavier Guimard committed
256 257
            flags         => 'hmp',
        },
258 259 260 261 262 263
        cfgNum => {
            type          => 'int',
            default       => 0,
            documentation => 'Enable Cross Domain Authentication',
        },
        cfgAuthor => {
264 265
            type          => 'text',
            documentation => 'Name of the author of the current configuration',
266 267
        },
        cfgAuthorIP => {
268 269
            type          => 'text',
            documentation => 'Uploader IP address of the current configuration',
270 271 272 273 274 275 276 277 278
        },
        cfgDate => {
            type          => 'int',
            documentation => 'Timestamp of the current configuration',
        },
        cfgLog => {
            type          => 'longtext',
            documentation => 'Configuration update log',
        },
279 280 281 282
        cfgVersion => {
            type          => 'text',
            documentation => 'Version of LLNG which build configuration',
        },
Xavier Guimard's avatar
Xavier Guimard committed
283 284 285 286 287
        status => {
            type          => 'bool',
            documentation => 'Status daemon activation',
            flags         => 'h',
        },
288 289 290
        confirmFormMethod => {
            type => "select",
            select =>
291
              [ { k => 'get', v => 'GET' }, { k => 'post', v => 'POST' }, ],
292 293 294
            default       => 'post',
            documentation => 'HTTP method for confirm page form',
        },
295 296
        customFunctions => {
            type          => 'text',
297
            test          => qr/^(?:\w+(?:::\w+)*(?:\s+\w+(?:::\w+)*)*)?$/,
298
            help          => 'customfunctions.html',
299
            msgFail       => "__badCustomFuncName__",
Xavier Guimard's avatar
Xavier Guimard committed
300 301
            documentation => 'List of custom functions',
            flags         => 'hmp',
302 303
        },
        https => {
304 305
            default       => -1,
            type          => 'trool',
306
            documentation => 'Use HTTPS for redirection from portal',
Xavier Guimard's avatar
Xavier Guimard committed
307
            flags         => 'h',
308 309 310 311
        },
        infoFormMethod => {
            type => "select",
            select =>
312
              [ { k => 'get', v => 'GET' }, { k => 'post', v => 'POST' }, ],
313 314 315
            default       => 'get',
            documentation => 'HTTP method for info page form',
        },
Xavier Guimard's avatar
Xavier Guimard committed
316
        port => {
317
            default       => -1,
Xavier Guimard's avatar
Xavier Guimard committed
318 319 320 321
            type          => 'int',
            documentation => 'Force port in redirection',
            flags         => 'h',
        },
322 323 324 325 326 327
        jsRedirect => {
            type          => 'boolOrExpr',
            default       => 0,
            documentation => 'Use javascript for redirections',
        },
        logoutServices => {
328 329 330 331
            type          => 'keyTextContainer',
            help          => 'logoutforward.html',
            default       => {},
            documentation => 'Send logout trough GET request to these services',
332 333 334 335 336
        },
        maintenance => {
            default       => 0,
            type          => 'bool',
            documentation => 'Maintenance mode for all virtual hosts',
Xavier Guimard's avatar
Xavier Guimard committed
337
            flags         => 'h',
338
        },
Xavier Guimard's avatar
Xavier Guimard committed
339 340 341 342
        nginxCustomHandlers => {
            type    => 'keyTextContainer',
            keyTest => qr/^\w+$/,
            test    => qr/^[a-zA-Z][a-zA-Z0-9]*(?:::[a-zA-Z][a-zA-Z0-9]*)*$/,
343
            help    => 'handlerarch.html',
Xavier Guimard's avatar
Xavier Guimard committed
344
            msgFail => '__badPerlPackageName__',
Xavier Guimard's avatar
Xavier Guimard committed
345
            documentation => 'Custom Nginx handler (deprecated)',
Xavier Guimard's avatar
Xavier Guimard committed
346
        },
347 348 349 350 351
        noAjaxHook => {
            default       => 0,
            type          => 'bool',
            documentation => 'Avoid replacing 302 by 401 for Ajax responses',
        },
352 353 354 355
        portal => {
            type          => 'url',
            default       => 'http://auth.example.com/',
            documentation => 'Portal URL',
Xavier Guimard's avatar
Xavier Guimard committed
356
            flags         => 'hmp',
357 358
            test          => $url,
            msgFail       => '__badUrl__',
359
        },
360 361 362
        portalStatus => {
            type          => 'bool',
            default       => 0,
Xavier Guimard's avatar
Typo  
Xavier Guimard committed
363
            help          => 'status.html',
364 365
            documentation => 'Enable portal status',
        },
366 367 368 369
        portalUserAttr => {
            type    => 'text',
            default => '_user',
            documentation =>
370
              'Session parameter to display connected user in portal',
371 372 373 374
        },
        redirectFormMethod => {
            type => "select",
            select =>
375
              [ { k => 'get', v => 'GET' }, { k => 'post', v => 'POST' }, ],
376 377 378
            default       => 'get',
            documentation => 'HTTP method for redirect page form',
        },
379 380 381 382 383 384
        reloadTimeout => {
            type          => 'int',
            default       => 5,
            documentation => 'Configuration reload timeout',
            flags         => 'm',
        },
385
        reloadUrls => {
386 387 388 389 390
            type          => 'keyTextContainer',
            help          => 'configlocation.html#configuration_reload',
            keyTest       => qr/^$Regexp::Common::URI::RFC2396::host(?::\d+)?$/,
            test          => $url,
            msgFail       => '__badUrl__',
Xavier Guimard's avatar
Xavier Guimard committed
391
            documentation => 'URL to call on reload',
392
        },
393 394 395 396 397
        dontCompactConf => {
            type          => 'bool',
            default       => 0,
            documentation => 'Don t compact configuration',
        },
Clément OUDOT's avatar
Clément OUDOT committed
398
        portalMainLogo => {
399 400 401 402
            type          => 'text',
            default       => 'common/logos/logo_llng_400px.png',
            documentation => 'Portal main logo path',
        },
403 404 405 406 407
        showLanguages => {
            type          => 'bool',
            default       => 1,
            documentation => 'Display langs icons',
        },
408 409 410 411
        staticPrefix => {
            type          => 'text',
            documentation => 'Prefix of static files for HTML templates',
        },
412 413 414 415
        multiValuesSeparator => {
            type          => 'authParamsText',
            default       => '; ',
            documentation => 'Separator for multiple values',
Xavier Guimard's avatar
Xavier Guimard committed
416
            flags         => 'hmp',
417
        },
418
        stayConnected => {
Xavier Guimard's avatar
Typo  
Xavier Guimard committed
419 420
            type => 'bool',

421
            #help          => 'stayconnected.html',
422
            default       => 0,
423 424
            documentation => 'Enable StayConnected plugin',
        },
425
        checkState => {
426
            type          => 'bool',
427
            default       => 0,
428 429
            documentation => 'Enable CheckState plugin',
        },
430
        checkStateSecret => {
431
            type          => 'text',
432 433
            documentation => 'Secret token for CheckState plugin',
        },
434 435 436 437 438 439
        checkUser => {
            default       => 0,
            type          => 'bool',
            documentation => 'Enable check user',
            flags         => 'p',
        },
440 441
        checkUserIdRule => {
            type          => 'text',
442
            test          => sub { return perlExpr(@_) },
443 444 445
            default       => 1,
            documentation => 'checkUser identities rule',
        },
446 447
        checkUserHiddenAttributes => {
            type          => 'text',
Christophe Maudoux's avatar
Christophe Maudoux committed
448
            default       => '_loginHistory _session_id hGroups',
449 450 451
            documentation => 'Attributes to hide in CheckUser plugin',
            flags         => 'p',
        },
452 453 454 455 456
        checkUserSearchAttributes => {
            type          => 'text',
            documentation => 'Attributes used for retrieving sessions in user DataBase',
            flags         => 'p',
        },
457 458 459 460 461 462 463 464 465 466 467 468
        checkUserDisplayPersistentInfo => {
            default       => 0,
            type          => 'bool',
            documentation => 'Display persistent session info',
            flags         => 'p',
        },
        checkUserDisplayEmptyValues => {
            default       => 0,
            type          => 'bool',
            documentation => 'Display session empty values',
            flags         => 'p',
        },
469
        favAppsMaxNumber => {
470
            default       => 3,
471 472 473 474
            type          => 'int',
            documentation => 'Maximum favorite Apps number',
            flags         => 'p',
        },
475 476 477 478 479 480
        portalDisplayFavApps => {
            type          => 'boolOrExpr',
            default       => 1,
            documentation => 'Display favorite applications tab in portal',
            flags         => 'p',
        },
481
        impersonationMergeSSOgroups => {
482
            default       => 0,
483
            type          => 'boolOrExpr',
484
            documentation => 'Merge spoofed and real SSO groups',
485 486
            flags         => 'p',
        },
487
        impersonationPrefix => {
488 489 490 491 492
            type          => 'text',
            default       => 'real_',
            documentation => 'Prefix to rename real session attributes',
            flags         => 'p',
        },
493
        impersonationRule => {
494
            type          => 'boolOrExpr',
495
            default       => 0,
496
            documentation => 'Impersonation activation rule',
497
            flags         => 'p',
498
        },
499 500
        impersonationIdRule => {
            type          => 'text',
501
            test          => sub { return perlExpr(@_) },
502
            default       => 1,
503
            documentation => 'Impersonation identities rule',
504
            flags         => 'p',
505
        },
506
        impersonationHiddenAttributes => {
507 508 509 510 511
            type          => 'text',
            default       => '_2fDevices _loginHistory',
            documentation => 'Attributes to skip',
            flags         => 'p',
        },
512
        impersonationSkipEmptyValues => {
513 514 515
            default       => 1,
            type          => 'bool',
            documentation => 'Skip session empty values',
516 517
            flags         => 'p',
        },
518
        contextSwitchingRule => {
519
            type          => 'boolOrExpr',
520 521
            default       => 0,
            documentation => 'Context switching activation rule',
522
            flags         => 'p',
523 524 525 526
        },
        contextSwitchingIdRule => {
            type          => 'text',
            test          => sub { return perlExpr(@_) },
527
            default       => 1,
528
            documentation => 'Context switching identities rule',
529
            flags         => 'p',
530 531 532 533 534
        },
        contextSwitchingStopWithLogout => {
            type          => 'bool',
            default       => 1,
            documentation => 'Stop context switching by logout',
535
            flags         => 'p',
536
        },
537 538 539 540 541 542
        decryptValueRule => {
            type          => 'boolOrExpr',
            default       => 0,
            documentation => 'Decrypt value activation rule',
            flags         => 'p',
        },
543 544 545 546 547 548 549
        decryptValueFunctions => {
            type          => 'text',
            test          => qr/^(?:\w+(?:::\w+)*(?:\s+\w+(?:::\w+)*)*)?$/,
            msgFail       => "__badCustomFuncName__",
            documentation => 'Custom function used for decrypting values',
            flags         => 'p',
        },
550
        skipRenewConfirmation => {
551 552
            type    => 'bool',
            default => 0,
553
            documentation =>
554
              'Avoid asking confirmation when an Issuer asks to renew auth',
555
        },
556 557 558 559 560
        forceGlobalStorageIssuerOTT => {
            type => 'bool',
            documentation =>
              'Force Issuer tokens be stored into Global Storage',
        },
561 562 563 564
        handlerInternalCache => {
            type          => 'int',
            default       => 15,
            documentation => 'Handler internal cache timeout',
Christophe Maudoux's avatar
Christophe Maudoux committed
565
            flags         => 'hp',
566
        },
Christophe Maudoux's avatar
Christophe Maudoux committed
567 568 569 570 571 572
        handlerServiceTokenTTL => {
            type          => 'int',
            default       => 30,
            documentation => 'Handler ServiceToken timeout',
            flags         => 'hp',
        },
573

574 575 576 577 578 579 580 581 582
        # Loggers (ini only)
        logLevel => {
            type          => 'text',
            documentation => 'Log level, must be set in .ini',
            flags         => 'hmp',
        },
        logger => {
            type          => 'text',
            documentation => 'technical logger',
583
            flags         => 'hmp',
584 585 586 587
        },
        userLogger => {
            type          => 'text',
            documentation => 'User actions logger',
588
            flags         => 'hmp',
589 590 591 592
        },
        log4perlConfFile => {
            type          => 'text',
            documentation => 'Log4Perl logger configuration file',
593
            flags         => 'hmp',
594 595 596 597
        },
        sentryDsn => {
            type          => 'text',
            documentation => 'Sentry logger DSN',
598
            flags         => 'hmp',
599 600 601 602
        },
        syslogFacility => {
            type          => 'text',
            documentation => 'Syslog logger technical facility',
603
            flags         => 'hmp',
604 605 606 607
        },
        userSyslogFacility => {
            type          => 'text',
            documentation => 'Syslog logger user-actions facility',
608
            flags         => 'hmp',
609 610 611
        },

        # Manager or PSGI protected apps
612
        protection => {
613 614 615
            type          => 'text',
            test          => qr/^(?:none|authenticate|manager|)$/,
            msgFail       => '__authorizedValues__: none authenticate manager',
616
            documentation => 'Manager protection method',
Xavier Guimard's avatar
Xavier Guimard committed
617
            flags         => 'hm',
618 619 620 621 622 623 624 625 626 627
        },

        # Menu
        activeTimer => {
            type          => 'bool',
            default       => 1,
            documentation => 'Enable timers on portal pages',
        },
        applicationList => {
            type    => 'catAndAppList',
628
            keyTest => qr/\w/,
629 630
            help    => 'portalmenu.html#categories_and_applications',
            default => {
631
                default => { catname => 'Default category', type => "category" }
632 633 634
            },
            documentation => 'Applications list',
        },
635 636 637 638 639
        portalErrorOnExpiredSession => {
            type          => 'bool',
            default       => 1,
            documentation => 'Show error if session is expired',
        },
640
        portalErrorOnMailNotFound => {
dcoutadeur dcoutadeur's avatar
dcoutadeur dcoutadeur committed
641 642 643
            type    => 'bool',
            default => 0,
            documentation =>
644
              'Show error if mail is not found in password reset process',
645
        },
646 647 648 649 650 651 652 653 654 655 656 657 658 659
        portalOpenLinkInNewWindow => {
            type          => 'bool',
            default       => 0,
            documentation => 'Open applications in new windows',
        },
        portalPingInterval => {
            type          => 'int',
            default       => 60000,
            documentation => 'Interval in ms between portal Ajax pings ',
        },
        portalSkin => {
            type          => 'portalskin',
            default       => 'bootstrap',
            documentation => 'Name of portal skin',
Xavier Guimard's avatar
Xavier Guimard committed
660
            select        => [ { k => 'bootstrap', v => 'Bootstrap' }, ],
661 662 663 664 665 666
        },
        portalSkinBackground => {
            type          => 'portalskinbackground',
            documentation => 'Background image of portal skin',
            select        => [
                { k => "", v => 'None' },
667 668
                {
                    k => "1280px-Anse_Source_d'Argent_2-La_Digue.jpg",
669 670
                    v => 'Anse'
                },
671 672 673
                {
                    k =>
"1280px-Autumn-clear-water-waterfall-landscape_-_Virginia_-_ForestWander.jpg",
674 675 676
                    v => 'Waterfall'
                },
                { k => "1280px-BrockenSnowedTrees.jpg", v => 'Snowed Trees' },
677 678
                {
                    k => "1280px-Cedar_Breaks_National_Monument_partially.jpg",
679 680
                    v => 'National Monument'
                },
681 682
                {
                    k => "1280px-Parry_Peak_from_Winter_Park.jpg",
683 684
                    v => 'Winter'
                },
685 686
                {
                    k => "Aletschgletscher_mit_Pinus_cembra1.jpg",
687 688
                    v => 'Pinus'
                },
689 690 691
            ],
        },
        portalSkinRules => {
Xavier Guimard's avatar
Xavier Guimard committed
692 693
            type          => 'keyTextContainer',
            help          => 'portalcustom.html',
694
            keyTest       => sub { return perlExpr(@_) },
Xavier Guimard's avatar
Xavier Guimard committed
695 696 697 698
            keyMsgFail    => '__badSkinRule__',
            test          => qr/^\w+$/,
            msgFail       => '__badValue__',
            documentation => 'Rules to choose portal skin',
699 700 701
        },

        # Security
702
        formTimeout => {
Xavier Guimard's avatar
Xavier Guimard committed
703 704
            default       => 120,
            type          => 'int',
705 706
            documentation => 'Token timeout for forms',
        },
707 708 709 710 711
        issuersTimeout => {
            default       => 120,
            type          => 'int',
            documentation => 'Token timeout for issuers',
        },
712
        requireToken => {
Xavier Guimard's avatar
Xavier Guimard committed
713
            default       => 1,
714
            type          => 'boolOrExpr',
715 716
            documentation => 'Enable token for forms',
        },
717 718 719 720 721
        tokenUseGlobalStorage => {
            default       => 0,
            type          => 'bool',
            documentation => 'Enable global token storage',
        },
722 723 724 725
        cda => {
            default       => 0,
            type          => 'bool',
            documentation => 'Enable Cross Domain Authentication',
Xavier Guimard's avatar
Xavier Guimard committed
726
            flags         => 'hp',
727 728 729 730 731 732
        },
        checkXSS => {
            default       => 1,
            type          => 'bool',
            documentation => 'Check XSS',
        },
733
        portalForceAuthn => {
734
            default => 0,
735
            help    => 'forcereauthn.html',
736 737
            type    => 'bool',
            documentation =>
738
              'Enable force to authenticate when displaying portal',
739
        },
740 741
        portalForceAuthnInterval => {
            default => 5,
742 743
            type    => 'int',
            documentation =>
744
'Maximum interval in seconds since last authentication to force reauthentication',
745
        },
746
        bruteForceProtection => {
747
            default       => 0,
748
            help          => 'bruteforceprotection.html',
749 750 751 752 753 754 755
            type          => 'bool',
            documentation => 'Enable brute force attack protection',
        },
        bruteForceProtectionTempo => {
            default => 30,
            type    => 'int',
            documentation =>
756
              'Brute force attack protection -> Tempo before try again',
757 758 759 760 761
        },
        bruteForceProtectionMaxAge => {
            default => 300,
            type    => 'int',
            documentation =>
762
'Brute force attack protection -> Max age between last and first allowed failed login',
763 764 765 766 767
        },
        bruteForceProtectionMaxFailed => {
            default => 3,
            type    => 'int',
            documentation =>
768
              'Brute force attack protection -> Max allowed failed login',
769
        },
770
        grantSessionRules => {
Xavier Guimard's avatar
Xavier Guimard committed
771
            type          => 'grantContainer',
772
            keyTest       => sub { return perlExpr(@_) },
773
            test          => sub { 1 },
Xavier Guimard's avatar
Xavier Guimard committed
774
            documentation => 'Rules to grant sessions',
775
            default       => {},
776 777 778
        },
        hiddenAttributes => {
            type          => 'text',
779
            default       => '_password _2fDevices',
780 781 782 783 784 785
            documentation => 'Name of attributes to hide in logs',
        },
        key => {
            type          => 'password',
            documentation => 'Secret key',
        },
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
        corsEnabled => {
            default       => 1,
            type          => 'bool',
            documentation => 'Enable Cross-Origin Resource Sharing',
        },
        corsAllow_Credentials => {
            type    => 'text',
            default => 'true',
            documentation =>
              'Allow credentials for Cross-Origin Resource Sharing',
        },
        corsAllow_Headers => {
            type    => 'text',
            default => '*',
            documentation =>
              'Allowed headers for Cross-Origin Resource Sharing',
        },
        corsAllow_Methods => {
            type    => 'text',
            default => 'POST,GET',
            documentation =>
              'Allowed methods for Cross-Origin Resource Sharing',
        },
        corsAllow_Origin => {
            type    => 'text',
            default => '*',
            documentation =>
              'Allowed origine for Cross-Origin Resource Sharing',
        },
        corsExpose_Headers => {
            type    => 'text',
            default => '*',
            documentation =>
              'Exposed headers for Cross-Origin Resource Sharing',
        },
        corsMax_Age => {
            type    => 'text',
823 824
            default => '86400',    # 24 hours
            documentation => 'MAx-age for Cross-Origin Resource Sharing',
825
        },
826 827
        cspDefault => {
            type          => 'text',
Xavier Guimard's avatar
Xavier Guimard committed
828
            default       => "'self'",
829 830
            documentation => 'Default value for Content-Security-Policy',
        },
831
        cspFormAction => {
832 833 834
            type    => 'text',
            default => "'self'",
            documentation =>
835
              'Form action destination for Content-Security-Policy',
836
        },
837 838
        cspImg => {
            type          => 'text',
839
            default       => "'self' data:",
840 841 842 843 844 845 846 847 848
            documentation => 'Image source for Content-Security-Policy',
        },
        cspScript => {
            type          => 'text',
            default       => "'self'",
            documentation => 'Javascript source for Content-Security-Policy',
        },
        cspStyle => {
            type          => 'text',
849
            default       => "'self'",
850 851 852 853 854 855
            documentation => 'Style source for Content-Security-Policy',
        },
        cspConnect => {
            type    => 'text',
            default => "'self'",
            documentation =>
856
              'Authorized Ajax destination for Content-Security-Policy',
857 858 859 860 861 862
        },
        cspFont => {
            type          => 'text',
            default       => "'self'",
            documentation => 'Font source for Content-Security-Policy',
        },
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
        portalAntiFrame => {
            default       => 1,
            type          => 'bool',
            documentation => 'Avoid portal to be displayed inside frames',
        },
        portalCheckLogins => {
            default       => 1,
            type          => 'bool',
            documentation => 'Display login history checkbox in portal',
        },
        randomPasswordRegexp => {
            type          => 'pcre',
            default       => '[A-Z]{3}[a-z]{5}.\d{2}',
            documentation => 'Regular expression to create a random password',
        },
Xavier Guimard's avatar
Xavier Guimard committed
878
        trustedDomains =>
879
          { type => 'text', documentation => 'Trusted domains', },
Xavier Guimard's avatar
Xavier Guimard committed
880
        storePassword => {
881 882 883 884 885 886
            default       => 0,
            type          => 'bool',
            documentation => 'Store password in session',
        },
        timeout => {
            type          => 'int',
Xavier Guimard's avatar
Xavier Guimard committed
887
            test          => sub { $_[0] > 0 },
888 889 890 891
            default       => 72000,
            documentation => 'Session timeout on server side',
        },
        timeoutActivity => {
892
            type          => 'int',
Xavier Guimard's avatar
Xavier Guimard committed
893
            test          => sub { $_[0] >= 0 },
894 895 896
            default       => 0,
            documentation => 'Session activity timeout on server side',
        },
897 898 899 900 901 902
        timeoutActivityInterval => {
            type          => 'int',
            test          => sub { $_[0] >= 0 },
            default       => 60,
            documentation => 'Update session timeout interval on server side',
        },
903 904 905 906 907
        userControl => {
            type          => 'pcre',
            default       => '^[\w\.\-@]+$',
            documentation => 'Regular expression to validate login',
        },
908 909 910 911 912
        browsersDontStorePassword => {
            default       => 0,
            type          => 'bool',
            documentation => 'Avoid browsers to store users password',
        },
913 914 915 916
        useRedirectOnError => {
            type          => 'bool',
            default       => 1,
            documentation => 'Use 302 redirect code for error (500)',
Xavier Guimard's avatar
Xavier Guimard committed
917
            flags         => 'h',
918 919 920 921 922 923 924 925 926
        },
        useRedirectOnForbidden => {
            default       => 0,
            type          => 'bool',
            documentation => 'Use 302 redirect code for forbidden (403)',
        },
        useSafeJail => {
            default       => 1,
            type          => 'bool',
Xavier Guimard's avatar
Xavier Guimard committed
927
            help          => 'safejail.html',
928
            documentation => 'Activate Safe jail',
Xavier Guimard's avatar
Xavier Guimard committed
929
            flags         => 'hp',
930 931 932 933 934
        },
        whatToTrace => {
            type          => 'lmAttrOrMacro',
            default       => 'uid',
            documentation => 'Session parameter used to fill REMOTE_USER',
Xavier Guimard's avatar
Xavier Guimard committed
935
            flags         => 'hp',
936
        },
937 938 939 940 941
        customToTrace => {
            type          => 'lmAttrOrMacro',
            documentation => 'Session parameter used to fill REMOTE_CUSTOM',
            flags         => 'hp',
        },
942
        lwpOpts => {
Xavier Guimard's avatar
Xavier Guimard committed
943 944 945
            type          => 'keyTextContainer',
            documentation => 'Options given to LWP::UserAgent',
        },
946 947 948 949
        lwpSslOpts => {
            type          => 'keyTextContainer',
            documentation => 'SSL options given to LWP::UserAgent',
        },
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988

        # History
        failedLoginNumber => {
            default       => 5,
            type          => 'int',
            documentation => 'Number of failures stored in login history',
        },
        loginHistoryEnabled => {
            default       => 0,
            type          => 'bool',
            documentation => 'Enable login history',
        },
        portalDisplayLoginHistory => {
            type          => 'boolOrExpr',
            default       => 1,
            documentation => 'Display login history tab in portal',
        },
        successLoginNumber => {
            default       => 5,
            type          => 'int',
            documentation => 'Number of success stored in login history',
        },

        # Other displays
        portalDisplayAppslist => {
            type          => 'boolOrExpr',
            default       => 1,
            documentation => 'Display applications tab in portal',
        },
        portalDisplayChangePassword => {
            type          => 'boolOrExpr',
            default       => '$_auth =~ /^(LDAP|DBI|Demo)$/',
            documentation => 'Display password tab in portal',
        },
        portalDisplayLogout => {
            default       => 1,
            type          => 'boolOrExpr',
            documentation => 'Display logout tab in portal',
        },
989 990 991 992 993
        portalDisplayCertificateResetByMail => {
            type          => 'boolOrExpr',
            default       => 0,
            documentation => 'Display Certificate Reset by mail tab in portal',
        },
994 995 996 997 998 999
        portalDisplayRegister => {
            default       => 1,
            type          => 'bool',
            documentation => 'Display register button in portal',
        },
        portalDisplayResetPassword => {
1000
            default       => 0,
1001 1002 1003
            type          => 'bool',
            documentation => 'Display reset password button in portal',
        },
1004
        passwordResetAllowedRetries => {
Christophe Maudoux's avatar
Christophe Maudoux committed
1005
            default       => 3,
1006 1007 1008
            type          => 'int',
            documentation => 'Maximum number of retries to reset password',
        },
1009 1010
        portalDisplayOidcConsents => {
            type          => 'boolOrExpr',
1011
            default       => '$_oidcConnectedRP',
1012 1013
            documentation => 'Display OIDC consent tab in portal',
        },
1014 1015 1016 1017 1018 1019
        portalDisplayGeneratePassword => {
            default => 1,
            type    => 'bool',
            documentation =>
              'Display password generate box in reset password form',
        },
1020 1021

        # Cookies
Xavier Guimard's avatar
Xavier Guimard committed
1022
        cookieExpiration => {
1023
            type          => 'int',
Xavier Guimard's avatar
Xavier Guimard committed
1024 1025 1026
            documentation => 'Cookie expiration',
            flags         => 'hp',
        },
Xavier Guimard's avatar
Xavier Guimard committed
1027
        cookieName => {
1028 1029 1030 1031 1032
            type          => 'text',
            test          => qr/^[a-zA-Z][a-zA-Z0-9_-]*$/,
            msgFail       => '__badCookieName__',
            default       => 'lemonldap',
            documentation => 'Name of the main cookie',
Xavier Guimard's avatar
Xavier Guimard committed
1033
            flags         => 'hp',
1034 1035
        },
        domain => {
1036 1037 1038 1039
            type          => 'text',
            test          => qr/^(?:$Regexp::Common::URI::RFC2396::hostname)?$/,
            msgFail       => '__badDomainName__',
            default       => 'example.com',
1040
            documentation => 'DNS domain',
Xavier Guimard's avatar
Xavier Guimard committed
1041
            flags         => 'hp',
1042
        },
1043 1044 1045 1046 1047 1048 1049 1050
        pdataDomain => {
            type          => 'text',
            test          => qr/^(?:$Regexp::Common::URI::RFC2396::hostname)?$/,
            msgFail       => '__badDomainName__',
            default       => '',
            documentation => 'pdata cookie DNS domain',
            flags         => 'hp',
        },
1051 1052 1053 1054
        httpOnly => {
            default       => 1,
            type          => 'bool',
            documentation => 'Enable httpOnly flag in cookie',
Xavier Guimard's avatar
Xavier Guimard committed
1055
            flags         => 'hp',
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
        },
        securedCookie => {
            type   => 'select',
            select => [
                { k => '0', v => 'unsecuredCookie' },
                { k => '1', v => 'securedCookie' },
                { k => '2', v => 'doubleCookie' },
                { k => '3', v => 'doubleCookieForSingleSession' },
            ],
            default       => 0,
            documentation => 'Cookie securisation method',
Xavier Guimard's avatar
Xavier Guimard committed
1067
            flags         => 'hp',
1068 1069
        },

1070
        # Viewer
1071
        viewerHiddenKeys => {
1072
            type          => 'text',
1073
            default       => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
1074
            documentation => 'Hidden Conf keys',
1075 1076
            flags         => 'm',
        },
1077
        viewerAllowBrowser => {
1078 1079 1080
            type          => 'bool',
            default       => 0,
            documentation => 'Allow configuration browser',
1081
        },
1082 1083 1084 1085 1086
        viewerAllowDiff => {
            type          => 'bool',
            default       => 0,
            documentation => 'Allow configuration diff',
        },
1087

1088
        # Notification
1089
        oldNotifFormat => {
Xavier Guimard's avatar
Xavier Guimard committed
1090 1091
            type          => 'bool',
            default       => 0,
Xavier Guimard's avatar
Xavier Guimard committed
1092
            documentation => 'Use old XML format for notifications',
1093
        },
1094 1095 1096 1097 1098
        notificationWildcard => {
            type          => 'text',
            default       => 'allusers',
            documentation => 'Notification string to match all users',
        },
Xavier Guimard's avatar
Xavier Guimard committed
1099 1100 1101 1102 1103
        notificationXSLTfile => {
            type          => 'text',
            documentation => 'Custom XSLT document for notifications',
        },
        notification => {
1104 1105 1106 1107
            default       => 0,
            type          => 'bool',
            documentation => 'Notification activation',