Bug 26922: Regression tests
[koha.git] / t / db_dependent / api / v1 / oauth.t
blob4e464d53f2e0df5f4363713166f7d410c0c7ad69
1 #!/usr/bin/env perl
3 # This file is part of Koha.
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
18 use Modern::Perl;
20 use Test::More;
21 use Test::MockModule;
22 use Test::Mojo;
24 use MIME::Base64;
25 use Module::Load::Conditional qw(can_load);
27 use Koha::ApiKeys;
28 use Koha::Database;
29 use Koha::Patrons;
31 use t::lib::Mocks;
32 use t::lib::TestBuilder;
34 my $t = Test::Mojo->new('Koha::REST::V1');
35 my $schema = Koha::Database->new->schema;
36 my $builder = t::lib::TestBuilder->new();
38 if ( can_load( modules => { 'Net::OAuth2::AuthorizationServer' => undef } ) ) {
39 plan tests => 2;
41 else {
42 plan skip_all => 'Net::OAuth2::AuthorizationServer not available';
45 subtest '/oauth/token tests' => sub {
47 plan tests => 10;
49 t::lib::Mocks::mock_preference('RESTOAuth2ClientCredentials', 0);
51 # Missing parameter grant_type
52 $t->post_ok('/api/v1/oauth/token')
53 ->status_is(400);
55 # Wrong grant type
56 $t->post_ok('/api/v1/oauth/token', form => { grant_type => 'password' })
57 ->status_is(400)
58 ->json_is({error => 'Unimplemented grant type'});
60 t::lib::Mocks::mock_preference('RESTOAuth2ClientCredentials', 1);
62 # No client_id/client_secret
63 $t->post_ok('/api/v1/oauth/token', form => { grant_type => 'client_credentials' })
64 ->status_is(403)
65 ->json_is({error => 'unauthorized_client'});
67 subtest 'Client credentials in body' => sub {
69 plan tests => 19;
71 run_oauth_tests( 'body' );
74 subtest 'Client credentials in Authorization header' => sub {
77 plan tests => 19;
79 run_oauth_tests( 'header' );
83 subtest 'Net::OAuth2::AuthorizationServer missing tests' => sub {
85 plan tests => 10;
87 $schema->storage->txn_begin;
89 my $load_conditional = Test::MockModule->new('Module::Load::Conditional');
91 # Enable the client credentials grant syspref
92 t::lib::Mocks::mock_preference( 'RESTOAuth2ClientCredentials', 1 );
94 my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { flags => 2**4 } });
95 my $api_key = Koha::ApiKey->new({ patron_id => $patron->id, description => 'blah' })->store;
97 my $form_data = {
98 grant_type => 'client_credentials',
99 client_id => $api_key->client_id,
100 client_secret => $api_key->secret
103 $t->post_ok( '/api/v1/oauth/token', form => $form_data )->status_is(200)
104 ->json_is( '/expires_in' => 3600 )->json_is( '/token_type' => 'Bearer' )
105 ->json_has('/access_token');
107 my $access_token = $t->tx->res->json->{access_token};
109 $load_conditional->mock( 'can_load', sub { return 0; } );
111 my $tx = $t->ua->build_tx( GET => '/api/v1/patrons' );
112 $tx->req->headers->authorization("Bearer $access_token");
113 $t->request_ok($tx)
114 ->status_is(403);
116 $t->post_ok( '/api/v1/oauth/token', form => $form_data )
117 ->status_is(400)
118 ->json_is( { error => 'Unimplemented grant type' } );
120 $schema->storage->txn_rollback;
123 sub run_oauth_tests {
124 my ( $test_case ) = @_;
126 $schema->storage->txn_begin;
128 my $patron = $builder->build_object({
129 class => 'Koha::Patrons',
130 value => {
131 flags => 0 # no permissions
135 my $api_key = Koha::ApiKey->new({ patron_id => $patron->id, description => 'blah' })->store;
137 t::lib::Mocks::mock_preference( 'RESTOAuth2ClientCredentials', 1 );
139 my $formData;
140 my $client_id = $api_key->client_id;
141 my $client_secret = $api_key->secret;
143 if ( $test_case eq 'header' ) {
145 $formData = { grant_type => 'client_credentials' };
147 $t->post_ok("//$client_id:$client_secret@/api/v1/oauth/token", form => $formData)
148 ->status_is(200)
149 ->json_is('/expires_in' => 3600)
150 ->json_is('/token_type' => 'Bearer')
151 ->json_has('/access_token');
152 } else {
154 $formData = {
155 grant_type => 'client_credentials',
156 client_id => $api_key->client_id,
157 client_secret => $api_key->secret
160 $t->post_ok('/api/v1/oauth/token', form => $formData)
161 ->status_is(200)
162 ->json_is('/expires_in' => 3600)
163 ->json_is('/token_type' => 'Bearer')
164 ->json_has('/access_token');
167 my $access_token = $t->tx->res->json->{access_token};
169 # Without access token, it returns 401
170 $t->get_ok('/api/v1/patrons')->status_is(401);
172 # With access token, but without permissions, it returns 403
173 my $tx = $t->ua->build_tx(GET => '/api/v1/patrons');
174 $tx->req->headers->authorization("Bearer $access_token");
175 $t->request_ok($tx)->status_is(403);
177 # With access token and permissions, it returns 200
178 $patron->flags(2**4)->store;
179 $tx = $t->ua->build_tx(GET => '/api/v1/patrons');
180 $tx->req->headers->authorization("Bearer $access_token");
181 $t->request_ok($tx)->status_is(200);
183 # expire token
184 my $token = Koha::OAuthAccessTokens->find($access_token);
185 $token->expires( time - 1 )->store;
186 $tx = $t->ua->build_tx( GET => '/api/v1/patrons' );
187 $tx->req->headers->authorization("Bearer $access_token");
188 $t->request_ok($tx)
189 ->status_is(401);
191 # revoke key
192 $api_key->active(0)->store;
194 if ( $test_case eq 'header' ) {
195 $t->post_ok("//$client_id:$client_secret@/api/v1/oauth/token", form => $formData)
196 ->status_is(403)
197 ->json_is({ error => 'unauthorized_client' });
198 } else {
199 $t->post_ok('/api/v1/oauth/token', form => $formData)
200 ->status_is(403)
201 ->json_is({ error => 'unauthorized_client' });
204 # disable client credentials grant
205 t::lib::Mocks::mock_preference('RESTOAuth2ClientCredentials', 0);
207 # enable API key
208 $api_key->active(1)->store;
210 # Wrong grant type
211 if ( $test_case eq 'header' ) {
212 $t->post_ok("//$client_id:$client_secret@/api/v1/oauth/token", form => $formData )
213 ->status_is(400)
214 ->json_is({ error => 'Unimplemented grant type' });
216 else {
217 $t->post_ok('/api/v1/oauth/token', form => $formData )
218 ->status_is(400)
219 ->json_is({ error => 'Unimplemented grant type' });
222 $schema->storage->txn_rollback;