aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStruan Donald <struan@exo.org.uk>2017-11-22 12:17:58 +0000
committerMatthew Somerville <matthew-github@dracos.co.uk>2017-11-29 20:55:41 +0000
commit7d3ddfbdd9ddaf07d79909262df898a631630d1e (patch)
treed5fc7e09578efff4e7ca37231f64cac64f2685d3
parent32a4a1455032e954301b1d129d9c70c6bce9606d (diff)
Staff user page for generating an access token.
Adds a link from /my to a page for generating an access token which is then stored in the user's extra field.
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth/Profile.pm22
-rw-r--r--t/app/controller/auth_profile.t93
-rw-r--r--templates/web/base/auth/generate_token.html44
-rw-r--r--templates/web/base/my/my.html3
4 files changed, 162 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Auth/Profile.pm b/perllib/FixMyStreet/App/Controller/Auth/Profile.pm
index acffd3019..5e6fe6266 100644
--- a/perllib/FixMyStreet/App/Controller/Auth/Profile.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth/Profile.pm
@@ -4,6 +4,8 @@ use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
+use mySociety::AuthToken;
+
=head1 NAME
FixMyStreet::App::Controller::Auth::Profile - Catalyst Controller
@@ -146,6 +148,26 @@ sub change_phone_success : Path('/auth/change_phone/success') {
$c->res->redirect('/my');
}
+sub generate_token : Path('/auth/generate_token') {
+ my ($self, $c) = @_;
+
+ $c->detach( '/page_error_403_access_denied', [] )
+ unless $c->user and ( $c->user->is_superuser or $c->user->from_body );
+
+ $c->stash->{template} = 'auth/generate_token.html';
+ $c->forward('/auth/get_csrf_token');
+
+ if ($c->req->method eq 'POST') {
+ $c->forward('/auth/check_csrf_token');
+ my $token = mySociety::AuthToken::random_token();
+ $c->user->set_extra_metadata('access_token', $token);
+ $c->user->update();
+ $c->stash->{token_generated} = 1;
+ }
+
+ $c->stash->{existing_token} = $c->user->get_extra_metadata('access_token');
+}
+
__PACKAGE__->meta->make_immutable;
1;
diff --git a/t/app/controller/auth_profile.t b/t/app/controller/auth_profile.t
index 519086ff5..74edccfe6 100644
--- a/t/app/controller/auth_profile.t
+++ b/t/app/controller/auth_profile.t
@@ -260,3 +260,96 @@ subtest "Test change phone to existing account" => sub {
is $_->user->email, $test_email;
}
};
+
+subtest "Test superuser can access generate token page" => sub {
+ my $user = FixMyStreet::App->model('DB::User')->find( { email => $test_email } );
+ ok $user->update({ is_superuser => 0 }), 'user not superuser';
+
+ $mech->log_out_ok;
+ $mech->get_ok('/auth');
+ $mech->submit_form_ok({
+ with_fields => {
+ username => $test_email,
+ password_sign_in => $test_password,
+ },
+ });
+
+ $mech->content_lacks('Generate token');
+
+ $mech->get('/auth/generate_token');
+ is $mech->res->code, 403, "access denied";
+
+ ok $user->update({ is_superuser => 1 }), 'user is superuser';
+
+ $mech->get_ok('/my');
+ $mech->content_contains('Generate token');
+ $mech->get_ok('/auth/generate_token');
+};
+
+subtest "Test staff user can access generate token page" => sub {
+ my $user = FixMyStreet::App->model('DB::User')->find( { email => $test_email } );
+ ok $user->update({ is_superuser => 0 }), 'user not superuser';
+
+ $mech->log_out_ok;
+ $mech->get_ok('/auth');
+ $mech->submit_form_ok({
+ with_fields => {
+ username => $test_email,
+ password_sign_in => $test_password,
+ },
+ });
+
+ $mech->content_lacks('Generate token');
+
+ my $body = $mech->create_body_ok(2237, 'Oxfordshire');
+
+ $mech->get('/auth/generate_token');
+ is $mech->res->code, 403, "access denied";
+
+ ok $user->update({ from_body => $body }), 'user is staff user';
+
+ $mech->get_ok('/my');
+ $mech->content_contains('Generate token');
+ $mech->get_ok('/auth/generate_token');
+};
+
+subtest "Test generate token page" => sub {
+ my $user = FixMyStreet::App->model('DB::User')->find( { email => $test_email } );
+ ok $user->update({ is_superuser => 1 }), 'user set to superuser';
+
+ $mech->log_out_ok;
+
+ $mech->get_ok('/auth');
+ $mech->submit_form_ok({
+ with_fields => {
+ username => $test_email,
+ password_sign_in => $test_password,
+ },
+ });
+
+ ok !$user->get_extra_metadata('access_token');
+
+ $mech->get_ok('/my');
+ $mech->follow_link_ok({url => '/auth/generate_token'});
+ $mech->content_lacks('Token:');
+ $mech->submit_form_ok(
+ { with_fields => { generate_token => 'Generate token' } },
+ "submit generate token form"
+ );
+ $mech->content_contains( 'Your token has been generated', "token generated" );
+
+ $user->discard_changes();
+ my $token = $user->get_extra_metadata('access_token');
+ ok $token, 'access token set';
+
+ $mech->content_contains($token, 'access token displayed');
+
+ $mech->get_ok('/auth/generate_token');
+ $mech->content_contains('Current token:');
+ $mech->content_contains($token, 'access token displayed');
+ $mech->content_contains('If you generate a new token');
+
+ $mech->log_out_ok;
+ $mech->add_header('Authorization', "Bearer $token");
+ $mech->logged_in_ok;
+}
diff --git a/templates/web/base/auth/generate_token.html b/templates/web/base/auth/generate_token.html
new file mode 100644
index 000000000..157335047
--- /dev/null
+++ b/templates/web/base/auth/generate_token.html
@@ -0,0 +1,44 @@
+[%
+INCLUDE 'header.html', title = loc('Generate token'), bodyclass = 'fullwidthpage'
+%]
+
+[% IF token_generated %]
+
+ <div class="confirmation-header">
+ <h1>[% loc('Your token has been generated') %]</h1>
+
+ <p>
+ <strong>[% loc('Token:') %]</strong>
+ <span>[% existing_token | html %]</span>
+ </p>
+
+ <p><a href="/my">[% loc('Your account') %]</a></p>
+ </div>
+
+[% ELSE %]
+
+<h1>[% loc('Generate token') %]</h1>
+
+<form action="[% c.uri_for_action('/auth/profile/generate_token') %]" method="post" name="generate_token">
+ <input type="hidden" name="token" value="[% csrf_token %]">
+
+ [% IF existing_token %]
+ <p>
+ <strong>[% loc('Current token:') %]</strong>
+ <span>[% existing_token | html %]</span>
+ </p>
+ [% END %]
+
+ <p>
+ <input name="generate_token" type="submit" class="btn" value="[% existing_token ? loc('Replace token') : loc('Generate token') %]">
+ </p>
+</form>
+
+[% IF existing_token %]
+ <p>
+ [% loc('If you generate a new token the existing token will no longer work.') %]
+ </p>
+[% END %]
+[% END %]
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/base/my/my.html b/templates/web/base/my/my.html
index 68fbc2ee8..e10dd96c8 100644
--- a/templates/web/base/my/my.html
+++ b/templates/web/base/my/my.html
@@ -61,6 +61,9 @@ li .my-account-buttons a {
<p class="my-account-buttons">
<a href="/auth/change_password">[% loc('Change password') %]</a>
+ [% IF c.user AND (c.user.from_body OR c.user.is_superuser) %]
+ <a href="/auth/generate_token">[% loc('Generate token') %]</a>
+ [% END %]
<a href="/auth/sign_out">[% loc('Sign out') %]</a>
</p>