Browse Source
Signed-off-by: Lukasz Koszyk <lukasz.koszyk@kit.edu> Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io> Signed-off-by: Nick Clemens <nick@bywatersolutions.com> Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com> Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>22.11.x
Agustin Moyano
2 years ago
committed by
Tomas Cohen Arazi
37 changed files with 1713 additions and 411 deletions
@ -0,0 +1,179 @@ |
|||
#!/usr/bin/perl |
|||
|
|||
# Copyright 2022 Theke Solutions |
|||
# |
|||
# This file is part of Koha |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use Test::More tests => 4; |
|||
|
|||
use Test::MockModule; |
|||
use Test::Exception; |
|||
|
|||
use JSON qw(encode_json); |
|||
use MIME::Base64 qw{ encode_base64url }; |
|||
|
|||
use Koha::Auth::Client; |
|||
use Koha::Auth::Client::OAuth; |
|||
use Koha::Patrons; |
|||
|
|||
use t::lib::TestBuilder; |
|||
use t::lib::Mocks; |
|||
|
|||
my $schema = Koha::Database->new->schema; |
|||
my $builder = t::lib::TestBuilder->new; |
|||
|
|||
subtest 'get_user() tests' => sub { |
|||
plan tests => 4; |
|||
|
|||
$schema->storage->txn_begin; |
|||
|
|||
my $client = Koha::Auth::Client::OAuth->new; |
|||
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { matchpoint => 'email' } } ); |
|||
my $domain = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => '', allow_opac => 1, allow_staff => 0 } } ); |
|||
my $patron = $builder->build_object( { class => 'Koha::Patrons', value => { email => 'patron@test.com' } } ); |
|||
my $mapping = { |
|||
email => 'electronic_mail', |
|||
firstname => 'given_name', |
|||
surname => 'family_name' |
|||
}; |
|||
$provider->set_mapping($mapping)->store; |
|||
|
|||
my $id_token = 'header.'.encode_base64url(encode_json({ |
|||
electronic_mail => 'patron@test.com', |
|||
given_name => 'test name' |
|||
})).'.footer'; |
|||
|
|||
my $data = { |
|||
id_token => $id_token |
|||
}; |
|||
|
|||
my ($resolved_patron, $mapped_data, $resolved_domain) = $client->get_user({ provider => $provider->code, data => $data, interface => 'opac' }); |
|||
is_deeply( $resolved_patron->to_api, $patron->to_api, 'Patron correctly retrieved' ); |
|||
is( $mapped_data->{firstname}, 'test name', 'Data mapped correctly' ); |
|||
is( $mapped_data->{surname}, undef, 'No surname mapped'); |
|||
is( $domain->identity_provider_domain_id, $resolved_domain->identity_provider_domain_id, 'Is the same domain'); |
|||
|
|||
$schema->storage->txn_rollback; |
|||
|
|||
}; |
|||
|
|||
subtest 'get_valid_domain_config() tests' => sub { |
|||
plan tests => 10; |
|||
|
|||
$schema->storage->txn_begin; |
|||
|
|||
my $client = Koha::Auth::Client->new; |
|||
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { matchpoint => 'email' } } ); |
|||
my $domain1 = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => '', allow_opac => 0, allow_staff => 0 } } ); |
|||
my $domain2 = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => '*library.com', allow_opac => 1, allow_staff => 0 } } ); |
|||
my $domain3 = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => '*.library.com', allow_opac => 1, allow_staff => 0 } } ); |
|||
my $domain4 = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => 'student.library.com', allow_opac => 1, allow_staff => 0 } } ); |
|||
my $domain5 = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => 'staff.library.com', allow_opac => 1, allow_staff => 1 } } ); |
|||
|
|||
my $retrieved_domain; |
|||
|
|||
# Test @gmail.com |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@gmail.com', interface => 'opac'}); |
|||
is($retrieved_domain, undef, 'gmail user cannot enter opac'); |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@gmail.com', interface => 'staff'}); |
|||
is($retrieved_domain, undef, 'gmail user cannot enter staff'); |
|||
|
|||
# Test @otherlibrary.com |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@otherlibrary.com', interface => 'opac'}); |
|||
is($retrieved_domain->identity_provider_domain_id, $domain2->identity_provider_domain_id, 'otherlibaray user can enter opac with domain2'); |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@otherlibrary.com', interface => 'staff'}); |
|||
is($retrieved_domain, undef, 'otherlibrary user cannot enter staff'); |
|||
|
|||
# Test @provider.library.com |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@provider.library.com', interface => 'opac'}); |
|||
is($retrieved_domain->identity_provider_domain_id, $domain3->identity_provider_domain_id, 'provider.library user can enter opac with domain3'); |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@provider.library.com', interface => 'staff'}); |
|||
is($retrieved_domain, undef, 'provider.library user cannot enter staff'); |
|||
|
|||
# Test @student.library.com |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@student.library.com', interface => 'opac'}); |
|||
is($retrieved_domain->identity_provider_domain_id, $domain4->identity_provider_domain_id, 'student.library user can enter opac with domain4'); |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@student.library.com', interface => 'staff'}); |
|||
is($retrieved_domain, undef, 'student.library user cannot enter staff'); |
|||
|
|||
# Test @staff.library.com |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@staff.library.com', interface => 'opac'}); |
|||
is($retrieved_domain->identity_provider_domain_id, $domain5->identity_provider_domain_id, 'staff.library user can enter opac with domain5'); |
|||
$retrieved_domain = $client->get_valid_domain_config({ provider => $provider, email => 'user@staff.library.com', interface => 'staff'}); |
|||
is($retrieved_domain->identity_provider_domain_id, $domain5->identity_provider_domain_id, 'staff.library user can enter staff with domain5'); |
|||
|
|||
$schema->storage->txn_rollback; |
|||
}; |
|||
|
|||
subtest 'has_valid_domain_config() tests' => sub { |
|||
plan tests => 2; |
|||
$schema->storage->txn_begin; |
|||
|
|||
my $client = Koha::Auth::Client->new; |
|||
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { matchpoint => 'email' } } ); |
|||
my $domain1 = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => '', allow_opac => 1, allow_staff => 0 } } ); |
|||
|
|||
# Test @gmail.com |
|||
my $retrieved_domain = $client->has_valid_domain_config({ provider => $provider, email => 'user@gmail.com', interface => 'opac'}); |
|||
is($retrieved_domain->identity_provider_domain_id, $domain1->identity_provider_domain_id, 'gmail user can enter opac with domain1'); |
|||
throws_ok { $client->has_valid_domain_config({ provider => $provider, email => 'user@gmail.com', interface => 'staff'}) } 'Koha::Exceptions::Auth::NoValidDomain', 'gmail user cannot enter staff'; |
|||
|
|||
$schema->storage->txn_rollback; |
|||
}; |
|||
|
|||
subtest '_traverse_hash() tests' => sub { |
|||
plan tests => 3; |
|||
|
|||
my $client = Koha::Auth::Client->new; |
|||
|
|||
my $hash = { |
|||
a => { |
|||
hash => { |
|||
with => 'complicated structure' |
|||
} |
|||
}, |
|||
an => { |
|||
array => [ |
|||
{ |
|||
inside => 'a hash' |
|||
}, |
|||
{ |
|||
inside => 'second element' |
|||
} |
|||
] |
|||
} |
|||
}; |
|||
|
|||
my $first_result = $client->_traverse_hash({ |
|||
base => $hash, |
|||
keys => 'a.hash.with' |
|||
}); |
|||
is($first_result, 'complicated structure', 'get the value whithin a hash structure'); |
|||
|
|||
my $second_result = $client->_traverse_hash({ |
|||
base => $hash, |
|||
keys => 'an.array.0.inside' |
|||
}); |
|||
is($second_result, 'a hash', 'get the value of the first element of an array within a hash structure'); |
|||
|
|||
my $third_result = $client->_traverse_hash({ |
|||
base => $hash, |
|||
keys => 'an.array.1.inside' |
|||
}); |
|||
is($third_result, 'second element', 'get the value of the second element of an array within a hash structure'); |
|||
}; |
@ -0,0 +1,133 @@ |
|||
#!/usr/bin/perl |
|||
|
|||
# Copyright 2022 Theke Solutions |
|||
# |
|||
# This file is part of Koha |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use Koha::Patrons; |
|||
use Koha::Auth::Identity::Provider::Domains; |
|||
use Koha::Patrons; |
|||
use Try::Tiny; |
|||
|
|||
# Dummy app for testing the plugin |
|||
use Mojolicious::Lite; |
|||
|
|||
plugin 'Koha::REST::Plugin::Auth::IdP'; |
|||
|
|||
post '/register_user' => sub { |
|||
my $c = shift; |
|||
my $params = $c->req->json; |
|||
try { |
|||
my $domain = Koha::Auth::Identity::Provider::Domains->find($params->{domain_id}); |
|||
my $patron = $c->auth->register({ |
|||
data => $params->{data}, |
|||
domain => $domain, |
|||
interface => $params->{interface} |
|||
}); |
|||
$c->render(status => 200, json => $patron->to_api); |
|||
} catch { |
|||
if ( ref($_) eq 'Koha::Exceptions::Auth::Unauthorized' ) { |
|||
$c->render(status => 401, json => {message => 'unauthorized'}); |
|||
} else { |
|||
$c->render(status => 500, json => {message => 'other error'}); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
post '/start_session' => sub { |
|||
my $c = shift; |
|||
my $userid = my $params = $c->req->json->{userid}; |
|||
|
|||
try { |
|||
my $patron = Koha::Patrons->search({userid => $userid}); |
|||
my ($status, $cookie, $session_id) = $c->auth->session($patron->next); |
|||
$c->render(status => 200, json => {status => $status}); |
|||
} catch { |
|||
if ( ref($_) eq 'Koha::Exceptions::Auth::CannotCreateSession' ) { |
|||
$c->render(status => 401, json => {message => 'unauthorized'}); |
|||
} else { |
|||
$c->render(status => 500, json => {message => 'other error'}); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
use Test::More tests => 2; |
|||
use Test::Mojo; |
|||
|
|||
use t::lib::Mocks; |
|||
use t::lib::TestBuilder; |
|||
use Koha::Database; |
|||
|
|||
my $schema = Koha::Database->new()->schema(); |
|||
my $builder = t::lib::TestBuilder->new; |
|||
|
|||
# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling |
|||
# this affects the other REST api tests |
|||
t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' ); |
|||
|
|||
subtest 'auth.register helper' => sub { |
|||
plan tests => 6; |
|||
|
|||
$schema->storage->txn_begin; |
|||
|
|||
# Remove existing patrons |
|||
Koha::Patrons->delete; |
|||
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { matchpoint => 'email' } } ); |
|||
my $domain_with_register = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => 'domain1.com', auto_register => 1 } } ); |
|||
my $domain_without_register = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => 'domain2.com', auto_register => 0 } } ); |
|||
my $library = $builder->build_object({ class => 'Koha::Libraries'}); |
|||
my $category = $builder->build_object( {class => 'Koha::Patron::Categories'}); |
|||
my $user_data = { |
|||
firstname => 'test', |
|||
surname => 'test', |
|||
userid => 'id1', |
|||
branchcode => $library->branchcode, |
|||
categorycode => $category->categorycode |
|||
}; |
|||
|
|||
my $t = Test::Mojo->new; |
|||
|
|||
$t->post_ok('/register_user' => json => {data => $user_data, domain_id => $domain_with_register->identity_provider_domain_id, interface => 'opac'}) |
|||
->status_is(200) |
|||
->json_has('/firstname', 'test'); |
|||
|
|||
$t->post_ok('/register_user' => json => {data => $user_data, domain_id => $domain_without_register->identity_provider_domain_id, interface => 'opac'}) |
|||
->status_is(401) |
|||
->json_has('/message', 'unauthorized'); |
|||
$schema->storage->txn_rollback; |
|||
}; |
|||
|
|||
subtest 'auth.session helper' => sub { |
|||
plan tests => 3; |
|||
|
|||
$schema->storage->txn_begin; |
|||
|
|||
# Remove existing patrons |
|||
Koha::Patrons->delete; |
|||
my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); |
|||
|
|||
|
|||
my $t = Test::Mojo->new; |
|||
$t->post_ok('/start_session' => json => {userid => $patron->userid}) |
|||
->status_is(200) |
|||
->json_has('/status', 'ok'); |
|||
|
|||
$schema->storage->txn_rollback; |
|||
}; |
|||
|
|||
1; |
@ -0,0 +1,341 @@ |
|||
#!/usr/bin/perl |
|||
|
|||
# Copyright 2022 Theke Solutions |
|||
# |
|||
# This file is part of Koha |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use Test::More tests => 3; |
|||
use Test::Mojo; |
|||
use Test::Warn; |
|||
use Mojo::JWT; |
|||
use Crypt::OpenSSL::RSA; |
|||
|
|||
use t::lib::TestBuilder; |
|||
use t::lib::Mocks; |
|||
|
|||
use Koha::Database; |
|||
use C4::Auth; |
|||
use Koha::Auth::Identity::Providers; |
|||
use Koha::Auth::Identity::Provider::Domains; |
|||
|
|||
my $schema = Koha::Database->new->schema; |
|||
my $builder = t::lib::TestBuilder->new; |
|||
|
|||
# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling |
|||
# this affects the other REST api tests |
|||
t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' ); |
|||
|
|||
my $remote_address = '127.0.0.1'; |
|||
|
|||
use t::lib::IdP::ExternalIdP; |
|||
|
|||
my $idp_port = t::lib::IdP::ExternalIdP->start; |
|||
|
|||
|
|||
my $oauth_provider_data = { |
|||
code => 'oauth_test', |
|||
description => 'OAuth provider', |
|||
protocol => 'OAuth', |
|||
mapping => { |
|||
email => 'users.0.email', |
|||
firstname => 'users.0.custom_name', |
|||
surname => 'users.0.custom_surname', |
|||
userid => 'users.0.id' |
|||
}, |
|||
matchpoint => 'email', |
|||
config => { |
|||
authorize_url => "http://localhost:$idp_port/idp/test/authorization_endpoint", |
|||
token_url => "http://localhost:$idp_port/idp/test/token_endpoint/without_id_token", |
|||
userinfo_url => "http://localhost:$idp_port/idp/test/userinfo_endpoint", |
|||
key => "client_id", |
|||
secret => "client_secret" |
|||
} |
|||
}; |
|||
|
|||
my $oidc_with_email_provider_data = { |
|||
code => 'oidc_email', |
|||
description => 'OIDC wiht email provider', |
|||
protocol => 'OIDC', |
|||
mapping => { |
|||
email => 'email', |
|||
firstname => 'given_name', |
|||
surname => 'family_name', |
|||
userid => 'sub' |
|||
}, |
|||
matchpoint => 'email', |
|||
config => { |
|||
authorize_url => "http://localhost:$idp_port/idp/test/authorization_endpoint", |
|||
well_known_url => "http://localhost:$idp_port/idp/test/with_email/.well_known", |
|||
key => "client_id", |
|||
secret => "client_secret" |
|||
} |
|||
}; |
|||
|
|||
my $oidc_without_email_provider_data = { |
|||
code => 'oidc_no_email', |
|||
description => 'OIDC wihtout email provider', |
|||
protocol => 'OIDC', |
|||
mapping => { |
|||
email => 'users.0.email', |
|||
firstname => 'given_name', |
|||
surname => 'family_name', |
|||
userid => 'sub' |
|||
}, |
|||
matchpoint => 'email', |
|||
config => { |
|||
authorize_url => "http://localhost:$idp_port/idp/test/authorization_endpoint", |
|||
well_known_url => "http://localhost:$idp_port/idp/test/without_email/.well_known", |
|||
key => "client_id", |
|||
secret => "client_secret" |
|||
} |
|||
}; |
|||
|
|||
my $domain_not_matching = { |
|||
domain => 'gmail.com', |
|||
auto_register => 0, |
|||
update_on_auth => 0, |
|||
default_library_id => undef, |
|||
default_category_id => undef, |
|||
allow_opac => 1, |
|||
allow_staff => 0 |
|||
}; |
|||
|
|||
my $domain_no_register = { |
|||
domain => 'some.library.com', |
|||
auto_register => 0, |
|||
update_on_auth => 0, |
|||
default_library_id => undef, |
|||
default_category_id => undef, |
|||
allow_opac => 1, |
|||
allow_staff => 0 |
|||
}; |
|||
|
|||
my $library = $builder->build_object({class => 'Koha::Libraries'}); |
|||
my $category = $builder->build_object({class => 'Koha::Patron::Categories'}); |
|||
|
|||
my $domain_register = { |
|||
domain => 'some.library.com', |
|||
auto_register => 1, |
|||
update_on_auth => 0, |
|||
default_library_id => $library->branchcode, |
|||
default_category_id => $category->categorycode, |
|||
allow_opac => 1, |
|||
allow_staff => 1 |
|||
}; |
|||
|
|||
my $domain_register_update = { |
|||
domain => 'some.library.com', |
|||
auto_register => 1, |
|||
update_on_auth => 1, |
|||
default_library_id => $library->branchcode, |
|||
default_category_id => $category->categorycode, |
|||
allow_opac => 1, |
|||
allow_staff => 0 |
|||
}; |
|||
|
|||
subtest 'provider endpoint tests' => sub { |
|||
plan tests => 12; |
|||
|
|||
$schema->storage->txn_begin; |
|||
|
|||
Koha::Auth::Identity::Provider::Domains->delete; |
|||
Koha::Auth::Identity::Providers->delete; |
|||
|
|||
my ( $borrowernumber, $session_id ) = create_user_and_session({ authorized => 1 }); |
|||
|
|||
my $t = Test::Mojo->new('Koha::REST::V1'); |
|||
|
|||
my $tx = $t->ua->build_tx( POST => "/api/v1/auth/identity_providers", json => $oauth_provider_data ); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->status_is(201); |
|||
|
|||
my $provider = Koha::Auth::Identity::Providers->search({code => 'oauth_test'})->next; |
|||
is ($provider->code, 'oauth_test', 'Provider was created'); |
|||
|
|||
$tx = $t->ua->build_tx( GET => "/api/v1/auth/identity_providers" ); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->json_has('/0/code', 'oauth_test'); |
|||
|
|||
my %modified_provider_data_hash = %{$oauth_provider_data}; |
|||
my $modified_provider_data = \%modified_provider_data_hash; |
|||
$modified_provider_data->{code} = 'some_code'; |
|||
|
|||
$tx = $t->ua->build_tx( PUT => "/api/v1/auth/identity_providers/".$provider->identity_provider_id, json => $modified_provider_data); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->status_is(200); |
|||
|
|||
$tx = $t->ua->build_tx( GET => "/api/v1/auth/identity_providers/".$provider->identity_provider_id); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->json_has('/code', 'some_code'); |
|||
|
|||
$tx = $t->ua->build_tx( DELETE => "/api/v1/auth/identity_providers/".$provider->identity_provider_id); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->status_is(204); |
|||
# p $t->tx->res; |
|||
|
|||
$provider = Koha::Auth::Identity::Providers->search->next; |
|||
is ($provider, undef, 'All providers deleted'); |
|||
|
|||
$schema->storage->txn_rollback; |
|||
}; |
|||
|
|||
subtest 'domain endpoint tests' => sub { |
|||
plan tests => 12; |
|||
|
|||
$schema->storage->txn_begin; |
|||
|
|||
Koha::Auth::Identity::Provider::Domains->delete; |
|||
Koha::Auth::Identity::Providers->delete; |
|||
|
|||
my ( $borrowernumber, $session_id ) = create_user_and_session({ authorized => 1 }); |
|||
|
|||
my $t = Test::Mojo->new('Koha::REST::V1'); |
|||
|
|||
my $provider = $builder->build_object({class => 'Koha::Auth::Identity::Providers'}); |
|||
|
|||
my $tx = $t->ua->build_tx( POST => "/api/v1/auth/identity_providers/".$provider->identity_provider_id."/domains", json => $domain_not_matching ); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->status_is(201); |
|||
|
|||
my $domain = Koha::Auth::Identity::Provider::Domains->search({domain => 'gmail.com'})->next; |
|||
is ($domain->domain, 'gmail.com', 'Provider was created'); |
|||
|
|||
$tx = $t->ua->build_tx( GET => "/api/v1/auth/identity_providers/".$provider->identity_provider_id."/domains" ); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->json_has('/0/domain', 'gmail.com'); |
|||
|
|||
my %modified_domain_data_hash = %{$domain_not_matching}; |
|||
my $modified_domain_data = \%modified_domain_data_hash; |
|||
$modified_domain_data->{domain} = 'some.domain.com'; |
|||
|
|||
$tx = $t->ua->build_tx( PUT => "/api/v1/auth/identity_providers/".$provider->identity_provider_id."/domains/".$domain->identity_provider_domain_id, json => $modified_domain_data); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->status_is(200); |
|||
|
|||
$tx = $t->ua->build_tx( GET => "/api/v1/auth/identity_providers/".$provider->identity_provider_id."/domains/".$domain->identity_provider_domain_id); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->json_has('/domain', 'some.domain.com'); |
|||
|
|||
$tx = $t->ua->build_tx( DELETE => "/api/v1/auth/identity_providers/".$provider->identity_provider_id."/domains/".$domain->identity_provider_domain_id); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx) |
|||
->status_is(204); |
|||
# p $t->tx->res; |
|||
|
|||
$domain = Koha::Auth::Identity::Provider::Domains->search->next; |
|||
is ($domain, undef, 'All domains deleted'); |
|||
|
|||
$schema->storage->txn_rollback; |
|||
}; |
|||
|
|||
subtest 'oauth login tests' => sub { |
|||
plan tests => 4; |
|||
|
|||
$schema->storage->txn_begin; |
|||
|
|||
Koha::Auth::Identity::Provider::Domains->delete; |
|||
Koha::Auth::Identity::Providers->delete; |
|||
|
|||
my ( $borrowernumber, $session_id ) = create_user_and_session({ authorized => 1 }); |
|||
|
|||
my $t = Test::Mojo->new('Koha::REST::V1'); |
|||
|
|||
# Build provider |
|||
my $tx = $t->ua->build_tx( POST => "/api/v1/auth/identity_providers", json => $oauth_provider_data ); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx); |
|||
my $provider_id = $t->tx->res->json->{identity_provider_id}; |
|||
|
|||
# Build domain |
|||
$tx = $t->ua->build_tx( POST => "/api/v1/auth/identity_providers/$provider_id/domains", json => $domain_not_matching ); |
|||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); |
|||
$tx->req->env( { REMOTE_ADDR => $remote_address } ); |
|||
|
|||
$t->request_ok($tx); |
|||
|
|||
t::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 ); |
|||
|
|||
# Simulate server restart |
|||
$t = Test::Mojo->new('Koha::REST::V1'); |
|||
|
|||
#$t->ua->max_redirects(10); |
|||
$t->get_ok("/api/v1/public/oauth/login/oauth_test/opac") |
|||
->status_is(302); |
|||
use Data::Printer colored => 1; |
|||
p $t->tx->res; |
|||
|
|||
$schema->storage->txn_rollback; |
|||
}; |
|||
|
|||
sub create_user_and_session { |
|||
|
|||
my $args = shift; |
|||
my $flags = ( $args->{authorized} ) ? 1 : 0; |
|||
|
|||
my $user = $builder->build( |
|||
{ |
|||
source => 'Borrower', |
|||
value => { |
|||
flags => $flags |
|||
} |
|||
} |
|||
); |
|||
|
|||
# Create a session for the authorized user |
|||
my $session = C4::Auth::get_session(''); |
|||
$session->param( 'number', $user->{borrowernumber} ); |
|||
$session->param( 'id', $user->{userid} ); |
|||
$session->param( 'ip', $remote_address ); |
|||
$session->param( 'lasttime', time() ); |
|||
$session->flush; |
|||
|
|||
return ( $user->{borrowernumber}, $session->id ); |
|||
} |
|||
|
|||
1; |
@ -0,0 +1,166 @@ |
|||
package t::lib::IdP::ExternalIdP; |
|||
|
|||
use Mojolicious::Lite; |
|||
use Mojo::IOLoop; |
|||
use Mojo::IOLoop::Server; |
|||
use Mojo::Server::Daemon; |
|||
|
|||
print "Configure idp routes\n"; |
|||
|
|||
any '/idp/test/authorization_endpoint' => sub { |
|||
my $c = shift; |
|||
print "pasa por acá\n"; |
|||
return $c->render(json => {error => 'invalid_request'}, status => 500) |
|||
unless (3 == grep { $c->param($_) } qw(response_type redirect_uri client_id)) |
|||
&& $c->param('response_type') eq 'code'; |
|||
|
|||
my $url = Mojo::URL->new($c->param('redirect_uri')); |
|||
$url->query({code => 'authorize-code', state => $c->param('state')}); |
|||
return $c->redirect_to($url); |
|||
}; |
|||
|
|||
any '/idp/test/token_endpoint/with_id_token/with_email' => sub { |
|||
my $c = shift; |
|||
return $c->render(json => {error => 'invalid_request'}, status => 500) |
|||
unless (4 == grep { $c->param($_) } qw(client_id client_secret redirect_uri code)) |
|||
&& $c->param('code') eq 'authorize-code'; |
|||
|
|||
my $claims = { |
|||
aud => $c->param('client_id'), |
|||
email => 'test.user@some.library.com', |
|||
iss => $c->url_for('/idp/test')->to_abs, |
|||
given_name => 'test', |
|||
family_name => 'user', |
|||
preferred_username => 'test.user@some.library.com', |
|||
sub => 'test.user' |
|||
}; |
|||
|
|||
my $rsa = Crypt::OpenSSL::RSA->generate_key(2048); |
|||
|
|||
my $id_token = Mojo::JWT->new( |
|||
algorithm => 'RS256', |
|||
secret => $rsa->get_private_key_string, |
|||
set_iat => 1, |
|||
claims => $claims, |
|||
header => {kid => 'TEST_SIGNING_KEY'} |
|||
); |
|||
|
|||
$c->render(status => 200, json => { |
|||
access_token => 'access', |
|||
expires_in => 3599, |
|||
ext_expires_in => 3599, |
|||
id_token => $id_token, |
|||
refresh_token => 'refresh-token', |
|||
scope => 'openid', |
|||
token_type => 'Bearer' |
|||
}); |
|||
}; |
|||
|
|||
any '/idp/test/token_endpoint/with_id_token/without_email' => sub { |
|||
my $c = shift; |
|||
return $c->render(json => {error => 'invalid_request'}, status => 500) |
|||
unless (4 == grep { $c->param($_) } qw(client_id client_secret redirect_uri code)) |
|||
&& $c->param('code') eq 'authorize-code'; |
|||
|
|||
my $claims = { |
|||
aud => $c->param('client_id'), |
|||
iss => $c->url_for('/idp/test')->to_abs, |
|||
given_name => 'test', |
|||
family_name => 'user', |
|||
preferred_username => 'test.user', |
|||
sub => 'test.user' |
|||
}; |
|||
|
|||
my $rsa = Crypt::OpenSSL::RSA->generate_key(2048); |
|||
|
|||
my $id_token = Mojo::JWT->new( |
|||
algorithm => 'RS256', |
|||
secret => $rsa->get_private_key_string, |
|||
set_iat => 1, |
|||
claims => $claims, |
|||
header => {kid => 'TEST_SIGNING_KEY'} |
|||
); |
|||
|
|||
$c->render(status => 200, json => { |
|||
access_token => 'access', |
|||
expires_in => 3599, |
|||
ext_expires_in => 3599, |
|||
id_token => $id_token, |
|||
refresh_token => 'refresh-token', |
|||
scope => 'openid', |
|||
token_type => 'Bearer' |
|||
}); |
|||
}; |
|||
|
|||
any '/idp/test/token_endpoint/without_id_token' => sub { |
|||
my $c = shift; |
|||
return $c->render(json => {error => 'invalid_request'}, status => 500) |
|||
unless (4 == grep { $c->param($_) } qw(client_id client_secret redirect_uri code)) |
|||
&& $c->param('code') eq 'authorize-code'; |
|||
|
|||
$c->render(status => 200, json => { |
|||
access_token => 'access', |
|||
expires_in => 3599, |
|||
ext_expires_in => 3599, |
|||
refresh_token => 'refresh-token', |
|||
scope => 'some list of scopes', |
|||
token_type => 'Bearer' |
|||
}); |
|||
}; |
|||
|
|||
any '/idp/test/userinfo_endpoint' => sub { |
|||
my $c = shift; |
|||
return $c->render(text => 'Unauthorized', status => 401) |
|||
unless $c->req->headers->authorization eq 'Bearer access'; |
|||
|
|||
$c->render(status => 200, json => { |
|||
users => [ |
|||
{ |
|||
email => 'test.user@some.library.com', |
|||
custom_name => 'test', |
|||
custom_surname => 'user', |
|||
id => 'test.user', |
|||
last_login => 'a long time ago' |
|||
} |
|||
] |
|||
}); |
|||
}; |
|||
|
|||
any '/idp/test/with_email/.well_known' => sub { |
|||
my $c = shift; |
|||
|
|||
$c->render(status => 200, json => { |
|||
authorization_endpoint => $c->url_for('/idp/test/authorization_endpoint')->to_abs, |
|||
token_endpoint => $c->url_for('/idp/test/token_endpoint/with_id_token/with_email')->to_abs, |
|||
userinfo_endpoint => $c->url_for('/idp/test/userinfo_endpoint')->to_abs, |
|||
}); |
|||
}; |
|||
|
|||
any '/idp/test/without_email/.well_known' => sub { |
|||
my $c = shift; |
|||
|
|||
$c->render(status => 200, json => { |
|||
authorization_endpoint => $c->url_for('/idp/test/authorization_endpoint')->to_abs, |
|||
token_endpoint => $c->url_for('/idp/test/token_endpoint/with_id_token/without_email')->to_abs, |
|||
userinfo_endpoint => $c->url_for('/idp/test/userinfo_endpoint')->to_abs, |
|||
}); |
|||
}; |
|||
|
|||
my $port = Mojo::IOLoop::Server->generate_port; |
|||
my $daemon = Mojo::Server::Daemon->new( |
|||
app => app, |
|||
listen => ["http://*:$port"] |
|||
); |
|||
|
|||
sub start { |
|||
print "Run daemon\n"; |
|||
$daemon->start; |
|||
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
|||
return $port; |
|||
} |
|||
|
|||
sub stop { |
|||
$daemon->stop; |
|||
} |
|||
|
|||
1; |
Loading…
Reference in new issue