Browse Source

Bug 31378: Rename Auth Provider to Identity Provider and add Client.t tests

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
parent
commit
016105cf8c
Signed by: tomascohen GPG Key ID: 0A272EA1B2F3C15F
  1. 22
      Koha/Auth/Client.pm
  2. 20
      Koha/Auth/Client/OAuth.pm
  3. 20
      Koha/Auth/Identity/Provider.pm
  4. 6
      Koha/Auth/Identity/Provider/Domain.pm
  5. 10
      Koha/Auth/Identity/Provider/Domains.pm
  6. 8
      Koha/Auth/Identity/Provider/OAuth.pm
  7. 8
      Koha/Auth/Identity/Provider/OIDC.pm
  8. 10
      Koha/Auth/Identity/Providers.pm
  9. 4
      Koha/REST/Plugin/Auth/IdP.pm
  10. 6
      Koha/REST/V1.pm
  11. 41
      Koha/REST/V1/Auth/Identity/Provider/Domains.pm
  12. 26
      Koha/REST/V1/Auth/Identity/Providers.pm
  13. 47
      Koha/Schema/Result/IdentityProvider.pm
  14. 78
      Koha/Schema/Result/IdentityProviderDomain.pm
  15. 4
      Koha/Template/Plugin/AuthClient.pm
  16. 66
      admin/identity_providers.pl
  17. 6
      api/v1/swagger/definitions/identity_provider.yaml
  18. 7
      api/v1/swagger/definitions/identity_provider_domain.yaml
  19. 490
      api/v1/swagger/paths/auth.yaml
  20. 38
      api/v1/swagger/swagger.yaml
  21. 40
      installer/data/mysql/atomicupdate/bug_31378.pl
  22. 32
      installer/data/mysql/kohastructure.sql
  23. 2
      installer/data/mysql/mandatory/userpermissions.sql
  24. 6
      koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc
  25. 6
      koha-tmpl/intranet-tmpl/prog/en/includes/permissions.inc
  26. 8
      koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt
  27. 112
      koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_provider_domains.tt
  28. 116
      koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_providers.tt
  29. 8
      koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt
  30. 8
      koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc
  31. 8
      koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt
  32. 8
      koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-main.tt
  33. 179
      t/db_dependent/Koha/Auth/Client.t
  34. 34
      t/db_dependent/Koha/Auth/Identity/Provider.t
  35. 133
      t/db_dependent/Koha/REST/Plugin/Auth/IdP.t
  36. 341
      t/db_dependent/api/v1/idp.t
  37. 166
      t/lib/IdP/ExternalIdP.pm

22
Koha/Auth/Client.pm

@ -20,7 +20,7 @@ package Koha::Auth::Client;
use Modern::Perl;
use Koha::Exceptions::Auth;
use Koha::Auth::Providers;
use Koha::Auth::Identity::Providers;
=head1 NAME
@ -58,7 +58,7 @@ sub get_user {
my $interface = $params->{interface};
my $config = $params->{config};
my $provider = Koha::Auth::Providers->search({ code => $provider_code })->next;
my $provider = Koha::Auth::Identity::Providers->search({ code => $provider_code })->next;
my ( $mapped_data, $patron ) = $self->_get_data_and_patron({ provider => $provider, data => $data, config => $config });
@ -68,6 +68,8 @@ sub get_user {
$mapped_data->{categorycode} = $domain->default_category_id;
$mapped_data->{branchcode} = $domain->default_library_id;
$patron->set($mapped_data)->store if $patron && $domain->update_on_auth;
return ( $patron, $mapped_data, $domain );
}
}
@ -93,7 +95,6 @@ sub get_valid_domain_config {
my $interface = $params->{interface};
my $domains = $provider->domains;
my $pattern = '@';
my $allow = "allow_$interface";
my @subdomain_matches;
my $default_match;
@ -101,19 +102,20 @@ sub get_valid_domain_config {
while ( my $domain = $domains->next ) {
next unless $domain->$allow;
my $pattern = '@';
my $domain_text = $domain->domain;
unless ( defined $domain_text && $domain_text ne '') {
$default_match = $domain;
next;
}
my ( $asterisk, $domain_name ) = ( $domain_text =~ /^(\*)?(.+)$/ );
if ( $asterisk eq '*' ) {
if ( defined $asterisk && $asterisk eq '*' ) {
$pattern .= '.*';
}
$domain_name =~ s/\./\\\./g;
$pattern .= $domain_name . '$';
if ( $user_email =~ /$pattern/ ) {
if ( $asterisk eq '*' ) {
if ( defined $asterisk && $asterisk eq '*' ) {
push @subdomain_matches, { domain => $domain, match_length => length $domain_name };
} else {
@ -129,7 +131,7 @@ sub get_valid_domain_config {
return $subdomain_matches[0]->{domain};
}
return $default_match || 0;
return $default_match;
}
=head3 has_valid_domain_config
@ -176,15 +178,15 @@ sub _get_data_and_patron {
return {};
}
=head3 _tranverse_hash
=head3 _traverse_hash
my $value = $auth_client->_tranverse_hash( { base => $base_hash, keys => $key_string } );
my $value = $auth_client->_traverse_hash( { base => $base_hash, keys => $key_string } );
Get deep nested value in a hash.
=cut
sub _tranverse_hash {
sub _traverse_hash {
my ($self, $params) = @_;
my $base = $params->{base};
my $keys = $params->{keys};
@ -192,7 +194,7 @@ sub _tranverse_hash {
return unless defined $key;
my $value = ref $base eq 'HASH' ? $base->{$key} : $base->[$key];
return $value unless $rest;
return $self->_tranverse_hash({ base => $value, keys => $rest });
return $self->_traverse_hash({ base => $value, keys => $rest });
}
1;

20
Koha/Auth/Client/OAuth.pm

@ -78,9 +78,6 @@ sub _get_data_and_patron {
if ( defined $value and $matchpoint_rs->count ) {
$patron = $matchpoint_rs->next;
}
return ( $mapped_data, $patron )
if $patron;
}
if ( defined $config->{userinfo_url} ) {
@ -97,22 +94,25 @@ sub _get_data_and_patron {
foreach my $key ( keys %$mapping ) {
my $pkey = $mapping->{$key};
my $value = $self->_tranverse_hash( { base => $claim, keys => $pkey } );
my $value = $self->_traverse_hash( { base => $claim, keys => $pkey } );
$mapped_data->{$key} = $value
if defined $value;
}
my $value = $mapped_data->{$matchpoint};
unless ($patron) {
my $value = $mapped_data->{$matchpoint};
my $matchpoint_rs = Koha::Patrons->search( { $matchpoint => $value } );
my $matchpoint_rs = Koha::Patrons->search( { $matchpoint => $value } );
if ( defined $value and $matchpoint_rs->count ) {
$patron = $matchpoint_rs->next;
if ( defined $value and $matchpoint_rs->count ) {
$patron = $matchpoint_rs->next;
}
}
return ( $mapped_data, $patron )
if $patron;
}
return ( $mapped_data, $patron )
if $patron;
}
1;

20
Koha/Auth/Provider.pm → Koha/Auth/Identity/Provider.pm

@ -1,4 +1,4 @@
package Koha::Auth::Provider;
package Koha::Auth::Identity::Provider;
# Copyright Theke Solutions 2022
#
@ -24,13 +24,13 @@ use base qw(Koha::Object);
use JSON qw( decode_json encode_json );
use Try::Tiny;
use Koha::Auth::Provider::Domains;
use Koha::Auth::Identity::Provider::Domains;
use Koha::Exceptions;
use Koha::Exceptions::Object;
=head1 NAME
Koha::Auth::Provider - Koha Auth Provider Object class
Koha::Auth::Identity::Provider - Koha Auth Provider Object class
=head1 API
@ -40,14 +40,14 @@ Koha::Auth::Provider - Koha Auth Provider Object class
my $domains = $provider->domains;
Returns the related I<Koha::Auth::Provider::Domains> iterator.
Returns the related I<Koha::Auth::Identity::Provider::Domains> iterator.
=cut
sub domains {
my ($self) = @_;
return Koha::Auth::Provider::Domains->_new_from_dbic( scalar $self->_result->domains );
return Koha::Auth::Identity::Provider::Domains->_new_from_dbic( scalar $self->_result->domains );
}
=head3 get_config
@ -183,7 +183,7 @@ sub upgrade_class {
my $json = $provider->to_api;
Overloaded method that returns a JSON representation of the Koha::Auth::Provider object,
Overloaded method that returns a JSON representation of the Koha::Auth::Identity::Provider object,
suitable for API output.
=cut
@ -206,12 +206,12 @@ sub to_api {
=cut
sub _type {
return 'AuthProvider';
return 'IdentityProvider';
}
=head3 protocol_to_class_mapping
my $mapping = Koha::Auth::Provider::protocol_to_class_mapping
my $mapping = Koha::Auth::Identity::Provider::protocol_to_class_mapping
Internal method that returns a mapping between I<protocol> codes and
implementing I<classes>. To be used by B<upgrade_class>.
@ -220,8 +220,8 @@ implementing I<classes>. To be used by B<upgrade_class>.
sub protocol_to_class_mapping {
return {
OAuth => 'Koha::Auth::Provider::OAuth',
OIDC => 'Koha::Auth::Provider::OIDC',
OAuth => 'Koha::Auth::Identity::Provider::OAuth',
OIDC => 'Koha::Auth::Identity::Provider::OIDC',
};
}

6
Koha/Auth/Provider/Domain.pm → Koha/Auth/Identity/Provider/Domain.pm

@ -1,4 +1,4 @@
package Koha::Auth::Provider::Domain;
package Koha::Auth::Identity::Provider::Domain;
# Copyright Theke Solutions 2022
#
@ -23,7 +23,7 @@ use base qw(Koha::Object);
=head1 NAME
Koha::Auth::Provider::Domain - Koha Auth Provider Domain Object class
Koha::Auth::Identity::Provider::Domain - Koha Auth Provider Domain Object class
=head1 API
@ -34,7 +34,7 @@ Koha::Auth::Provider::Domain - Koha Auth Provider Domain Object class
=cut
sub _type {
return 'AuthProviderDomain';
return 'IdentityProviderDomain';
}
1;

10
Koha/Auth/Provider/Domains.pm → Koha/Auth/Identity/Provider/Domains.pm

@ -1,4 +1,4 @@
package Koha::Auth::Provider::Domains;
package Koha::Auth::Identity::Provider::Domains;
# Copyright Theke Solutions 2022
#
@ -20,13 +20,13 @@ package Koha::Auth::Provider::Domains;
use Modern::Perl;
use Koha::Database;
use Koha::Auth::Provider::Domain;
use Koha::Auth::Identity::Provider::Domain;
use base qw(Koha::Objects);
=head1 NAME
Koha::Auth::Providers - Koha Auth Provider Object class
Koha::Auth::Identity::Providers - Koha Auth Provider Object class
=head1 API
@ -39,7 +39,7 @@ Koha::Auth::Providers - Koha Auth Provider Object class
=cut
sub _type {
return 'AuthProviderDomain';
return 'IdentityProviderDomain';
}
=head3 object_class
@ -47,7 +47,7 @@ sub _type {
=cut
sub object_class {
return 'Koha::Auth::Provider::Domain';
return 'Koha::Auth::Identity::Provider::Domain';
}
1;

8
Koha/Auth/Provider/OAuth.pm → Koha/Auth/Identity/Provider/OAuth.pm

@ -1,4 +1,4 @@
package Koha::Auth::Provider::OAuth;
package Koha::Auth::Identity::Provider::OAuth;
# Copyright Theke Solutions 2022
#
@ -19,11 +19,11 @@ package Koha::Auth::Provider::OAuth;
use Modern::Perl;
use base qw(Koha::Auth::Provider);
use base qw(Koha::Auth::Identity::Provider);
=head1 NAME
Koha::Auth::Provider::OAuth - Koha Auth Provider Object class
Koha::Auth::Identity::Provider::OAuth - Koha Auth Provider Object class
=head1 API
@ -31,7 +31,7 @@ Koha::Auth::Provider::OAuth - Koha Auth Provider Object class
=head3 new
my $oauth = Koha::Auth::Provider::OAuth->new( \%{params} );
my $oauth = Koha::Auth::Identity::Provider::OAuth->new( \%{params} );
Overloaded class to create a new OAuth provider.

8
Koha/Auth/Provider/OIDC.pm → Koha/Auth/Identity/Provider/OIDC.pm

@ -1,4 +1,4 @@
package Koha::Auth::Provider::OIDC;
package Koha::Auth::Identity::Provider::OIDC;
# Copyright Theke Solutions 2022
#
@ -19,11 +19,11 @@ package Koha::Auth::Provider::OIDC;
use Modern::Perl;
use base qw(Koha::Auth::Provider);
use base qw(Koha::Auth::Identity::Provider);
=head1 NAME
Koha::Auth::Provider::OIDC - Koha Auth Provider Object class
Koha::Auth::Identity::Provider::OIDC - Koha Auth Provider Object class
=head1 API
@ -31,7 +31,7 @@ Koha::Auth::Provider::OIDC - Koha Auth Provider Object class
=head3 new
my $oidc = Koha::Auth::Provider::OIDC->new( \%{params} );
my $oidc = Koha::Auth::Identity::Provider::OIDC->new( \%{params} );
Overloaded class to create a new OIDC provider.

10
Koha/Auth/Providers.pm → Koha/Auth/Identity/Providers.pm

@ -1,4 +1,4 @@
package Koha::Auth::Providers;
package Koha::Auth::Identity::Providers;
# Copyright Theke Solutions 2022
#
@ -20,13 +20,13 @@ package Koha::Auth::Providers;
use Modern::Perl;
use Koha::Database;
use Koha::Auth::Provider;
use Koha::Auth::Identity::Provider;
use base qw(Koha::Objects);
=head1 NAME
Koha::Auth::Providers - Koha Auth Provider Object class
Koha::Auth::Identity::Providers - Koha Auth Provider Object class
=head1 API
@ -39,7 +39,7 @@ Koha::Auth::Providers - Koha Auth Provider Object class
=cut
sub _type {
return 'AuthProvider';
return 'IdentityProvider';
}
=head3 object_class
@ -47,7 +47,7 @@ sub _type {
=cut
sub object_class {
return 'Koha::Auth::Provider';
return 'Koha::Auth::Identity::Provider';
}
1;

4
Koha/REST/Plugin/Auth.pm → Koha/REST/Plugin/Auth/IdP.pm

@ -1,4 +1,4 @@
package Koha::REST::Plugin::Auth;
package Koha::REST::Plugin::Auth::IdP;
# Copyright Theke Solutions 2022
#
@ -31,7 +31,7 @@ use CGI;
=head1 NAME
Koha::REST::Plugin::Auth
Koha::REST::Plugin::Auth::IdP
=head1 API

6
Koha/REST/V1.pm

@ -21,7 +21,7 @@ use Mojo::Base 'Mojolicious';
use C4::Context;
use Koha::Logger;
use Koha::Auth::Providers;
use Koha::Auth::Identity::Providers;
use Mojolicious::Plugin::OAuth2;
use JSON::Validator::Schema::OpenAPIv2;
@ -141,7 +141,7 @@ sub startup {
my $oauth_configuration = {};
my $search_options = { protocol => [ "OIDC", "OAuth" ] };
my $providers = Koha::Auth::Providers->search( $search_options );
my $providers = Koha::Auth::Identity::Providers->search( $search_options );
while(my $provider = $providers->next) {
$oauth_configuration->{$provider->code} = decode_json($provider->config);
@ -151,7 +151,7 @@ sub startup {
$self->plugin( 'Koha::REST::Plugin::Query' );
$self->plugin( 'Koha::REST::Plugin::Objects' );
$self->plugin( 'Koha::REST::Plugin::Exceptions' );
$self->plugin( 'Koha::REST::Plugin::Auth' );
$self->plugin( 'Koha::REST::Plugin::Auth::IdP' );
$self->plugin( 'Mojolicious::Plugin::OAuth2' => $oauth_configuration );
}

41
Koha/REST/V1/Auth/Provider/Domains.pm → Koha/REST/V1/Auth/Identity/Provider/Domains.pm

@ -1,4 +1,4 @@
package Koha::REST::V1::Auth::Provider::Domains;
package Koha::REST::V1::Auth::Identity::Provider::Domains;
# This file is part of Koha.
#
@ -19,8 +19,8 @@ use Modern::Perl;
use Mojo::Base 'Mojolicious::Controller';
use Koha::Auth::Provider::Domains;
use Koha::Auth::Providers;
use Koha::Auth::Identity::Provider::Domains;
use Koha::Auth::Identity::Providers;
use Koha::Database;
@ -29,7 +29,7 @@ use Try::Tiny;
=head1 NAME
Koha::REST::V1::Auth::Provider::Domains - Controller library for handling
Koha::REST::V1::Auth::Identity::Provider::Domains - Controller library for handling
authentication provider domains routes.
=head2 Operations
@ -44,8 +44,8 @@ sub list {
my $c = shift->openapi->valid_input or return;
return try {
my $auth_provider_id = $c->validation->param('auth_provider_id');
my $provider = Koha::Auth::Providers->find($auth_provider_id);
my $identity_provider_id = $c->validation->param('identity_provider_id');
my $provider = Koha::Auth::Identity::Providers->find($identity_provider_id);
unless ($provider) {
return $c->render(
@ -78,8 +78,8 @@ sub get {
return try {
my $auth_provider_id = $c->validation->param('auth_provider_id');
my $provider = Koha::Auth::Providers->find($auth_provider_id);
my $identity_provider_id = $c->validation->param('identity_provider_id');
my $provider = Koha::Auth::Identity::Providers->find($identity_provider_id);
unless ($provider) {
return $c->render(
@ -93,8 +93,8 @@ sub get {
my $domains_rs = $provider->domains;
my $auth_provider_domain_id = $c->validation->param('auth_provider_domain_id');
my $domain = $c->objects->find( $domains_rs, $auth_provider_domain_id );
my $identity_provider_domain_id = $c->validation->param('identity_provider_domain_id');
my $domain = $c->objects->find( $domains_rs, $identity_provider_domain_id );
unless ($domain) {
return $c->render(
@ -122,10 +122,11 @@ sub add {
my $c = shift->openapi->valid_input or return;
return try {
my $params = $c->validation->param('body');
$params->{identity_provider_id} = $c->validation->param('identity_provider_id');
Koha::Database->new->schema->txn_do(
sub {
my $domain = Koha::Auth::Provider::Domain->new_from_api( $c->validation->param('body') );
my $domain = Koha::Auth::Identity::Provider::Domain->new_from_api( $params );
$domain->store;
$c->res->headers->location( $c->req->url->to_string . '/' . $domain->id );
@ -159,11 +160,11 @@ Controller method for updating an authentication provider domain.
sub update {
my $c = shift->openapi->valid_input or return;
my $auth_provider_id = $c->validation->param('auth_provider_id');
my $auth_provider_domain_id = $c->validation->param('auth_provider_domain_id');
my $identity_provider_id = $c->validation->param('identity_provider_id');
my $identity_provider_domain_id = $c->validation->param('identity_provider_domain_id');
my $domain = Koha::Auth::Provider::Domains->find(
{ auth_provider_id => $auth_provider_id, auth_provider_domain_id => $auth_provider_domain_id } );
my $domain = Koha::Auth::Identity::Provider::Domains->find(
{ identity_provider_id => $identity_provider_id, identity_provider_domain_id => $identity_provider_domain_id } );
unless ($domain) {
return $c->render(
@ -203,11 +204,11 @@ Controller method for deleting an authentication provider.
sub delete {
my $c = shift->openapi->valid_input or return;
my $auth_provider_id = $c->validation->param('auth_provider_id');
my $auth_provider_domain_id = $c->validation->param('auth_provider_domain_id');
my $identity_provider_id = $c->validation->param('identity_provider_id');
my $identity_provider_domain_id = $c->validation->param('identity_provider_domain_id');
my $domain = Koha::Auth::Provider::Domains->find(
{ auth_provider_id => $auth_provider_id, auth_provider_domain_id => $auth_provider_domain_id } );
my $domain = Koha::Auth::Identity::Provider::Domains->find(
{ identity_provider_id => $identity_provider_id, identity_provider_domain_id => $identity_provider_domain_id } );
unless ($domain) {
return $c->render(

26
Koha/REST/V1/Auth/Providers.pm → Koha/REST/V1/Auth/Identity/Providers.pm

@ -1,4 +1,4 @@
package Koha::REST::V1::Auth::Providers;
package Koha::REST::V1::Auth::Identity::Providers;
# This file is part of Koha.
#
@ -19,9 +19,9 @@ use Modern::Perl;
use Mojo::Base 'Mojolicious::Controller';
use Koha::Auth::Provider::OAuth;
use Koha::Auth::Provider::OIDC;
use Koha::Auth::Providers;
use Koha::Auth::Identity::Provider::OAuth;
use Koha::Auth::Identity::Provider::OIDC;
use Koha::Auth::Identity::Providers;
use Koha::Database;
@ -30,7 +30,7 @@ use Try::Tiny;
=head1 NAME
Koha::REST::V1::Auth::Providers - Controller library for handling
Koha::REST::V1::Auth::Identity::Providers - Controller library for handling
authentication providers routes.
=head2 Operations
@ -45,7 +45,7 @@ sub list {
my $c = shift->openapi->valid_input or return;
return try {
my $providers_rs = Koha::Auth::Providers->new;
my $providers_rs = Koha::Auth::Identity::Providers->new;
return $c->render(
status => 200,
openapi => $c->objects->search($providers_rs)
@ -66,8 +66,8 @@ sub get {
return try {
my $auth_provider_id = $c->validation->param('auth_provider_id');
my $provider = $c->objects->find( Koha::Auth::Providers->new, $auth_provider_id );
my $identity_provider_id = $c->validation->param('identity_provider_id');
my $provider = $c->objects->find( Koha::Auth::Identity::Providers->new, $identity_provider_id );
unless ( $provider ) {
return $c->render(
@ -106,7 +106,7 @@ sub add {
my $mapping = delete $body->{mapping};
my $protocol = delete $body->{protocol};
my $class = Koha::Auth::Provider::protocol_to_class_mapping->{$protocol};
my $class = Koha::Auth::Identity::Provider::protocol_to_class_mapping->{$protocol};
my $provider = $class->new_from_api( $body );
$provider->store;
@ -114,7 +114,7 @@ sub add {
$provider->set_config( $config );
$provider->set_mapping( $mapping );
$c->res->headers->location( $c->req->url->to_string . '/' . $provider->auth_provider_id );
$c->res->headers->location( $c->req->url->to_string . '/' . $provider->identity_provider_id );
return $c->render(
status => 201,
openapi => $provider->to_api
@ -148,8 +148,8 @@ Controller method for updating an authentication provider.
sub update {
my $c = shift->openapi->valid_input or return;
my $auth_provider_id = $c->validation->param('auth_provider_id');
my $provider = Koha::Auth::Providers->find( $auth_provider_id );
my $identity_provider_id = $c->validation->param('identity_provider_id');
my $provider = Koha::Auth::Identity::Providers->find( $identity_provider_id );
unless ( $provider ) {
return $c->render(
@ -211,7 +211,7 @@ Controller method for deleting an authentication provider.
sub delete {
my $c = shift->openapi->valid_input or return;
my $provider = Koha::Auth::Providers->find( $c->validation->param('auth_provider_id') );
my $provider = Koha::Auth::Identity::Providers->find( $c->validation->param('identity_provider_id') );
unless ( $provider ) {
return $c->render(
status => 404,

47
Koha/Schema/Result/AuthProvider.pm → Koha/Schema/Result/IdentityProvider.pm

@ -1,12 +1,12 @@
use utf8;
package Koha::Schema::Result::AuthProvider;
package Koha::Schema::Result::IdentityProvider;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
=head1 NAME
Koha::Schema::Result::AuthProvider
Koha::Schema::Result::IdentityProvider
=cut
@ -15,15 +15,15 @@ use warnings;
use base 'DBIx::Class::Core';
=head1 TABLE: C<auth_providers>
=head1 TABLE: C<identity_providers>
=cut
__PACKAGE__->table("auth_providers");
__PACKAGE__->table("identity_providers");
=head1 ACCESSORS
=head2 auth_provider_id
=head2 identity_provider_id
data_type: 'integer'
is_auto_increment: 1
@ -90,7 +90,7 @@ Provider icon URL
=cut
__PACKAGE__->add_columns(
"auth_provider_id",
"identity_provider_id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"code",
{ data_type => "varchar", is_nullable => 0, size => 20 },
@ -120,13 +120,13 @@ __PACKAGE__->add_columns(
=over 4
=item * L</auth_provider_id>
=item * L</identity_provider_id>
=back
=cut
__PACKAGE__->set_primary_key("auth_provider_id");
__PACKAGE__->set_primary_key("identity_provider_id");
=head1 UNIQUE CONSTRAINTS
@ -144,46 +144,37 @@ __PACKAGE__->add_unique_constraint("code", ["code"]);
=head1 RELATIONS
=head2 auth_provider_domains
=head2 identity_provider_domains
Type: has_many
Related object: L<Koha::Schema::Result::AuthProviderDomain>
Related object: L<Koha::Schema::Result::IdentityProviderDomain>
=cut
__PACKAGE__->has_many(
"auth_provider_domains",
"Koha::Schema::Result::AuthProviderDomain",
{ "foreign.auth_provider_id" => "self.auth_provider_id" },
"identity_provider_domains",
"Koha::Schema::Result::IdentityProviderDomain",
{ "foreign.identity_provider_id" => "self.identity_provider_id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-09-30 19:43:00
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ZqUo3by0ZXca5RI3QFNypw
=head2 domains
Type: has_many
Related object: L<Koha::Schema::Result::AuthProviderDomain>
=cut
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-10-20 15:27:55
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jmqAwH7/6QvawJ73/0rkQg
__PACKAGE__->has_many(
"domains",
"Koha::Schema::Result::AuthProviderDomain",
{ "foreign.auth_provider_id" => "self.auth_provider_id" },
"Koha::Schema::Result::IdentityProviderDomain",
{ "foreign.identity_provider_id" => "self.identity_provider_id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
sub koha_object_class {
'Koha::Auth::Provider';
'Koha::Auth::Identity::Provider';
}
sub koha_objects_class {
'Koha::Auth::Providers';
'Koha::Auth::Identity::Providers';
}
1;

78
Koha/Schema/Result/AuthProviderDomain.pm → Koha/Schema/Result/IdentityProviderDomain.pm

@ -1,12 +1,12 @@
use utf8;
package Koha::Schema::Result::AuthProviderDomain;
package Koha::Schema::Result::IdentityProviderDomain;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
=head1 NAME
Koha::Schema::Result::AuthProviderDomain
Koha::Schema::Result::IdentityProviderDomain
=cut
@ -15,15 +15,15 @@ use warnings;
use base 'DBIx::Class::Core';
=head1 TABLE: C<auth_provider_domains>
=head1 TABLE: C<identity_provider_domains>
=cut
__PACKAGE__->table("auth_provider_domains");
__PACKAGE__->table("identity_provider_domains");
=head1 ACCESSORS
=head2 auth_provider_domain_id
=head2 identity_provider_domain_id
data_type: 'integer'
is_auto_increment: 1
@ -31,7 +31,7 @@ __PACKAGE__->table("auth_provider_domains");
unique key, used to identify providers domain
=head2 auth_provider_id
=head2 identity_provider_id
data_type: 'integer'
is_foreign_key: 1
@ -92,7 +92,7 @@ Allow provider from opac interface
=head2 allow_staff
data_type: 'tinyint'
default_value: 1
default_value: 0
is_nullable: 0
Allow provider from staff interface
@ -100,9 +100,9 @@ Allow provider from staff interface
=cut
__PACKAGE__->add_columns(
"auth_provider_domain_id",
"identity_provider_domain_id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"auth_provider_id",
"identity_provider_id",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
"domain",
{ data_type => "varchar", is_nullable => 1, size => 100 },
@ -117,28 +117,28 @@ __PACKAGE__->add_columns(
"allow_opac",
{ data_type => "tinyint", default_value => 1, is_nullable => 0 },
"allow_staff",
{ data_type => "tinyint", default_value => 1, is_nullable => 0 },
{ data_type => "tinyint", default_value => 0, is_nullable => 0 },
);
=head1 PRIMARY KEY
=over 4
=item * L</auth_provider_domain_id>
=item * L</identity_provider_domain_id>
=back
=cut
__PACKAGE__->set_primary_key("auth_provider_domain_id");
__PACKAGE__->set_primary_key("identity_provider_domain_id");
=head1 UNIQUE CONSTRAINTS
=head2 C<auth_provider_id>
=head2 C<identity_provider_id>
=over 4
=item * L</auth_provider_id>
=item * L</identity_provider_id>
=item * L</domain>
@ -146,25 +146,10 @@ __PACKAGE__->set_primary_key("auth_provider_domain_id");
=cut
__PACKAGE__->add_unique_constraint("auth_provider_id", ["auth_provider_id", "domain"]);
__PACKAGE__->add_unique_constraint("identity_provider_id", ["identity_provider_id", "domain"]);
=head1 RELATIONS
=head2 auth_provider
Type: belongs_to
Related object: L<Koha::Schema::Result::AuthProvider>
=cut
__PACKAGE__->belongs_to(
"auth_provider",
"Koha::Schema::Result::AuthProvider",
{ auth_provider_id => "auth_provider_id" },
{ is_deferrable => 1, on_delete => "CASCADE", on_update => "RESTRICT" },
);
=head2 default_category
Type: belongs_to
@ -205,22 +190,37 @@ __PACKAGE__->belongs_to(
},
);
=head2 identity_provider
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-08-24 15:03:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1b0q+e8Ym8icJ6bYAY/Mbw
Type: belongs_to
Related object: L<Koha::Schema::Result::IdentityProvider>
=cut
__PACKAGE__->belongs_to(
"identity_provider",
"Koha::Schema::Result::IdentityProvider",
{ identity_provider_id => "identity_provider_id" },
{ is_deferrable => 1, on_delete => "CASCADE", on_update => "RESTRICT" },
);
sub koha_object_class {
'Koha::Auth::Provider::Domain';
}
sub koha_objects_class {
'Koha::Auth::Providers::Domains';
}
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-11-08 17:35:26
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:uUnzFzRKWAiYUsmapofXwQ
__PACKAGE__->add_columns(
'+auto_register' => { is_boolean => 1 },
'+update_on_auth' => { is_boolean => 1 },
'+allow_opac' => { is_boolean => 1 },
'+allow_staff' => { is_boolean => 1 },
'+allow_staff' => { is_boolean => 1 }
);
sub koha_object_class {
'Koha::Auth::Identity::Provider::Domain';
}
sub koha_objects_class {
'Koha::Auth::Identity::Provider::Domains';
}
1;

4
Koha/Template/Plugin/AuthClient.pm

@ -22,7 +22,7 @@ use Modern::Perl;
use Template::Plugin;
use base qw( Template::Plugin );
use Koha::Auth::Providers;
use Koha::Auth::Identity::Providers;
=head1 NAME
@ -49,7 +49,7 @@ sub get_providers {
$interface = 'staff'
if $interface eq 'intranet';
my $providers = Koha::Auth::Providers->search( { "domains.allow_$interface" => 1 }, { prefetch => 'domains' } );
my $providers = Koha::Auth::Identity::Providers->search( { "domains.allow_$interface" => 1 }, { prefetch => 'domains' } );
my $base_url = ( $interface ne 'staff' ) ? "/api/v1/public/oauth/login" : "/api/v1/public/oauth/login";
my @urls;

66
admin/authentication_providers.pl → admin/identity_providers.pl

@ -26,24 +26,24 @@ use Try::Tiny qw( catch try );
use C4::Auth qw( get_template_and_user );
use C4::Output qw( output_html_with_http_headers );
use Koha::Auth::Providers;
use Koha::Auth::Identity::Providers;
my $input = CGI->new;
my $op = $input->param('op') || 'list';
my $domain_ops = $input->param('domain_ops');
my $auth_provider_id = $input->param('auth_provider_id');
my $auth_provider;
my $identity_provider_id = $input->param('identity_provider_id');
my $identity_provider;
$auth_provider = Koha::Auth::Providers->find($auth_provider_id)
unless !$auth_provider_id;
$identity_provider = Koha::Auth::Identity::Providers->find($identity_provider_id)
unless !$identity_provider_id;
my $template_name = $domain_ops ? 'admin/authentication_provider_domains.tt' : 'admin/authentication_providers.tt';
my $template_name = $domain_ops ? 'admin/identity_provider_domains.tt' : 'admin/identity_providers.tt';
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
{ template_name => $template_name,
query => $input,
type => "intranet",
flagsrequired => { parameters => 'manage_authentication_providers' },
flagsrequired => { parameters => 'manage_identity_providers' },
}
);
@ -60,7 +60,7 @@ if ( !$domain_ops && $op eq 'add' ) {
my $protocol = $input->param('protocol');
try {
my $provider = Koha::Auth::Provider->new(
my $provider = Koha::Auth::Identity::Provider->new(
{ code => $code,
config => $config,
description => $description,
@ -71,9 +71,9 @@ if ( !$domain_ops && $op eq 'add' ) {
}
)->store;
Koha::Auth::Provider::Domain->new(
Koha::Auth::Identity::Provider::Domain->new(
{
auth_provider_id => $provider->auth_provider_id,
identity_provider_id => $provider->identity_provider_id,
}
)->store;
@ -97,7 +97,7 @@ elsif ( $domain_ops && $op eq 'add' ) {
my $allow_opac = $input->param('allow_opac');
my $allow_staff = $input->param('allow_staff');
my $auth_provider_id = $input->param('auth_provider_id');
my $identity_provider_id = $input->param('identity_provider_id');
my $auto_register = $input->param('auto_register');
my $default_category_id = $input->param('default_category_id');
my $default_library_id = $input->param('default_library_id');
@ -106,11 +106,11 @@ elsif ( $domain_ops && $op eq 'add' ) {
try {
Koha::Auth::Provider::Domain->new(
Koha::Auth::Identity::Provider::Domain->new(
{
allow_opac => $allow_opac,
allow_staff => $allow_staff,
auth_provider_id => $auth_provider_id,
identity_provider_id => $identity_provider_id,
auto_register => $auto_register,
default_category_id => $default_category_id,
default_library_id => $default_library_id,
@ -137,9 +137,9 @@ elsif ( $domain_ops && $op eq 'add' ) {
}
elsif ( !$domain_ops && $op eq 'edit_form' ) {
if ( $auth_provider ) {
if ( $identity_provider ) {
$template->param(
auth_provider => $auth_provider
identity_provider => $identity_provider
);
}
else {
@ -152,15 +152,15 @@ elsif ( !$domain_ops && $op eq 'edit_form' ) {
}
}
elsif ( $domain_ops && $op eq 'edit_form' ) {
my $auth_provider_domain_id = $input->param('auth_provider_domain_id');
my $auth_provider_domain;
my $identity_provider_domain_id = $input->param('identity_provider_domain_id');
my $identity_provider_domain;
$auth_provider_domain = Koha::Auth::Provider::Domains->find($auth_provider_domain_id)
unless !$auth_provider_domain_id;
$identity_provider_domain = Koha::Auth::Identity::Provider::Domains->find($identity_provider_domain_id)
unless !$identity_provider_domain_id;
if ( $auth_provider_domain ) {
if ( $identity_provider_domain ) {
$template->param(
auth_provider_domain => $auth_provider_domain
identity_provider_domain => $identity_provider_domain
);
}
else {
@ -174,7 +174,7 @@ elsif ( $domain_ops && $op eq 'edit_form' ) {
}
elsif ( !$domain_ops && $op eq 'edit_save' ) {
if ( $auth_provider ) {
if ( $identity_provider ) {
my $code = $input->param('code');
my $config = $input->param('config');
@ -186,7 +186,7 @@ elsif ( !$domain_ops && $op eq 'edit_save' ) {
try {
$auth_provider->set(
$identity_provider->set(
{ code => $code,
config => $config,
description => $description,
@ -225,15 +225,15 @@ elsif ( !$domain_ops && $op eq 'edit_save' ) {
}
elsif ( $domain_ops && $op eq 'edit_save' ) {
my $auth_provider_domain_id = $input->param('auth_provider_domain_id');
my $auth_provider_domain;
my $identity_provider_domain_id = $input->param('identity_provider_domain_id');
my $identity_provider_domain;
$auth_provider_domain = Koha::Auth::Provider::Domains->find($auth_provider_domain_id)
unless !$auth_provider_domain_id;
$identity_provider_domain = Koha::Auth::Identity::Provider::Domains->find($identity_provider_domain_id)
unless !$identity_provider_domain_id;
if ( $auth_provider_domain ) {
if ( $identity_provider_domain ) {
my $auth_provider_id = $input->param('auth_provider_id');
my $identity_provider_id = $input->param('identity_provider_id');
my $domain = $input->param('domain');
my $auto_register = $input->param('auto_register');
my $update_on_auth = $input->param('update_on_auth');
@ -244,9 +244,9 @@ elsif ( $domain_ops && $op eq 'edit_save' ) {
try {
$auth_provider_domain->set(
$identity_provider_domain->set(
{
auth_provider_id => $auth_provider_id,
identity_provider_id => $identity_provider_id,
domain => $domain,
auto_register => $auto_register,
update_on_auth => $update_on_auth,
@ -286,8 +286,8 @@ elsif ( $domain_ops && $op eq 'edit_save' ) {
if ( $domain_ops ) {
$template->param(
auth_provider_code => $auth_provider->code,
auth_provider_id => $auth_provider_id,
identity_provider_code => $identity_provider->code,
identity_provider_id => $identity_provider_id,
);
}

6
api/v1/swagger/definitions/auth_provider.yaml → api/v1/swagger/definitions/identity_provider.yaml

@ -1,7 +1,7 @@
---
type: object
properties:
auth_provider_id:
identity_provider_id:
type: integer
description: Internally assigned authentication provider identifier
readOnly: true
@ -36,7 +36,9 @@ properties:
type: object
icon_url:
description: Icon url
type: string
type:
- string
- "null"
domains:
description: Configured domains for the authentication provider
type:

7
api/v1/swagger/definitions/auth_provider_domain.yaml → api/v1/swagger/definitions/identity_provider_domain.yaml

@ -1,11 +1,11 @@
---
type: object
properties:
auth_provider_domain_id:
identity_provider_domain_id:
type: integer
description: Internally assigned authentication provider domain identifier
readOnly: true
auth_provider_id:
identity_provider_id:
type: integer
description: Internally assigned authentication provider identifier
domain:
@ -37,8 +37,7 @@ properties:
type: boolean
additionalProperties: false
required:
- auth_provider_domain_id
- auth_provider_id
- identity_provider_domain_id
- domain
- auto_register
- update_on_auth

490
api/v1/swagger/paths/auth.yaml

@ -567,4 +567,492 @@
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_authentication_providers
parameters: manage_authentication_providers
/auth/identity_providers:
get:
x-mojo-to: Auth::Identity::Providers#list
operationId: listIdentityProviders
tags:
- identity_providers
summary: List configured authentication providers
parameters:
- $ref: ../swagger.yaml#/parameters/match
- $ref: ../swagger.yaml#/parameters/order_by
- $ref: ../swagger.yaml#/parameters/page
- $ref: ../swagger.yaml#/parameters/per_page
- $ref: ../swagger.yaml#/parameters/q_param
- $ref: ../swagger.yaml#/parameters/q_body
- $ref: ../swagger.yaml#/parameters/q_header
- $ref: ../swagger.yaml#/parameters/request_id_header
- name: x-koha-embed
in: header
required: false
description: Embed list sent as a request header
type: array
items:
type: string
enum:
- domains
collectionFormat: csv
produces:
- application/json
responses:
"200":
description: A list of authentication providers
schema:
type: array
items:
$ref: ../swagger.yaml#/definitions/identity_provider
"400":
description: Bad Request
schema:
$ref: ../swagger.yaml#/definitions/error
"403":
description: Access forbidden
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
schema:
$ref: ../swagger.yaml#/definitions/error
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers
post:
x-mojo-to: Auth::Identity::Providers#add
operationId: addIdentityProvider
tags:
- identity_providers
summary: Add a new authentication provider
parameters:
- name: body
in: body
description: |
A JSON object containing OAuth provider parameters.
The `config` object required attributes depends on the chosen `protocol`
## OAuth
Requires:
* key
* secret
* authorize_url
* token_url
## OIDC
Requires:
* key
* secret
* well_known_url
required: true
schema:
$ref: ../swagger.yaml#/definitions/identity_provider
produces:
- application/json
responses:
"201":
description: The generated authentication provider
schema:
$ref: ../swagger.yaml#/definitions/identity_provider
"400":
description: Bad Request
schema:
$ref: ../swagger.yaml#/definitions/error
"403":
description: Access forbidden
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
schema:
$ref: ../swagger.yaml#/definitions/error
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers
"/auth/identity_providers/{identity_provider_id}":
get:
x-mojo-to: Auth::Identity::Providers#get
operationId: getIdentityProvider
tags:
- identity_providers
summary: Get authentication provider
parameters:
- $ref: ../swagger.yaml#/parameters/identity_provider_id_pp
- name: x-koha-embed
in: header
required: false
description: Embed list sent as a request header
type: array
items:
type: string
enum:
- domains
collectionFormat: csv
produces:
- application/json
responses:
"200":
description: An authentication provider
schema:
$ref: ../swagger.yaml#/definitions/identity_provider
"404":
description: Object not found
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
schema:
$ref: ../swagger.yaml#/definitions/error
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers
put:
x-mojo-to: Auth::Identity::Providers#update
operationId: updateIdentityProvider
tags:
- identity_providers
summary: Update an authentication provider
parameters:
- $ref: ../swagger.yaml#/parameters/identity_provider_id_pp
- name: body
in: body
description: |
A JSON object containing OAuth provider parameters.
The `config` object required attributes depends on the chosen `protocol`
## OAuth
Requires:
* key
* secret
* authorize_url
* token_url
## OIDC
Requires:
* key
* secret
* well_known_url
required: true
schema:
$ref: ../swagger.yaml#/definitions/identity_provider
produces:
- application/json
responses:
"200":
description: Updated authentication provider
schema:
$ref: ../swagger.yaml#/definitions/identity_provider
"400":
description: Bad Request
schema:
$ref: ../swagger.yaml#/definitions/error
"403":
description: Access forbidden
schema:
$ref: ../swagger.yaml#/definitions/error
"404":
description: Object not found
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
schema:
$ref: ../swagger.yaml#/definitions/error
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers
delete:
x-mojo-to: Auth::Identity::Providers#delete
operationId: delIdentityProvider
tags:
- identity_providers
summary: Delete authentication provider
parameters:
- $ref: ../swagger.yaml#/parameters/identity_provider_id_pp
produces:
- application/json
responses:
"204":
description: Authentication provider deleted
"401":
description: Authentication required
schema:
$ref: ../swagger.yaml#/definitions/error
"403":
description: Access forbidden
schema:
$ref: ../swagger.yaml#/definitions/error
"404":
description: City not found
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers
"/auth/identity_providers/{identity_provider_id}/domains":
get:
x-mojo-to: Auth::Identity::Provider::Domains#list
operationId: listIdentityProviderDomains
tags:
- identity_providers
summary: Get authentication provider configured domains
parameters:
- $ref: ../swagger.yaml#/parameters/identity_provider_id_pp
- $ref: ../swagger.yaml#/parameters/match
- $ref: ../swagger.yaml#/parameters/order_by
- $ref: ../swagger.yaml#/parameters/page
- $ref: ../swagger.yaml#/parameters/per_page
- $ref: ../swagger.yaml#/parameters/q_param
- $ref: ../swagger.yaml#/parameters/q_body
- $ref: ../swagger.yaml#/parameters/q_header
- $ref: ../swagger.yaml#/parameters/request_id_header
- name: x-koha-embed
in: header
required: false
description: Embed list sent as a request header
type: array
items:
type: string
enum:
- domains
collectionFormat: csv
produces:
- application/json
responses:
"200":
description: An authentication provider
schema:
items:
$ref: ../swagger.yaml#/definitions/identity_provider_domain
"404":
description: Object not found
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
schema:
$ref: ../swagger.yaml#/definitions/error
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers
post:
x-mojo-to: Auth::Identity::Provider::Domains#add
operationId: addIdentityProviderDomain
tags:
- identity_providers
summary: Add an authentication provider domain
parameters:
- $ref: ../swagger.yaml#/parameters/identity_provider_id_pp
- name: body
in: body
description: An authentication provider domain object
required: true
schema:
$ref: ../swagger.yaml#/definitions/identity_provider_domain
produces:
- application/json
responses:
"201":
description: Updated authentication provider domain
schema:
$ref: ../swagger.yaml#/definitions/identity_provider_domain
"400":
description: Bad Request
schema:
$ref: ../swagger.yaml#/definitions/error
"403":
description: Access forbidden
schema:
$ref: ../swagger.yaml#/definitions/error
"404":
description: Object not found
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
schema:
$ref: ../swagger.yaml#/definitions/error
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers
"/auth/identity_providers/{identity_provider_id}/domains/{identity_provider_domain_id}":
get:
x-mojo-to: Auth::Identity::Provider::Domains#get
operationId: getIdentityProviderDomain
tags:
- identity_providers
summary: Get authentication provider domain
parameters:
- $ref: ../swagger.yaml#/parameters/identity_provider_id_pp
- $ref: ../swagger.yaml#/parameters/identity_provider_domain_id_pp
produces:
- application/json
responses:
"200":
description: An authentication provider
schema:
$ref: ../swagger.yaml#/definitions/identity_provider_domain
"404":
description: Object not found
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
schema:
$ref: ../swagger.yaml#/definitions/error
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers
put:
x-mojo-to: Auth::Identity::Provider::Domains#update
operationId: updateIdentityProviderDomain
tags:
- identity_providers
summary: Update an authentication provider domain
parameters:
- $ref: ../swagger.yaml#/parameters/identity_provider_id_pp
- $ref: ../swagger.yaml#/parameters/identity_provider_domain_id_pp
- name: body
in: body
description: An authentication provider domain object
required: true
schema:
$ref: ../swagger.yaml#/definitions/identity_provider_domain
produces:
- application/json
responses:
"200":
description: Updated authentication provider domain
schema:
$ref: ../swagger.yaml#/definitions/identity_provider_domain
"400":
description: Bad Request
schema:
$ref: ../swagger.yaml#/definitions/error
"403":
description: Access forbidden
schema:
$ref: ../swagger.yaml#/definitions/error
"404":
description: Object not found
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
schema:
$ref: ../swagger.yaml#/definitions/error
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers
delete:
x-mojo-to: Auth::Identity::Provider::Domains#delete
operationId: delIdentityProviderDomain
tags:
- identity_providers
summary: Delete authentication provider
parameters:
- $ref: ../swagger.yaml#/parameters/identity_provider_id_pp
- $ref: ../swagger.yaml#/parameters/identity_provider_domain_id_pp
produces:
- application/json
responses:
"204":
description: Authentication provider deleted
"401":
description: Authentication required
schema:
$ref: ../swagger.yaml#/definitions/error
"403":
description: Access forbidden
schema:
$ref: ../swagger.yaml#/definitions/error
"404":
description: City not found
schema:
$ref: ../swagger.yaml#/definitions/error
"500":
description: |
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
"503":
description: Under maintenance
schema:
$ref: ../swagger.yaml#/definitions/error
x-koha-authorization:
permissions:
parameters: manage_identity_providers

38
api/v1/swagger/swagger.yaml

@ -8,10 +8,10 @@ definitions:
$ref: ./definitions/advancededitormacro.yaml
allows_renewal:
$ref: ./definitions/allows_renewal.yaml
auth_provider:
"$ref": ./definitions/auth_provider.yaml
auth_provider_domain:
"$ref": ./definitions/auth_provider_domain.yaml
identity_provider:
"$ref": ./definitions/identity_provider.yaml
identity_provider_domain:
"$ref": ./definitions/identity_provider_domain.yaml
basket:
$ref: ./definitions/basket.yaml
bundle_link:
@ -129,14 +129,14 @@ paths:
$ref: paths/auth.yaml#/~1auth~1two-factor~1registration
/auth/two-factor/registration/verification:
$ref: paths/auth.yaml#/~1auth~1two-factor~1registration~1verification
/auth/providers:
$ref: paths/auth.yaml#/~1auth~1providers
"/auth/providers/{auth_provider_id}":
$ref: paths/auth.yaml#/~1auth~1providers~1{auth_provider_id}
"/auth/providers/{auth_provider_id}/domains":
$ref: paths/auth.yaml#/~1auth~1providers~1{auth_provider_id}~1domains
"/auth/providers/{auth_provider_id}/domains/{auth_provider_domain_id}":
$ref: paths/auth.yaml#/~1auth~1providers~1{auth_provider_id}~1domains~1{auth_provider_domain_id}
/auth/identity_providers:
$ref: paths/auth.yaml#/~1auth~1identity_providers
"/auth/identity_providers/{identity_provider_id}":
$ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}
"/auth/identity_providers/{identity_provider_id}/domains":
$ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains
"/auth/identity_providers/{identity_provider_id}/domains/{identity_provider_domain_id}":
$ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains~1{identity_provider_domain_id}
"/biblios/{biblio_id}":
$ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}"
"/biblios/{biblio_id}/checkouts":
@ -336,16 +336,16 @@ parameters:
name: agreement_period_id
required: true
type: integer
auth_provider_id_pp:
identity_provider_id_pp:
description: Authentication provider internal identifier
in: path
name: auth_provider_id
name: identity_provider_id
required: true
type: integer
auth_provider_domain_id_pp:
identity_provider_domain_id_pp:
description: Authentication provider domain internal identifier
in: path
name: auth_provider_domain_id
name: identity_provider_domain_id
required: true
type: integer
biblio_id_pp:
@ -680,9 +680,9 @@ tags:
- description: "Manage article requests\n"
name: article_requests
x-displayName: Article requests
- description: "Manage authentication providers\n"
name: auth_providers
x-displayName: Authentication providers
- description: "Manage identity providers\n"
name: identity_providers
x-displayName: Identity providers
- description: "Manage baskets for the acquisitions module\n"
name: baskets
x-displayName: Baskets

40
installer/data/mysql/atomicupdate/bug_31378.pl

@ -3,7 +3,7 @@ use C4::Context;
return {
bug_number => "31378",
description => "Add auth_provider and auth_provider_domains configuration tables",
description => "Add identity_provider and identity_provider_domains configuration tables",
up => sub {
my ($args) = @_;
my ($dbh, $out) = @$args{qw(dbh out)};
@ -12,15 +12,15 @@ return {
$dbh->do(qq{
INSERT IGNORE permissions (module_bit, code, description)
VALUES
( 3, 'manage_authentication_providers', 'Manage authentication providers')
( 3, 'manage_identity_providers', 'Manage authentication providers')
});
say $out "manage_authentication_providers permission added";
say $out "manage_identity_providers permission added";
unless (TableExists('auth_providers')) {
unless (TableExists('identity_providers')) {
$dbh->do(q{
CREATE TABLE `auth_providers` (
`auth_provider_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique key, used to identify the provider',
CREATE TABLE `identity_providers` (
`identity_provider_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique key, used to identify the provider',
`code` varchar(20) NOT NULL COMMENT 'Provider code',
`description` varchar(255) NOT NULL COMMENT 'Description for the provider',
`protocol` enum('OAuth', 'OIDC', 'LDAP', 'CAS') COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Protocol provider speaks',
@ -28,33 +28,33 @@ return {
`mapping` longtext NOT NULL DEFAULT '{}' COMMENT 'Configuration to map provider data to Koha user',
`matchpoint` enum('email','userid','cardnumber') NOT NULL COMMENT 'The patron attribute to be used as matchpoint',
`icon_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Provider icon URL',
PRIMARY KEY (`auth_provider_id`),
PRIMARY KEY (`identity_provider_id`),
UNIQUE KEY (`code`),
KEY `protocol` (`protocol`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
});
}
unless (TableExists('auth_provider_domains')) {
unless (TableExists('identity_provider_domains')) {
$dbh->do(q{
CREATE TABLE `auth_provider_domains` (
`auth_provider_domain_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique key, used to identify providers domain',
`auth_provider_id` int(11) NOT NULL COMMENT 'Reference to provider',
CREATE TABLE `identity_provider_domains` (
`identity_provider_domain_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique key, used to identify providers domain',
`identity_provider_id` int(11) NOT NULL COMMENT 'Reference to provider',
`domain` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Domain name. If null means all domains',
`auto_register` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Allow user auto register',
`update_on_auth` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Update user data on auth login',
`default_library_id` varchar(10) DEFAULT NULL COMMENT 'Default library to create user if auto register is enabled',
`default_category_id` varchar(10) DEFAULT NULL COMMENT 'Default category to create user if auto register is enabled',
`allow_opac` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Allow provider from opac interface',
`allow_staff` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Allow provider from staff interface',
PRIMARY KEY (`auth_provider_domain_id`),
UNIQUE KEY (`auth_provider_id`, `domain`),
`allow_staff` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Allow provider from staff interface',
PRIMARY KEY (`identity_provider_domain_id`),
UNIQUE KEY (`identity_provider_id`, `domain`),
KEY `domain` (`domain`),
KEY `allow_opac` (`allow_opac`),
KEY `allow_staff` (`allow_staff`),
CONSTRAINT `auth_provider_domain_ibfk_1` FOREIGN KEY (`auth_provider_id`) REFERENCES `auth_providers` (`auth_provider_id`) ON DELETE CASCADE,
CONSTRAINT `auth_provider_domain_ibfk_2` FOREIGN KEY (`default_library_id`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE,
CONSTRAINT `auth_provider_domain_ibfk_3` FOREIGN KEY (`default_category_id`) REFERENCES `categories` (`categorycode`) ON DELETE CASCADE
CONSTRAINT `identity_provider_domain_ibfk_1` FOREIGN KEY (`identity_provider_id`) REFERENCES `identity_providers` (`identity_provider_id`) ON DELETE CASCADE,
CONSTRAINT `identity_provider_domain_ibfk_2` FOREIGN KEY (`default_library_id`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE,
CONSTRAINT `identity_provider_domain_ibfk_3` FOREIGN KEY (`default_category_id`) REFERENCES `categories` (`categorycode`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
});
}
@ -63,7 +63,7 @@ return {
# Print useful stuff here
say $out "Setting google provider";
$dbh->do(q{
INSERT INTO `auth_providers` (name, protocol, config, mapping), auto_register, registration_config, interface)
INSERT INTO `identity_providers` (name, protocol, config, mapping), auto_register, registration_config, interface)
SELECT 'google' as name,
'OIDC' as protocol,
JSON_OBJECT("key", k.value, "secret", s.value, "well_known_url", "https://accounts.google.com/.well-known/openid-configuration", "scope", "openid email profile") as config,
@ -75,7 +75,7 @@ return {
});
$dbh->do(q{
INSERT INTO `auth_provider_domains` (auth_provider_id, domain, auto_register, update_on_auth, default_library_id, default_category_id, allow_opac, allow_staff)
INSERT INTO `identity_provider_domains` (identity_provider_id, domain, auto_register, update_on_auth, default_library_id, default_category_id, allow_opac, allow_staff)
p.id as provider_id,
d.value as domain,
r.value as auto_register,
@ -85,7 +85,7 @@ return {
1 as allow_opac,
0 as allow_interface
FROM
(SELECT id FROM `auth_provider` WHERE name = 'google') p
(SELECT id FROM `identity_provider` WHERE name = 'google') p
JOIN
(SELECT CASE WHEN value = '' OR value IS NULL THEN NULL ELSE value END as value FROM `systempreferences` where variable = 'GoogleOpenIDConnectDomain') d
JOIN

32
installer/data/mysql/kohastructure.sql

@ -851,14 +851,14 @@ CREATE TABLE `auth_header` (
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `auth_provider`
-- Table structure for table `identity_provider`
--
DROP TABLE IF EXISTS `auth_providers`;
DROP TABLE IF EXISTS `identity_providers`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `auth_providers` (
`auth_provider_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique key, used to identify the provider',
CREATE TABLE `identity_providers` (
`identity_provider_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique key, used to identify the provider',
`code` varchar(20) NOT NULL COMMENT 'Provider code',
`description` varchar(255) NOT NULL COMMENT 'Description for the provider',
`protocol` enum('OAuth', 'OIDC', 'LDAP', 'CAS') COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Protocol provider speaks',
@ -866,37 +866,37 @@ CREATE TABLE `auth_providers` (
`mapping` longtext NOT NULL DEFAULT '{}' COMMENT 'Configuration to map provider data to Koha user',
`matchpoint` enum('email','userid','cardnumber') NOT NULL COMMENT 'The patron attribute to be used as matchpoint',
`icon_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Provider icon URL',
PRIMARY KEY (`auth_provider_id`),
PRIMARY KEY (`identity_provider_id`),
UNIQUE KEY (`code`),
KEY `protocol` (`protocol`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `auth_provider`
-- Table structure for table `identity_provider`
--
DROP TABLE IF EXISTS `auth_provider_domains`;
DROP TABLE IF EXISTS `identity_provider_domains`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `auth_provider_domains` (
`auth_provider_domain_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique key, used to identify providers domain',
`auth_provider_id` int(11) NOT NULL COMMENT 'Reference to provider',
CREATE TABLE `identity_provider_domains` (
`identity_provider_domain_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique key, used to identify providers domain',
`identity_provider_id` int(11) NOT NULL COMMENT 'Reference to provider',
`domain` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Domain name. If null means all domains',
`auto_register` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Allow user auto register',
`update_on_auth` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Update user data on auth login',
`default_library_id` varchar(10) DEFAULT NULL COMMENT 'Default library to create user if auto register is enabled',
`default_category_id` varchar(10) DEFAULT NULL COMMENT 'Default category to create user if auto register is enabled',
`allow_opac` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Allow provider from opac interface',
`allow_staff` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Allow provider from staff interface',
PRIMARY KEY (`auth_provider_domain_id`),
UNIQUE KEY (`auth_provider_id`, `domain`),
`allow_staff` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Allow provider from staff interface',
PRIMARY KEY (`identity_provider_domain_id`),
UNIQUE KEY (`identity_provider_id`, `domain`),
KEY `domain` (`domain`),
KEY `allow_opac` (`allow_opac`),
KEY `allow_staff` (`allow_staff`),
CONSTRAINT `auth_provider_domain_ibfk_1` FOREIGN KEY (`auth_provider_id`) REFERENCES `auth_providers` (`auth_provider_id`) ON DELETE CASCADE,
CONSTRAINT `auth_provider_domain_ibfk_2` FOREIGN KEY (`default_library_id`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE,
CONSTRAINT `auth_provider_domain_ibfk_3` FOREIGN KEY (`default_category_id`) REFERENCES `categories` (`categorycode`) ON DELETE CASCADE
CONSTRAINT `identity_provider_domain_ibfk_1` FOREIGN KEY (`identity_provider_id`) REFERENCES `identity_providers` (`identity_provider_id`) ON DELETE CASCADE,
CONSTRAINT `identity_provider_domain_ibfk_2` FOREIGN KEY (`default_library_id`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE,
CONSTRAINT `identity_provider_domain_ibfk_3` FOREIGN KEY (`default_category_id`) REFERENCES `categories` (`categorycode`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--

2
installer/data/mysql/mandatory/userpermissions.sql

@ -41,7 +41,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
( 3, 'manage_background_jobs', 'Manage background jobs'),
( 3, 'manage_curbside_pickups', 'Manage curbside pickups'),
( 3, 'manage_search_filters', 'Manage custom search filters'),
( 3, 'manage_authentication_providers', 'Manage authentication providers'),
( 3, 'manage_identity_providers', 'Manage authentication providers'),
( 4, 'delete_borrowers', 'Delete patrons'),
( 4, 'edit_borrowers', 'Add, modify and view patron information'),
( 4, 'view_borrower_infos_from_any_libraries', 'View patron infos from any libraries'),

6
koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc

@ -141,11 +141,11 @@
</ul>
[% END %]
[% IF ( CAN_user_parameters_manage_authentication_providers || CAN_user_parameters_manage_smtp_servers || CAN_user_parameters_manage_search_targets || CAN_user_parameters_manage_didyoumean || CAN_user_parameters_manage_column_config || CAN_user_parameters_manage_audio_alerts || ( CAN_user_parameters_manage_sms_providers && Koha.Preference('SMSSendDriver') == 'Email' ) || CAN_user_parameters_manage_usage_stats || CAN_user_parameters_manage_additional_fields || ( Koha.Preference('EnableAdvancedCatalogingEditor') && CAN_user_parameters_manage_keyboard_shortcuts ) ) %]
[% IF ( CAN_user_parameters_manage_identity_providers || CAN_user_parameters_manage_smtp_servers || CAN_user_parameters_manage_search_targets || CAN_user_parameters_manage_didyoumean || CAN_user_parameters_manage_column_config || CAN_user_parameters_manage_audio_alerts || ( CAN_user_parameters_manage_sms_providers && Koha.Preference('SMSSendDriver') == 'Email' ) || CAN_user_parameters_manage_usage_stats || CAN_user_parameters_manage_additional_fields || ( Koha.Preference('EnableAdvancedCatalogingEditor') && CAN_user_parameters_manage_keyboard_shortcuts ) ) %]
<h5>Additional parameters</h5>
<ul>
[% IF ( CAN_user_parameters_manage_authentication_providers) %]
<li><a href="/cgi-bin/koha/admin/authentication_providers.pl">Authentication providers</a></li>
[% IF ( CAN_user_parameters_manage_identity_providers) %]
<li><a href="/cgi-bin/koha/admin/identity_providers.pl">Authentication providers</a></li>
[% END %]
[% IF ( CAN_user_parameters_manage_search_targets ) %]
<li><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50/SRU servers</a></li>

6
koha-tmpl/intranet-tmpl/prog/en/includes/permissions.inc

@ -830,9 +830,9 @@
Manage recalls for patrons
</span>
<span class="permissioncode">([% name | html %])</span>
[%# authentication_providers %]
[%- CASE 'manage_authentication_providers' -%]
<span class="sub_permission manage_authentication_providers_subpermission">
[%# identity_providers %]
[%- CASE 'manage_identity_providers' -%]
<span class="sub_permission manage_identity_providers_subpermission">
Manage authentication providers
</span>
<span class="permissioncode">([% name | html %])</span>

8
koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt

@ -238,14 +238,14 @@
</dl>
[% END %]
[% IF ( ( CAN_user_parameters_manage_authentication_providers || CAN_user_parameters_manage_smtp_servers || CAN_user_parameters_manage_search_targets || CAN_user_parameters_manage_didyoumean || CAN_user_parameters_manage_column_config || CAN_user_parameters_manage_audio_alerts || CAN_user_parameters_manage_sms_providers && Koha.Preference('SMSSendDriver') == 'Email' ) || CAN_user_parameters_manage_usage_stats || CAN_user_parameters_manage_additional_fields || CAN_user_parameters_manage_mana || (Koha.Preference('EnableAdvancedCatalogingEditor') && CAN_user_parameters_manage_keyboard_shortcuts) ) %]
[% IF ( ( CAN_user_parameters_manage_identity_providers || CAN_user_parameters_manage_smtp_servers || CAN_user_parameters_manage_search_targets || CAN_user_parameters_manage_didyoumean || CAN_user_parameters_manage_column_config || CAN_user_parameters_manage_audio_alerts || CAN_user_parameters_manage_sms_providers && Koha.Preference('SMSSendDriver') == 'Email' ) || CAN_user_parameters_manage_usage_stats || CAN_user_parameters_manage_additional_fields || CAN_user_parameters_manage_mana || (Koha.Preference('EnableAdvancedCatalogingEditor') && CAN_user_parameters_manage_keyboard_shortcuts) ) %]
<h3>Additional parameters</h3>
<dl>
<!-- <dt><a href="/cgi-bin/koha/admin/printers.pl">Network Printers</a></dt>
<dd>Printers (UNIX paths).</dd> -->
[% IF ( CAN_user_parameters_manage_authentication_providers) %]
<dt><a href="/cgi-bin/koha/admin/authentication_providers.pl">Authentication providers</a></dt>
<dd>Define which external authentication providers to use</dd>
[% IF ( CAN_user_parameters_manage_identity_providers) %]
<dt><a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a></dt>
<dd>Define which external identity providers to use</dd>
[% END %]
[% IF ( CAN_user_parameters_manage_search_targets ) %]
<dt><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50/SRU servers</a></dt>

112
koha-tmpl/intranet-tmpl/prog/en/modules/admin/authentication_provider_domains.tt → koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_provider_domains.tt

@ -6,15 +6,15 @@
[% INCLUDE 'doc-head-open.inc' %]
<title>
[% IF op == 'add_form' %]
New authentication provider domain &rsaquo; [% ELSIF op == 'edit_form' %]
Edit authentication provider domain &rsaquo; [% END %]
New identity provider domain &rsaquo; [% ELSIF op == 'edit_form' %]
Edit identity provider domain &rsaquo; [% END %]
Authentication providers &rsaquo; Administration &rsaquo; Koha
Identity providers &rsaquo; Administration &rsaquo; Koha
</title>
[% INCLUDE 'doc-head-close.inc' %]
</head>
<body id="admin_auth_provider_domains" class="admin">
<body id="admin_identity_provider_domains" class="admin">
[% INCLUDE 'header.inc' %]
[% INCLUDE 'prefs-admin-search.inc' %]
@ -28,12 +28,12 @@
</li>
<li>
<a href="/cgi-bin/koha/admin/authentication_providers.pl">Authentication providers</a>
<a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
</li>
[% IF op == 'add_form' %]
<li>
<a href="/cgi-bin/koha/admin/authentication_providers.pl?domain_ops=1&amp;auth_provider_id=[%- auth_provider_id | uri -%]">Domains for [%- auth_provider_name | html -%]</a>
<a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_name | html -%]</a>
</li>
<li>
<a href="#" aria-current="page">
@ -43,7 +43,7 @@
[% ELSIF op == 'edit_form' %]
<li>
<a href="/cgi-bin/koha/admin/authentication_providers.pl?domain_ops=1&amp;auth_provider_id=[%- auth_provider_id | uri -%]">Domains for [%- auth_provider_name | html -%]</a>
<a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_name | html -%]</a>
</li>
<li>
<a href="#" aria-current="page">
@ -54,7 +54,7 @@
[% ELSE %]
<li>
<a href="#" aria-current="page">
Domains for [%- auth_provider_code | html -%]
Domains for [%- identity_provider_code | html -%]
</a>
</li>
[% END %]
@ -67,31 +67,31 @@
<main>
[% FOREACH m IN messages %]
<div class="dialog [% m.type | html %]" id="auth_provider_domain_action_result_dialog">
<div class="dialog [% m.type | html %]" id="identity_provider_domain_action_result_dialog">
[% SWITCH m.code %]
[% CASE 'error_on_update' %]
<span>An error occurred trying to open the authentication provider domain for editing. The passed id is invalid.</span>
<span>An error occurred trying to open the identity provider domain for editing. The passed id is invalid.</span>
[% CASE 'error_on_insert' %]
<span>An error occurred when adding a new authentication provider domain.</span>
<span>An error occurred when adding a new identity provider domain.</span>
[% CASE 'success_on_update' %]
<span>Authentication provider domain updated successfully.</span>
<span>Identity provider domain updated successfully.</span>
[% CASE 'success_on_insert' %]
<span>Authentication provider domain added successfully.</span>
<span>Identity provider domain added successfully.</span>
[% CASE %]
<span>[% m.code | html %]</span>
[% END %]
</div>
[% END %]
<div class="dialog message" id="auth_provider_domain_delete_success" style="display: none;"></div>
<div class="dialog alert" id="auth_provider_domain_delete_error" style="display: none;"></div>
<div class="dialog message" id="identity_provider_domain_delete_success" style="display: none;"></div>
<div class="dialog alert" id="identity_provider_domain_delete_error" style="display: none;"></div>
[% IF op == 'add_form' %]
<h1>New authentication provider domain</h1>
<form action="/cgi-bin/koha/admin/authentication_providers.pl" id="add" name="add" class="validated" method="post">
<h1>New identity provider domain</h1>
<form action="/cgi-bin/koha/admin/identity_providers.pl" id="add" name="add" class="validated" method="post">
<input type="hidden" name="op" value="add" />
<input type="hidden" name="domain_ops" value="1" />
<input type="hidden" name="auth_provider_id" value="[%- auth_provider_id | html -%]" />
<input type="hidden" name="identity_provider_id" value="[%- identity_provider_id | html -%]" />
<fieldset class="rows">
<ol>
<li>
@ -140,7 +140,7 @@
<option value="1" selected="selected">Allow</option>
<option value="0">Don't allow</option>
</select>
<span>opac users of this domain to login with this authentication provider</span>
<span>opac users of this domain to login with this identity provider</span>
</li>
<li>
<label for="allow_opac">Allow staff: </label>
@ -154,23 +154,23 @@
</fieldset>
<fieldset class="action">
<input type="submit" value="Submit" />
<a class="cancel" href="/cgi-bin/koha/admin/authentication_providers.pl?domain_ops=1&amp;auth_provider_id=[%- auth_provider_id | html -%]">Cancel</a>
<a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
</fieldset>
</form>
[% END %]
[% IF op == 'edit_form' %]
<h1>Edit authentication provider domain</h1>
<form action="/cgi-bin/koha/admin/authentication_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
<h1>Edit identity provider domain</h1>
<form action="/cgi-bin/koha/admin/identity_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
<input type="hidden" name="op" value="edit_save" />
<input type="hidden" name="domain_ops" value="1" />
<input type="hidden" name="auth_provider_id" value="[%- auth_provider_id | html -%]" />
<input type="hidden" name="auth_provider_domain_id" value="[%- auth_provider_domain.auth_provider_domain_id | html -%]" />
<input type="hidden" name="identity_provider_id" value="[%- identity_provider_id | html -%]" />
<input type="hidden" name="identity_provider_domain_id" value="[%- identity_provider_domain.identity_provider_domain_id | html -%]" />
<fieldset class="rows">
<ol>
<li>
<label for="domain">Domain: </label>
<input type="text" name="domain" id="domain" size="60" value="[%- auth_provider_domain.domain | html -%]"/>
<input type="text" name="domain" id="domain" size="60" value="[%- identity_provider_domain.domain | html -%]"/>
</li>
</ol>
</fieldset>
@ -180,7 +180,7 @@
<li>
<label for="update_on_auth">Update on login: </label>
<select name="update_on_auth" id="update_on_auth">
[% IF auth_provider_domain.update_on_auth == "1" %]
[% IF identity_provider_domain.update_on_auth == "1" %]
<option value="1" selected="selected">Update</option>
<option value="0">Don't update</option>
[% ELSE %]
@ -193,7 +193,7 @@
<li>
<label for="auto_register">Auto register: </label>
<select name="auto_register" id="auto_register">
[% IF auth_provider_domain.auto_register == "1" %]
[% IF identity_provider_domain.auto_register == "1" %]
<option value="1" selected="selected">Allow</option>
<option value="0">Don't allow</option>
[% ELSE %]
@ -206,7 +206,7 @@
<li>
<label for="default_library_id">Default library: </label>
<select id="default_library_id" name="default_library_id">
[% PROCESS options_for_libraries libraries => Branches.all( selected => auth_provider_domain.default_library_id, unfiltered => 1, do_not_select_my_library => 1 ) %]
[% PROCESS options_for_libraries libraries => Branches.all( selected => identity_provider_domain.default_library_id, unfiltered => 1, do_not_select_my_library => 1 ) %]
</select>
</li>
<li>
@ -214,7 +214,7 @@
[% SET categories = Categories.all() %]
<select name="default_category_id" id="default_category_id">
[% FOREACH category IN categories %]
[% IF category.categorycode == auth_provider_domain.default_category_id %]
[% IF category.categorycode == identity_provider_domain.default_category_id %]
<option value="[% category.categorycode | html %]" selected="selected">[% category.description | html %]</option>
[% ELSE %]
<option value="[% category.categorycode | html %]">[% category.description | html %]</option>
@ -225,7 +225,7 @@
<li>
<label for="allow_opac">Allow opac: </label>
<select name="allow_opac" id="allow_opac">
[% IF auth_provider_domain.allow_opac == "1" %]
[% IF identity_provider_domain.allow_opac == "1" %]
<option value="1" selected="selected">Allow</option>
<option value="0">Don't allow</option>
[% ELSE %]
@ -233,12 +233,12 @@
<option value="0" selected="selected">Don't allow</option>
[% END %]
</select>
<span>opac users of this domain to login with this authentication provider</span>
<span>opac users of this domain to login with this identity provider</span>
</li>
<li>
<label for="allow_opac">Allow staff: </label>
<select name="allow_staff" id="allow_staff">
[% IF auth_provider_domain.allow_staff == "1" %]
[% IF identity_provider_domain.allow_staff == "1" %]
<option value="1" selected="selected">Allow</option>
<option value="0">Don't allow</option>
[% ELSE %]
@ -246,13 +246,13 @@
<option value="0" selected="selected">Don't allow</option>
[% END %]
</select>
<span>staff users of this domain to login with this authentication provider</span>
<span>staff users of this domain to login with this identity provider</span>
</li>
</ol>
</fieldset>
<fieldset class="action">
<input type="submit" value="Submit" />
<a class="cancel" href="/cgi-bin/koha/admin/authentication_providers.pl?domain_ops=1&amp;auth_provider_id=[%- auth_provider_id | html -%]">Cancel</a>
<a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
</fieldset>
</form>
[% END %]
@ -260,12 +260,12 @@
[% IF op == 'list' %]
<div id="toolbar" class="btn-toolbar">
<a class="btn btn-default" id="new_auth_provider_domain" href="/cgi-bin/koha/admin/authentication_providers.pl?domain_ops=1&amp;auth_provider_id=[%- auth_provider_id | html -%]&amp;op=add_form"><i class="fa fa-plus"></i> New authentication provider domain</a>
<a class="btn btn-default" id="new_identity_provider_domain" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]&amp;op=add_form"><i class="fa fa-plus"></i> New identity provider domain</a>
</div>
<h1>Authentication provider domains</h1>
<h1>Identity provider domains</h1>
<table id="auth_provider_domains">
<table id="identity_provider_domains">
<thead>
<tr>
<th>Domain</th>
@ -286,7 +286,7 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="delete_confirm_modal_label">Delete authentication provider domain</h3>
<h3 id="delete_confirm_modal_label">Delete identity provider domain</h3>
</div>
<div class="modal-body">
<div id="delete_confirm_dialog"></div>
@ -316,7 +316,7 @@
<script>
$(document).ready(function() {
var auth_provider_domains_url = '/api/v1/auth/providers/[%- auth_provider_id | html -%]/domains';
var identity_provider_domains_url = '/api/v1/auth/identity_providers/[%- identity_provider_id | html -%]/domains';
[% SET categories = Categories.all() %]
var categories = {
[% FOREACH category IN categories %]
@ -329,12 +329,12 @@
"[% library.branchcode | html %]": "[% library.branchname | html %]",
[% END %]
};
window.auth_provider_domains = $("#auth_provider_domains").kohaTable({
window.identity_provider_domains = $("#identity_provider_domains").kohaTable({
"ajax": {
"url": auth_provider_domains_url
"url": identity_provider_domains_url
},
'language': {
'emptyTable': '<div class="dialog message">'+_("There are no authentication provider domains defined.")+'</div>'
'emptyTable': '<div class="dialog message">'+_("There are no identity provider domains defined.")+'</div>'
},
"columnDefs": [ {
"targets": [1],
@ -424,8 +424,8 @@
},
{
"data": function( row, type, val, meta ) {
var result = '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/admin/authentication_providers.pl?domain_ops=1&amp;auth_provider_id=[%- auth_provider_id | html -%]&amp;op=edit_form&amp;auth_provider_domain_id='+ encodeURIComponent(row.auth_provider_domain_id) +'"><i class="fa fa-pencil" aria-hidden="true"></i> '+_("Edit")+'</a>'+"\n";
result += '<a class="btn btn-default btn-xs delete_auth_provider_domain" role="button" href="#" data-toggle="modal" data-target="#delete_confirm_modal" data-auth-provider-domain-id="'+ encodeURIComponent(row.auth_provider_domain_id) +'" data-auth-provider-domain="'+ encodeURIComponent((row.domain || '').escapeHtml()) +'"><i class="fa fa-trash" aria-hidden="true"></i> '+_("Delete")+'</a>';
var result = '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]&amp;op=edit_form&amp;identity_provider_domain_id='+ encodeURIComponent(row.identity_provider_domain_id) +'"><i class="fa fa-pencil" aria-hidden="true"></i> '+_("Edit")+'</a>'+"\n";
result += '<a class="btn btn-default btn-xs delete_identity_provider_domain" role="button" href="#" data-toggle="modal" data-target="#delete_confirm_modal" data-auth-provider-domain-id="'+ encodeURIComponent(row.identity_provider_domain_id) +'" data-auth-provider-domain="'+ encodeURIComponent((row.domain || '').escapeHtml()) +'"><i class="fa fa-trash" aria-hidden="true"></i> '+_("Delete")+'</a>';
return result;
},
"searchable": false,
@ -439,32 +439,32 @@
},
});
$('#auth_provider_domains').on( "click", '.delete_auth_provider_domain', function () {
var auth_provider_domain_id = $(this).data('auth-provider-domain-id');
var auth_provider_domain = decodeURIComponent($(this).data('auth-provider-domain'));
$('#identity_provider_domains').on( "click", '.delete_identity_provider_domain', function () {
var identity_provider_domain_id = $(this).data('auth-provider-domain-id');
var identity_provider_domain = decodeURIComponent($(this).data('auth-provider-domain'));
$("#delete_confirm_dialog").html(
_("You are about to delete the '%s' authentication provider domain.").format(auth_provider_domain)
_("You are about to delete the '%s' identity provider domain.").format(identity_provider_domain)
);
$("#delete_confirm_modal_button").data('auth-provider-domain-id', auth_provider_domain_id);
$("#delete_confirm_modal_button").data('auth-provider-domain', auth_provider_domain);
$("#delete_confirm_modal_button").data('auth-provider-domain-id', identity_provider_domain_id);
$("#delete_confirm_modal_button").data('auth-provider-domain', identity_provider_domain);
});
$("#delete_confirm_modal_button").on( "click", function () {
var auth_provider_domain_id = $(this).data('auth-provider-domain-id');
var auth_provider_domain = $(this).data('auth-provider-domain');
var identity_provider_domain_id = $(this).data('auth-provider-domain-id');
var identity_provider_domain = $(this).data('auth-provider-domain');
$.ajax({
method: "DELETE",
url: auth_provider_domains_url+"/"+auth_provider_domain_id
url: identity_provider_domains_url+"/"+identity_provider_domain_id
}).success(function() {
window.auth_provider_domains.api().ajax.reload(function (data) {
window.identity_provider_domains.api().ajax.reload(function (data) {
$("#smtp_action_result_dialog").hide();
$("#smtp_delete_success").html(_("Server '%s' deleted successfully.").format(auth_provider_domain)).show();
$("#smtp_delete_success").html(_("Server '%s' deleted successfully.").format(identity_provider_domain)).show();
});
}).fail(function () {
$("#smtp_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(auth_provider_domain)).show();
$("#smtp_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(identity_provider_domain)).show();
}).done(function () {
$("#delete_confirm_modal").modal('hide');
});

116
koha-tmpl/intranet-tmpl/prog/en/modules/admin/authentication_providers.tt → koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_providers.tt

@ -4,15 +4,15 @@
[% INCLUDE 'doc-head-open.inc' %]
<title>
[% IF op == 'add_form' %]
New authentication provider &rsaquo; [% ELSIF op == 'edit_form' %]
Edit authentication provider &rsaquo; [% END %]
New identity provider &rsaquo; [% ELSIF op == 'edit_form' %]
Edit identity provider &rsaquo; [% END %]
Authentication providers &rsaquo; Administration &rsaquo; Koha
Identity providers &rsaquo; Administration &rsaquo; Koha
</title>
[% INCLUDE 'doc-head-close.inc' %]
</head>
<body id="admin_auth_providers" class="admin">
<body id="admin_identity_providers" class="admin">
[% INCLUDE 'header.inc' %]
[% INCLUDE 'prefs-admin-search.inc' %]
@ -27,7 +27,7 @@
[% IF op == 'add_form' %]
<li>
<a href="/cgi-bin/koha/admin/authentication_providers.pl">Authentication providers</a>
<a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
</li>
<li>
<a href="#" aria-current="page">
@ -37,7 +37,7 @@
[% ELSIF op == 'edit_form' %]
<li>
<a href="/cgi-bin/koha/admin/authentication_providers.pl">Authentication providers</a>
<a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
</li>
<li>
<a href="#" aria-current="page">
@ -48,7 +48,7 @@
[% ELSE %]
<li>
<a href="#" aria-current="page">
Authentication providers
Identity providers
</a>
</li>
[% END %]
@ -61,28 +61,28 @@
<main>
[% FOREACH m IN messages %]
<div class="dialog [% m.type | html %]" id="auth_provider_action_result_dialog">
<div class="dialog [% m.type | html %]" id="identity_provider_action_result_dialog">
[% SWITCH m.code %]
[% CASE 'error_on_update' %]
<span>An error occurred trying to open the authentication provider for editing. The passed id is invalid.</span>
<span>An error occurred trying to open the identity provider for editing. The passed id is invalid.</span>
[% CASE 'error_on_insert' %]
<span>An error occurred when adding a new authentication provider.</span>
<span>An error occurred when adding a new identity provider.</span>
[% CASE 'success_on_update' %]
<span>Authentication provider updated successfully.</span>
<span>Identity provider updated successfully.</span>
[% CASE 'success_on_insert' %]
<span>Authentication provider added successfully.</span>
<span>Identity provider added successfully.</span>
[% CASE %]
<span>[% m.code | html %]</span>
[% END %]
</div>
[% END %]
<div class="dialog message" id="auth_provider_delete_success" style="display: none;"></div>
<div class="dialog alert" id="auth_provider_delete_error" style="display: none;"></div>
<div class="dialog message" id="identity_provider_delete_success" style="display: none;"></div>
<div class="dialog alert" id="identity_provider_delete_error" style="display: none;"></div>
[% IF op == 'add_form' %]
<h1>New authentication provider</h1>
<form action="/cgi-bin/koha/admin/authentication_providers.pl" id="add" name="add" class="validated" method="post">
<h1>New identity provider</h1>
<form action="/cgi-bin/koha/admin/identity_providers.pl" id="add" name="add" class="validated" method="post">
<input type="hidden" name="op" value="add" />
<fieldset class="rows">
<ol>
@ -151,32 +151,32 @@
</fieldset>
<fieldset class="action">
<input type="submit" value="Submit" />
<a class="cancel" href="/cgi-bin/koha/admin/authentication_providers.pl">Cancel</a>
<a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
</fieldset>
</form>
[% END %]
[% IF op == 'edit_form' %]
<h1>Edit authentication provider</h1>
<form action="/cgi-bin/koha/admin/authentication_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
<h1>Edit identity provider</h1>
<form action="/cgi-bin/koha/admin/identity_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
<input type="hidden" name="op" value="edit_save" />
<input type="hidden" name="auth_provider_id" value="[%- auth_provider.auth_provider_id | html -%]" />
<input type="hidden" name="identity_provider_id" value="[%- identity_provider.identity_provider_id | html -%]" />
<fieldset class="rows">
<ol>
<li>
<label for="code" class="required">Code: </label>
<input type="text" name="code" id="code" size="60" class="required" required="required" value="[%- auth_provider.code | html -%]"/>
<input type="text" name="code" id="code" size="60" class="required" required="required" value="[%- identity_provider.code | html -%]"/>
<span class="required">Required</span>
</li>
<li>
<label for="description" class="required">Description: </label>
<input type="text" name="description" id="description" size="60" class="required" required="required" value="[%- auth_provider.description | html -%]"/>
<input type="text" name="description" id="description" size="60" class="required" required="required" value="[%- identity_provider.description | html -%]"/>
<span class="required">Required</span>
</li>
<li>
<label for="protocol">Protocol: </label>
<select name="protocol" id="protocol">
[% IF auth_provider.protocol == 'OAuth' %]
[% IF identity_provider.protocol == 'OAuth' %]
<option value="OAuth" selected="selected">OAuth</option>
<option value="OIDC">OIDC</option>
<!-- Not implemented yet
@ -201,39 +201,39 @@
<li>
<div>
<label for="config" class="required json">Configuration: </label>
<textarea name="config" id="config" class="required">[%- auth_provider.config | html -%]</textarea>
<textarea name="config" id="config" class="required">[%- identity_provider.config | html -%]</textarea>
<span class="required">Required</span>
</div>
<div>
<label></label>
<button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default [%- auth_provider.protocol | html -%] configuration</button>
<button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default [%- identity_provider.protocol | html -%] configuration</button>
</div>
</li>
<li>
<div>
<label for="mapping" class="required json">Mapping: </label>
<textarea name="mapping" id="mapping" class="required">[%- auth_provider.mapping | html -%]</textarea>
<textarea name="mapping" id="mapping" class="required">[%- identity_provider.mapping | html -%]</textarea>
<span class="required">Required</span>
</div>
<div>
<label></label>
<button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default [%- auth_provider.protocol | html -%] mapping</button>
<button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default [%- identity_provider.protocol | html -%] mapping</button>
</div>
</li>
<li>
<label for="matchpoint" class="required">matchpoint: </label>
<select name="matchpoint" id="matchpoint" class="required">
[%- IF auth_provider.matchpoint == 'email' -%]
[%- IF identity_provider.matchpoint == 'email' -%]
<option value="email" selected="selected">Email</option>
[%- ELSE -%]
<option value="email">Email</option>
[%- END -%]
[%- IF auth_provider.matchpoint == 'userid' -%]
[%- IF identity_provider.matchpoint == 'userid' -%]
<option value="userid" selected="selected">User id</option>
[%- ELSE -%]
<option value="userid">User id</option>
[%- END -%]
[%- IF auth_provider.matchpoint == 'cardnumber' -%]
[%- IF identity_provider.matchpoint == 'cardnumber' -%]
<option value="cardnumber" selected="selected">Card number</option>
[%- ELSE -%]
<option value="cardnumber">Card number</option>
@ -243,13 +243,13 @@
</li>
<li>
<label for="icon_url">Icon URL: </label>
<input type="text" name="icon_url" id="icon_url" size="60" value="[%- auth_provider.icon_url | html -%]"/>
<input type="text" name="icon_url" id="icon_url" size="60" value="[%- identity_provider.icon_url | html -%]"/>
</li>
</ol>
</fieldset>
<fieldset class="action">
<input type="submit" value="Submit" />
<a class="cancel" href="/cgi-bin/koha/admin/authentication_providers.pl">Cancel</a>
<a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
</fieldset>
</form>
[% END %]
@ -257,12 +257,12 @@
[% IF op == 'list' %]
<div id="toolbar" class="btn-toolbar">
<a class="btn btn-default" id="new_auth_provider" href="/cgi-bin/koha/admin/authentication_providers.pl?op=add_form"><i class="fa fa-plus"></i> New authentication provider</a>
<a class="btn btn-default" id="new_identity_provider" href="/cgi-bin/koha/admin/identity_providers.pl?op=add_form"><i class="fa fa-plus"></i> New identity provider</a>
</div>
<h1>Authentication providers</h1>
<h1>Identity providers</h1>
<table id="auth_providers">
<table id="identity_providers">
<thead>
<tr>
<th>Code</th>
@ -279,7 +279,7 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="delete_confirm_modal_label">Delete authentication provider</h3>
<h3 id="delete_confirm_modal_label">Delete identity provider</h3>
</div>
<div class="modal-body">
<div id="delete_confirm_dialog"></div>
@ -309,13 +309,13 @@
<script>
$(document).ready(function() {
var auth_providers_url = '/api/v1/auth/providers';
window.auth_providers = $("#auth_providers").kohaTable({
var identity_providers_url = '/api/v1/auth/identity_providers';
window.identity_providers = $("#identity_providers").kohaTable({
"ajax": {
"url": auth_providers_url
"url": identity_providers_url
},
'language': {
'emptyTable': '<div class="dialog message">'+_("There are no authentication providers defined.")+'</div>'
'emptyTable': '<div class="dialog message">'+_("There are no identity providers defined.")+'</div>'
},
"columnDefs": [ {
"targets": [0,1,2],
@ -349,9 +349,9 @@
},
{
"data": function( row, type, val, meta ) {
var result = '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/admin/authentication_providers.pl?op=edit_form&amp;auth_provider_id='+ encodeURIComponent(row.auth_provider_id) +'"><i class="fa fa-pencil" aria-hidden="true"></i> '+_("Edit")+'</a>'+"\n";
result += '<a class="btn btn-default btn-xs delete_auth_provider" role="button" href="#" data-toggle="modal" data-target="#delete_confirm_modal" data-auth-provider-id="'+ encodeURIComponent(row.auth_provider_id) +'" data-auth-provider-code="'+ encodeURIComponent(row.code.escapeHtml()) +'"><i class="fa fa-trash" aria-hidden="true"></i> '+_("Delete")+'</a>'+"\n";
result += '<a class="btn btn-default btn-xs edit_domains" role="button" href="/cgi-bin/koha/admin/authentication_providers.pl?domain_ops=1&amp;auth_provider_id='+ encodeURIComponent(row.auth_provider_id) +'"><i class="fa fa-cog" aria-hidden="true"></i> '+_("Manage Domains")+'</a>';
var result = '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/admin/identity_providers.pl?op=edit_form&amp;identity_provider_id='+ encodeURIComponent(row.identity_provider_id) +'"><i class="fa fa-pencil" aria-hidden="true"></i> '+_("Edit")+'</a>'+"\n";
result += '<a class="btn btn-default btn-xs delete_identity_provider" role="button" href="#" data-toggle="modal" data-target="#delete_confirm_modal" data-auth-provider-id="'+ encodeURIComponent(row.identity_provider_id) +'" data-auth-provider-code="'+ encodeURIComponent(row.code.escapeHtml()) +'"><i class="fa fa-trash" aria-hidden="true"></i> '+_("Delete")+'</a>'+"\n";
result += '<a class="btn btn-default btn-xs edit_domains" role="button" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id='+ encodeURIComponent(row.identity_provider_id) +'"><i class="fa fa-cog" aria-hidden="true"></i> '+_("Manage Domains")+'</a>';
return result;
},
"searchable": false,
@ -365,32 +365,32 @@
},
});
$('#auth_providers').on( "click", '.delete_auth_provider', function () {
var auth_provider_id = $(this).data('auth-provider-id');
var auth_provider_code = decodeURIComponent($(this).data('auth-provider-code'));
$('#identity_providers').on( "click", '.delete_identity_provider', function () {
var identity_provider_id = $(this).data('auth-provider-id');
var identity_provider_code = decodeURIComponent($(this).data('auth-provider-code'));
$("#delete_confirm_dialog").html(
_("You are about to delete the '%s' authentication provider.").format(auth_provider_code)
_("You are about to delete the '%s' identity provider.").format(identity_provider_code)
);
$("#delete_confirm_modal_button").data('auth-provider-id', auth_provider_id);
$("#delete_confirm_modal_button").data('auth-provider-code', auth_provider_code);
$("#delete_confirm_modal_button").data('auth-provider-id', identity_provider_id);
$("#delete_confirm_modal_button").data('auth-provider-code', identity_provider_code);
});
$("#delete_confirm_modal_button").on( "click", function () {
var auth_provider_id = $(this).data('auth-provider-id');
var auth_provider_code = $(this).data('auth-provider-code');
var identity_provider_id = $(this).data('auth-provider-id');
var identity_provider_code = $(this).data('auth-provider-code');
$.ajax({
method: "DELETE",
url: auth_providers_url+"/"+auth_provider_id
url: identity_providers_url+"/"+identity_provider_id
}).success(function() {
window.auth_providers.api().ajax.reload(function (data) {
$("#auth_provider_action_result_dialog").hide();
$("#auth_provider_delete_success").html(_("Server '%s' deleted successfully.").format(auth_provider_code)).show();
window.identity_providers.api().ajax.reload(function (data) {
$("#identity_provider_action_result_dialog").hide();
$("#identity_provider_delete_success").html(_("Server '%s' deleted successfully.").format(identity_provider_code)).show();
});
}).fail(function () {
$("#auth_provider_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(auth_provider_code)).show();
$("#identity_provider_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(identity_provider_code)).show();
}).done(function () {
$("#delete_confirm_modal").modal('hide');
});
@ -438,8 +438,8 @@
},
mapping: {
email: "email",
given_name: "firstname",
family_name: "surname"
firstname: "given_name",
surname: "family_name"
}
}
};

8
koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt

@ -84,9 +84,9 @@
[% IF !TwoFA_prompt && !TwoFA_setup && !Koha.Preference('staffShibOnly') %]
<!-- login prompt time-->
[% SET auth_providers = AuthClient.get_providers('staff') %]
[% IF ( ! auth_providers.empty ) %]
[% FOREACH provider IN auth_providers %]
[% SET identity_providers = AuthClient.get_providers('staff') %]
[% IF ( ! identity_providers.empty ) %]
[% FOREACH provider IN identity_providers %]
<p class="clearfix">
<a href="[% provider.url | url %]" class="btn btn-light col-xs-12" id="provider_[% provider.code | html %]">
[% IF provider.icon_url %]
@ -100,7 +100,7 @@
[% END %]
<hr/>
<p>If you do not have an external account, but do have a local account, you can still log in: </p>
[% END # /IF auth_providers.size %]
[% END # /IF identity_providers.size %]
<form action="[% script_name | html %]" method="post" name="loginform" id="loginform">
<input type="hidden" name="koha_login_context" value="intranet" />

8
koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc

@ -385,9 +385,9 @@
[% END %]
[% END %]
[% UNLESS Koha.Preference('opacShibOnly') %]
[% SET auth_providers = AuthClient.get_providers('opac') %]
[% IF ( ! auth_providers.empty ) %]
[% FOREACH provider IN auth_providers %]
[% SET identity_providers = AuthClient.get_providers('opac') %]
[% IF ( ! identity_providers.empty ) %]
[% FOREACH provider IN identity_providers %]
<p class="clearfix">
<a href="[% provider.url | url %]" class="btn btn-light col-md-12" id="provider_[% provider.code | html %]">
[% IF provider.icon_url %]
@ -401,7 +401,7 @@
[% END %]
<hr/>
<p>If you do not have an external account, but do have a local account, you can still log in: </p>
[% END # /IF auth_providers.size %]
[% END # /IF identity_providers.size %]
<input type="hidden" name="koha_login_context" value="opac" />
<fieldset class="brief">
<div class="local-login">

8
koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt

@ -163,9 +163,9 @@
[% END # / IF casAuthentication %]
[% SET auth_providers = AuthClient.get_providers('opac') %]
[% IF ( ! auth_providers.empty ) %]
[% FOREACH provider IN auth_providers %]
[% SET identity_providers = AuthClient.get_providers('opac') %]
[% IF ( ! identity_providers.empty ) %]
[% FOREACH provider IN identity_providers %]
<p class="clearfix">
<a href="[% provider.url | url %]" class="btn btn-light col-md-12" id="provider_[% provider.code | html %]">
[% IF provider.icon_url %]
@ -179,7 +179,7 @@
[% END %]
<hr/>
<p>If you do not have an external account, but do have a local account, you can still log in: </p>
[% END # /IF auth_providers %]
[% END # /IF identity_providers %]
[% IF ( Koha.Preference('GoogleOpenIDConnect') == 1 ) %]
[% IF ( invalidGoogleOpenIDConnectLogin ) %]

8
koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-main.tt

@ -192,9 +192,9 @@
<a href="/cgi-bin/koha/svc/auth/googleopenidconnect" class="btn btn-light" id="openid_connect"><i class="fa fa-google" aria-hidden="true"></i> Log in with Google</a>
<p>If you do not have a Google account, but do have a local account, you can still log in: </p>
[% END # /IF GoogleOpenIDConnect %]
[% SET auth_providers = AuthClient.get_providers('opac') %]
[% IF ( ! auth_providers.empty ) %]
[% FOREACH provider IN auth_providers %]
[% SET identity_providers = AuthClient.get_providers('opac') %]
[% IF ( ! identity_providers.empty ) %]
[% FOREACH provider IN identity_providers %]
<p class="clearfix">
<a href="[% provider.url | url %]" class="btn btn-light col-md-12" id="provider_[% provider.code | html %]">
[% IF provider.icon_url %]
@ -208,7 +208,7 @@
[% END %]
<hr/>
<p>If you do not have an external account, but do have a local account, you can still log in: </p>
[% END # /IF auth_providers.size %]
[% END # /IF identity_providers.size %]
<div class="local-login">
<label for="userid">Login:</label>
<input class="form-control" type="text" id="userid" name="userid" autocomplete="off" />

179
t/db_dependent/Koha/Auth/Client.t

@ -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');
};

34
t/db_dependent/Koha/Auth/Provider.t → t/db_dependent/Koha/Auth/Identity/Provider.t

@ -26,7 +26,7 @@ use Test::Exception;
use JSON qw(encode_json);
use Koha::Auth::Providers;
use Koha::Auth::Identity::Providers;
use t::lib::TestBuilder;
use t::lib::Mocks;
@ -40,14 +40,14 @@ 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::Identity::Providers' } );
my $domains = $provider->domains;
is( ref($domains), 'Koha::Auth::Provider::Domains', 'Type is correct' );
is( ref($domains), 'Koha::Auth::Identity::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::Identity::Provider::Domains', value => { identity_provider_id => $provider->id } } );
$builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id } } );
is( $provider->domains->count, 2, 'The provider has 2 domains defined' );
@ -60,7 +60,7 @@ subtest 'get_config() tests' => sub {
$schema->storage->txn_begin;
my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { config => '{' } } );
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { config => '{' } } );
throws_ok { $provider->get_config() }
'Koha::Exceptions::Object::BadValue', 'Expected exception thrown on bad JSON';
@ -83,7 +83,7 @@ subtest 'set_config() tests' => sub {
plan tests => 4;
my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { protocol => 'OIDC' } } );
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { protocol => 'OIDC' } } );
$provider = $provider->upgrade_class;
my $config = {
@ -99,7 +99,7 @@ subtest 'set_config() tests' => sub {
$config->{well_known_url} = 'https://koha-community.org/auth';
my $return = $provider->set_config($config);
is( ref($return), 'Koha::Auth::Provider::OIDC', 'Return type is correct' );
is( ref($return), 'Koha::Auth::Identity::Provider::OIDC', 'Return type is correct' );
is_deeply( $provider->get_config, $config, 'Configuration stored correctly' );
};
@ -108,7 +108,7 @@ subtest 'set_config() tests' => sub {
plan tests => 4;
my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { protocol => 'OAuth' } } );
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { protocol => 'OAuth' } } );
$provider = $provider->upgrade_class;
my $config = {
@ -125,7 +125,7 @@ subtest 'set_config() tests' => sub {
$config->{authorize_url} = 'https://koha-community.org/auth/authorize';
my $return = $provider->set_config($config);
is( ref($return), 'Koha::Auth::Provider::OAuth', 'Return type is correct' );
is( ref($return), 'Koha::Auth::Identity::Provider::OAuth', 'Return type is correct' );
is_deeply( $provider->get_config, $config, 'Configuration stored correctly' );
};
@ -134,7 +134,7 @@ subtest 'set_config() tests' => sub {
plan tests => 2;
my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { protocol => 'CAS' } } );
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { protocol => 'CAS' } } );
throws_ok { $provider->set_config() }
'Koha::Exception', 'Exception thrown on unsupported protocol';
@ -151,7 +151,7 @@ subtest 'get_mapping() tests' => sub {
$schema->storage->txn_begin;
my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { config => '{' } } );
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { config => '{' } } );
throws_ok { $provider->get_mapping() }
'Koha::Exceptions::Object::BadValue', 'Expected exception thrown on bad JSON';
@ -170,7 +170,7 @@ subtest 'set_mapping() tests' => sub {
$schema->storage->txn_begin;
my $provider = $builder->build_object( { class => 'Koha::Auth::Providers' } );
my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers' } );
my $mapping = { some => 'value', and => 'another' };
$provider->set_mapping($mapping)->store;
@ -186,25 +186,25 @@ subtest 'upgrade_class() tests' => sub {
$schema->storage->txn_begin;
my $mapping = Koha::Auth::Provider::protocol_to_class_mapping;
my $mapping = Koha::Auth::Identity::Provider::protocol_to_class_mapping;
my @protocols = keys %{ $mapping };
foreach my $protocol (@protocols) {
my $provider = $builder->build_object(
{
class => 'Koha::Auth::Providers',
class => 'Koha::Auth::Identity::Providers',
value => { protocol => $protocol },
}
);
is( ref($provider), 'Koha::Auth::Provider', "Base class used for $protocol" );
is( ref($provider), 'Koha::Auth::Identity::Provider', "Base class used for $protocol" );
# upgrade
$provider = $provider->upgrade_class;
is( ref($provider), $mapping->{$protocol}, "Class upgraded to " . $mapping->{$protocol} . "for protocol $protocol" );
}
my $provider = Koha::Auth::Provider->new({ protocol => 'Invalid' });
my $provider = Koha::Auth::Identity::Provider->new({ protocol => 'Invalid' });
throws_ok
{ $provider->upgrade }
'Koha::Exception',

133
t/db_dependent/Koha/REST/Plugin/Auth/IdP.t

@ -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;

341
t/db_dependent/api/v1/idp.t

@ -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;

166
t/lib/IdP/ExternalIdP.pm

@ -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…
Cancel
Save