Attributes.pm 116 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;

9
our $VERSION = '2.0.0';
10 11 12 13
use strict;
use Regexp::Common qw/URI/;

my $perlExpr = sub {
14
    my ( $val, $conf ) = @_;
15
    my $s = '';
Xavier Guimard's avatar
Xavier Guimard committed
16
    no warnings( 'redefine', 'uninitialized' );
17
    eval "$s $val";
18 19 20
    my $err = join( '',
        grep { $_ =~ /Undefined subroutine/ ? () : $_ } split( /\n/, $@ ) );
    return $err ? ( 1, "__badExpression__: $err" ) : (1);
21 22
};

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

27 28 29 30 31
sub types {
    return {

        # Simple text types
        text => {
Clément OUDOT's avatar
Clément OUDOT committed
32
            test    => sub { 1 },
33 34 35
            msgFail => '__malformedValue__',
        },
        password => {
Clément OUDOT's avatar
Clément OUDOT committed
36
            test    => sub { 1 },
37 38 39
            msgFail => '__malformedValue__',
        },
        longtext => {
Clément OUDOT's avatar
Clément OUDOT committed
40
            test => sub { 1 }
41 42 43
        },
        url => {
            form    => 'text',
Xavier Guimard's avatar
Xavier Guimard committed
44
            test    => $url,
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
            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 {
Clément OUDOT's avatar
Clément OUDOT committed
60
                eval { qr/$_[0]/ };
61 62 63 64 65
                return $@ ? ( 0, "__badRegexp__: $@" ) : (1);
            },
        },
        lmAttrOrMacro => {
            form => 'text',
Xavier Guimard's avatar
Xavier Guimard committed
66 67
            test => sub {
                my ( $val, $conf ) = @_;
68
                return 1
Clément OUDOT's avatar
Clément OUDOT committed
69
                  if ( defined $conf->{macros}->{$val}
70
                    or $val eq '_timezone' );
71 72
                foreach ( keys %$conf ) {
                    return 1
Clément OUDOT's avatar
Clément OUDOT committed
73
                      if ( $_ =~ /exportedvars$/i
74
                        and defined $conf->{$_}->{$val} );
Xavier Guimard's avatar
Xavier Guimard committed
75
                }
76
                return ( 1, "__unknownAttrOrMacro__: $val" );
Xavier Guimard's avatar
Xavier Guimard committed
77
            },
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
        },

        # 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 => {
            test    => $perlExpr,
            msgFail => '__notAValidPerlExpression__',
        },
Xavier Guimard's avatar
Xavier Guimard committed
97 98
        keyTextContainer => {
            test       => qr/./,
Xavier Guimard's avatar
Xavier Guimard committed
99
            msgFail    => '__emptyValueNotAllowed__',
Xavier Guimard's avatar
Xavier Guimard committed
100
            keyTest    => qr/^\w[\w\.\-]*$/,
Xavier Guimard's avatar
Xavier Guimard committed
101
            keyMsgFail => '__badKeyName__',
Xavier Guimard's avatar
Xavier Guimard committed
102 103 104
        },
        subContainer => {
            keyTest => qr/\w/,
Clément OUDOT's avatar
Clément OUDOT committed
105
            test    => sub { 1 },
Xavier Guimard's avatar
Xavier Guimard committed
106
        },
Xavier Guimard's avatar
Xavier Guimard committed
107 108
        select => {
            test => sub {
109
                my $test = grep ( { $_ eq $_[0] }
Xavier Guimard's avatar
Xavier Guimard committed
110
                    map ( { $_->{k} } @{ $_[2]->{select} } ) );
Xavier Guimard's avatar
Xavier Guimard committed
111
                return $test
Clément OUDOT's avatar
Clément OUDOT committed
112 113
                  ? 1
                  : ( 1, "Invalid value '$_[0]' for this select" );
Xavier Guimard's avatar
Xavier Guimard committed
114 115
            },
        },
116 117 118

        # Files type (long text)
        file => {
Clément OUDOT's avatar
Clément OUDOT committed
119
            test => sub { 1 }
120 121
        },
        RSAPublicKey => {
122
            test => sub {
123
                return (
Clément OUDOT's avatar
Clément OUDOT committed
124 125
                    $_[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
126
                    ? (1)
127 128
                    : ( 1, '__badPemEncoding__' )
                );
129
            },
130
        },
131
        'RSAPublicKeyOrCertificate' => {
132
            'test' => sub {
133
                return (
Clément OUDOT's avatar
Clément OUDOT committed
134 135
                    $_[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
136
                    ? (1)
137 138
                    : ( 1, '__badPemEncoding__' )
                );
139
            },
140
        },
141
        RSAPrivateKey => {
142
            test => sub {
143
                return (
Clément OUDOT's avatar
Clément OUDOT committed
144 145
                    $_[0] =~
/^(?:(?:\-+\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
146
                    ? (1)
147 148
                    : ( 1, '__badPemEncoding__' )
                );
149
            },
150 151 152
        },

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

sub attributes {
    return {

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

431 432 433 434 435 436 437 438 439
        # Loggers (ini only)
        logLevel => {
            type          => 'text',
            documentation => 'Log level, must be set in .ini',
            flags         => 'hmp',
        },
        logger => {
            type          => 'text',
            documentation => 'technical logger',
440
            flags         => 'hmp',
441 442 443 444
        },
        userLogger => {
            type          => 'text',
            documentation => 'User actions logger',
445
            flags         => 'hmp',
446 447 448 449
        },
        log4perlConfFile => {
            type          => 'text',
            documentation => 'Log4Perl logger configuration file',
450
            flags         => 'hmp',
451 452 453 454
        },
        sentryDsn => {
            type          => 'text',
            documentation => 'Sentry logger DSN',
455
            flags         => 'hmp',
456 457 458 459
        },
        syslogFacility => {
            type          => 'text',
            documentation => 'Syslog logger technical facility',
460
            flags         => 'hmp',
461 462 463 464
        },
        userSyslogFacility => {
            type          => 'text',
            documentation => 'Syslog logger user-actions facility',
465
            flags         => 'hmp',
466 467 468
        },

        # Manager or PSGI protected apps
469
        protection => {
Clément OUDOT's avatar
Clément OUDOT committed
470 471 472
            type          => 'text',
            test          => qr/^(?:none|authenticate|manager|)$/,
            msgFail       => '__authorizedValues__: none authenticate manager',
473
            documentation => 'Manager protection method',
Xavier Guimard's avatar
Xavier Guimard committed
474
            flags         => 'hm',
475 476 477 478 479 480 481 482 483 484
        },

        # Menu
        activeTimer => {
            type          => 'bool',
            default       => 1,
            documentation => 'Enable timers on portal pages',
        },
        applicationList => {
            type    => 'catAndAppList',
485
            keyTest => qr/\w/,
486 487
            help    => 'portalmenu.html#categories_and_applications',
            default => {
Clément OUDOT's avatar
Clément OUDOT committed
488
                default => { catname => 'Default category', type => "category" }
489 490 491
            },
            documentation => 'Applications list',
        },
492 493 494 495 496
        portalErrorOnExpiredSession => {
            type          => 'bool',
            default       => 1,
            documentation => 'Show error if session is expired',
        },
497
        portalErrorOnMailNotFound => {
dcoutadeur dcoutadeur's avatar
dcoutadeur dcoutadeur committed
498 499 500
            type    => 'bool',
            default => 0,
            documentation =>
Clément OUDOT's avatar
Clément OUDOT committed
501
              'Show error if mail is not found in password reset process',
502
        },
503 504 505 506 507 508 509 510 511 512 513 514 515 516
        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
517
            select        => [ { k => 'bootstrap', v => 'Bootstrap' }, ],
518 519 520 521 522 523
        },
        portalSkinBackground => {
            type          => 'portalskinbackground',
            documentation => 'Background image of portal skin',
            select        => [
                { k => "", v => 'None' },
Clément OUDOT's avatar
Clément OUDOT committed
524 525
                {
                    k => "1280px-Anse_Source_d'Argent_2-La_Digue.jpg",
526 527
                    v => 'Anse'
                },
Clément OUDOT's avatar
Clément OUDOT committed
528 529 530
                {
                    k =>
"1280px-Autumn-clear-water-waterfall-landscape_-_Virginia_-_ForestWander.jpg",
531 532 533
                    v => 'Waterfall'
                },
                { k => "1280px-BrockenSnowedTrees.jpg", v => 'Snowed Trees' },
Clément OUDOT's avatar
Clément OUDOT committed
534 535
                {
                    k => "1280px-Cedar_Breaks_National_Monument_partially.jpg",
536 537
                    v => 'National Monument'
                },
Clément OUDOT's avatar
Clément OUDOT committed
538 539
                {
                    k => "1280px-Parry_Peak_from_Winter_Park.jpg",
540 541
                    v => 'Winter'
                },
Clément OUDOT's avatar
Clément OUDOT committed
542 543
                {
                    k => "Aletschgletscher_mit_Pinus_cembra1.jpg",
544 545
                    v => 'Pinus'
                },
546 547 548
            ],
        },
        portalSkinRules => {
Xavier Guimard's avatar
Xavier Guimard committed
549 550 551 552 553 554 555
            type          => 'keyTextContainer',
            help          => 'portalcustom.html',
            keyTest       => $perlExpr,
            keyMsgFail    => '__badSkinRule__',
            test          => qr/^\w+$/,
            msgFail       => '__badValue__',
            documentation => 'Rules to choose portal skin',
556 557 558
        },

        # Security
559
        formTimeout => {
Xavier Guimard's avatar
Xavier Guimard committed
560 561
            default       => 120,
            type          => 'int',
562 563 564
            documentation => 'Token timeout for forms',
        },
        requireToken => {
Xavier Guimard's avatar
Xavier Guimard committed
565 566
            default       => 1,
            type          => 'bool',
567 568
            documentation => 'Enable token for forms',
        },
569 570 571 572 573
        tokenUseGlobalStorage => {
            default       => 0,
            type          => 'bool',
            documentation => 'Enable global token storage',
        },
574 575 576 577
        cda => {
            default       => 0,
            type          => 'bool',
            documentation => 'Enable Cross Domain Authentication',
Xavier Guimard's avatar
Xavier Guimard committed
578
            flags         => 'hp',
579 580 581 582 583 584
        },
        checkXSS => {
            default       => 1,
            type          => 'bool',
            documentation => 'Check XSS',
        },
585
        portalForceAuthn => {
586
            default => 0,
587
            help    => 'forcereauthn.html',
588 589
            type    => 'bool',
            documentation =>
Clément OUDOT's avatar
Clément OUDOT committed
590
              'Enable force to authenticate when displaying portal',
591
        },
592 593
        portalForceAuthnInterval => {
            default => 5,
594 595
            type    => 'int',
            documentation =>
Clément OUDOT's avatar
Clément OUDOT committed
596
'Maximun interval in seconds since last authentifcation to force reauthentication',
597
        },
598
        bruteForceProtection => {
599
            default       => 0,
600
            help          => 'bruteforceprotection.html',
601 602 603 604 605 606 607
            type          => 'bool',
            documentation => 'Enable brute force attack protection',
        },
        bruteForceProtectionTempo => {
            default => 30,
            type    => 'int',
            documentation =>
Clément OUDOT's avatar
Clément OUDOT committed
608
              'Brute force attack protection -> Tempo before try again',
609 610 611 612 613
        },
        bruteForceProtectionMaxAge => {
            default => 300,
            type    => 'int',
            documentation =>
Clément OUDOT's avatar
Clément OUDOT committed
614
              'Brute force attack protection -> Max age third failed login',
615
        },
616
        grantSessionRules => {
Xavier Guimard's avatar
Xavier Guimard committed
617 618
            type          => 'grantContainer',
            keyTest       => $perlExpr,
Clément OUDOT's avatar
Clément OUDOT committed
619
            test          => sub { 1 },
Xavier Guimard's avatar
Xavier Guimard committed
620
            documentation => 'Rules to grant sessions',
621 622 623 624 625 626 627 628 629 630
        },
        hiddenAttributes => {
            type          => 'text',
            default       => '_password',
            documentation => 'Name of attributes to hide in logs',
        },
        key => {
            type          => 'password',
            documentation => 'Secret key',
        },
631 632
        cspDefault => {
            type          => 'text',
Xavier Guimard's avatar
Xavier Guimard committed
633
            default       => "'self'",
634 635
            documentation => 'Default value for Content-Security-Policy',
        },
636
        cspFormAction => {
637 638 639 640
            type    => 'text',
            default => "'self'",
            documentation =>
              'Form action destination for Content-Security-Policy',
641
        },
642 643
        cspImg => {
            type          => 'text',
644
            default       => "'self' data:",
645 646 647 648 649 650 651 652 653
            documentation => 'Image source for Content-Security-Policy',
        },
        cspScript => {
            type          => 'text',
            default       => "'self'",
            documentation => 'Javascript source for Content-Security-Policy',
        },
        cspStyle => {
            type          => 'text',
654
            default       => "'self'",
655 656 657 658 659 660
            documentation => 'Style source for Content-Security-Policy',
        },
        cspConnect => {
            type    => 'text',
            default => "'self'",
            documentation =>
Christophe Maudoux's avatar
Typo  
Christophe Maudoux committed
661
              'Authorized Ajax destination for Content-Security-Policy',
662 663 664 665 666 667
        },
        cspFont => {
            type          => 'text',
            default       => "'self'",
            documentation => 'Font source for Content-Security-Policy',
        },
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
        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
683
        trustedDomains =>
Clément OUDOT's avatar
Clément OUDOT committed
684
          { type => 'text', documentation => 'Trusted domains', },
Xavier Guimard's avatar
Xavier Guimard committed
685
        storePassword => {
686 687 688 689 690 691
            default       => 0,
            type          => 'bool',
            documentation => 'Store password in session',
        },
        timeout => {
            type          => 'int',
Xavier Guimard's avatar
Xavier Guimard committed
692
            test          => sub { $_[0] > 0 },
693 694 695 696
            default       => 72000,
            documentation => 'Session timeout on server side',
        },
        timeoutActivity => {
697
            type          => 'int',
Xavier Guimard's avatar
Xavier Guimard committed
698
            test          => sub { $_[0] >= 0 },
699 700 701
            default       => 0,
            documentation => 'Session activity timeout on server side',
        },
702 703 704 705 706 707
        timeoutActivityInterval => {
            type          => 'int',
            test          => sub { $_[0] >= 0 },
            default       => 60,
            documentation => 'Update session timeout interval on server side',
        },
708 709 710 711 712 713 714 715 716 717 718 719 720 721
        trustedProxies => {
            type          => 'text',
            default       => '',
            documentation => 'Trusted proxies',
        },
        userControl => {
            type          => 'pcre',
            default       => '^[\w\.\-@]+$',
            documentation => 'Regular expression to validate login',
        },
        useRedirectOnError => {
            type          => 'bool',
            default       => 1,
            documentation => 'Use 302 redirect code for error (500)',
Xavier Guimard's avatar
Xavier Guimard committed
722
            flags         => 'h',
723 724 725 726 727 728 729 730 731
        },
        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
732
            help          => 'safejail.html',
733
            documentation => 'Activate Safe jail',
Xavier Guimard's avatar
Xavier Guimard committed
734
            flags         => 'hp',
735 736 737 738 739
        },
        whatToTrace => {
            type          => 'lmAttrOrMacro',
            default       => 'uid',
            documentation => 'Session parameter used to fill REMOTE_USER',
Xavier Guimard's avatar
Xavier Guimard committed
740
            flags         => 'hp',
741
        },
742
        lwpOpts => {
Xavier Guimard's avatar
Xavier Guimard committed
743 744 745
            type          => 'keyTextContainer',
            documentation => 'Options given to LWP::UserAgent',
        },
746 747 748 749
        lwpSslOpts => {
            type          => 'keyTextContainer',
            documentation => 'SSL options given to LWP::UserAgent',
        },
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794

        # 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',
        },
        portalDisplayRegister => {
            default       => 1,
            type          => 'bool',
            documentation => 'Display register button in portal',
        },
        portalDisplayResetPassword => {
795
            default       => 0,
796 797 798
            type          => 'bool',
            documentation => 'Display reset password button in portal',
        },
799
        passwordResetAllowedRetries => {
Christophe Maudoux's avatar
Christophe Maudoux committed
800
            default       => 3,
801 802 803
            type          => 'int',
            documentation => 'Maximum number of retries to reset password',
        },
804 805
        portalDisplayOidcConsents => {
            type          => 'boolOrExpr',
806
            default       => '$_oidcConnectedRP',
807 808
            documentation => 'Display OIDC consent tab in portal',
        },
809 810

        # Cookies
Xavier Guimard's avatar
Xavier Guimard committed
811
        cookieExpiration => {
812
            type          => 'int',
Xavier Guimard's avatar
Xavier Guimard committed
813 814 815
            documentation => 'Cookie expiration',
            flags         => 'hp',
        },
Xavier Guimard's avatar
Xavier Guimard committed
816
        cookieName => {
817 818 819 820 821
            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
822
            flags         => 'hp',
823 824
        },
        domain => {
Clément OUDOT's avatar
Clément OUDOT committed
825 826 827 828
            type          => 'text',
            test          => qr/^(?:$Regexp::Common::URI::RFC2396::hostname)?$/,
            msgFail       => '__badDomainName__',
            default       => 'example.com',
829
            documentation => 'DNS domain',
Xavier Guimard's avatar
Xavier Guimard committed
830
            flags         => 'hp',
831 832 833 834 835
        },
        httpOnly => {
            default       => 1,
            type          => 'bool',
            documentation => 'Enable httpOnly flag in cookie',
Xavier Guimard's avatar
Xavier Guimard committed
836
            flags         => 'hp',
837 838 839 840 841 842 843 844 845 846 847
        },
        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
848
            flags         => 'hp',
849 850 851
        },

        # Notification
852
        oldNotifFormat => {
Xavier Guimard's avatar
Xavier Guimard committed
853 854
            type          => 'bool',
            default       => 0,
Xavier Guimard's avatar
Xavier Guimard committed
855
            documentation => 'Use old XML format for notifications',
856
        },
857 858 859 860 861
        notificationWildcard => {
            type          => 'text',
            default       => 'allusers',
            documentation => 'Notification string to match all users',
        },
Xavier Guimard's avatar
Xavier Guimard committed
862 863 864 865 866
        notificationXSLTfile => {
            type          => 'text',
            documentation => 'Custom XSLT document for notifications',
        },
        notification => {
867 868 869 870
            default       => 0,
            type          => 'bool',
            documentation => 'Notification activation',
        },
871 872 873 874 875
        notificationServer => {
            default       => 0,
            type          => 'bool',
            documentation => 'Notification server activation',
        },
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
        notificationStorage => {
            type          => 'PerlModule',
            default       => 'File',
            documentation => 'Notification backend',
        },
        notificationStorageOptions => {
            type    => 'keyTextContainer',
            default => { dirName => '/var/lib/lemonldap-ng/notifications', },
            documentation => 'Notification backend options',
        },

        # Captcha
        captcha_login_enabled => {
            default       => 0,
            type          => 'bool',
            documentation => 'Captcha on login page',
        },
        captcha_mail_enabled => {
894
            default       => 1,
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
            type          => 'bool',
            documentation => 'Captcha on password reset page',
        },
        captcha_register_enabled => {
            default       => 1,
            type          => 'bool',
            documentation => 'Captcha on account creation page',
        },
        captcha_size => {
            type          => 'int',
            default       => 6,
            documentation => 'Captcha size',
        },

        # Variables
        exportedVars => {
            type          => 'keyTextContainer',
            help          => 'exportedvars.html',
            keyTest       => qr/^!?[_a-zA-Z][a-zA-Z0-9_]*$/,
Xavier Guimard's avatar
Xavier Guimard committed
914
            keyMsgFail    => '__badVariableName__',
915 916 917 918 919 920 921 922
            test          => qr/^[_a-zA-Z][a-zA-Z0-9_:\-]*$/,
            msgFail       => '__badValue__',
            default       => { 'UA' => 'HTTP_USER_AGENT' },
            documentation => 'Main exported variables',
        },
        groups => {
            type => 'keyTextContainer',
            help =>
Clément OUDOT's avatar
Clément OUDOT committed
923
              'exportedvars.html#extend_variables_using_macros_and_groups',
924 925 926 927 928 929 930
            test          => $perlExpr,
            default       => {},
            documentation => 'Groups',
        },
        macros => {
            type => 'keyTextContainer',
            help =>
Clément OUDOT's avatar
Clément OUDOT committed
931
              'exportedvars.html#extend_variables_using_macros_and_groups',
932
            keyTest       => qr/^[_a-zA-Z][a-zA-Z0-9_]*$/,
Xavier Guimard's avatar
Xavier Guimard committed
933
            keyMsgFail    => '__badMacroName__',
934 935 936 937 938 939 940 941 942 943
            test          => $perlExpr,
            default       => {},
            documentation => 'Macros',
        },

        # Storage
        globalStorage => {
            type          => 'PerlModule',
            default       => 'Apache::Session::File',
            documentation => 'Session backend module',
Xavier Guimard's avatar
Xavier Guimard committed
944
            flags         => 'hp',
945 946 947 948 949 950 951
        },
        globalStorageOptions => {
            type    => 'keyTextContainer',
            default => {
                'Directory'     => '/var/lib/lemonldap-ng/sessions/',
                'LockDirectory' => '/var/lib/lemonldap-ng/sessions/lock/',
                'generateModule' =>
Clément OUDOT's avatar
Clément OUDOT committed
952
                  'Lemonldap::NG::Common::Apache::Session::Generate::SHA256',
953 954
            },
            documentation => 'Session backend module options',
Xavier Guimard's avatar
Xavier Guimard committed
955
            flags         => 'hp',
956 957
        },
        localSessionStorage => {
Xavier Guimard's avatar
Xavier Guimard committed
958 959
            type          => 'PerlModule',
            default       => 'Cache::FileCache',
Xavier Guimard's avatar
Xavier Guimard committed
960
            documentation => 'Local sessions cache module',
961 962 963 964 965 966 967 968 969 970 971 972 973 974
        },
        localSessionStorageOptions => {
            type    => 'keyTextContainer',
            default => {
                'namespace'          => 'lemonldap-ng-sessions',
                'default_expires_in' => 600,
                'directory_umask'    => '007',
                'cache_root'         => '/tmp',
                'cache_depth'        => 3,
            },
            documentation => 'Sessions cache module options',
        },

        # Persistent storage
Xavier Guimard's avatar
Xavier Guimard committed
975 976 977 978 979 980 981 982 983 984 985 986 987
        persistentStorage => {
            type          => 'PerlModule',
            documentation => 'Storage module for persistent sessions'
        },
        persistentStorageOptions => {
            type          => 'keyTextContainer',
            documentation => 'Options for persistent sessions storage module'
        },
        sessionDataToRemember => {
            type          => 'keyTextContainer',
            keyTest       => qr/^[_a-zA-Z][a-zA-Z0-9_]*$/,
            keyMsgFail    => '__invalidSessionData__',
            documentation => 'Data to remember in login history',
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
        },

        # SAML issuer
        issuerDBSAMLActivation => {
            default       => 0,
            type          => 'bool',
            documentation => 'SAML IDP activation',
        },
        issuerDBSAMLPath => {
            type          => 'pcre',
            default       => '^/saml/',
            documentation => 'SAML IDP request path',
        },
        issuerDBSAMLRule => {
            type          => 'boolOrExpr',
            default       => 1,
            documentation => 'SAML IDP rule',
        },

        # OpenID-Connect issuer
        issuerDBOpenIDConnectActivation => {
            type          => 'bool',
1010
            default       => 0,
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
            documentation => 'OpenID Connect server activation',
        },
        issuerDBOpenIDConnectPath => {
            type          => 'text',
            default       => '^/oauth2/',
            documentation => 'OpenID Connect server request path',
        },
        issuerDBOpenIDConnectRule => {
            type          => 'boolOrExpr',
            default       => 1,
            documentation => 'OpenID Connect server rule',
        },

1024 1025 1026
        # GET issuer
        issuerDBGetActivation => {
            type          => 'bool',
1027
            default       => 0,
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
            documentation => 'Get issuer activation',
        },
        issuerDBGetPath => {
            type          => 'text',
            default       => '^/get/',
            documentation => 'Get issuer request path',
        },
        issuerDBGetRule => {
            type          => 'boolOrExpr',
            default       => 1,
            documentation => 'Get issuer rule',
        },
        issuerDBGetParameters => {
            type       => 'doubleHash',
            default    => {},
            keyTest    => qr/^$Regexp::Common::URI::RFC2396::hostname$/,
            keyMsgFail => '__badHostname__',
            test       => {
                keyTest    => qr/^(?=[^\-])[\w\-]+(?<=[^-])$/,
                keyMsgFail => '__badKeyName__',
                test       => sub {
                    my ( $val, $conf ) = @_;
1050
                    return 1
Clément OUDOT's avatar
Clément OUDOT committed
1051
                      if ( defined $conf->{macros}->{$val}
1052 1053 1054
                        or $val eq '_timezone' );
                    foreach ( keys %$conf ) {
                        return 1
Clément OUDOT's avatar
Clément OUDOT committed
1055
                          if ( $_ =~ /exportedvars$/i
1056
                            and defined $conf->{$_}->{$val} );
1057
                    }
1058
                    return ( 1, "__unknownAttrOrMacro__: $val" );
1059 1060 1061 1062 1063
                },
            },
            documentation => 'List of virtualHosts with their get parameters',
        },

1064 1065 1066 1067 1068 1069 1070
        # Password
        mailOnPasswordChange => {
            default       => 0,
            type          => 'bool',
            documentation => 'Send a mail when password is changed',
        },
        portalRequireOldPassword => {
Clément OUDOT's avatar
Clément OUDOT committed
1071 1072 1073
            default       => 1,
            type          => 'bool',
            documentation => 'Old password is required to change the password',
1074 1075 1076 1077 1078 1079 1080 1081
        },
        hideOldPassword => {
            default       => 0,
            type          => 'bool',
            documentation => 'Hide old password in portal',
        },

        # Mails
Xavier Guimard's avatar
Xavier Guimard committed
1082
        mailBody =>
Clément OUDOT's avatar
Clément OUDOT committed
1083
          { type => 'longtext', documentation => 'Custom mail body', },
1084 1085 1086 1087 1088
        mailCharset => {
            type          => 'text',
            default       => 'utf-8',
            documentation => 'Mail charset',
        },
1089 1090 1091 1092
        mailConfirmBody => {
            type          => 'longtext',
            documentation => 'Custom confirm mail body',
        },
1093 1094 1095 1096 1097 1098 1099 1100 1101
        mailConfirmSubject => {
            type          => 'text',
            documentation => 'Mail subject for reset confirmation',
        },
        mailFrom => {
            type          => 'text',
            default       => 'noreply@example.com',
            documentation => 'Sender email',
        },
Clément OUDOT's avatar
Clément OUDOT committed
1102
        mailReplyTo => { type => 'text', documentation => 'Reply-To address' },
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
        mailSessionKey => {
            type          => 'text',
            default       => 'mail',
            documentation => 'Session parameter where mail is stored',
        },
        mailSubject => {
            type          => 'text',
            documentation => 'Mail subject for new password email',
        },
        mailTimeout => {
            type          => 'int',
            default       => 0,
            documentation => 'Mail session timeout',
        },
        mailUrl => {
            type          => 'url',
1119
            default       => 'http://auth.example.com/resetpwd',
1120 1121 1122
            documentation => 'URL of password reset page',
        },
        SMTPServer => {
1123 1124
            type    => 'text',
            default => '',
Clément OUDOT's avatar
Clément OUDOT committed
1125
            test    => qr/^(?:$Regexp::Common::URI::RFC2396::host(?::\d+)?)?$/,
1126 1127
            documentation => 'SMTP Server',
        },
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
        SMTPPort => {
            type          => 'int',
            documentation => 'Fix SMTP port',
        },
        SMTPTLS => {
            type    => 'select',
            default => '',
            select  => [
                { k => '',         v => 'none' },
                { k => 'starttls', v => 'SMTP + STARTTLS' },
                { k => 'ssl',      v => 'SMTPS' },
            ],
            documentation => 'TLS protocol to use with SMTP',
        },
        SMTPTLSOpts => {
            type          => 'keyTextContainer',
            documentation => 'TLS/SSL options for SMTP',
        },
Xavier Guimard's avatar
Xavier Guimard committed
1146 1147 1148 1149 1150 1151 1152 1153
        SMTPAuthUser => {
            type          => 'text',
            documentation => 'Login to use to send mails',
        },
        SMTPAuthPass => {
            type          => 'password',
            documentation => 'Password to use to send mails',
        },
1154 1155 1156 1157 1158 1159 1160 1161 1162

        # Registration
        registerConfirmSubject => {
            type          => 'text',
            documentation => 'Mail subject for register confirmation',
        },
        registerDB => {
            type   => 'select',
            select => [
1163 1164 1165 1166 1167
                { k => 'AD',     v => 'Active Directory' },
                { k => 'Demo',   v => 'Demonstration' },
                { k => 'LDAP',   v => 'LDAP' },
                { k => 'Null',   v => 'None' },
                { k => 'Custom', v => 'customModule' },
1168
            ],
1169
            default       => 'Null',
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
            documentation => 'Register module',
        },
        registerDoneSubject => {
            type          => 'text',
            documentation => 'Mail subject when register is done',
        },
        registerTimeout => {
            default       => 0,
            type          => 'int',
            documentation => 'Register session timeout',
        },
1181 1182
        registerUrl => {
            type          => 'text',
1183
            default       => 'http://auth.example.com/register',
1184 1185
            documentation => 'URL of register page',
        },
1186

1187 1188 1189
        # Upgrade session
        upgradeSession => {
            type          => 'bool',
1190
            default       => 1,
1191 1192
            documentation => 'Upgrade session activation',
        },
1193

1194 1195 1196 1197
        # 2F
        max2FDevices => {
            default       => 10,
            type          => 'int',
1198
            documentation => 'Maximum registered 2F devices',
1199 1200 1201 1202
        },
        max2FDevicesNameLength => {
            default       => 20,
            type          => 'int',
1203
            documentation => 'Maximum 2F devices name length',
1204
        },
1205

Xavier Guimard's avatar
Xavier Guimard committed
1206 1207
        # U2F
        u2fActivation => {
Xavier Guimard's avatar
Xavier Guimard committed
1208
            type          => 'boolOrExpr',
Xavier Guimard's avatar
Xavier Guimard committed
1209 1210 1211
            default       => 0,