From c94e2534a9b720d9b9560e88b696faf5d42aea77 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Mon, 16 Sep 2019 12:12:19 +0200 Subject: [PATCH] Send CORS headers when doing JSON responses too (#1765) --- .../lib/Lemonldap/NG/Portal/Main/Run.pm | 12 +++ .../t/01-CSP-and-CORS-headers.t | 94 +++++++------------ 2 files changed, 48 insertions(+), 58 deletions(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm index 7e949d5a8..7b9f36566 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm @@ -1061,6 +1061,18 @@ sub corsPreflight { return [ 204, \@headers, [] ]; } +sub sendJSONresponse { + my ( $self, $req, $j, %args ) = @_; + my $res = Lemonldap::NG::Common::PSGI::sendJSONresponse(@_); + if ( $self->conf->{corsEnabled} ) { + my @cors = split /;/, $self->cors; + push @{ $res->[1] }, @cors; + $self->logger->debug('Apply following CORS policy :'); + $self->logger->debug(" $_") for @cors; + } + return $res; +} + # Temlate loader sub loadTemplate { my ( $self, $req, $name, %prm ) = @_; diff --git a/lemonldap-ng-portal/t/01-CSP-and-CORS-headers.t b/lemonldap-ng-portal/t/01-CSP-and-CORS-headers.t index 23292b5ad..2173b8870 100644 --- a/lemonldap-ng-portal/t/01-CSP-and-CORS-headers.t +++ b/lemonldap-ng-portal/t/01-CSP-and-CORS-headers.t @@ -24,6 +24,10 @@ ok( $res = $client->_get('/'), 'Unauth JSON request' ); count(1); expectReject($res); +ok( $res = $client->_get('/ping'), 'Unauth JSON request' ); +count(1); +checkCorsPolicy($res); + # Test "first access" with good url ok( $res = @@ -33,57 +37,23 @@ ok( count(1); expectReject($res); -# Test CORS "Preflight" ok( $res = $client->_options( '/', accept => 'text/html' ), 'Get Menu' ); -my %policy = @{ $res->[1] }; count(1); -# CORS -ok( $policy{'Access-Control-Allow-Origin'} eq '', "CORS origin '' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Allow-Credentials'} eq 'true', - "CORS credentials 'true' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Allow-Headers'} eq '*', "CORS headers '*' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Allow-Methods'} eq 'POST', - "CORS methods 'POST' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Expose-Headers'} eq '*', - "CORS expose-headers '*' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Max-Age'} eq '86400', "CORS max-age '86400' found" ) - or print STDERR Dumper( $res->[1] ); -count(6); +checkCorsPolicy($res); ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu' ); ok( $res->[2]->[0] =~ m%%, ' Language icons found' ) or print STDERR Dumper( $res->[2]->[0] ); count(2); -%policy = @{ $res->[1] }; +checkCorsPolicy($res); -# CORS -ok( $policy{'Access-Control-Allow-Origin'} eq '', "CORS origin '' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Allow-Credentials'} eq 'true', - "CORS credentials 'true' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Allow-Headers'} eq '*', "CORS headers '*' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Allow-Methods'} eq 'POST', - "CORS methods 'POST' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Expose-Headers'} eq '*', - "CORS expose-headers '*' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Max-Age'} eq '86400', "CORS max-age '86400' found" ) - or print STDERR Dumper( $res->[1] ); -count(6); +my %headers = @{ $res->[1] }; #CSP ok( - $policy{'Content-Security-Policy'} =~ + $headers{'Content-Security-Policy'} =~ /default-src 'self';img-src 'self' data:;style-src 'self';font-src 'self';connect-src 'self';script-src 'self';form-action \*;frame-ancestors 'none'/, 'CSP header value found' ) or print STDERR Dumper( $res->[1] ); @@ -128,36 +98,44 @@ ok( ); count(1); -%policy = @{ $res->[1] }; +%headers = @{ $res->[1] }; # Lm-Remote headers -ok( $policy{'Lm-Remote-User'} eq 'dwho', "Lm-Remote-User found" ) +ok( $headers{'Lm-Remote-User'} eq 'dwho', "Lm-Remote-User found" ) or print STDERR Dumper( $res->[1] ); -ok( $policy{'Lm-Remote-Custom'} eq 'dwho@badwolf.org', +ok( $headers{'Lm-Remote-Custom'} eq 'dwho@badwolf.org', "Lm-Remote-Custom found" ) or print STDERR Dumper( $res->[1] ); count(2); -# CORS -ok( $policy{'Access-Control-Allow-Origin'} eq '', "CORS origin '' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Allow-Credentials'} eq 'true', - "CORS credentials 'true' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Allow-Headers'} eq '*', "CORS headers '*' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Allow-Methods'} eq 'POST', - "CORS methods 'POST' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Expose-Headers'} eq '*', - "CORS expose-headers '*' found" ) - or print STDERR Dumper( $res->[1] ); -ok( $policy{'Access-Control-Max-Age'} eq '86400', "CORS max-age '86400' found" ) - or print STDERR Dumper( $res->[1] ); -count(6); +checkCorsPolicy($res); $client->logout($id); clean_sessions(); done_testing( count() ); + +sub checkCorsPolicy { + my ($res) = @_; + my %headers = @{ $res->[1] }; + + ok( $headers{'Access-Control-Allow-Origin'} eq '', "CORS origin '' found" ) + or print STDERR Dumper( $res->[1] ); + ok( $headers{'Access-Control-Allow-Credentials'} eq 'true', + "CORS credentials 'true' found" ) + or print STDERR Dumper( $res->[1] ); + ok( $headers{'Access-Control-Allow-Headers'} eq '*', + "CORS headers '*' found" ) + or print STDERR Dumper( $res->[1] ); + ok( $headers{'Access-Control-Allow-Methods'} eq 'POST', + "CORS methods 'POST' found" ) + or print STDERR Dumper( $res->[1] ); + ok( $headers{'Access-Control-Expose-Headers'} eq '*', + "CORS expose-headers '*' found" ) + or print STDERR Dumper( $res->[1] ); + ok( $headers{'Access-Control-Max-Age'} eq '86400', + "CORS max-age '86400' found" ) + or print STDERR Dumper( $res->[1] ); + count(6); +}