diff options
author | Struan Donald <struan@exo.org.uk> | 2017-11-22 12:17:58 +0000 |
---|---|---|
committer | Matthew Somerville <matthew-github@dracos.co.uk> | 2017-11-29 20:55:41 +0000 |
commit | 7d3ddfbdd9ddaf07d79909262df898a631630d1e (patch) | |
tree | d5fc7e09578efff4e7ca37231f64cac64f2685d3 | |
parent | 32a4a1455032e954301b1d129d9c70c6bce9606d (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.pm | 22 | ||||
-rw-r--r-- | t/app/controller/auth_profile.t | 93 | ||||
-rw-r--r-- | templates/web/base/auth/generate_token.html | 44 | ||||
-rw-r--r-- | templates/web/base/my/my.html | 3 |
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> |