Manage CORS headers (#1765)
This commit is contained in:
parent
7ab5c3e654
commit
132e57b4b3
|
@ -24,7 +24,7 @@ use constant MANAGERSECTION => "manager";
|
|||
use constant SESSIONSEXPLORERSECTION => "sessionsExplorer";
|
||||
use constant APPLYSECTION => "apply";
|
||||
our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|(?:(?:d(?:emo|bi)|facebook|webID)ExportedVa|exported(?:Heade|Va)|issuerDBGetParamete)r|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|macro)s|o(?:idc(?:RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node)|S(?:erviceMetaDataAuthnContext|torageOptions))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars)|c(?:as(?:S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions)|A(?:ppMetaData(?:(?:ExportedVar|Option)s|Node)|ttributes))|(?:ustomAddParam|ombModule)s)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|a(?:ut(?:hChoiceMod|oSigninR)ules|pplicationList)|v(?:hostOptions|irtualHost)|S(?:MTPTLSOpts|SLVarIf))$/;
|
||||
our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|ingle(?:Session(?:UserByIP)?|(?:UserBy)?IP)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|howLanguages|slByAjax)|o(?:idc(?:ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|RPMetaDataOptions(?:LogoutSessionRequired|BypassConsent|RequirePKCE|Public)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:ErrorOn(?:ExpiredSession|MailNotFound)|DisplayRe(?:setPassword|gister)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|da)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonation(?:SkipEmptyValue|MergeSSOgroup)s)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|no(?:tif(?:ication(?:Server)?|y(?:Deleted|Other))|AjaxHook)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|(?:(?:rest(?:Session|Config)|wsdl)Serv|activeTim)er|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|dbiDynamicHashEnabled|bruteForceProtection)$/;
|
||||
our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|ingle(?:Session(?:UserByIP)?|(?:UserBy)?IP)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|howLanguages|slByAjax)|o(?:idc(?:ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|RPMetaDataOptions(?:LogoutSessionRequired|BypassConsent|RequirePKCE|Public)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:ErrorOn(?:ExpiredSession|MailNotFound)|DisplayRe(?:setPassword|gister)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|orsEnabled|da)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonation(?:SkipEmptyValue|MergeSSOgroup)s)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|no(?:tif(?:ication(?:Server)?|y(?:Deleted|Other))|AjaxHook)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|(?:(?:rest(?:Session|Config)|wsdl)Serv|activeTim)er|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|dbiDynamicHashEnabled|bruteForceProtection)$/;
|
||||
|
||||
our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' );
|
||||
|
||||
|
|
|
@ -33,6 +33,13 @@ sub defaultValues {
|
|||
'checkXSS' => 1,
|
||||
'confirmFormMethod' => 'post',
|
||||
'cookieName' => 'lemonldap',
|
||||
'corsAllow_Credentials' => 'true',
|
||||
'corsAllow_Headers' => '*',
|
||||
'corsAllow_Methods' => 'POST,GET',
|
||||
'corsAllow_Origin' => '*',
|
||||
'corsEnabled' => 1,
|
||||
'corsExpose_Headers' => '*',
|
||||
'corsMax_Age' => '86400',
|
||||
'cspConnect' => '\'self\'',
|
||||
'cspDefault' => '\'self\'',
|
||||
'cspFont' => '\'self\'',
|
||||
|
|
|
@ -940,6 +940,34 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
|
|||
'test' => qr/^[a-zA-Z][a-zA-Z0-9_-]*$/,
|
||||
'type' => 'text'
|
||||
},
|
||||
'corsAllow_Credentials' => {
|
||||
'default' => 'true',
|
||||
'type' => 'text'
|
||||
},
|
||||
'corsAllow_Headers' => {
|
||||
'default' => '*',
|
||||
'type' => 'text'
|
||||
},
|
||||
'corsAllow_Methods' => {
|
||||
'default' => 'POST,GET',
|
||||
'type' => 'text'
|
||||
},
|
||||
'corsAllow_Origin' => {
|
||||
'default' => '*',
|
||||
'type' => 'text'
|
||||
},
|
||||
'corsEnabled' => {
|
||||
'default' => 1,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'corsExpose_Headers' => {
|
||||
'default' => '*',
|
||||
'type' => 'text'
|
||||
},
|
||||
'corsMax_Age' => {
|
||||
'default' => '86400',
|
||||
'type' => 'text'
|
||||
},
|
||||
'cspConnect' => {
|
||||
'default' => '\'self\'',
|
||||
'type' => 'text'
|
||||
|
|
|
@ -705,6 +705,47 @@ sub attributes {
|
|||
type => 'password',
|
||||
documentation => 'Secret key',
|
||||
},
|
||||
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',
|
||||
default => '86400', # 24 hours
|
||||
documentation =>
|
||||
'MAx-age for Cross-Origin Resource Sharing',
|
||||
},
|
||||
cspDefault => {
|
||||
type => 'text',
|
||||
default => "'self'",
|
||||
|
|
|
@ -805,6 +805,17 @@ sub tree {
|
|||
'cspConnect',
|
||||
]
|
||||
},
|
||||
{
|
||||
title => 'crossOrigineResourceSharing',
|
||||
help => 'security.html#portal',
|
||||
form => 'simpleInputContainer',
|
||||
nodes => [
|
||||
'corsEnabled', 'corsAllow_Credentials',
|
||||
'corsAllow_Headers', 'corsAllow_Methods',
|
||||
'corsAllow_Origin', 'corsExpose_Headers',
|
||||
'corsMax_Age',
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -147,6 +147,14 @@
|
|||
"cspStyle":"مصدر الأسلوب ",
|
||||
"cspConnect":"وجهات أجاكس",
|
||||
"cspFont":" مصدر نوع الخط",
|
||||
"crossOrigineResourceSharing":"Cross-Origin Resource Sharing",
|
||||
"corsEnabled":"Activation",
|
||||
"corsAllow_Credentials":"Access-Control-Allow-Credentials",
|
||||
"corsAllow_Headers":"Access-Control-Allow-Headers",
|
||||
"corsAllow_Methods":"Access-Control-Allow-Methods",
|
||||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"استئنف",
|
||||
"cfgVersion":"عملية ضبط الإصدارات",
|
||||
"checkXSS":"تحقق من هجمات XSS",
|
||||
|
|
|
@ -147,6 +147,14 @@
|
|||
"cspStyle":"Style source",
|
||||
"cspConnect":"Ajax destinations",
|
||||
"cspFont":"Font source",
|
||||
"crossOrigineResourceSharing":"Cross-Origin Resource Sharing",
|
||||
"corsEnabled":"Activation",
|
||||
"corsAllow_Credentials":"Access-Control-Allow-Credentials",
|
||||
"corsAllow_Headers":"Access-Control-Allow-Headers",
|
||||
"corsAllow_Methods":"Access-Control-Allow-Methods",
|
||||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"Resume",
|
||||
"cfgVersion":"Configuration version",
|
||||
"checkXSS":"Check XSS attacks",
|
||||
|
|
|
@ -147,6 +147,14 @@
|
|||
"cspStyle":"Style source",
|
||||
"cspConnect":"Ajax destinations",
|
||||
"cspFont":"Font source",
|
||||
"crossOrigineResourceSharing":"Cross-Origin Resource Sharing",
|
||||
"corsEnabled":"Activation",
|
||||
"corsAllow_Credentials":"Access-Control-Allow-Credentials",
|
||||
"corsAllow_Headers":"Access-Control-Allow-Headers",
|
||||
"corsAllow_Methods":"Access-Control-Allow-Methods",
|
||||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"Resume",
|
||||
"cfgVersion":"Configuration version",
|
||||
"checkXSS":"Check XSS attacks",
|
||||
|
|
|
@ -147,6 +147,14 @@
|
|||
"cspStyle":"Sources des styles",
|
||||
"cspConnect":"Destinations des requêtes AJAX",
|
||||
"cspFont":"Sources des polices",
|
||||
"crossOrigineResourceSharing":"Partage des ressources entre origines multiples",
|
||||
"corsEnabled":"Activation",
|
||||
"corsAllow_Credentials":"Informations d'authentification autorisées",
|
||||
"corsAllow_Headers":"Entêtes autorisés",
|
||||
"corsAllow_Methods":"Méthodes autorisées",
|
||||
"corsAllow_Origin":"Origine autorisée",
|
||||
"corsExpose_Headers":"Entêtes en liste blanche",
|
||||
"corsMax_Age":"Durée de mise en cache de la requête préliminaire",
|
||||
"cfgLog":"Résumé",
|
||||
"cfgVersion":"Version de la configuration",
|
||||
"checkXSS":"Contrôler les attaques XSS",
|
||||
|
|
|
@ -147,6 +147,14 @@
|
|||
"cspStyle":"Origine di stile",
|
||||
"cspConnect":"Destinazioni Ajax",
|
||||
"cspFont":"Origine carattere",
|
||||
"crossOrigineResourceSharing":"Cross-Origin Resource Sharing",
|
||||
"corsEnabled":"Activation",
|
||||
"corsAllow_Credentials":"Access-Control-Allow-Credentials",
|
||||
"corsAllow_Headers":"Access-Control-Allow-Headers",
|
||||
"corsAllow_Methods":"Access-Control-Allow-Methods",
|
||||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"Riprendi",
|
||||
"cfgVersion":"Versione configurazione",
|
||||
"checkXSS":"Verifica attacchi XSS",
|
||||
|
|
|
@ -147,6 +147,14 @@
|
|||
"cspStyle":"Nguồn phong cách",
|
||||
"cspConnect":"Đích cúa Ajax",
|
||||
"cspFont":"Nguồn phông chữ",
|
||||
"crossOrigineResourceSharing":"Cross-Origin Resource Sharing",
|
||||
"corsEnabled":"Activation",
|
||||
"corsAllow_Credentials":"Access-Control-Allow-Credentials",
|
||||
"corsAllow_Headers":"Access-Control-Allow-Headers",
|
||||
"corsAllow_Methods":"Access-Control-Allow-Methods",
|
||||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"Tiếp tục",
|
||||
"cfgVersion":"Phiên bản cấu hình",
|
||||
"checkXSS":"Kiểm tra tấn công XSS",
|
||||
|
|
|
@ -147,6 +147,14 @@
|
|||
"cspStyle":"Style source",
|
||||
"cspConnect":"Ajax destinations",
|
||||
"cspFont":"字体源",
|
||||
"crossOrigineResourceSharing":"Cross-Origin Resource Sharing",
|
||||
"corsEnabled":"Activation",
|
||||
"corsAllow_Credentials":"Access-Control-Allow-Credentials",
|
||||
"corsAllow_Headers":"Access-Control-Allow-Headers",
|
||||
"corsAllow_Methods":"Access-Control-Allow-Methods",
|
||||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"档案",
|
||||
"cfgVersion":"配置信息",
|
||||
"checkXSS":"Check XSS attacks",
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,7 @@
|
|||
# of lemonldap-ng.ini) and underlying handler configuration
|
||||
package Lemonldap::NG::Portal::Main::Init;
|
||||
|
||||
our $VERSION = '2.0.3';
|
||||
our $VERSION = '2.0.5';
|
||||
|
||||
package Lemonldap::NG::Portal::Main;
|
||||
|
||||
|
@ -80,9 +80,12 @@ has spRules => (
|
|||
# Custom template parameters
|
||||
has customParameters => ( is => 'rw', default => sub { {} } );
|
||||
|
||||
# Content-Security-Policy header
|
||||
# Content-Security-Policy headers
|
||||
has csp => ( is => 'rw' );
|
||||
|
||||
# Cross-Origine Resource Sharing headers
|
||||
has cors => ( is => 'rw' );
|
||||
|
||||
# INITIALIZATION
|
||||
|
||||
sub init {
|
||||
|
@ -179,13 +182,29 @@ sub reloadConf {
|
|||
$self->{conf}->{$key} ||= $conf->{$key};
|
||||
}
|
||||
|
||||
# Initialize content-security-policy header
|
||||
# Initialize content-security-policy headers
|
||||
my $csp = '';
|
||||
foreach (qw(default img src style font connect script)) {
|
||||
my $prm = $self->conf->{ 'csp' . ucfirst($_) };
|
||||
$csp .= "$_-src $prm;" if ($prm);
|
||||
}
|
||||
$self->csp($csp);
|
||||
$self->logger->debug( "Initialized CSP headers : " . $self->csp );
|
||||
|
||||
# Initialize Cross-Origin Resource Sharing headers
|
||||
my $cors = '';
|
||||
foreach (
|
||||
qw(Allow_Origin Allow_Credentials Allow_Headers Allow_Methods Expose_Headers Max_Age)
|
||||
)
|
||||
{
|
||||
my $header = $_;
|
||||
my $prm = $self->conf->{ 'cors' . $_ };
|
||||
$header =~ s/_/-/;
|
||||
$prm =~ s/\s+//;
|
||||
$cors .= "Access-Control-$header; $prm;";
|
||||
}
|
||||
$self->cors($cors);
|
||||
$self->logger->debug( "Initialized CORS headers : " . $self->cors );
|
||||
|
||||
# Initialize templateDir
|
||||
$self->{templateDir} =
|
||||
|
|
|
@ -792,6 +792,9 @@ sub sendHtml {
|
|||
'Pragma' => 'no-cache', # HTTP 1.0
|
||||
'Expires' => '0'; # Proxies
|
||||
|
||||
my @cors = split /;/, $self->cors;
|
||||
push @{ $res->[1] }, @cors if $self->conf->{corsEnabled};
|
||||
|
||||
# Set authorized URL for POST
|
||||
my $csp = $self->csp . "form-action " . $self->conf->{cspFormAction};
|
||||
if ( my $url = $req->urldc ) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user