From f26f67d1a1b0d8d9a314ac61a847c60f0a9530d3 Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Wed, 24 Aug 2022 12:21:08 -0300 Subject: [PATCH] Bug 31378: Add accessor methods for JSON attributes Signed-off-by: Lukasz Koszyk Signed-off-by: Tomas Cohen Arazi Signed-off-by: Nick Clemens Signed-off-by: Martin Renvoize --- Koha/Auth/Provider.pm | 122 ++++++++++++++++++++++++ t/db_dependent/Koha/Auth/Provider.t | 141 ++++++++++++++++++++++++++-- 2 files changed, 257 insertions(+), 6 deletions(-) diff --git a/Koha/Auth/Provider.pm b/Koha/Auth/Provider.pm index d70a41b7bf..e8de84ada5 100644 --- a/Koha/Auth/Provider.pm +++ b/Koha/Auth/Provider.pm @@ -21,7 +21,12 @@ use Modern::Perl; use base qw(Koha::Object); +use JSON qw( decode_json encode_json ); +use Try::Tiny; + use Koha::Auth::Provider::Domains; +use Koha::Exceptions; +use Koha::Exceptions::Object; =head1 NAME @@ -45,6 +50,123 @@ sub domains { return Koha::Auth::Provider::Domains->_new_from_dbic( scalar $self->_result->domains ); } +=head3 get_config + + my $config = $provider->get_config; + +Returns a I containing the configuration parameters for the provider. + +=cut + +sub get_config { + my ($self) = @_; + + return try { + return decode_json( $self->config ); + } + catch { + Koha::Exceptions::Object::BadValue->throw("Error reading JSON data: $_"); + }; +} + +=head3 set_config + + # OAuth + $provider->set_config( + { + key => 'APP_ID', + secret => 'SECRET_KEY', + authorize_url => 'https://provider.example.com/auth', + token_url => 'https://provider.example.com/token', + } + ); + + # OIDC + $provider->set_config( + { + key => 'APP_ID', + secret => 'SECRET_KEY', + well_known_url => 'https://login.microsoftonline.com/tenant-id/v2.0/.well-known/openid-configuration', + } + ); + +This method stores the passed config in JSON format. + +=cut + +sub set_config { + my ($self, $config) = @_; + + my @mandatory; + + if ( $self->protocol eq 'OIDC' ) { + @mandatory = qw(key secret well_known_url); + } + elsif ( $self->protocol eq 'OAuth' ) { + @mandatory = qw(key secret authorize_url token_url); + } + else { + Koha::Exception->throw( 'Unsupported protocol ' . $self->protocol ); + } + + for my $param (@mandatory) { + unless ( defined( $config->{$param} ) ) { + Koha::Exceptions::MissingParameter->throw( + error => "The $param parameter is mandatory" ); + } + } + + try { + my $encoded_config = encode_json($config); + $self->config($encoded_config)->store; + } catch { + Koha::Exceptions::Object::BadValue->throw("Error serializing data into JSON: $_"); + }; + + return $self; +} + +=head3 get_mapping + + my $mapping = $provider->get_mapping; + +Returns a I containing the attribute mapping for the provider. + +=cut + +sub get_mapping { + my ($self) = @_; + + return try { + return decode_json( $self->mapping ); + } + catch { + Koha::Exceptions::Object::BadValue->throw("Error reading JSON data: $_"); + }; +} + +=head3 set_mapping + + $provider->mapping( $mapping ); + +This method stores the passed mappings in JSON format. + +=cut + +sub set_mapping { + my ($self, $mapping) = @_; + + try { + my $encoded_mapping = encode_json( $mapping ); + $self->mapping( $encoded_mapping )->store; + } + catch { + Koha::Exceptions::Object::BadValue->throw("Error serializing data into JSON: $_"); + }; + + return $self; +} + =head2 Internal methods =head3 _type diff --git a/t/db_dependent/Koha/Auth/Provider.t b/t/db_dependent/Koha/Auth/Provider.t index cfe2ccf37a..d55b7bb000 100755 --- a/t/db_dependent/Koha/Auth/Provider.t +++ b/t/db_dependent/Koha/Auth/Provider.t @@ -19,7 +19,12 @@ use Modern::Perl; -use Test::More tests => 1; +use Test::More tests => 5; + +use Test::MockModule; +use Test::Exception; + +use JSON qw(encode_json); use Koha::Auth::Providers; @@ -35,16 +40,140 @@ subtest 'domains() tests' => sub { $schema->storage->txn_begin; - my $provider = $builder->build_object({ class => 'Koha::Auth::Providers' }); + my $provider = $builder->build_object( { class => 'Koha::Auth::Providers' } ); my $domains = $provider->domains; - is( ref($domains), 'Koha::Auth::Provider::Domains', 'Type is correct' ); - is( $domains->count, 0, 'No domains defined' ); + is( ref($domains), 'Koha::Auth::Provider::Domains', 'Type is correct' ); + is( $domains->count, 0, 'No domains defined' ); - $builder->build_object({ class => 'Koha::Auth::Provider::Domains', value => { auth_provider_id => $provider->id } }); - $builder->build_object({ class => 'Koha::Auth::Provider::Domains', value => { auth_provider_id => $provider->id } }); + $builder->build_object( { class => 'Koha::Auth::Provider::Domains', value => { auth_provider_id => $provider->id } } ); + $builder->build_object( { class => 'Koha::Auth::Provider::Domains', value => { auth_provider_id => $provider->id } } ); is( $provider->domains->count, 2, 'The provider has 2 domains defined' ); $schema->storage->txn_rollback; }; + +subtest 'get_config() tests' => sub { + + plan tests => 2; + + $schema->storage->txn_begin; + + my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { config => '{' } } ); + + throws_ok { $provider->get_config() } + 'Koha::Exceptions::Object::BadValue', 'Expected exception thrown on bad JSON'; + + my $config = { some => 'value', and => 'another' }; + $provider->config( encode_json($config) )->store; + + is_deeply( $provider->get_config, $config, 'Config correctly retrieved' ); + + $schema->storage->txn_rollback; +}; + +subtest 'set_config() tests' => sub { + + plan tests => 3; + + $schema->storage->txn_begin; + + subtest 'OIDC protocol tests' => sub { + + plan tests => 4; + + my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { protocol => 'OIDC' } } ); + + my $config = { + key => 'key', + secret => 'secret', + }; + + throws_ok { $provider->set_config($config) } + 'Koha::Exceptions::MissingParameter', 'Exception thrown on missing parameter'; + + is( $@->error, 'The well_known_url parameter is mandatory', 'Message is correct' ); + + $config->{well_known_url} = 'https://koha-community.org/auth'; + + my $return = $provider->set_config($config); + is( ref($return), 'Koha::Auth::Provider', 'Return type is correct' ); + + is_deeply( $provider->get_config, $config, 'Configuration stored correctly' ); + }; + + subtest 'OAuth protocol tests' => sub { + + plan tests => 4; + + my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { protocol => 'OAuth' } } ); + + my $config = { + key => 'key', + secret => 'secret', + token_url => 'https://koha-community.org/auth/token', + }; + + throws_ok { $provider->set_config($config) } + 'Koha::Exceptions::MissingParameter', 'Exception thrown on missing parameter'; + + is( $@->error, 'The authorize_url parameter is mandatory', 'Message is correct' ); + + $config->{authorize_url} = 'https://koha-community.org/auth/authorize'; + + my $return = $provider->set_config($config); + is( ref($return), 'Koha::Auth::Provider', 'Return type is correct' ); + + is_deeply( $provider->get_config, $config, 'Configuration stored correctly' ); + }; + + subtest 'Unsupported protocol tests' => sub { + + plan tests => 2; + + my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { protocol => 'CAS' } } ); + + throws_ok { $provider->set_config() } + 'Koha::Exception', 'Exception thrown on unsupported protocol'; + + like( "$@", qr/Unsupported protocol CAS/, 'Message is correct' ); + }; + + $schema->storage->txn_rollback; +}; + +subtest 'get_mapping() tests' => sub { + + plan tests => 2; + + $schema->storage->txn_begin; + + my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { config => '{' } } ); + + throws_ok { $provider->get_mapping() } + 'Koha::Exceptions::Object::BadValue', 'Expected exception thrown on bad JSON'; + + my $mapping = { some => 'value', and => 'another' }; + $provider->mapping( encode_json($mapping) )->store; + + is_deeply( $provider->get_mapping, $mapping, 'Mapping correctly retrieved' ); + + $schema->storage->txn_rollback; +}; + +subtest 'set_mapping() tests' => sub { + + plan tests => 1; + + $schema->storage->txn_begin; + + my $provider = $builder->build_object( { class => 'Koha::Auth::Providers' } ); + + my $mapping = { some => 'value', and => 'another' }; + $provider->set_mapping($mapping)->store; + + is_deeply( $provider->get_mapping, $mapping, 'Mapping correctly retrieved' ); + + $schema->storage->txn_rollback; +}; -- 2.20.1