Bug 29523: Add redaction for inaccessible objects

This patch switches from removing inaccessible items from the responses
to instead redacting fields in innaccessible responses.

This allows for embed traversal and keeps counts etc correct but also
hides the data we want to hide.

We add support for an 'unredact_list' method at the Koha::* class level
allowing for individual classes to specify which fields they wish to
expose to restricted users regardless of their restriction.

It is to be used in combination with the is_accessible method introduced
earlier in this patchset which is used to denote whether the current
user should be allowed to see the full record or only a subset of it as
defined in the unredacted_list.

We undefine any fields not listed in the unredact_list for the API
response. This has the effect of still returning the full object of
keys, but setting most fields to a JSON null.

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
Martin Renvoize 2023-08-31 14:13:54 +02:00 committed by Tomas Cohen Arazi
parent aa3b7fb50d
commit ed6791d64e
No known key found for this signature in database
GPG Key ID: 0A272EA1B2F3C15F
3 changed files with 51 additions and 8 deletions

View File

@ -405,7 +405,6 @@ sub TO_JSON {
elsif ( _numeric_column_type( $columns_info->{$col}->{data_type} )
and looks_like_number( $unblessed->{$col} )
) {
# TODO: Remove once the solution for
# https://github.com/perl5-dbi/DBD-mysql/issues/212
# is ported to whatever distro we support by that time
@ -415,7 +414,6 @@ sub TO_JSON {
elsif ( _decimal_column_type( $columns_info->{$col}->{data_type} )
and looks_like_number( $unblessed->{$col} )
) {
# TODO: Remove once the solution for
# https://github.com/perl5-dbi/DBD-mysql/issues/212
# is ported to whatever distro we support by that time
@ -552,8 +550,6 @@ Returns a representation of the object, suitable for API output.
sub to_api {
my ( $self, $params ) = @_;
return unless $self->is_accessible($params);
my $json_object = $self->TO_JSON;
# Make sure we duplicate the $params variable to avoid
@ -585,6 +581,23 @@ sub to_api {
}
}
# Remove forbidden attributes if required (including their coded values)
if ( !$self->is_accessible($params) ) {
for my $field ( keys %{$json_object} ) {
unless ( any { $_ eq $field } @{ $self->unredact_list } ) {
$json_object->{$field} = undef;
}
}
if ($strings) {
foreach my $field ( keys %{$string_map} ) {
unless ( any { $_ eq $field } @{ $self->unredact_list } ) {
$string_map->{$field} = undef;
}
}
}
}
my $to_api_mapping = $self->to_api_mapping;
# Rename attributes and coded values if there's a mapping
@ -717,6 +730,23 @@ sub public_read_list
return [];
}
=head3 unredact_list
my @unredact_list = @{$object->unredact_list};
Generic method that returns the list of database columns that are allowed to
be passed to render objects on the API when the user making the request should
not ordinarily have unrestricted access to the data (as returned by the is_accesible method).
Note: this only returns an empty I<arrayref>. Each class should have its
own implementation.
=cut
sub unredact_list {
return [];
}
=head3 from_api_mapping
my $mapping = $object->from_api_mapping;

View File

@ -2279,7 +2279,7 @@ sub set_default_messaging_preferences {
if ( $patron->is_accessible({ user => $logged_in_user }) ) { ... }
This overloaded method validates wether the current I<Koha::Patron> object can be accessed
This overloaded method validates whether the current I<Koha::Patron> object can be accessed
by the logged in user.
Returns 0 if the I<user> parameter is missing.
@ -2297,6 +2297,17 @@ sub is_accessible {
return $consumer->can_see_patron_infos($self);
}
=head3 unredact_list
This method returns the list of database fields that should be visible, even for restricted users,
for both API and UI output purposes
=cut
sub unredact_list {
return ['branchcode'];
}
=head3 to_api
my $json = $patron->to_api;

View File

@ -554,7 +554,6 @@ subtest "to_api() tests" => sub {
}
);
my $patron_1 = $builder->build_object(
{ class => 'Koha::Patrons', value => { branchcode => $library_1->id } }
);
@ -564,8 +563,11 @@ subtest "to_api() tests" => sub {
t::lib::Mocks::mock_userenv( { patron => $patron } );
is( ref($patron_1->to_api({ user => $patron })), 'HASH', 'Returns the object hash' );
is( $patron_2->to_api({ user => $patron }), undef, 'Not accessible, returns undef' );
is(
$patron_1->to_api( { user => $patron } )->{firstname}, $patron_1->firstname,
'Returns unredacted object hash'
);
is( $patron_2->to_api( { user => $patron } )->{firstname}, undef, 'Returns redacted object hash' );
$schema->storage->txn_rollback;
};