aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Arter <davea@mysociety.org>2017-06-08 17:05:38 +0100
committerDave Arter <davea@mysociety.org>2017-08-31 13:36:27 +0100
commitabc843d671365365bd3e88441721c39f0bb12ca5 (patch)
tree38beb6b24c9539df92457a365ab1dec34c9f4723
parent0221eb4faaa5df503b951019b17b8f691b4b4373 (diff)
Add LOGIN_REQUIRED config key
If set to 1, this restricts all pages on the site to logged-in users.
-rw-r--r--CHANGELOG.md1
-rw-r--r--conf/general.yml-example3
-rw-r--r--perllib/FixMyStreet/App/Controller/Root.pm33
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm18
-rw-r--r--t/app/controller/root.t76
5 files changed, 125 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ba7225e4b..b4d296cee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
- Body users can now create reports as an anonymous user. #1796
- Extra fields can be added to report form site-wide. #1743
- Body users can filter reports by all states. #1790
+ - `LOGIN_REQUIRED` config key to limit site access to logged-in users.
- Front end improvements:
- Always show pagination figures even if only one page. #1787
- Report pages list every update to a report. #1806
diff --git a/conf/general.yml-example b/conf/general.yml-example
index 0e437fac3..70bfd48d2 100644
--- a/conf/general.yml-example
+++ b/conf/general.yml-example
@@ -204,3 +204,6 @@ TESTING_COUNCILS: ''
# if you're using Message Manager, include the URL here (see https://github.com/mysociety/message-manager/)
MESSAGE_MANAGER_URL: ''
+
+# If you want to hide all pages from non-logged-in users, set this to 1.
+LOGIN_REQUIRED: 0
diff --git a/perllib/FixMyStreet/App/Controller/Root.pm b/perllib/FixMyStreet/App/Controller/Root.pm
index 64d7fa6ae..7f70623ae 100644
--- a/perllib/FixMyStreet/App/Controller/Root.pm
+++ b/perllib/FixMyStreet/App/Controller/Root.pm
@@ -16,6 +16,18 @@ FixMyStreet::App::Controller::Root - Root Controller for FixMyStreet::App
=head1 METHODS
+=head2 begin
+
+Any pre-flight checking for all requests
+
+=cut
+sub begin : Private {
+ my ( $self, $c ) = @_;
+
+ $c->forward( 'check_login_required' );
+}
+
+
=head2 auto
Set up general things for this instance
@@ -130,6 +142,27 @@ sub page_error : Private {
$c->response->status($code);
}
+sub check_login_required : Private {
+ my ($self, $c) = @_;
+
+ return if $c->user_exists || !FixMyStreet->config('LOGIN_REQUIRED');
+
+ # Whitelisted URL patterns are allowed without login
+ my $whitelist = qr{
+ ^auth(/|$)
+ | ^js/translation_strings\.(.*?)\.js
+ | ^[PACQM]/ # various tokens that log the user in
+ }x;
+ return if $c->request->path =~ $whitelist;
+
+ # Blacklisted URLs immediately 404
+ # This is primarily to work around a Safari bug where the appcache
+ # URL is requested in an infinite loop if it returns a 302 redirect.
+ $c->detach('/page_error_404_not_found', []) if $c->request->path =~ /^offline/;
+
+ $c->detach( '/auth/redirect' );
+}
+
=head2 end
Attempt to render a view, if needed.
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index a74a04828..51805fa51 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -920,15 +920,21 @@ sub photos {
my $id = $self->id;
my @photos = map {
my $cachebust = substr($_, 0, 8);
+ # Some Varnish configurations (e.g. on mySociety infra) strip cookies from
+ # images, which means image requests will be redirected to the login page
+ # if LOGIN_REQUIRED is set. To stop this happening, Varnish should be
+ # configured to not strip cookies if the cookie_passthrough param is
+ # present, which this line ensures will be if LOGIN_REQUIRED is set.
+ my $extra = (FixMyStreet->config('LOGIN_REQUIRED')) ? "&cookie_passthrough=1" : "";
my ($hash, $format) = split /\./, $_;
{
id => $hash,
- url_temp => "/photo/temp.$hash.$format",
- url_temp_full => "/photo/fulltemp.$hash.$format",
- url => "/photo/$id.$i.$format?$cachebust",
- url_full => "/photo/$id.$i.full.$format?$cachebust",
- url_tn => "/photo/$id.$i.tn.$format?$cachebust",
- url_fp => "/photo/$id.$i.fp.$format?$cachebust",
+ url_temp => "/photo/temp.$hash.$format$extra",
+ url_temp_full => "/photo/fulltemp.$hash.$format$extra",
+ url => "/photo/$id.$i.$format?$cachebust$extra",
+ url_full => "/photo/$id.$i.full.$format?$cachebust$extra",
+ url_tn => "/photo/$id.$i.tn.$format?$cachebust$extra",
+ url_fp => "/photo/$id.$i.fp.$format?$cachebust$extra",
idx => $i++,
}
} $photoset->all_ids;
diff --git a/t/app/controller/root.t b/t/app/controller/root.t
new file mode 100644
index 000000000..413341d89
--- /dev/null
+++ b/t/app/controller/root.t
@@ -0,0 +1,76 @@
+use FixMyStreet::TestMech;
+
+ok( my $mech = FixMyStreet::TestMech->new, 'Created mech object' );
+
+my @urls = (
+ "/",
+ "/reports",
+ "/about/faq",
+ "/around?longitude=-1.351488&latitude=51.847235"
+);
+
+
+FixMyStreet::override_config {
+ LOGIN_REQUIRED => 0,
+ MAPIT_URL => 'http://mapit.uk/'
+}, sub {
+ subtest 'LOGIN_REQUIRED = 0 behaves correctly' => sub {
+ foreach my $url (@urls) {
+ $mech->get_ok($url);
+ is $mech->res->code, 200, "got 200 for page";
+ is $mech->res->previous, undef, 'No redirect';
+ }
+ };
+};
+
+
+FixMyStreet::override_config {
+ LOGIN_REQUIRED => 1,
+ MAPIT_URL => 'http://mapit.uk/'
+}, sub {
+ subtest 'LOGIN_REQUIRED = 1 redirects to /auth if not logged in' => sub {
+ foreach my $url (@urls) {
+ $mech->get_ok($url);
+ is $mech->res->code, 200, "got 200 for final destination";
+ is $mech->res->previous->code, 302, "got 302 for redirect";
+ is $mech->uri->path, '/auth';
+ }
+ };
+
+ subtest 'LOGIN_REQUIRED = 1 does not redirect if logged in' => sub {
+ $mech->log_in_ok('user@example.org');
+ foreach my $url (@urls) {
+ $mech->get_ok($url);
+ is $mech->res->code, 200, "got 200 for final destination";
+ is $mech->res->previous, undef, 'No redirect';
+ }
+ $mech->log_out_ok;
+ };
+
+ subtest 'LOGIN_REQUIRED = 1 allows whitelisted URLs' => sub {
+ my @whitelist = (
+ '/auth',
+ '/js/translation_strings.en-gb.js'
+ );
+
+ foreach my $url (@whitelist) {
+ $mech->get_ok($url);
+ is $mech->res->code, 200, "got 200 for final destination";
+ is $mech->res->previous, undef, 'No redirect';
+ }
+ };
+
+ subtest 'LOGIN_REQUIRED = 1 404s blacklisted URLs' => sub {
+ my @blacklist = (
+ '/offline/appcache',
+ );
+
+ foreach my $url (@blacklist) {
+ $mech->get($url);
+ ok !$mech->res->is_success(), "want a bad response";
+ is $mech->res->code, 404, "got 404";
+ }
+ };
+};
+
+done_testing();