Bug 31378: Rename Auth Provider to Identity Provider and add Client.t tests
authorAgustin Moyano <agustinmoyano@theke.io>
Wed, 26 Oct 2022 12:00:09 +0000 (09:00 -0300)
committerTomas Cohen Arazi <tomascohen@theke.io>
Tue, 8 Nov 2022 17:39:51 +0000 (14:39 -0300)
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>
54 files changed:
Koha/Auth/Client.pm
Koha/Auth/Client/OAuth.pm
Koha/Auth/Identity/Provider.pm [new file with mode: 0644]
Koha/Auth/Identity/Provider/Domain.pm [new file with mode: 0644]
Koha/Auth/Identity/Provider/Domains.pm [new file with mode: 0644]
Koha/Auth/Identity/Provider/OAuth.pm [new file with mode: 0644]
Koha/Auth/Identity/Provider/OIDC.pm [new file with mode: 0644]
Koha/Auth/Identity/Providers.pm [new file with mode: 0644]
Koha/Auth/Provider.pm [deleted file]
Koha/Auth/Provider/Domain.pm [deleted file]
Koha/Auth/Provider/Domains.pm [deleted file]
Koha/Auth/Provider/OAuth.pm [deleted file]
Koha/Auth/Provider/OIDC.pm [deleted file]
Koha/Auth/Providers.pm [deleted file]
Koha/REST/Plugin/Auth.pm [deleted file]
Koha/REST/Plugin/Auth/IdP.pm [new file with mode: 0644]
Koha/REST/V1.pm
Koha/REST/V1/Auth/Identity/Provider/Domains.pm [new file with mode: 0644]
Koha/REST/V1/Auth/Identity/Providers.pm [new file with mode: 0644]
Koha/REST/V1/Auth/Provider/Domains.pm [deleted file]
Koha/REST/V1/Auth/Providers.pm [deleted file]
Koha/Schema/Result/AuthProvider.pm [deleted file]
Koha/Schema/Result/AuthProviderDomain.pm [deleted file]
Koha/Schema/Result/IdentityProvider.pm [new file with mode: 0644]
Koha/Schema/Result/IdentityProviderDomain.pm [new file with mode: 0644]
Koha/Template/Plugin/AuthClient.pm
admin/authentication_providers.pl [deleted file]
admin/identity_providers.pl [new file with mode: 0644]
api/v1/swagger/definitions/auth_provider.yaml [deleted file]
api/v1/swagger/definitions/auth_provider_domain.yaml [deleted file]
api/v1/swagger/definitions/identity_provider.yaml [new file with mode: 0644]
api/v1/swagger/definitions/identity_provider_domain.yaml [new file with mode: 0644]
api/v1/swagger/paths/auth.yaml
api/v1/swagger/swagger.yaml
installer/data/mysql/atomicupdate/bug_31378.pl
installer/data/mysql/kohastructure.sql
installer/data/mysql/mandatory/userpermissions.sql
koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc
koha-tmpl/intranet-tmpl/prog/en/includes/permissions.inc
koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt
koha-tmpl/intranet-tmpl/prog/en/modules/admin/authentication_provider_domains.tt [deleted file]
koha-tmpl/intranet-tmpl/prog/en/modules/admin/authentication_providers.tt [deleted file]
koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_provider_domains.tt [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_providers.tt [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt
koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc
koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt
koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-main.tt
t/db_dependent/Koha/Auth/Client.t [new file with mode: 0644]
t/db_dependent/Koha/Auth/Identity/Provider.t [new file with mode: 0755]
t/db_dependent/Koha/Auth/Provider.t [deleted file]
t/db_dependent/Koha/REST/Plugin/Auth/IdP.t [new file with mode: 0644]
t/db_dependent/api/v1/idp.t [new file with mode: 0644]
t/lib/IdP/ExternalIdP.pm [new file with mode: 0644]

index 7fd6627..4bb71f6 100644 (file)
@@ -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;
index 728fa4e..3ea30f7 100644 (file)
@@ -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;
diff --git a/Koha/Auth/Identity/Provider.pm b/Koha/Auth/Identity/Provider.pm
new file mode 100644 (file)
index 0000000..4d29b81
--- /dev/null
@@ -0,0 +1,239 @@
+package Koha::Auth::Identity::Provider;
+
+# Copyright Theke Solutions 2022
+#
+# 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 base qw(Koha::Object);
+
+use JSON qw( decode_json encode_json );
+use Try::Tiny;
+
+use Koha::Auth::Identity::Provider::Domains;
+use Koha::Exceptions;
+use Koha::Exceptions::Object;
+
+=head1 NAME
+
+Koha::Auth::Identity::Provider - Koha Auth Provider Object class
+
+=head1 API
+
+=head2 Class methods
+
+=head3 domains
+
+    my $domains = $provider->domains;
+
+Returns the related I<Koha::Auth::Identity::Provider::Domains> iterator.
+
+=cut
+
+sub domains {
+    my ($self) = @_;
+
+    return Koha::Auth::Identity::Provider::Domains->_new_from_dbic( scalar $self->_result->domains );
+}
+
+=head3 get_config
+
+    my $config = $provider->get_config;
+
+Returns a I<hashref> containing the configuration parameters for the provider.
+
+=cut
+
+sub get_config {
+    my ($self) = @_;
+
+    return try {
+        return decode_json( $self->config );
+    }
+    catch {
+        Koha::Exceptions::Object::BadValue->throw("Error reading JSON data: $_");
+    };
+}
+
+=head3 set_config
+
+    # OAuth
+    $provider->set_config(
+        {
+            key           => 'APP_ID',
+            secret        => 'SECRET_KEY',
+            authorize_url => 'https://provider.example.com/auth',
+            token_url     => 'https://provider.example.com/token',
+        }
+    );
+
+    # OIDC
+    $provider->set_config(
+        {
+            key           => 'APP_ID',
+            secret        => 'SECRET_KEY',
+            well_known_url => 'https://login.microsoftonline.com/tenant-id/v2.0/.well-known/openid-configuration',
+        }
+    );
+
+This method stores the passed config in JSON format.
+
+=cut
+
+sub set_config {
+    my ($self, $config) = @_;
+
+    my @mandatory = $self->mandatory_config_attributes;
+
+    for my $param (@mandatory) {
+        unless ( defined( $config->{$param} ) ) {
+            Koha::Exceptions::MissingParameter->throw( parameter => $param );
+        }
+    }
+
+    try {
+        my $encoded_config = encode_json($config);
+        $self->config($encoded_config)->store;
+    } catch {
+        Koha::Exceptions::Object::BadValue->throw("Error serializing data into JSON: $_");
+    };
+
+    return $self;
+}
+
+=head3 get_mapping
+
+    my $mapping = $provider->get_mapping;
+
+Returns a I<hashref> containing the attribute mapping for the provider.
+
+=cut
+
+sub get_mapping {
+    my ($self) = @_;
+
+    return try {
+        return decode_json( $self->mapping );
+    }
+    catch {
+        Koha::Exceptions::Object::BadValue->throw("Error reading JSON data: $_");
+    };
+}
+
+=head3 set_mapping
+
+    $provider->mapping( $mapping );
+
+This method stores the passed mappings in JSON format.
+
+=cut
+
+sub set_mapping {
+    my ($self, $mapping) = @_;
+
+    try {
+        my $encoded_mapping = encode_json( $mapping );
+        $self->mapping( $encoded_mapping )->store;
+    }
+    catch {
+        Koha::Exceptions::Object::BadValue->throw("Error serializing data into JSON: $_");
+    };
+
+    return $self;
+}
+
+=head3 upgrade_class
+
+    my $upgraded_object = $provider->upgrade_class
+
+Returns a new instance of the object, with the right class.
+
+=cut
+
+sub upgrade_class {
+    my ( $self ) = @_;
+    my $protocol = $self->protocol;
+
+    my $class = $self->protocol_to_class_mapping->{$protocol};
+
+    Koha::Exception->throw($protocol . ' is not a valid protocol')
+        unless $class;
+
+    eval "require $class";
+    return $class->_new_from_dbic( $self->_result );
+}
+
+=head2 Internal methods
+
+=head3 to_api
+
+    my $json = $provider->to_api;
+
+Overloaded method that returns a JSON representation of the Koha::Auth::Identity::Provider object,
+suitable for API output.
+
+=cut
+
+sub to_api {
+    my ( $self, $params ) = @_;
+
+    my $config  = $self->get_config;
+    my $mapping = $self->get_mapping;
+
+    my $json = $self->SUPER::to_api($params);
+    $json->{config}  = $config;
+    $json->{mapping} = $mapping;
+
+    return $json;
+}
+
+=head3 _type
+
+=cut
+
+sub _type {
+    return 'IdentityProvider';
+}
+
+=head3 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>.
+
+=cut
+
+sub protocol_to_class_mapping {
+    return {
+        OAuth => 'Koha::Auth::Identity::Provider::OAuth',
+        OIDC  => 'Koha::Auth::Identity::Provider::OIDC',
+    };
+}
+
+=head3 mandatory_config_attributes
+
+Stub method for raising exceptions on invalid protocols.
+
+=cut
+
+sub mandatory_config_attributes {
+    my ($self) = @_;
+    Koha::Exception->throw("This method needs to be subclassed");
+}
+
+1;
diff --git a/Koha/Auth/Identity/Provider/Domain.pm b/Koha/Auth/Identity/Provider/Domain.pm
new file mode 100644 (file)
index 0000000..16d8a5d
--- /dev/null
@@ -0,0 +1,40 @@
+package Koha::Auth::Identity::Provider::Domain;
+
+# Copyright Theke Solutions 2022
+#
+# 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 base qw(Koha::Object);
+
+=head1 NAME
+
+Koha::Auth::Identity::Provider::Domain - Koha Auth Provider Domain Object class
+
+=head1 API
+
+=head2 Internal methods
+
+=head3 _type
+
+=cut
+
+sub _type {
+    return 'IdentityProviderDomain';
+}
+
+1;
diff --git a/Koha/Auth/Identity/Provider/Domains.pm b/Koha/Auth/Identity/Provider/Domains.pm
new file mode 100644 (file)
index 0000000..4ab2e75
--- /dev/null
@@ -0,0 +1,53 @@
+package Koha::Auth::Identity::Provider::Domains;
+
+# Copyright Theke Solutions 2022
+#
+# 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::Database;
+use Koha::Auth::Identity::Provider::Domain;
+
+use base qw(Koha::Objects);
+
+=head1 NAME
+
+Koha::Auth::Identity::Providers - Koha Auth Provider Object class
+
+=head1 API
+
+=head2 Internal methods
+
+=cut
+
+=head3 _type
+
+=cut
+
+sub _type {
+    return 'IdentityProviderDomain';
+}
+
+=head3 object_class
+
+=cut
+
+sub object_class {
+    return 'Koha::Auth::Identity::Provider::Domain';
+}
+
+1;
diff --git a/Koha/Auth/Identity/Provider/OAuth.pm b/Koha/Auth/Identity/Provider/OAuth.pm
new file mode 100644 (file)
index 0000000..45f74a3
--- /dev/null
@@ -0,0 +1,65 @@
+package Koha::Auth::Identity::Provider::OAuth;
+
+# Copyright Theke Solutions 2022
+#
+# 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 base qw(Koha::Auth::Identity::Provider);
+
+=head1 NAME
+
+Koha::Auth::Identity::Provider::OAuth - Koha Auth Provider Object class
+
+=head1 API
+
+=head2 Class methods
+
+=head3 new
+
+    my $oauth = Koha::Auth::Identity::Provider::OAuth->new( \%{params} );
+
+Overloaded class to create a new OAuth provider.
+
+=cut
+
+sub new {
+    my ( $class, $params ) = @_;
+
+    $params->{protocol} = 'OAuth';
+
+    return $class->SUPER::new($params);
+}
+
+=head2 Internal methods
+
+=head3 mandatory_config_attributes
+
+Returns a list of the mandatory config entries for the protocol.
+
+=cut
+
+sub mandatory_config_attributes {
+    return qw(
+      key
+      secret
+      authorize_url
+      token_url
+    );
+}
+
+1;
diff --git a/Koha/Auth/Identity/Provider/OIDC.pm b/Koha/Auth/Identity/Provider/OIDC.pm
new file mode 100644 (file)
index 0000000..56bacff
--- /dev/null
@@ -0,0 +1,64 @@
+package Koha::Auth::Identity::Provider::OIDC;
+
+# Copyright Theke Solutions 2022
+#
+# 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 base qw(Koha::Auth::Identity::Provider);
+
+=head1 NAME
+
+Koha::Auth::Identity::Provider::OIDC - Koha Auth Provider Object class
+
+=head1 API
+
+=head2 Class methods
+
+=head3 new
+
+    my $oidc = Koha::Auth::Identity::Provider::OIDC->new( \%{params} );
+
+Overloaded class to create a new OIDC provider.
+
+=cut
+
+sub new {
+    my ( $class, $params ) = @_;
+
+    $params->{protocol} = 'OIDC';
+
+    return $class->SUPER::new($params);
+}
+
+=head2 Internal methods
+
+=head3 mandatory_config_attributes
+
+Returns a list of the mandatory config entries for the protocol.
+
+=cut
+
+sub mandatory_config_attributes {
+    return qw(
+      key
+      secret
+      well_known_url
+    );
+}
+
+1;
diff --git a/Koha/Auth/Identity/Providers.pm b/Koha/Auth/Identity/Providers.pm
new file mode 100644 (file)
index 0000000..6f1f85c
--- /dev/null
@@ -0,0 +1,53 @@
+package Koha::Auth::Identity::Providers;
+
+# Copyright Theke Solutions 2022
+#
+# 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::Database;
+use Koha::Auth::Identity::Provider;
+
+use base qw(Koha::Objects);
+
+=head1 NAME
+
+Koha::Auth::Identity::Providers - Koha Auth Provider Object class
+
+=head1 API
+
+=head2 Internal methods
+
+=cut
+
+=head3 _type
+
+=cut
+
+sub _type {
+    return 'IdentityProvider';
+}
+
+=head3 object_class
+
+=cut
+
+sub object_class {
+    return 'Koha::Auth::Identity::Provider';
+}
+
+1;
diff --git a/Koha/Auth/Provider.pm b/Koha/Auth/Provider.pm
deleted file mode 100644 (file)
index 7a652de..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-package Koha::Auth::Provider;
-
-# Copyright Theke Solutions 2022
-#
-# 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 base qw(Koha::Object);
-
-use JSON qw( decode_json encode_json );
-use Try::Tiny;
-
-use Koha::Auth::Provider::Domains;
-use Koha::Exceptions;
-use Koha::Exceptions::Object;
-
-=head1 NAME
-
-Koha::Auth::Provider - Koha Auth Provider Object class
-
-=head1 API
-
-=head2 Class methods
-
-=head3 domains
-
-    my $domains = $provider->domains;
-
-Returns the related I<Koha::Auth::Provider::Domains> iterator.
-
-=cut
-
-sub domains {
-    my ($self) = @_;
-
-    return Koha::Auth::Provider::Domains->_new_from_dbic( scalar $self->_result->domains );
-}
-
-=head3 get_config
-
-    my $config = $provider->get_config;
-
-Returns a I<hashref> containing the configuration parameters for the provider.
-
-=cut
-
-sub get_config {
-    my ($self) = @_;
-
-    return try {
-        return decode_json( $self->config );
-    }
-    catch {
-        Koha::Exceptions::Object::BadValue->throw("Error reading JSON data: $_");
-    };
-}
-
-=head3 set_config
-
-    # OAuth
-    $provider->set_config(
-        {
-            key           => 'APP_ID',
-            secret        => 'SECRET_KEY',
-            authorize_url => 'https://provider.example.com/auth',
-            token_url     => 'https://provider.example.com/token',
-        }
-    );
-
-    # OIDC
-    $provider->set_config(
-        {
-            key           => 'APP_ID',
-            secret        => 'SECRET_KEY',
-            well_known_url => 'https://login.microsoftonline.com/tenant-id/v2.0/.well-known/openid-configuration',
-        }
-    );
-
-This method stores the passed config in JSON format.
-
-=cut
-
-sub set_config {
-    my ($self, $config) = @_;
-
-    my @mandatory = $self->mandatory_config_attributes;
-
-    for my $param (@mandatory) {
-        unless ( defined( $config->{$param} ) ) {
-            Koha::Exceptions::MissingParameter->throw( parameter => $param );
-        }
-    }
-
-    try {
-        my $encoded_config = encode_json($config);
-        $self->config($encoded_config)->store;
-    } catch {
-        Koha::Exceptions::Object::BadValue->throw("Error serializing data into JSON: $_");
-    };
-
-    return $self;
-}
-
-=head3 get_mapping
-
-    my $mapping = $provider->get_mapping;
-
-Returns a I<hashref> containing the attribute mapping for the provider.
-
-=cut
-
-sub get_mapping {
-    my ($self) = @_;
-
-    return try {
-        return decode_json( $self->mapping );
-    }
-    catch {
-        Koha::Exceptions::Object::BadValue->throw("Error reading JSON data: $_");
-    };
-}
-
-=head3 set_mapping
-
-    $provider->mapping( $mapping );
-
-This method stores the passed mappings in JSON format.
-
-=cut
-
-sub set_mapping {
-    my ($self, $mapping) = @_;
-
-    try {
-        my $encoded_mapping = encode_json( $mapping );
-        $self->mapping( $encoded_mapping )->store;
-    }
-    catch {
-        Koha::Exceptions::Object::BadValue->throw("Error serializing data into JSON: $_");
-    };
-
-    return $self;
-}
-
-=head3 upgrade_class
-
-    my $upgraded_object = $provider->upgrade_class
-
-Returns a new instance of the object, with the right class.
-
-=cut
-
-sub upgrade_class {
-    my ( $self ) = @_;
-    my $protocol = $self->protocol;
-
-    my $class = $self->protocol_to_class_mapping->{$protocol};
-
-    Koha::Exception->throw($protocol . ' is not a valid protocol')
-        unless $class;
-
-    eval "require $class";
-    return $class->_new_from_dbic( $self->_result );
-}
-
-=head2 Internal methods
-
-=head3 to_api
-
-    my $json = $provider->to_api;
-
-Overloaded method that returns a JSON representation of the Koha::Auth::Provider object,
-suitable for API output.
-
-=cut
-
-sub to_api {
-    my ( $self, $params ) = @_;
-
-    my $config  = $self->get_config;
-    my $mapping = $self->get_mapping;
-
-    my $json = $self->SUPER::to_api($params);
-    $json->{config}  = $config;
-    $json->{mapping} = $mapping;
-
-    return $json;
-}
-
-=head3 _type
-
-=cut
-
-sub _type {
-    return 'AuthProvider';
-}
-
-=head3 protocol_to_class_mapping
-
-    my $mapping = Koha::Auth::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>.
-
-=cut
-
-sub protocol_to_class_mapping {
-    return {
-        OAuth => 'Koha::Auth::Provider::OAuth',
-        OIDC  => 'Koha::Auth::Provider::OIDC',
-    };
-}
-
-=head3 mandatory_config_attributes
-
-Stub method for raising exceptions on invalid protocols.
-
-=cut
-
-sub mandatory_config_attributes {
-    my ($self) = @_;
-    Koha::Exception->throw("This method needs to be subclassed");
-}
-
-1;
diff --git a/Koha/Auth/Provider/Domain.pm b/Koha/Auth/Provider/Domain.pm
deleted file mode 100644 (file)
index 6208ff2..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-package Koha::Auth::Provider::Domain;
-
-# Copyright Theke Solutions 2022
-#
-# 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 base qw(Koha::Object);
-
-=head1 NAME
-
-Koha::Auth::Provider::Domain - Koha Auth Provider Domain Object class
-
-=head1 API
-
-=head2 Internal methods
-
-=head3 _type
-
-=cut
-
-sub _type {
-    return 'AuthProviderDomain';
-}
-
-1;
diff --git a/Koha/Auth/Provider/Domains.pm b/Koha/Auth/Provider/Domains.pm
deleted file mode 100644 (file)
index 8f15f6e..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-package Koha::Auth::Provider::Domains;
-
-# Copyright Theke Solutions 2022
-#
-# 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::Database;
-use Koha::Auth::Provider::Domain;
-
-use base qw(Koha::Objects);
-
-=head1 NAME
-
-Koha::Auth::Providers - Koha Auth Provider Object class
-
-=head1 API
-
-=head2 Internal methods
-
-=cut
-
-=head3 _type
-
-=cut
-
-sub _type {
-    return 'AuthProviderDomain';
-}
-
-=head3 object_class
-
-=cut
-
-sub object_class {
-    return 'Koha::Auth::Provider::Domain';
-}
-
-1;
diff --git a/Koha/Auth/Provider/OAuth.pm b/Koha/Auth/Provider/OAuth.pm
deleted file mode 100644 (file)
index b77f4af..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-package Koha::Auth::Provider::OAuth;
-
-# Copyright Theke Solutions 2022
-#
-# 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 base qw(Koha::Auth::Provider);
-
-=head1 NAME
-
-Koha::Auth::Provider::OAuth - Koha Auth Provider Object class
-
-=head1 API
-
-=head2 Class methods
-
-=head3 new
-
-    my $oauth = Koha::Auth::Provider::OAuth->new( \%{params} );
-
-Overloaded class to create a new OAuth provider.
-
-=cut
-
-sub new {
-    my ( $class, $params ) = @_;
-
-    $params->{protocol} = 'OAuth';
-
-    return $class->SUPER::new($params);
-}
-
-=head2 Internal methods
-
-=head3 mandatory_config_attributes
-
-Returns a list of the mandatory config entries for the protocol.
-
-=cut
-
-sub mandatory_config_attributes {
-    return qw(
-      key
-      secret
-      authorize_url
-      token_url
-    );
-}
-
-1;
diff --git a/Koha/Auth/Provider/OIDC.pm b/Koha/Auth/Provider/OIDC.pm
deleted file mode 100644 (file)
index 5945555..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-package Koha::Auth::Provider::OIDC;
-
-# Copyright Theke Solutions 2022
-#
-# 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 base qw(Koha::Auth::Provider);
-
-=head1 NAME
-
-Koha::Auth::Provider::OIDC - Koha Auth Provider Object class
-
-=head1 API
-
-=head2 Class methods
-
-=head3 new
-
-    my $oidc = Koha::Auth::Provider::OIDC->new( \%{params} );
-
-Overloaded class to create a new OIDC provider.
-
-=cut
-
-sub new {
-    my ( $class, $params ) = @_;
-
-    $params->{protocol} = 'OIDC';
-
-    return $class->SUPER::new($params);
-}
-
-=head2 Internal methods
-
-=head3 mandatory_config_attributes
-
-Returns a list of the mandatory config entries for the protocol.
-
-=cut
-
-sub mandatory_config_attributes {
-    return qw(
-      key
-      secret
-      well_known_url
-    );
-}
-
-1;
diff --git a/Koha/Auth/Providers.pm b/Koha/Auth/Providers.pm
deleted file mode 100644 (file)
index 51e32b7..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-package Koha::Auth::Providers;
-
-# Copyright Theke Solutions 2022
-#
-# 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::Database;
-use Koha::Auth::Provider;
-
-use base qw(Koha::Objects);
-
-=head1 NAME
-
-Koha::Auth::Providers - Koha Auth Provider Object class
-
-=head1 API
-
-=head2 Internal methods
-
-=cut
-
-=head3 _type
-
-=cut
-
-sub _type {
-    return 'AuthProvider';
-}
-
-=head3 object_class
-
-=cut
-
-sub object_class {
-    return 'Koha::Auth::Provider';
-}
-
-1;
diff --git a/Koha/REST/Plugin/Auth.pm b/Koha/REST/Plugin/Auth.pm
deleted file mode 100644 (file)
index 0aa261a..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-package Koha::REST::Plugin::Auth;
-
-# Copyright Theke Solutions 2022
-#
-# 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 Mojo::Base 'Mojolicious::Plugin';
-
-use Koha::Exceptions;
-use Koha::Exceptions::Auth;
-use Koha::Patron;
-
-use C4::Auth;
-
-use CGI;
-
-=head1 NAME
-
-Koha::REST::Plugin::Auth
-
-=head1 API
-
-=head2 Helper methods
-
-=cut
-
-sub register {
-    my ( $self, $app ) = @_;
-
-=head3 auth.register
-
-    my $patron = $c->auth->register(
-        {   data      => $patron_data,
-            domain    => $domain,
-            interface => $interface
-        }
-    );
-
-If no patron passed, creates a new I<Koha::Patron> if the provider is configured
-to do so for the domain.
-
-=cut
-
-    $app->helper(
-        'auth.register' => sub {
-            my ( $c, $params ) = @_;
-            my $data = $params->{data};
-            my $domain = $params->{domain};
-            my $interface = $params->{interface};
-
-            unless ( $interface eq 'opac' && $domain->auto_register ) {
-                Koha::Exceptions::Auth::Unauthorized->throw( code => 401 );
-            }
-
-            return Koha::Patron->new($data)->store;
-        }
-    );
-
-=head3 auth.session
-
-    my ( $status, $cookie, $session_id ) = $c->auth->session( $patron );
-
-Generates a new session.
-
-=cut
-
-    $app->helper(
-        'auth.session' => sub {
-            my ( $c, $patron ) = @_;
-            my $userid     = $patron->userid;
-            my $cardnumber = $patron->cardnumber;
-            my $cgi        = CGI->new;
-
-            $cgi->param( userid            => $userid );
-            $cgi->param( cardnumber        => $cardnumber );
-            $cgi->param( auth_client_login => 1 );
-
-            my ( $status, $cookie, $session_id ) = C4::Auth::check_api_auth($cgi);
-
-            Koha::Exceptions::UnderMaintenance->throw( code => 503 )
-              if $status eq "maintenance";
-
-            Koha::Exceptions::Auth::CannotCreateSession->throw( code => 500 )
-              unless $status eq "ok";
-
-            return ( $status, $cookie, $session_id );
-        }
-    );
-}
-
-1;
diff --git a/Koha/REST/Plugin/Auth/IdP.pm b/Koha/REST/Plugin/Auth/IdP.pm
new file mode 100644 (file)
index 0000000..e1a0e2f
--- /dev/null
@@ -0,0 +1,106 @@
+package Koha::REST::Plugin::Auth::IdP;
+
+# Copyright Theke Solutions 2022
+#
+# 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 Mojo::Base 'Mojolicious::Plugin';
+
+use Koha::Exceptions;
+use Koha::Exceptions::Auth;
+use Koha::Patron;
+
+use C4::Auth;
+
+use CGI;
+
+=head1 NAME
+
+Koha::REST::Plugin::Auth::IdP
+
+=head1 API
+
+=head2 Helper methods
+
+=cut
+
+sub register {
+    my ( $self, $app ) = @_;
+
+=head3 auth.register
+
+    my $patron = $c->auth->register(
+        {   data      => $patron_data,
+            domain    => $domain,
+            interface => $interface
+        }
+    );
+
+If no patron passed, creates a new I<Koha::Patron> if the provider is configured
+to do so for the domain.
+
+=cut
+
+    $app->helper(
+        'auth.register' => sub {
+            my ( $c, $params ) = @_;
+            my $data = $params->{data};
+            my $domain = $params->{domain};
+            my $interface = $params->{interface};
+
+            unless ( $interface eq 'opac' && $domain->auto_register ) {
+                Koha::Exceptions::Auth::Unauthorized->throw( code => 401 );
+            }
+
+            return Koha::Patron->new($data)->store;
+        }
+    );
+
+=head3 auth.session
+
+    my ( $status, $cookie, $session_id ) = $c->auth->session( $patron );
+
+Generates a new session.
+
+=cut
+
+    $app->helper(
+        'auth.session' => sub {
+            my ( $c, $patron ) = @_;
+            my $userid     = $patron->userid;
+            my $cardnumber = $patron->cardnumber;
+            my $cgi        = CGI->new;
+
+            $cgi->param( userid            => $userid );
+            $cgi->param( cardnumber        => $cardnumber );
+            $cgi->param( auth_client_login => 1 );
+
+            my ( $status, $cookie, $session_id ) = C4::Auth::check_api_auth($cgi);
+
+            Koha::Exceptions::UnderMaintenance->throw( code => 503 )
+              if $status eq "maintenance";
+
+            Koha::Exceptions::Auth::CannotCreateSession->throw( code => 500 )
+              unless $status eq "ok";
+
+            return ( $status, $cookie, $session_id );
+        }
+    );
+}
+
+1;
index c0cd596..0c35c6f 100644 (file)
@@ -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 );
 }
 
diff --git a/Koha/REST/V1/Auth/Identity/Provider/Domains.pm b/Koha/REST/V1/Auth/Identity/Provider/Domains.pm
new file mode 100644 (file)
index 0000000..cac05a8
--- /dev/null
@@ -0,0 +1,234 @@
+package Koha::REST::V1::Auth::Identity::Provider::Domains;
+
+# 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 Mojo::Base 'Mojolicious::Controller';
+
+use Koha::Auth::Identity::Provider::Domains;
+use Koha::Auth::Identity::Providers;
+
+use Koha::Database;
+
+use Scalar::Util qw(blessed);
+use Try::Tiny;
+
+=head1 NAME
+
+Koha::REST::V1::Auth::Identity::Provider::Domains - Controller library for handling
+authentication provider domains routes.
+
+=head2 Operations
+
+=head3 list
+
+Controller method for listing authentication provider domains.
+
+=cut
+
+sub list {
+    my $c = shift->openapi->valid_input or return;
+
+    return try {
+        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(
+                status  => 404,
+                openapi => {
+                    error      => 'Object not found',
+                    error_code => 'not_found',
+                }
+            );
+        }
+
+        my $domains_rs = $provider->domains;
+        return $c->render(
+            status  => 200,
+            openapi => $c->objects->search($domains_rs)
+        );
+    } catch {
+        $c->unhandled_exception($_);
+    };
+}
+
+=head3 get
+
+Controller method for retrieving an authentication provider domain.
+
+=cut
+
+sub get {
+    my $c = shift->openapi->valid_input or return;
+
+    return try {
+
+        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(
+                status  => 404,
+                openapi => {
+                    error      => 'Object not found',
+                    error_code => 'not_found',
+                }
+            );
+        }
+
+        my $domains_rs = $provider->domains;
+
+        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(
+                status  => 404,
+                openapi => {
+                    error      => 'Object not found',
+                    error_code => 'not_found',
+                }
+            );
+        }
+
+        return $c->render( status => 200, openapi => $domain );
+    } catch {
+        $c->unhandled_exception($_);
+    }
+}
+
+=head3 add
+
+Controller method for adding an authentication provider.
+
+=cut
+
+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::Identity::Provider::Domain->new_from_api( $params );
+                $domain->store;
+
+                $c->res->headers->location( $c->req->url->to_string . '/' . $domain->id );
+                return $c->render(
+                    status  => 201,
+                    openapi => $domain->to_api
+                );
+            }
+        );
+    } catch {
+        if ( blessed($_) and $_->isa('Koha::Exceptions::Object::FKConstraint') ) {
+            return $c->render(
+                status  => 404,
+                openapi => {
+                    error      => 'Object not found',
+                    error_code => 'not_found',
+                }
+            );
+        }
+
+        $c->unhandled_exception($_);
+    };
+}
+
+=head3 update
+
+Controller method for updating an authentication provider domain.
+
+=cut
+
+sub update {
+    my $c = shift->openapi->valid_input or return;
+
+    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::Identity::Provider::Domains->find(
+        { identity_provider_id => $identity_provider_id, identity_provider_domain_id => $identity_provider_domain_id } );
+
+    unless ($domain) {
+        return $c->render(
+            status  => 404,
+            openapi => {
+                error      => 'Object not found',
+                error_code => 'not_found',
+            }
+        );
+    }
+
+    return try {
+
+        Koha::Database->new->schema->txn_do(
+            sub {
+
+                $domain->set_from_api( $c->validation->param('body') );
+                $domain->store->discard_changes;
+
+                return $c->render(
+                    status  => 200,
+                    openapi => $domain->to_api
+                );
+            }
+        );
+    } catch {
+        $c->unhandled_exception($_);
+    };
+}
+
+=head3 delete
+
+Controller method for deleting an authentication provider.
+
+=cut
+
+sub delete {
+    my $c = shift->openapi->valid_input or return;
+
+    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::Identity::Provider::Domains->find(
+        { identity_provider_id => $identity_provider_id, identity_provider_domain_id => $identity_provider_domain_id } );
+
+    unless ($domain) {
+        return $c->render(
+            status  => 404,
+            openapi => {
+                error      => 'Object not found',
+                error_code => 'not_found',
+            }
+        );
+    }
+
+    return try {
+        $domain->delete;
+        return $c->render(
+            status  => 204,
+            openapi => q{}
+        );
+    } catch {
+        $c->unhandled_exception($_);
+    };
+}
+
+1;
diff --git a/Koha/REST/V1/Auth/Identity/Providers.pm b/Koha/REST/V1/Auth/Identity/Providers.pm
new file mode 100644 (file)
index 0000000..6862ae7
--- /dev/null
@@ -0,0 +1,237 @@
+package Koha::REST::V1::Auth::Identity::Providers;
+
+# 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 Mojo::Base 'Mojolicious::Controller';
+
+use Koha::Auth::Identity::Provider::OAuth;
+use Koha::Auth::Identity::Provider::OIDC;
+use Koha::Auth::Identity::Providers;
+
+use Koha::Database;
+
+use Scalar::Util qw(blessed);
+use Try::Tiny;
+
+=head1 NAME
+
+Koha::REST::V1::Auth::Identity::Providers - Controller library for handling
+authentication providers routes.
+
+=head2 Operations
+
+=head3 list
+
+Controller method for listing authentication providers.
+
+=cut
+
+sub list {
+    my $c = shift->openapi->valid_input or return;
+
+    return try {
+        my $providers_rs = Koha::Auth::Identity::Providers->new;
+        return $c->render(
+            status  => 200,
+            openapi => $c->objects->search($providers_rs)
+        );
+    } catch {
+        $c->unhandled_exception($_);
+    };
+}
+
+=head3 get
+
+Controller method for retrieving an authentication provider.
+
+=cut
+
+sub get {
+    my $c = shift->openapi->valid_input or return;
+
+    return try {
+
+        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(
+                status  => 404,
+                openapi => {
+                    error      => 'Object not found',
+                    error_code => 'not_found',
+                }
+            );
+        }
+
+        return $c->render( status => 200, openapi => $provider );
+    }
+    catch {
+        $c->unhandled_exception($_);
+    }
+}
+
+=head3 add
+
+Controller method for adding an authentication provider.
+
+=cut
+
+sub add {
+    my $c = shift->openapi->valid_input or return;
+
+    return try {
+
+        Koha::Database->new->schema->txn_do(
+            sub {
+
+                my $body = $c->validation->param('body');
+
+                my $config   = delete $body->{config};
+                my $mapping  = delete $body->{mapping};
+                my $protocol = delete $body->{protocol};
+
+                my $class = Koha::Auth::Identity::Provider::protocol_to_class_mapping->{$protocol};
+
+                my $provider = $class->new_from_api( $body );
+                $provider->store;
+
+                $provider->set_config( $config );
+                $provider->set_mapping( $mapping );
+
+                $c->res->headers->location( $c->req->url->to_string . '/' . $provider->identity_provider_id );
+                return $c->render(
+                    status  => 201,
+                    openapi => $provider->to_api
+                );
+            }
+        );
+    }
+    catch {
+        if ( blessed($_) ) {
+            if ( $_->isa('Koha::Exceptions::MissingParameter') ) {
+                return $c->render(
+                    status  => 400,
+                    openapi => {
+                        error      => "Missing parameter config." . $_->parameter,
+                        error_code => 'missing_parameter'
+                    }
+                );
+            }
+        }
+
+        $c->unhandled_exception($_);
+    };
+}
+
+=head3 update
+
+Controller method for updating an authentication provider.
+
+=cut
+
+sub update {
+    my $c = shift->openapi->valid_input or return;
+
+    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(
+            status  => 404,
+            openapi => {
+                error      => 'Object not found',
+                error_code => 'not_found',
+            }
+        );
+    }
+
+    return try {
+
+        Koha::Database->new->schema->txn_do(
+            sub {
+
+                my $body = $c->validation->param('body');
+
+                my $config   = delete $body->{config};
+                my $mapping  = delete $body->{mapping};
+
+                $provider = $provider->set_from_api( $body )->upgrade_class;
+
+                $provider->set_config( $config );
+                $provider->set_mapping( $mapping );
+                # set_config and set_mapping already called store()
+                $provider->discard_changes;
+
+                return $c->render(
+                    status  => 200,
+                    openapi => $provider->to_api
+                );
+            }
+        );
+    }
+    catch {
+        if ( blessed($_) ) {
+            if ( $_->isa('Koha::Exceptions::MissingParameter') ) {
+                return $c->render(
+                    status  => 400,
+                    openapi => {
+                        error      => "Missing parameter config." . $_->parameter,
+                        error_code => 'missing_parameter'
+                    }
+                );
+            }
+        }
+
+        $c->unhandled_exception($_);
+    };
+}
+
+=head3 delete
+
+Controller method for deleting an authentication provider.
+
+=cut
+
+sub delete {
+    my $c = shift->openapi->valid_input or return;
+
+    my $provider = Koha::Auth::Identity::Providers->find( $c->validation->param('identity_provider_id') );
+    unless ( $provider ) {
+        return $c->render(
+            status  => 404,
+            openapi => {
+                error      => 'Object not found',
+                error_code => 'not_found',
+            }
+        );
+    }
+
+    return try {
+        $provider->delete;
+        return $c->render(
+            status  => 204,
+            openapi => q{}
+        );
+    }
+    catch {
+        $c->unhandled_exception($_);
+    };
+}
+
+1;
diff --git a/Koha/REST/V1/Auth/Provider/Domains.pm b/Koha/REST/V1/Auth/Provider/Domains.pm
deleted file mode 100644 (file)
index f53954a..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-package Koha::REST::V1::Auth::Provider::Domains;
-
-# 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 Mojo::Base 'Mojolicious::Controller';
-
-use Koha::Auth::Provider::Domains;
-use Koha::Auth::Providers;
-
-use Koha::Database;
-
-use Scalar::Util qw(blessed);
-use Try::Tiny;
-
-=head1 NAME
-
-Koha::REST::V1::Auth::Provider::Domains - Controller library for handling
-authentication provider domains routes.
-
-=head2 Operations
-
-=head3 list
-
-Controller method for listing authentication provider domains.
-
-=cut
-
-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);
-
-        unless ($provider) {
-            return $c->render(
-                status  => 404,
-                openapi => {
-                    error      => 'Object not found',
-                    error_code => 'not_found',
-                }
-            );
-        }
-
-        my $domains_rs = $provider->domains;
-        return $c->render(
-            status  => 200,
-            openapi => $c->objects->search($domains_rs)
-        );
-    } catch {
-        $c->unhandled_exception($_);
-    };
-}
-
-=head3 get
-
-Controller method for retrieving an authentication provider domain.
-
-=cut
-
-sub get {
-    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);
-
-        unless ($provider) {
-            return $c->render(
-                status  => 404,
-                openapi => {
-                    error      => 'Object not found',
-                    error_code => 'not_found',
-                }
-            );
-        }
-
-        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 );
-
-        unless ($domain) {
-            return $c->render(
-                status  => 404,
-                openapi => {
-                    error      => 'Object not found',
-                    error_code => 'not_found',
-                }
-            );
-        }
-
-        return $c->render( status => 200, openapi => $domain );
-    } catch {
-        $c->unhandled_exception($_);
-    }
-}
-
-=head3 add
-
-Controller method for adding an authentication provider.
-
-=cut
-
-sub add {
-    my $c = shift->openapi->valid_input or return;
-
-    return try {
-
-        Koha::Database->new->schema->txn_do(
-            sub {
-                my $domain = Koha::Auth::Provider::Domain->new_from_api( $c->validation->param('body') );
-                $domain->store;
-
-                $c->res->headers->location( $c->req->url->to_string . '/' . $domain->id );
-                return $c->render(
-                    status  => 201,
-                    openapi => $domain->to_api
-                );
-            }
-        );
-    } catch {
-        if ( blessed($_) and $_->isa('Koha::Exceptions::Object::FKConstraint') ) {
-            return $c->render(
-                status  => 404,
-                openapi => {
-                    error      => 'Object not found',
-                    error_code => 'not_found',
-                }
-            );
-        }
-
-        $c->unhandled_exception($_);
-    };
-}
-
-=head3 update
-
-Controller method for updating an authentication provider domain.
-
-=cut
-
-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 $domain = Koha::Auth::Provider::Domains->find(
-        { auth_provider_id => $auth_provider_id, auth_provider_domain_id => $auth_provider_domain_id } );
-
-    unless ($domain) {
-        return $c->render(
-            status  => 404,
-            openapi => {
-                error      => 'Object not found',
-                error_code => 'not_found',
-            }
-        );
-    }
-
-    return try {
-
-        Koha::Database->new->schema->txn_do(
-            sub {
-
-                $domain->set_from_api( $c->validation->param('body') );
-                $domain->store->discard_changes;
-
-                return $c->render(
-                    status  => 200,
-                    openapi => $domain->to_api
-                );
-            }
-        );
-    } catch {
-        $c->unhandled_exception($_);
-    };
-}
-
-=head3 delete
-
-Controller method for deleting an authentication provider.
-
-=cut
-
-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 $domain = Koha::Auth::Provider::Domains->find(
-        { auth_provider_id => $auth_provider_id, auth_provider_domain_id => $auth_provider_domain_id } );
-
-    unless ($domain) {
-        return $c->render(
-            status  => 404,
-            openapi => {
-                error      => 'Object not found',
-                error_code => 'not_found',
-            }
-        );
-    }
-
-    return try {
-        $domain->delete;
-        return $c->render(
-            status  => 204,
-            openapi => q{}
-        );
-    } catch {
-        $c->unhandled_exception($_);
-    };
-}
-
-1;
diff --git a/Koha/REST/V1/Auth/Providers.pm b/Koha/REST/V1/Auth/Providers.pm
deleted file mode 100644 (file)
index c31b258..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-package Koha::REST::V1::Auth::Providers;
-
-# 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 Mojo::Base 'Mojolicious::Controller';
-
-use Koha::Auth::Provider::OAuth;
-use Koha::Auth::Provider::OIDC;
-use Koha::Auth::Providers;
-
-use Koha::Database;
-
-use Scalar::Util qw(blessed);
-use Try::Tiny;
-
-=head1 NAME
-
-Koha::REST::V1::Auth::Providers - Controller library for handling
-authentication providers routes.
-
-=head2 Operations
-
-=head3 list
-
-Controller method for listing authentication providers.
-
-=cut
-
-sub list {
-    my $c = shift->openapi->valid_input or return;
-
-    return try {
-        my $providers_rs = Koha::Auth::Providers->new;
-        return $c->render(
-            status  => 200,
-            openapi => $c->objects->search($providers_rs)
-        );
-    } catch {
-        $c->unhandled_exception($_);
-    };
-}
-
-=head3 get
-
-Controller method for retrieving an authentication provider.
-
-=cut
-
-sub get {
-    my $c = shift->openapi->valid_input or return;
-
-    return try {
-
-        my $auth_provider_id = $c->validation->param('auth_provider_id');
-        my $provider = $c->objects->find( Koha::Auth::Providers->new, $auth_provider_id );
-
-        unless ( $provider ) {
-            return $c->render(
-                status  => 404,
-                openapi => {
-                    error      => 'Object not found',
-                    error_code => 'not_found',
-                }
-            );
-        }
-
-        return $c->render( status => 200, openapi => $provider );
-    }
-    catch {
-        $c->unhandled_exception($_);
-    }
-}
-
-=head3 add
-
-Controller method for adding an authentication provider.
-
-=cut
-
-sub add {
-    my $c = shift->openapi->valid_input or return;
-
-    return try {
-
-        Koha::Database->new->schema->txn_do(
-            sub {
-
-                my $body = $c->validation->param('body');
-
-                my $config   = delete $body->{config};
-                my $mapping  = delete $body->{mapping};
-                my $protocol = delete $body->{protocol};
-
-                my $class = Koha::Auth::Provider::protocol_to_class_mapping->{$protocol};
-
-                my $provider = $class->new_from_api( $body );
-                $provider->store;
-
-                $provider->set_config( $config );
-                $provider->set_mapping( $mapping );
-
-                $c->res->headers->location( $c->req->url->to_string . '/' . $provider->auth_provider_id );
-                return $c->render(
-                    status  => 201,
-                    openapi => $provider->to_api
-                );
-            }
-        );
-    }
-    catch {
-        if ( blessed($_) ) {
-            if ( $_->isa('Koha::Exceptions::MissingParameter') ) {
-                return $c->render(
-                    status  => 400,
-                    openapi => {
-                        error      => "Missing parameter config." . $_->parameter,
-                        error_code => 'missing_parameter'
-                    }
-                );
-            }
-        }
-
-        $c->unhandled_exception($_);
-    };
-}
-
-=head3 update
-
-Controller method for updating an authentication provider.
-
-=cut
-
-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 );
-
-    unless ( $provider ) {
-        return $c->render(
-            status  => 404,
-            openapi => {
-                error      => 'Object not found',
-                error_code => 'not_found',
-            }
-        );
-    }
-
-    return try {
-
-        Koha::Database->new->schema->txn_do(
-            sub {
-
-                my $body = $c->validation->param('body');
-
-                my $config   = delete $body->{config};
-                my $mapping  = delete $body->{mapping};
-
-                $provider = $provider->set_from_api( $body )->upgrade_class;
-
-                $provider->set_config( $config );
-                $provider->set_mapping( $mapping );
-                # set_config and set_mapping already called store()
-                $provider->discard_changes;
-
-                return $c->render(
-                    status  => 200,
-                    openapi => $provider->to_api
-                );
-            }
-        );
-    }
-    catch {
-        if ( blessed($_) ) {
-            if ( $_->isa('Koha::Exceptions::MissingParameter') ) {
-                return $c->render(
-                    status  => 400,
-                    openapi => {
-                        error      => "Missing parameter config." . $_->parameter,
-                        error_code => 'missing_parameter'
-                    }
-                );
-            }
-        }
-
-        $c->unhandled_exception($_);
-    };
-}
-
-=head3 delete
-
-Controller method for deleting an authentication provider.
-
-=cut
-
-sub delete {
-    my $c = shift->openapi->valid_input or return;
-
-    my $provider = Koha::Auth::Providers->find( $c->validation->param('auth_provider_id') );
-    unless ( $provider ) {
-        return $c->render(
-            status  => 404,
-            openapi => {
-                error      => 'Object not found',
-                error_code => 'not_found',
-            }
-        );
-    }
-
-    return try {
-        $provider->delete;
-        return $c->render(
-            status  => 204,
-            openapi => q{}
-        );
-    }
-    catch {
-        $c->unhandled_exception($_);
-    };
-}
-
-1;
diff --git a/Koha/Schema/Result/AuthProvider.pm b/Koha/Schema/Result/AuthProvider.pm
deleted file mode 100644 (file)
index c62a79a..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-use utf8;
-package Koha::Schema::Result::AuthProvider;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Koha::Schema::Result::AuthProvider
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<auth_providers>
-
-=cut
-
-__PACKAGE__->table("auth_providers");
-
-=head1 ACCESSORS
-
-=head2 auth_provider_id
-
-  data_type: 'integer'
-  is_auto_increment: 1
-  is_nullable: 0
-
-unique key, used to identify the provider
-
-=head2 code
-
-  data_type: 'varchar'
-  is_nullable: 0
-  size: 20
-
-Provider code
-
-=head2 description
-
-  data_type: 'varchar'
-  is_nullable: 0
-  size: 255
-
-Description for the provider
-
-=head2 protocol
-
-  data_type: 'enum'
-  extra: {list => ["OAuth","OIDC","LDAP","CAS"]}
-  is_nullable: 0
-
-Protocol provider speaks
-
-=head2 config
-
-  data_type: 'longtext'
-  default_value: ''{}''
-  is_nullable: 0
-
-Configuration of the provider in JSON format
-
-=head2 mapping
-
-  data_type: 'longtext'
-  default_value: ''{}''
-  is_nullable: 0
-
-Configuration to map provider data to Koha user
-
-=head2 matchpoint
-
-  data_type: 'enum'
-  extra: {list => ["email","userid","cardnumber"]}
-  is_nullable: 0
-
-The patron attribute to be used as matchpoint
-
-=head2 icon_url
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 255
-
-Provider icon URL
-
-=cut
-
-__PACKAGE__->add_columns(
-  "auth_provider_id",
-  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
-  "code",
-  { data_type => "varchar", is_nullable => 0, size => 20 },
-  "description",
-  { data_type => "varchar", is_nullable => 0, size => 255 },
-  "protocol",
-  {
-    data_type => "enum",
-    extra => { list => ["OAuth", "OIDC", "LDAP", "CAS"] },
-    is_nullable => 0,
-  },
-  "config",
-  { data_type => "longtext", default_value => "'{}'", is_nullable => 0 },
-  "mapping",
-  { data_type => "longtext", default_value => "'{}'", is_nullable => 0 },
-  "matchpoint",
-  {
-    data_type => "enum",
-    extra => { list => ["email", "userid", "cardnumber"] },
-    is_nullable => 0,
-  },
-  "icon_url",
-  { data_type => "varchar", is_nullable => 1, size => 255 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</auth_provider_id>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("auth_provider_id");
-
-=head1 UNIQUE CONSTRAINTS
-
-=head2 C<code>
-
-=over 4
-
-=item * L</code>
-
-=back
-
-=cut
-
-__PACKAGE__->add_unique_constraint("code", ["code"]);
-
-=head1 RELATIONS
-
-=head2 auth_provider_domains
-
-Type: has_many
-
-Related object: L<Koha::Schema::Result::AuthProviderDomain>
-
-=cut
-
-__PACKAGE__->has_many(
-  "auth_provider_domains",
-  "Koha::Schema::Result::AuthProviderDomain",
-  { "foreign.auth_provider_id" => "self.auth_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
-
-__PACKAGE__->has_many(
-  "domains",
-  "Koha::Schema::Result::AuthProviderDomain",
-  { "foreign.auth_provider_id" => "self.auth_provider_id" },
-  { cascade_copy => 0, cascade_delete => 0 },
-);
-
-sub koha_object_class {
-    'Koha::Auth::Provider';
-}
-sub koha_objects_class {
-    'Koha::Auth::Providers';
-}
-
-1;
diff --git a/Koha/Schema/Result/AuthProviderDomain.pm b/Koha/Schema/Result/AuthProviderDomain.pm
deleted file mode 100644 (file)
index 117627f..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-use utf8;
-package Koha::Schema::Result::AuthProviderDomain;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Koha::Schema::Result::AuthProviderDomain
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<auth_provider_domains>
-
-=cut
-
-__PACKAGE__->table("auth_provider_domains");
-
-=head1 ACCESSORS
-
-=head2 auth_provider_domain_id
-
-  data_type: 'integer'
-  is_auto_increment: 1
-  is_nullable: 0
-
-unique key, used to identify providers domain
-
-=head2 auth_provider_id
-
-  data_type: 'integer'
-  is_foreign_key: 1
-  is_nullable: 0
-
-Reference to provider
-
-=head2 domain
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 100
-
-Domain name. If null means all domains
-
-=head2 auto_register
-
-  data_type: 'tinyint'
-  default_value: 0
-  is_nullable: 0
-
-Allow user auto register
-
-=head2 update_on_auth
-
-  data_type: 'tinyint'
-  default_value: 0
-  is_nullable: 0
-
-Update user data on auth login
-
-=head2 default_library_id
-
-  data_type: 'varchar'
-  is_foreign_key: 1
-  is_nullable: 1
-  size: 10
-
-Default library to create user if auto register is enabled
-
-=head2 default_category_id
-
-  data_type: 'varchar'
-  is_foreign_key: 1
-  is_nullable: 1
-  size: 10
-
-Default category to create user if auto register is enabled
-
-=head2 allow_opac
-
-  data_type: 'tinyint'
-  default_value: 1
-  is_nullable: 0
-
-Allow provider from opac interface
-
-=head2 allow_staff
-
-  data_type: 'tinyint'
-  default_value: 1
-  is_nullable: 0
-
-Allow provider from staff interface
-
-=cut
-
-__PACKAGE__->add_columns(
-  "auth_provider_domain_id",
-  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
-  "auth_provider_id",
-  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
-  "domain",
-  { data_type => "varchar", is_nullable => 1, size => 100 },
-  "auto_register",
-  { data_type => "tinyint", default_value => 0, is_nullable => 0 },
-  "update_on_auth",
-  { data_type => "tinyint", default_value => 0, is_nullable => 0 },
-  "default_library_id",
-  { data_type => "varchar", is_foreign_key => 1, is_nullable => 1, size => 10 },
-  "default_category_id",
-  { data_type => "varchar", is_foreign_key => 1, is_nullable => 1, size => 10 },
-  "allow_opac",
-  { data_type => "tinyint", default_value => 1, is_nullable => 0 },
-  "allow_staff",
-  { data_type => "tinyint", default_value => 1, is_nullable => 0 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</auth_provider_domain_id>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("auth_provider_domain_id");
-
-=head1 UNIQUE CONSTRAINTS
-
-=head2 C<auth_provider_id>
-
-=over 4
-
-=item * L</auth_provider_id>
-
-=item * L</domain>
-
-=back
-
-=cut
-
-__PACKAGE__->add_unique_constraint("auth_provider_id", ["auth_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
-
-Related object: L<Koha::Schema::Result::Category>
-
-=cut
-
-__PACKAGE__->belongs_to(
-  "default_category",
-  "Koha::Schema::Result::Category",
-  { categorycode => "default_category_id" },
-  {
-    is_deferrable => 1,
-    join_type     => "LEFT",
-    on_delete     => "CASCADE",
-    on_update     => "RESTRICT",
-  },
-);
-
-=head2 default_library
-
-Type: belongs_to
-
-Related object: L<Koha::Schema::Result::Branch>
-
-=cut
-
-__PACKAGE__->belongs_to(
-  "default_library",
-  "Koha::Schema::Result::Branch",
-  { branchcode => "default_library_id" },
-  {
-    is_deferrable => 1,
-    join_type     => "LEFT",
-    on_delete     => "CASCADE",
-    on_update     => "RESTRICT",
-  },
-);
-
-
-# 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
-
-sub koha_object_class {
-    'Koha::Auth::Provider::Domain';
-}
-sub koha_objects_class {
-    'Koha::Auth::Providers::Domains';
-}
-
-__PACKAGE__->add_columns(
-    '+auto_register'  => { is_boolean => 1 },
-    '+update_on_auth' => { is_boolean => 1 },
-    '+allow_opac'     => { is_boolean => 1 },
-    '+allow_staff'    => { is_boolean => 1 },
-);
-
-1;
diff --git a/Koha/Schema/Result/IdentityProvider.pm b/Koha/Schema/Result/IdentityProvider.pm
new file mode 100644 (file)
index 0000000..3528a4e
--- /dev/null
@@ -0,0 +1,180 @@
+use utf8;
+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::IdentityProvider
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 TABLE: C<identity_providers>
+
+=cut
+
+__PACKAGE__->table("identity_providers");
+
+=head1 ACCESSORS
+
+=head2 identity_provider_id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+
+unique key, used to identify the provider
+
+=head2 code
+
+  data_type: 'varchar'
+  is_nullable: 0
+  size: 20
+
+Provider code
+
+=head2 description
+
+  data_type: 'varchar'
+  is_nullable: 0
+  size: 255
+
+Description for the provider
+
+=head2 protocol
+
+  data_type: 'enum'
+  extra: {list => ["OAuth","OIDC","LDAP","CAS"]}
+  is_nullable: 0
+
+Protocol provider speaks
+
+=head2 config
+
+  data_type: 'longtext'
+  default_value: ''{}''
+  is_nullable: 0
+
+Configuration of the provider in JSON format
+
+=head2 mapping
+
+  data_type: 'longtext'
+  default_value: ''{}''
+  is_nullable: 0
+
+Configuration to map provider data to Koha user
+
+=head2 matchpoint
+
+  data_type: 'enum'
+  extra: {list => ["email","userid","cardnumber"]}
+  is_nullable: 0
+
+The patron attribute to be used as matchpoint
+
+=head2 icon_url
+
+  data_type: 'varchar'
+  is_nullable: 1
+  size: 255
+
+Provider icon URL
+
+=cut
+
+__PACKAGE__->add_columns(
+  "identity_provider_id",
+  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
+  "code",
+  { data_type => "varchar", is_nullable => 0, size => 20 },
+  "description",
+  { data_type => "varchar", is_nullable => 0, size => 255 },
+  "protocol",
+  {
+    data_type => "enum",
+    extra => { list => ["OAuth", "OIDC", "LDAP", "CAS"] },
+    is_nullable => 0,
+  },
+  "config",
+  { data_type => "longtext", default_value => "'{}'", is_nullable => 0 },
+  "mapping",
+  { data_type => "longtext", default_value => "'{}'", is_nullable => 0 },
+  "matchpoint",
+  {
+    data_type => "enum",
+    extra => { list => ["email", "userid", "cardnumber"] },
+    is_nullable => 0,
+  },
+  "icon_url",
+  { data_type => "varchar", is_nullable => 1, size => 255 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</identity_provider_id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("identity_provider_id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<code>
+
+=over 4
+
+=item * L</code>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("code", ["code"]);
+
+=head1 RELATIONS
+
+=head2 identity_provider_domains
+
+Type: has_many
+
+Related object: L<Koha::Schema::Result::IdentityProviderDomain>
+
+=cut
+
+__PACKAGE__->has_many(
+  "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-10-20 15:27:55
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jmqAwH7/6QvawJ73/0rkQg
+
+__PACKAGE__->has_many(
+  "domains",
+  "Koha::Schema::Result::IdentityProviderDomain",
+  { "foreign.identity_provider_id" => "self.identity_provider_id" },
+  { cascade_copy => 0, cascade_delete => 0 },
+);
+
+sub koha_object_class {
+    'Koha::Auth::Identity::Provider';
+}
+sub koha_objects_class {
+    'Koha::Auth::Identity::Providers';
+}
+
+1;
diff --git a/Koha/Schema/Result/IdentityProviderDomain.pm b/Koha/Schema/Result/IdentityProviderDomain.pm
new file mode 100644 (file)
index 0000000..897c796
--- /dev/null
@@ -0,0 +1,226 @@
+use utf8;
+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::IdentityProviderDomain
+
+=cut
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+
+=head1 TABLE: C<identity_provider_domains>
+
+=cut
+
+__PACKAGE__->table("identity_provider_domains");
+
+=head1 ACCESSORS
+
+=head2 identity_provider_domain_id
+
+  data_type: 'integer'
+  is_auto_increment: 1
+  is_nullable: 0
+
+unique key, used to identify providers domain
+
+=head2 identity_provider_id
+
+  data_type: 'integer'
+  is_foreign_key: 1
+  is_nullable: 0
+
+Reference to provider
+
+=head2 domain
+
+  data_type: 'varchar'
+  is_nullable: 1
+  size: 100
+
+Domain name. If null means all domains
+
+=head2 auto_register
+
+  data_type: 'tinyint'
+  default_value: 0
+  is_nullable: 0
+
+Allow user auto register
+
+=head2 update_on_auth
+
+  data_type: 'tinyint'
+  default_value: 0
+  is_nullable: 0
+
+Update user data on auth login
+
+=head2 default_library_id
+
+  data_type: 'varchar'
+  is_foreign_key: 1
+  is_nullable: 1
+  size: 10
+
+Default library to create user if auto register is enabled
+
+=head2 default_category_id
+
+  data_type: 'varchar'
+  is_foreign_key: 1
+  is_nullable: 1
+  size: 10
+
+Default category to create user if auto register is enabled
+
+=head2 allow_opac
+
+  data_type: 'tinyint'
+  default_value: 1
+  is_nullable: 0
+
+Allow provider from opac interface
+
+=head2 allow_staff
+
+  data_type: 'tinyint'
+  default_value: 0
+  is_nullable: 0
+
+Allow provider from staff interface
+
+=cut
+
+__PACKAGE__->add_columns(
+  "identity_provider_domain_id",
+  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
+  "identity_provider_id",
+  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+  "domain",
+  { data_type => "varchar", is_nullable => 1, size => 100 },
+  "auto_register",
+  { data_type => "tinyint", default_value => 0, is_nullable => 0 },
+  "update_on_auth",
+  { data_type => "tinyint", default_value => 0, is_nullable => 0 },
+  "default_library_id",
+  { data_type => "varchar", is_foreign_key => 1, is_nullable => 1, size => 10 },
+  "default_category_id",
+  { data_type => "varchar", is_foreign_key => 1, is_nullable => 1, size => 10 },
+  "allow_opac",
+  { data_type => "tinyint", default_value => 1, is_nullable => 0 },
+  "allow_staff",
+  { data_type => "tinyint", default_value => 0, is_nullable => 0 },
+);
+
+=head1 PRIMARY KEY
+
+=over 4
+
+=item * L</identity_provider_domain_id>
+
+=back
+
+=cut
+
+__PACKAGE__->set_primary_key("identity_provider_domain_id");
+
+=head1 UNIQUE CONSTRAINTS
+
+=head2 C<identity_provider_id>
+
+=over 4
+
+=item * L</identity_provider_id>
+
+=item * L</domain>
+
+=back
+
+=cut
+
+__PACKAGE__->add_unique_constraint("identity_provider_id", ["identity_provider_id", "domain"]);
+
+=head1 RELATIONS
+
+=head2 default_category
+
+Type: belongs_to
+
+Related object: L<Koha::Schema::Result::Category>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "default_category",
+  "Koha::Schema::Result::Category",
+  { categorycode => "default_category_id" },
+  {
+    is_deferrable => 1,
+    join_type     => "LEFT",
+    on_delete     => "CASCADE",
+    on_update     => "RESTRICT",
+  },
+);
+
+=head2 default_library
+
+Type: belongs_to
+
+Related object: L<Koha::Schema::Result::Branch>
+
+=cut
+
+__PACKAGE__->belongs_to(
+  "default_library",
+  "Koha::Schema::Result::Branch",
+  { branchcode => "default_library_id" },
+  {
+    is_deferrable => 1,
+    join_type     => "LEFT",
+    on_delete     => "CASCADE",
+    on_update     => "RESTRICT",
+  },
+);
+
+=head2 identity_provider
+
+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" },
+);
+
+
+# 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 }
+);
+
+sub koha_object_class {
+    'Koha::Auth::Identity::Provider::Domain';
+}
+sub koha_objects_class {
+    'Koha::Auth::Identity::Provider::Domains';
+}
+
+1;
index 6e4ee14..db07509 100644 (file)
@@ -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;
diff --git a/admin/authentication_providers.pl b/admin/authentication_providers.pl
deleted file mode 100644 (file)
index 07c33b9..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-#!/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 CGI qw ( -utf8 );
-use Scalar::Util qw( blessed );
-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;
-
-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;
-
-$auth_provider = Koha::Auth::Providers->find($auth_provider_id)
-    unless !$auth_provider_id;
-
-my $template_name = $domain_ops ? 'admin/authentication_provider_domains.tt' : 'admin/authentication_providers.tt';
-
-my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
-    {   template_name   => $template_name,
-        query           => $input,
-        type            => "intranet",
-        flagsrequired   => { parameters => 'manage_authentication_providers' },
-    }
-);
-
-my @messages;
-
-if ( !$domain_ops && $op eq 'add' ) {
-
-    my $code        = $input->param('code');
-    my $config      = $input->param('config');
-    my $description = $input->param('description');
-    my $icon_url    = $input->param('icon_url');
-    my $mapping     = $input->param('mapping');
-    my $matchpoint  = $input->param('matchpoint'),
-    my $protocol    = $input->param('protocol');
-
-    try {
-        my $provider = Koha::Auth::Provider->new(
-            {   code        => $code,
-                config      => $config,
-                description => $description,
-                icon_url    => $icon_url,
-                mapping     => $mapping,
-                matchpoint  => $matchpoint,
-                protocol    => $protocol,
-            }
-        )->store;
-
-        Koha::Auth::Provider::Domain->new(
-            {
-                auth_provider_id => $provider->auth_provider_id,
-            }
-        )->store;
-
-        push @messages, { type => 'message', code => 'success_on_insert' };
-    }
-    catch {
-        if ( blessed $_ and $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
-            push @messages,
-              {
-                type   => 'alert',
-                code   => 'error_on_insert',
-                reason => 'duplicate_id'
-              };
-        }
-    };
-
-    # list servers after adding
-    $op = 'list';
-}
-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 $auto_register       = $input->param('auto_register');
-    my $default_category_id = $input->param('default_category_id');
-    my $default_library_id  = $input->param('default_library_id');
-    my $domain              = $input->param('domain');
-    my $update_on_auth      = $input->param('update_on_auth');
-
-    try {
-
-        Koha::Auth::Provider::Domain->new(
-            {
-                allow_opac          => $allow_opac,
-                allow_staff         => $allow_staff,
-                auth_provider_id    => $auth_provider_id,
-                auto_register       => $auto_register,
-                default_category_id => $default_category_id,
-                default_library_id  => $default_library_id,
-                domain              => $domain,
-                update_on_auth      => $update_on_auth,
-            }
-        )->store;
-
-        push @messages, { type => 'message', code => 'success_on_insert' };
-    }
-    catch {
-        if ( blessed $_ and $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
-            push @messages,
-              {
-                type   => 'alert',
-                code   => 'error_on_insert',
-                reason => 'duplicate_id'
-              };
-        }
-    };
-
-    # list servers after adding
-    $op = 'list';
-}
-elsif ( !$domain_ops && $op eq 'edit_form' ) {
-
-    if ( $auth_provider ) {
-        $template->param(
-            auth_provider => $auth_provider
-        );
-    }
-    else {
-        push @messages,
-            {
-                type   => 'alert',
-                code   => 'error_on_edit',
-                reason => 'invalid_id'
-            };
-    }
-}
-elsif ( $domain_ops && $op eq 'edit_form' ) {
-    my $auth_provider_domain_id = $input->param('auth_provider_domain_id');
-    my $auth_provider_domain;
-
-    $auth_provider_domain = Koha::Auth::Provider::Domains->find($auth_provider_domain_id)
-        unless !$auth_provider_domain_id;
-
-    if ( $auth_provider_domain ) {
-        $template->param(
-            auth_provider_domain => $auth_provider_domain
-        );
-    }
-    else {
-        push @messages,
-            {
-                type   => 'alert',
-                code   => 'error_on_edit',
-                reason => 'invalid_id'
-            };
-    }
-}
-elsif ( !$domain_ops && $op eq 'edit_save' ) {
-
-    if ( $auth_provider ) {
-
-        my $code        = $input->param('code');
-        my $config      = $input->param('config');
-        my $description = $input->param('description');
-        my $icon_url    = $input->param('icon_url');
-        my $mapping     = $input->param('mapping');
-        my $matchpoint  = $input->param('matchpoint');
-        my $protocol    = $input->param('protocol');
-
-        try {
-
-            $auth_provider->set(
-                {   code        => $code,
-                    config      => $config,
-                    description => $description,
-                    icon_url    => $icon_url,
-                    mapping     => $mapping,
-                    matchpoint  => $matchpoint,
-                    protocol    => $protocol,
-                }
-            )->store;
-
-            push @messages,
-            {
-                type => 'message',
-                code => 'success_on_update'
-            };
-        }
-        catch {
-            push @messages,
-            {
-                type   => 'alert',
-                code   => 'error_on_update'
-            };
-        };
-
-        # list servers after adding
-        $op = 'list';
-    }
-    else {
-        push @messages,
-            {
-                type   => 'alert',
-                code   => 'error_on_update',
-                reason => 'invalid_id'
-            };
-    }
-}
-elsif ( $domain_ops && $op eq 'edit_save' ) {
-
-    my $auth_provider_domain_id = $input->param('auth_provider_domain_id');
-    my $auth_provider_domain;
-
-    $auth_provider_domain = Koha::Auth::Provider::Domains->find($auth_provider_domain_id)
-        unless !$auth_provider_domain_id;
-
-    if ( $auth_provider_domain ) {
-
-        my $auth_provider_id    = $input->param('auth_provider_id');
-        my $domain              = $input->param('domain');
-        my $auto_register       = $input->param('auto_register');
-        my $update_on_auth      = $input->param('update_on_auth');
-        my $default_library_id  = $input->param('default_library_id');
-        my $default_category_id = $input->param('default_category_id');
-        my $allow_opac          = $input->param('allow_opac');
-        my $allow_staff         = $input->param('allow_staff');
-
-        try {
-
-            $auth_provider_domain->set(
-                {
-                    auth_provider_id    => $auth_provider_id,
-                    domain              => $domain,
-                    auto_register       => $auto_register,
-                    update_on_auth      => $update_on_auth,
-                    default_library_id  => $default_library_id,
-                    default_category_id => $default_category_id,
-                    allow_opac          => $allow_opac,
-                    allow_staff         => $allow_staff,
-                }
-            )->store;
-
-            push @messages,
-            {
-                type => 'message',
-                code => 'success_on_update'
-            };
-        }
-        catch {
-            push @messages,
-            {
-                type   => 'alert',
-                code   => 'error_on_update'
-            };
-        };
-
-        # list servers after adding
-        $op = 'list';
-    }
-    else {
-        push @messages,
-            {
-                type   => 'alert',
-                code   => 'error_on_update',
-                reason => 'invalid_id'
-            };
-    }
-}
-
-if ( $domain_ops ) {
-    $template->param(
-        auth_provider_code => $auth_provider->code,
-        auth_provider_id   => $auth_provider_id,
-    );
-}
-
-$template->param(
-    op       => $op,
-    messages => \@messages,
-);
-
-output_html_with_http_headers $input, $cookie, $template->output;
diff --git a/admin/identity_providers.pl b/admin/identity_providers.pl
new file mode 100644 (file)
index 0000000..2f7a433
--- /dev/null
@@ -0,0 +1,299 @@
+#!/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 CGI qw ( -utf8 );
+use Scalar::Util qw( blessed );
+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::Identity::Providers;
+
+my $input         = CGI->new;
+my $op            = $input->param('op') || 'list';
+my $domain_ops    = $input->param('domain_ops');
+my $identity_provider_id = $input->param('identity_provider_id');
+my $identity_provider;
+
+$identity_provider = Koha::Auth::Identity::Providers->find($identity_provider_id)
+    unless !$identity_provider_id;
+
+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_identity_providers' },
+    }
+);
+
+my @messages;
+
+if ( !$domain_ops && $op eq 'add' ) {
+
+    my $code        = $input->param('code');
+    my $config      = $input->param('config');
+    my $description = $input->param('description');
+    my $icon_url    = $input->param('icon_url');
+    my $mapping     = $input->param('mapping');
+    my $matchpoint  = $input->param('matchpoint'),
+    my $protocol    = $input->param('protocol');
+
+    try {
+        my $provider = Koha::Auth::Identity::Provider->new(
+            {   code        => $code,
+                config      => $config,
+                description => $description,
+                icon_url    => $icon_url,
+                mapping     => $mapping,
+                matchpoint  => $matchpoint,
+                protocol    => $protocol,
+            }
+        )->store;
+
+        Koha::Auth::Identity::Provider::Domain->new(
+            {
+                identity_provider_id => $provider->identity_provider_id,
+            }
+        )->store;
+
+        push @messages, { type => 'message', code => 'success_on_insert' };
+    }
+    catch {
+        if ( blessed $_ and $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
+            push @messages,
+              {
+                type   => 'alert',
+                code   => 'error_on_insert',
+                reason => 'duplicate_id'
+              };
+        }
+    };
+
+    # list servers after adding
+    $op = 'list';
+}
+elsif ( $domain_ops && $op eq 'add' ) {
+
+    my $allow_opac          = $input->param('allow_opac');
+    my $allow_staff         = $input->param('allow_staff');
+    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');
+    my $domain              = $input->param('domain');
+    my $update_on_auth      = $input->param('update_on_auth');
+
+    try {
+
+        Koha::Auth::Identity::Provider::Domain->new(
+            {
+                allow_opac          => $allow_opac,
+                allow_staff         => $allow_staff,
+                identity_provider_id    => $identity_provider_id,
+                auto_register       => $auto_register,
+                default_category_id => $default_category_id,
+                default_library_id  => $default_library_id,
+                domain              => $domain,
+                update_on_auth      => $update_on_auth,
+            }
+        )->store;
+
+        push @messages, { type => 'message', code => 'success_on_insert' };
+    }
+    catch {
+        if ( blessed $_ and $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
+            push @messages,
+              {
+                type   => 'alert',
+                code   => 'error_on_insert',
+                reason => 'duplicate_id'
+              };
+        }
+    };
+
+    # list servers after adding
+    $op = 'list';
+}
+elsif ( !$domain_ops && $op eq 'edit_form' ) {
+
+    if ( $identity_provider ) {
+        $template->param(
+            identity_provider => $identity_provider
+        );
+    }
+    else {
+        push @messages,
+            {
+                type   => 'alert',
+                code   => 'error_on_edit',
+                reason => 'invalid_id'
+            };
+    }
+}
+elsif ( $domain_ops && $op eq 'edit_form' ) {
+    my $identity_provider_domain_id = $input->param('identity_provider_domain_id');
+    my $identity_provider_domain;
+
+    $identity_provider_domain = Koha::Auth::Identity::Provider::Domains->find($identity_provider_domain_id)
+        unless !$identity_provider_domain_id;
+
+    if ( $identity_provider_domain ) {
+        $template->param(
+            identity_provider_domain => $identity_provider_domain
+        );
+    }
+    else {
+        push @messages,
+            {
+                type   => 'alert',
+                code   => 'error_on_edit',
+                reason => 'invalid_id'
+            };
+    }
+}
+elsif ( !$domain_ops && $op eq 'edit_save' ) {
+
+    if ( $identity_provider ) {
+
+        my $code        = $input->param('code');
+        my $config      = $input->param('config');
+        my $description = $input->param('description');
+        my $icon_url    = $input->param('icon_url');
+        my $mapping     = $input->param('mapping');
+        my $matchpoint  = $input->param('matchpoint');
+        my $protocol    = $input->param('protocol');
+
+        try {
+
+            $identity_provider->set(
+                {   code        => $code,
+                    config      => $config,
+                    description => $description,
+                    icon_url    => $icon_url,
+                    mapping     => $mapping,
+                    matchpoint  => $matchpoint,
+                    protocol    => $protocol,
+                }
+            )->store;
+
+            push @messages,
+            {
+                type => 'message',
+                code => 'success_on_update'
+            };
+        }
+        catch {
+            push @messages,
+            {
+                type   => 'alert',
+                code   => 'error_on_update'
+            };
+        };
+
+        # list servers after adding
+        $op = 'list';
+    }
+    else {
+        push @messages,
+            {
+                type   => 'alert',
+                code   => 'error_on_update',
+                reason => 'invalid_id'
+            };
+    }
+}
+elsif ( $domain_ops && $op eq 'edit_save' ) {
+
+    my $identity_provider_domain_id = $input->param('identity_provider_domain_id');
+    my $identity_provider_domain;
+
+    $identity_provider_domain = Koha::Auth::Identity::Provider::Domains->find($identity_provider_domain_id)
+        unless !$identity_provider_domain_id;
+
+    if ( $identity_provider_domain ) {
+
+        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');
+        my $default_library_id  = $input->param('default_library_id');
+        my $default_category_id = $input->param('default_category_id');
+        my $allow_opac          = $input->param('allow_opac');
+        my $allow_staff         = $input->param('allow_staff');
+
+        try {
+
+            $identity_provider_domain->set(
+                {
+                    identity_provider_id    => $identity_provider_id,
+                    domain              => $domain,
+                    auto_register       => $auto_register,
+                    update_on_auth      => $update_on_auth,
+                    default_library_id  => $default_library_id,
+                    default_category_id => $default_category_id,
+                    allow_opac          => $allow_opac,
+                    allow_staff         => $allow_staff,
+                }
+            )->store;
+
+            push @messages,
+            {
+                type => 'message',
+                code => 'success_on_update'
+            };
+        }
+        catch {
+            push @messages,
+            {
+                type   => 'alert',
+                code   => 'error_on_update'
+            };
+        };
+
+        # list servers after adding
+        $op = 'list';
+    }
+    else {
+        push @messages,
+            {
+                type   => 'alert',
+                code   => 'error_on_update',
+                reason => 'invalid_id'
+            };
+    }
+}
+
+if ( $domain_ops ) {
+    $template->param(
+        identity_provider_code => $identity_provider->code,
+        identity_provider_id   => $identity_provider_id,
+    );
+}
+
+$template->param(
+    op       => $op,
+    messages => \@messages,
+);
+
+output_html_with_http_headers $input, $cookie, $template->output;
diff --git a/api/v1/swagger/definitions/auth_provider.yaml b/api/v1/swagger/definitions/auth_provider.yaml
deleted file mode 100644 (file)
index 93e587b..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
----
-type: object
-properties:
-  auth_provider_id:
-    type: integer
-    description: Internally assigned authentication provider identifier
-    readOnly: true
-  code:
-    description: Authentication provider code
-    type: string
-  description:
-    description: User-oriented description for the provider
-    type: string
-  protocol:
-    description: Authentication protocol
-    type: string
-    enum:
-      - OAuth
-      - OIDC
-      - CAS (not implemented)
-      - LDAP (not implemented)
-  mapping:
-    description: Attribute mapping
-    type:
-      - object
-      - "null"
-  matchpoint:
-    description: Patron attribute that will be used to match
-    type: string
-    enum:
-      - email
-      - userid
-      - cardnumber
-  config:
-    description: Configuration
-    type: object
-  icon_url:
-    description: Icon url
-    type: string
-  domains:
-    description: Configured domains for the authentication provider
-    type:
-      - array
-      - "null"
-additionalProperties: false
-required:
-  - config
-  - code
-  - protocol
diff --git a/api/v1/swagger/definitions/auth_provider_domain.yaml b/api/v1/swagger/definitions/auth_provider_domain.yaml
deleted file mode 100644 (file)
index bc9f60a..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
----
-type: object
-properties:
-  auth_provider_domain_id:
-    type: integer
-    description: Internally assigned authentication provider domain identifier
-    readOnly: true
-  auth_provider_id:
-    type: integer
-    description: Internally assigned authentication provider identifier
-  domain:
-    description: Matching domain ('*' used as wildcard)
-    type:
-      - string
-      - "null"
-  auto_register:
-    description: If patrons will be generated on login if required
-    type: boolean
-  update_on_auth:
-    description: If patron data is updated on login
-    type: boolean
-  default_library_id:
-    description: Internal identifier for the default library to be assigned to the new patrons
-    type:
-      - string
-      - "null"
-  default_category_id:
-    description: Internal identifier for the default patron's category
-    type:
-      - string
-      - "null"
-  allow_opac:
-    description: If this domain can be used for OPAC login
-    type: boolean
-  allow_staff:
-    description: If this domain can be used for staff login
-    type: boolean
-additionalProperties: false
-required:
-  - auth_provider_domain_id
-  - auth_provider_id
-  - domain
-  - auto_register
-  - update_on_auth
-  - default_library_id
-  - default_category_id
-  - allow_opac
-  - allow_staff
diff --git a/api/v1/swagger/definitions/identity_provider.yaml b/api/v1/swagger/definitions/identity_provider.yaml
new file mode 100644 (file)
index 0000000..c69d60a
--- /dev/null
@@ -0,0 +1,51 @@
+---
+type: object
+properties:
+  identity_provider_id:
+    type: integer
+    description: Internally assigned authentication provider identifier
+    readOnly: true
+  code:
+    description: Authentication provider code
+    type: string
+  description:
+    description: User-oriented description for the provider
+    type: string
+  protocol:
+    description: Authentication protocol
+    type: string
+    enum:
+      - OAuth
+      - OIDC
+      - CAS (not implemented)
+      - LDAP (not implemented)
+  mapping:
+    description: Attribute mapping
+    type:
+      - object
+      - "null"
+  matchpoint:
+    description: Patron attribute that will be used to match
+    type: string
+    enum:
+      - email
+      - userid
+      - cardnumber
+  config:
+    description: Configuration
+    type: object
+  icon_url:
+    description: Icon url
+    type:
+     - string
+     - "null"
+  domains:
+    description: Configured domains for the authentication provider
+    type:
+      - array
+      - "null"
+additionalProperties: false
+required:
+  - config
+  - code
+  - protocol
diff --git a/api/v1/swagger/definitions/identity_provider_domain.yaml b/api/v1/swagger/definitions/identity_provider_domain.yaml
new file mode 100644 (file)
index 0000000..d03e99d
--- /dev/null
@@ -0,0 +1,47 @@
+---
+type: object
+properties:
+  identity_provider_domain_id:
+    type: integer
+    description: Internally assigned authentication provider domain identifier
+    readOnly: true
+  identity_provider_id:
+    type: integer
+    description: Internally assigned authentication provider identifier
+  domain:
+    description: Matching domain ('*' used as wildcard)
+    type:
+      - string
+      - "null"
+  auto_register:
+    description: If patrons will be generated on login if required
+    type: boolean
+  update_on_auth:
+    description: If patron data is updated on login
+    type: boolean
+  default_library_id:
+    description: Internal identifier for the default library to be assigned to the new patrons
+    type:
+      - string
+      - "null"
+  default_category_id:
+    description: Internal identifier for the default patron's category
+    type:
+      - string
+      - "null"
+  allow_opac:
+    description: If this domain can be used for OPAC login
+    type: boolean
+  allow_staff:
+    description: If this domain can be used for staff login
+    type: boolean
+additionalProperties: false
+required:
+  - identity_provider_domain_id
+  - domain
+  - auto_register
+  - update_on_auth
+  - default_library_id
+  - default_category_id
+  - allow_opac
+  - allow_staff
index ae9c655..d7be7e8 100644 (file)
           $ref: ../swagger.yaml#/definitions/error
     x-koha-authorization:
       permissions:
-        parameters: manage_authentication_providers
\ No newline at end of file
+        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
\ No newline at end of file
index 0344c0c..696a73b 100644 (file)
@@ -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
index 915bd2f..37563e4 100755 (executable)
@@ -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
index b524b89..c30cd7a 100644 (file)
@@ -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;
 
 --
index 78d06a9..8733ce9 100644 (file)
@@ -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'),
index fa771e6..9c9a24c 100644 (file)
         </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>
index d0ca376..c071e1a 100644 (file)
             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>
index 4cc7f83..0e83b36 100644 (file)
                 </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>
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authentication_provider_domains.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authentication_provider_domains.tt
deleted file mode 100644 (file)
index 582842a..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-[% USE raw %]
-[% USE Asset %]
-[% USE Branches %]
-[% USE Categories %]
-[% SET footerjs = 1 %]
-[% 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 %]
-
-    Authentication providers &rsaquo; Administration &rsaquo; Koha
-</title>
-[% INCLUDE 'doc-head-close.inc' %]
-</head>
-
-<body id="admin_auth_provider_domains" class="admin">
-[% INCLUDE 'header.inc' %]
-[% INCLUDE 'prefs-admin-search.inc' %]
-
-<nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
-    <ol>
-        <li>
-            <a href="/cgi-bin/koha/mainpage.pl">Home</a>
-        </li>
-        <li>
-            <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
-        </li>
-
-        <li>
-            <a href="/cgi-bin/koha/admin/authentication_providers.pl">Authentication 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>
-            </li>
-            <li>
-                <a href="#" aria-current="page">
-                    New Domain
-                </a>
-            </li>
-
-        [% 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>
-            </li>
-            <li>
-                <a href="#" aria-current="page">
-                    Edit Domain
-                </a>
-            </li>
-
-        [% ELSE %]
-            <li>
-                <a href="#" aria-current="page">
-                    Domains for [%- auth_provider_code | html -%]
-                </a>
-            </li>
-        [% END %]
-    </ol>
-</nav>
-
-<div class="main container-fluid">
-    <div class="row">
-        <div class="col-sm-10 col-sm-push-2">
-            <main>
-
-[% FOREACH m IN messages %]
-    <div class="dialog [% m.type | html %]" id="auth_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>
-        [% CASE 'error_on_insert' %]
-            <span>An error occurred when adding a new authentication provider domain.</span>
-        [% CASE 'success_on_update' %]
-            <span>Authentication provider domain updated successfully.</span>
-        [% CASE 'success_on_insert' %]
-            <span>Authentication 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>
-
-[% 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">
-        <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 -%]" />
-        <fieldset class="rows">
-            <ol>
-                <li>
-                    <label for="domain">Domain: </label>
-                    <input type="text" name="domain" id="domain" size="60" />
-                </li>
-            </ol>
-        </fieldset>
-
-        <fieldset class="rows">
-            <ol>
-                <li>
-                    <label for="update_on_auth">Update on login: </label>
-                    <select name="update_on_auth" id="update_on_auth">
-                        <option value="1">Update</option>
-                        <option value="0" selected="selected">Don't update</option>
-                    </select>
-                    <span>user data on login</span>
-                </li>
-                <li>
-                    <label for="auto_register">Auto register: </label>
-                    <select name="auto_register" id="auto_register">
-                        <option value="1">Allow</option>
-                        <option value="0" selected="selected">Don't allow</option>
-                    </select>
-                    <span>users to auto register on login</span>
-                </li>
-                <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( unfiltered => 1, do_not_select_my_library => 1 ) %]
-                    </select>
-                </li>
-                <li>
-                    <label for="default_category_id">Default category: </label>
-                    [% SET categories = Categories.all() %]
-                    <select name="default_category_id" id="default_category_id">
-                        [% FOREACH category IN categories %]
-                            <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
-                        [% END %]
-                    </select>
-                </li>
-                <li>
-                    <label for="allow_opac">Allow opac: </label>
-                    <select name="allow_opac" id="allow_opac">
-                        <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>
-                </li>
-                <li>
-                    <label for="allow_opac">Allow staff: </label>
-                    <select name="allow_staff" id="allow_staff">
-                        <option value="1" selected="selected">Allow</option>
-                        <option value="0">Don't allow</option>
-                    </select>
-                    <span>of this domain </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>
-        </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">
-        <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 -%]" />
-        <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 -%]"/>
-                </li>
-            </ol>
-        </fieldset>
-
-        <fieldset class="rows">
-            <ol>
-                <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" %]
-                        <option value="1" selected="selected">Update</option>
-                        <option value="0">Don't update</option>
-                    [% ELSE %]
-                        <option value="1">Update</option>
-                        <option value="0" selected="selected">Don't update</option>
-                    [% END %]
-                    </select>
-                    <span>user data on login</span>
-                </li>
-                <li>
-                    <label for="auto_register">Auto register: </label>
-                    <select name="auto_register" id="auto_register">
-                    [% IF auth_provider_domain.auto_register == "1" %]
-                        <option value="1" selected="selected">Allow</option>
-                        <option value="0">Don't allow</option>
-                    [% ELSE %]
-                        <option value="1">Allow</option>
-                        <option value="0" selected="selected">Don't allow</option>
-                    [% END %]
-                    </select>
-                    <span>users to auto register on login</span>
-                </li>
-                <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 ) %]
-                    </select>
-                </li>
-                <li>
-                    <label for="default_category_id">Default category: </label>
-                    [% 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 %]
-                                <option value="[% category.categorycode | html %]" selected="selected">[% category.description | html %]</option>
-                            [% ELSE %]
-                                <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
-                            [% END %]
-                        [% END %]
-                    </select>
-                </li>
-                <li>
-                    <label for="allow_opac">Allow opac: </label>
-                    <select name="allow_opac" id="allow_opac">
-                    [% IF auth_provider_domain.allow_opac == "1" %]
-                        <option value="1" selected="selected">Allow</option>
-                        <option value="0">Don't allow</option>
-                    [% ELSE %]
-                        <option value="1">Allow</option>
-                        <option value="0" selected="selected">Don't allow</option>
-                    [% END %]
-                    </select>
-                    <span>opac users of this domain to login with this authentication 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" %]
-                        <option value="1" selected="selected">Allow</option>
-                        <option value="0">Don't allow</option>
-                    [% ELSE %]
-                        <option value="1">Allow</option>
-                        <option value="0" selected="selected">Don't allow</option>
-                    [% END %]
-                    </select>
-                    <span>staff users of this domain to login with this authentication 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>
-        </fieldset>
-    </form>
-[% END %]
-
-[% 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>
-    </div>
-
-    <h1>Authentication provider domains</h1>
-
-    <table id="auth_provider_domains">
-        <thead>
-            <tr>
-                <th>Domain</th>
-                <th>Update on login</th>
-                <th>Auto register</th>
-                <th>Default library</th>
-                <th>Default category</th>
-                <th>Allow opac</th>
-                <th>Allow staff</th>
-                <th data-class-name="actions noExport">Actions</th>
-            </tr>
-        </thead>
-    </table>
-[% END %]
-
-            <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
-                <div class="modal-dialog">
-                    <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>
-                        </div>
-                        <div class="modal-body">
-                            <div id="delete_confirm_dialog"></div>
-                        </div>
-                        <div class="modal-footer">
-                            <a href="#" class="btn btn-default" id="delete_confirm_modal_button" role="button" data-toggle="modal">Delete</a>
-                            <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
-                        </div>
-                    </div> <!-- /.modal-content -->
-                </div> <!-- /.modal-dialog -->
-            </div> <!-- #delete_confirm_modal -->
-
-            </main>
-        </div> <!-- /.col-sm-10.col-sm-push-2 -->
-
-        <div class="col-sm-2 col-sm-pull-10">
-            <aside>
-                [% INCLUDE 'admin-menu.inc' %]
-            </aside>
-        </div> <!-- /.col-sm-2.col-sm-pull-10 -->
-     </div> <!-- /.row -->
-
-
-[% MACRO jsinclude BLOCK %]
-    [% Asset.js("js/admin-menu.js") | $raw %]
-    [% INCLUDE 'datatables.inc' %]
-    <script>
-        $(document).ready(function() {
-
-            var auth_provider_domains_url = '/api/v1/auth/providers/[%- auth_provider_id | html -%]/domains';
-            [% SET categories = Categories.all() %]
-            var categories = {
-            [% FOREACH category IN categories %]
-                "[% category.categorycode | html %]": "[% category.description | html %]",
-            [% END %]
-            };
-            [% SET libraries = Branches.all() %]
-            var libraries = {
-            [% FOREACH library IN libraries %]
-                "[% library.branchcode | html %]": "[% library.branchname | html %]",
-            [% END %]
-            };
-            window.auth_provider_domains = $("#auth_provider_domains").kohaTable({
-                "ajax": {
-                    "url": auth_provider_domains_url
-                },
-                'language': {
-                    'emptyTable': '<div class="dialog message">'+_("There are no authentication provider domains defined.")+'</div>'
-                },
-                "columnDefs": [ {
-                    "targets": [1],
-                    "render": function (data, type, row, meta) {
-                        if ( type == 'display' ) {
-                            if ( data != null ) {
-                                return data.escapeHtml();
-                            }
-                            else {
-                                return "";
-                            }
-                        }
-                        return data;
-                    }
-                } ],
-                "columns": [
-                    {
-                        "data": "domain",
-                        "searchable": true,
-                        "orderable": true,
-                        "render": function(data, type, row, meta) {
-                            if ( data != null ) {
-                                return data.escapeHtml();
-                            }
-                            else {
-                                return "*";
-                            }
-                        }
-                    },
-                    {
-                        "data": function( row, type, val, meta ) {
-                            if (row.update_on_auth) {
-                                return _("Yes");
-                            } else {
-                                return _("No");
-                            }
-                        },
-                        "searchable": true,
-                        "orderable": true
-                    },
-                    {
-                        "data": function( row, type, val, meta ) {
-                            if (row.auto_register) {
-                                return _("Yes");
-                            } else {
-                                return _("No");
-                            }
-                        },
-                        "searchable": true,
-                        "orderable": true
-                    },
-                    {
-                        "data": function( row, type, val, meta ) {
-                            return libraries[row.default_library_id] || "";
-                        },
-                        "searchable": true,
-                        "orderable": true
-                    },
-                    {
-                        "data": function( row, type, val, meta ) {
-                            return categories[row.default_category_id] || "";
-                        },
-                        "searchable": true,
-                        "orderable": true
-                    },
-                    {
-                        "data": function( row, type, val, meta ) {
-                            if (row.allow_opac) {
-                                return _("Yes");
-                            } else {
-                                return _("No");
-                            }
-                        },
-                        "searchable": true,
-                        "orderable": true
-                    },
-                    {
-                        "data": function( row, type, val, meta ) {
-                            if (row.allow_staff) {
-                                return _("Yes");
-                            } else {
-                                return _("No");
-                            }
-                        },
-                        "searchable": true,
-                        "orderable": true
-                    },
-                    {
-                        "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>';
-                            return result;
-                        },
-                        "searchable": false,
-                        "orderable": false
-                    }
-                ],
-                createdRow: function (row, data, dataIndex) {
-                    if ( data.debug ) {
-                        $(row).addClass('debug');
-                    }
-                },
-            });
-
-            $('#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'));
-
-                $("#delete_confirm_dialog").html(
-                    _("You are about to delete the '%s' authentication provider domain.").format(auth_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").on( "click", function () {
-
-                var auth_provider_domain_id   = $(this).data('auth-provider-domain-id');
-                var auth_provider_domain = $(this).data('auth-provider-domain');
-
-                $.ajax({
-                    method: "DELETE",
-                    url: auth_provider_domains_url+"/"+auth_provider_domain_id
-                }).success(function() {
-                    window.auth_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();
-                    });
-                }).fail(function () {
-                    $("#smtp_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(auth_provider_domain)).show();
-                }).done(function () {
-                    $("#delete_confirm_modal").modal('hide');
-                });
-            });
-        });
-    </script>
-[% END %]
-
-[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authentication_providers.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authentication_providers.tt
deleted file mode 100644 (file)
index a334288..0000000
+++ /dev/null
@@ -1,466 +0,0 @@
-[% USE raw %]
-[% USE Asset %]
-[% SET footerjs = 1 %]
-[% INCLUDE 'doc-head-open.inc' %]
-<title>
-    [% IF op == 'add_form' %]
-        New authentication provider &rsaquo; [% ELSIF op == 'edit_form' %]
-        Edit authentication provider &rsaquo; [% END %]
-
-    Authentication providers &rsaquo; Administration &rsaquo; Koha
-</title>
-[% INCLUDE 'doc-head-close.inc' %]
-</head>
-
-<body id="admin_auth_providers" class="admin">
-[% INCLUDE 'header.inc' %]
-[% INCLUDE 'prefs-admin-search.inc' %]
-
-<nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
-    <ol>
-        <li>
-            <a href="/cgi-bin/koha/mainpage.pl">Home</a>
-        </li>
-        <li>
-            <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
-        </li>
-
-        [% IF op == 'add_form' %]
-            <li>
-                <a href="/cgi-bin/koha/admin/authentication_providers.pl">Authentication providers</a>
-            </li>
-            <li>
-                <a href="#" aria-current="page">
-                    New
-                </a>
-            </li>
-
-        [% ELSIF op == 'edit_form' %]
-            <li>
-                <a href="/cgi-bin/koha/admin/authentication_providers.pl">Authentication providers</a>
-            </li>
-            <li>
-                <a href="#" aria-current="page">
-                    Edit
-                </a>
-            </li>
-
-        [% ELSE %]
-            <li>
-                <a href="#" aria-current="page">
-                    Authentication providers
-                </a>
-            </li>
-        [% END %]
-    </ol>
-</nav>
-
-<div class="main container-fluid">
-    <div class="row">
-        <div class="col-sm-10 col-sm-push-2">
-            <main>
-
-[% FOREACH m IN messages %]
-    <div class="dialog [% m.type | html %]" id="auth_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>
-        [% CASE 'error_on_insert' %]
-            <span>An error occurred when adding a new authentication provider.</span>
-        [% CASE 'success_on_update' %]
-            <span>Authentication provider updated successfully.</span>
-        [% CASE 'success_on_insert' %]
-            <span>Authentication 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>
-
-[% 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">
-        <input type="hidden" name="op" value="add" />
-        <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" />
-                    <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" />
-                    <span class="required">Required</span>
-                </li>
-                <li>
-                    <label for="protocol">Protocol: </label>
-                    <select name="protocol" id="protocol">
-                        <option value="OAuth">OAuth</option>
-                        <option value="OIDC">OIDC</option>
-                        <!-- Not implemented yet
-                        <option value="LDAP">LDAP</option>
-                        <option value="CAS">CAS</option>
-                        -->
-                    </select>
-                </li>
-            </ol>
-        </fieldset>
-
-        <fieldset class="rows">
-            <ol>
-                <li>
-                    <div>
-                        <label for="config" class="required json">Configuration: </label>
-                        <textarea name="config" id="config" class="required"></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 OAuth configuration</button>
-                    </div>
-                </li>
-                <li>
-                    <div>
-                        <label for="mapping" class="required json">Mapping: </label>
-                        <textarea name="mapping" id="mapping" class="required"></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 OAuth mapping</button>
-                    </div>
-                </li>
-                <li>
-                    <label for="matchpoint" class="required">Matchpoint: </label>
-                    <select name="matchpoint" id="matchpoint" class="required">
-                        <option value="email">Email</option>
-                        <option value="userid">User id</option>
-                        <option value="cardnumber">Card number</option>
-                    </select>
-                    <span class="required">Required</span>
-                </li>
-                <li>
-                    <label for="icon_url">Icon URL: </label>
-                    <input type="text" name="icon_url" id="icon_url" size="60" />
-                </li>
-            </ol>
-        </fieldset>
-        <fieldset class="action">
-            <input type="submit" value="Submit" />
-            <a class="cancel" href="/cgi-bin/koha/admin/authentication_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">
-        <input type="hidden" name="op" value="edit_save" />
-        <input type="hidden" name="auth_provider_id" value="[%- auth_provider.auth_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 -%]"/>
-                    <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 -%]"/>
-                    <span class="required">Required</span>
-                </li>
-                <li>
-                    <label for="protocol">Protocol: </label>
-                    <select name="protocol" id="protocol">
-                    [% IF auth_provider.protocol == 'OAuth' %]
-                        <option value="OAuth" selected="selected">OAuth</option>
-                        <option value="OIDC">OIDC</option>
-                        <!-- Not implemented yet
-                        <option value="LDAP">LDAP</option>
-                        <option value="CAS">CAS</option>
-                        -->
-                    [% ELSE %]
-                        <option value="OAuth">OAuth</option>
-                        <option value="OIDC" selected="selected">OIDC</option>
-                        <!-- Not implemented yet
-                        <option value="LDAP">LDAP</option>
-                        <option value="CAS">CAS</option>
-                        -->
-                    [% END %]
-                    </select>
-                </li>
-            </ol>
-        </fieldset>
-
-        <fieldset class="rows">
-            <ol>
-                <li>
-                    <div>
-                        <label for="config" class="required json">Configuration: </label>
-                        <textarea name="config" id="config" class="required">[%- auth_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>
-                    </div>
-                </li>
-                <li>
-                    <div>
-                        <label for="mapping" class="required json">Mapping: </label>
-                        <textarea name="mapping" id="mapping" class="required">[%- auth_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>
-                    </div>
-                </li>
-                <li>
-                    <label for="matchpoint" class="required">matchpoint: </label>
-                    <select name="matchpoint" id="matchpoint" class="required">
-                        [%- IF auth_provider.matchpoint == 'email'      -%]
-                            <option value="email" selected="selected">Email</option>
-                        [%- ELSE -%]
-                            <option value="email">Email</option>
-                        [%- END -%]
-                        [%- IF auth_provider.matchpoint == 'userid'     -%]
-                            <option value="userid" selected="selected">User id</option>
-                        [%- ELSE -%]
-                            <option value="userid">User id</option>
-                        [%- END -%]
-                        [%- IF auth_provider.matchpoint == 'cardnumber' -%]
-                            <option value="cardnumber" selected="selected">Card number</option>
-                        [%- ELSE -%]
-                            <option value="cardnumber">Card number</option>
-                        [%- END -%]
-                    </select>
-                    <span class="required">Required</span>
-                </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 -%]"/>
-                </li>
-            </ol>
-        </fieldset>
-        <fieldset class="action">
-            <input type="submit" value="Submit" />
-            <a class="cancel" href="/cgi-bin/koha/admin/authentication_providers.pl">Cancel</a>
-        </fieldset>
-    </form>
-[% END %]
-
-[% 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>
-    </div>
-
-    <h1>Authentication providers</h1>
-
-    <table id="auth_providers">
-        <thead>
-            <tr>
-                <th>Code</th>
-                <th>Description</th>
-                <th>Protocol</th>
-                <th data-class-name="actions noExport">Actions</th>
-            </tr>
-        </thead>
-    </table>
-[% END %]
-
-            <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
-                <div class="modal-dialog">
-                    <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>
-                        </div>
-                        <div class="modal-body">
-                            <div id="delete_confirm_dialog"></div>
-                        </div>
-                        <div class="modal-footer">
-                            <a href="#" class="btn btn-default" id="delete_confirm_modal_button" role="button" data-toggle="modal">Delete</a>
-                            <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
-                        </div>
-                    </div> <!-- /.modal-content -->
-                </div> <!-- /.modal-dialog -->
-            </div> <!-- #delete_confirm_modal -->
-
-            </main>
-        </div> <!-- /.col-sm-10.col-sm-push-2 -->
-
-        <div class="col-sm-2 col-sm-pull-10">
-            <aside>
-                [% INCLUDE 'admin-menu.inc' %]
-            </aside>
-        </div> <!-- /.col-sm-2.col-sm-pull-10 -->
-     </div> <!-- /.row -->
-
-
-[% MACRO jsinclude BLOCK %]
-    [% Asset.js("js/admin-menu.js") | $raw %]
-    [% INCLUDE 'datatables.inc' %]
-    <script>
-        $(document).ready(function() {
-
-            var auth_providers_url = '/api/v1/auth/providers';
-            window.auth_providers = $("#auth_providers").kohaTable({
-                "ajax": {
-                    "url": auth_providers_url
-                },
-                'language': {
-                    'emptyTable': '<div class="dialog message">'+_("There are no authentication providers defined.")+'</div>'
-                },
-                "columnDefs": [ {
-                    "targets": [0,1,2],
-                    "render": function (data, type, row, meta) {
-                        if ( type == 'display' ) {
-                            if ( data != null ) {
-                                return data.escapeHtml();
-                            }
-                            else {
-                                return "Default";
-                            }
-                        }
-                        return data;
-                    }
-                } ],
-                "columns": [
-                    {
-                        "data": "code",
-                        "searchable": true,
-                        "orderable": true
-                    },
-                    {
-                        "data": "description",
-                        "searchable": true,
-                        "orderable": true
-                    },
-                    {
-                        "data": "protocol",
-                        "searchable": true,
-                        "orderable": true
-                    },
-                    {
-                        "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>';
-                            return result;
-                        },
-                        "searchable": false,
-                        "orderable": false
-                    }
-                ],
-                createdRow: function (row, data, dataIndex) {
-                    if ( data.debug ) {
-                        $(row).addClass('debug');
-                    }
-                },
-            });
-
-            $('#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'));
-
-                $("#delete_confirm_dialog").html(
-                    _("You are about to delete the '%s' authentication provider.").format(auth_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").on( "click", function () {
-
-                var auth_provider_id   = $(this).data('auth-provider-id');
-                var auth_provider_code = $(this).data('auth-provider-code');
-
-                $.ajax({
-                    method: "DELETE",
-                    url: auth_providers_url+"/"+auth_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();
-                    });
-                }).fail(function () {
-                    $("#auth_provider_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(auth_provider_code)).show();
-                }).done(function () {
-                    $("#delete_confirm_modal").modal('hide');
-                });
-            });
-
-            $.validator.addMethod('json', function(value, element) {
-                if (this.optional(element)) return true;
-                try {
-                    JSON.parse(value)
-                } catch (error) {
-                    return false;
-                }
-                return true;
-            }, _('Not a valid JSON'));
-
-            $('#config, #mapping').each(function() {
-                $(this).rules('add', {
-                    required: true,
-                    json: true
-                });
-            });
-
-            var defaults = {
-                OIDC: {
-                    config: {
-                        key: "<enter client id>",
-                        secret: "<enter client secret>",
-                        well_known_url: "<enter openid configuration endpoint>",
-                        scope: "openid email"
-                    },
-                    mapping: {
-                        email: "email",
-                        given_name: "firstname",
-                           family_name: "surname"
-                    }
-                },
-                OAuth: {
-                    config: {
-                        key: "<enter client id>",
-                        secret: "<enter client secret>",
-                        authorize_url: "<enter authorization endpoint>",
-                        token_url: "<enter token endpoint>",
-                        userinfo_url: "<enter user info endpoint (optional)>",
-                        scope: "email"
-                    },
-                    mapping: {
-                        email: "email",
-                        given_name: "firstname",
-                           family_name: "surname"
-                    }
-                }
-            };
-
-            $('#protocol').on('change', function() {
-                var protocol = $(this).val();
-                $('#default-config').html(_('Add default %s configuration').format(protocol));
-                $('#default-mapping').html(_('Add default %s mapping').format(protocol));
-            });
-
-            $('button.defaults').on('click', function(event) {
-                event.preventDefault();
-                var target = $(this).data('defaultTarget');
-                if($('#'+target).html() !== '' && !confirm(_('Are you sure you want to replace current %s contents?').format(target))) {
-                    return;
-                }
-                var protocol = $('#protocol').val();
-                $('#'+target).html(JSON.stringify(defaults[protocol][target], null, 2));
-            })
-        });
-    </script>
-[% END %]
-
-[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_provider_domains.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_provider_domains.tt
new file mode 100644 (file)
index 0000000..7a7cd85
--- /dev/null
@@ -0,0 +1,476 @@
+[% USE raw %]
+[% USE Asset %]
+[% USE Branches %]
+[% USE Categories %]
+[% SET footerjs = 1 %]
+[% INCLUDE 'doc-head-open.inc' %]
+<title>
+    [% IF op == 'add_form' %]
+        New identity provider domain &rsaquo; [% ELSIF op == 'edit_form' %]
+        Edit identity provider domain &rsaquo; [% END %]
+
+    Identity providers &rsaquo; Administration &rsaquo; Koha
+</title>
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+
+<body id="admin_identity_provider_domains" class="admin">
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'prefs-admin-search.inc' %]
+
+<nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
+    <ol>
+        <li>
+            <a href="/cgi-bin/koha/mainpage.pl">Home</a>
+        </li>
+        <li>
+            <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
+        </li>
+
+        <li>
+            <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
+        </li>
+
+        [% IF op == 'add_form' %]
+            <li>
+                <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">
+                    New Domain
+                </a>
+            </li>
+
+        [% ELSIF op == 'edit_form' %]
+            <li>
+                <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">
+                    Edit Domain
+                </a>
+            </li>
+
+        [% ELSE %]
+            <li>
+                <a href="#" aria-current="page">
+                    Domains for [%- identity_provider_code | html -%]
+                </a>
+            </li>
+        [% END %]
+    </ol>
+</nav>
+
+<div class="main container-fluid">
+    <div class="row">
+        <div class="col-sm-10 col-sm-push-2">
+            <main>
+
+[% FOREACH m IN messages %]
+    <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 identity provider domain for editing. The passed id is invalid.</span>
+        [% CASE 'error_on_insert' %]
+            <span>An error occurred when adding a new identity provider domain.</span>
+        [% CASE 'success_on_update' %]
+            <span>Identity provider domain updated successfully.</span>
+        [% CASE 'success_on_insert' %]
+            <span>Identity provider domain added successfully.</span>
+        [% CASE %]
+            <span>[% m.code | html %]</span>
+        [% END %]
+    </div>
+[% END %]
+
+    <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 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="identity_provider_id" value="[%- identity_provider_id | html -%]" />
+        <fieldset class="rows">
+            <ol>
+                <li>
+                    <label for="domain">Domain: </label>
+                    <input type="text" name="domain" id="domain" size="60" />
+                </li>
+            </ol>
+        </fieldset>
+
+        <fieldset class="rows">
+            <ol>
+                <li>
+                    <label for="update_on_auth">Update on login: </label>
+                    <select name="update_on_auth" id="update_on_auth">
+                        <option value="1">Update</option>
+                        <option value="0" selected="selected">Don't update</option>
+                    </select>
+                    <span>user data on login</span>
+                </li>
+                <li>
+                    <label for="auto_register">Auto register: </label>
+                    <select name="auto_register" id="auto_register">
+                        <option value="1">Allow</option>
+                        <option value="0" selected="selected">Don't allow</option>
+                    </select>
+                    <span>users to auto register on login</span>
+                </li>
+                <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( unfiltered => 1, do_not_select_my_library => 1 ) %]
+                    </select>
+                </li>
+                <li>
+                    <label for="default_category_id">Default category: </label>
+                    [% SET categories = Categories.all() %]
+                    <select name="default_category_id" id="default_category_id">
+                        [% FOREACH category IN categories %]
+                            <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
+                        [% END %]
+                    </select>
+                </li>
+                <li>
+                    <label for="allow_opac">Allow opac: </label>
+                    <select name="allow_opac" id="allow_opac">
+                        <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 identity provider</span>
+                </li>
+                <li>
+                    <label for="allow_opac">Allow staff: </label>
+                    <select name="allow_staff" id="allow_staff">
+                        <option value="1" selected="selected">Allow</option>
+                        <option value="0">Don't allow</option>
+                    </select>
+                    <span>of this domain </span>
+                </li>
+            </ol>
+        </fieldset>
+        <fieldset class="action">
+            <input type="submit" value="Submit" />
+            <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 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="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="[%- identity_provider_domain.domain | html -%]"/>
+                </li>
+            </ol>
+        </fieldset>
+
+        <fieldset class="rows">
+            <ol>
+                <li>
+                    <label for="update_on_auth">Update on login: </label>
+                    <select name="update_on_auth" id="update_on_auth">
+                    [% IF identity_provider_domain.update_on_auth == "1" %]
+                        <option value="1" selected="selected">Update</option>
+                        <option value="0">Don't update</option>
+                    [% ELSE %]
+                        <option value="1">Update</option>
+                        <option value="0" selected="selected">Don't update</option>
+                    [% END %]
+                    </select>
+                    <span>user data on login</span>
+                </li>
+                <li>
+                    <label for="auto_register">Auto register: </label>
+                    <select name="auto_register" id="auto_register">
+                    [% IF identity_provider_domain.auto_register == "1" %]
+                        <option value="1" selected="selected">Allow</option>
+                        <option value="0">Don't allow</option>
+                    [% ELSE %]
+                        <option value="1">Allow</option>
+                        <option value="0" selected="selected">Don't allow</option>
+                    [% END %]
+                    </select>
+                    <span>users to auto register on login</span>
+                </li>
+                <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 => identity_provider_domain.default_library_id, unfiltered => 1, do_not_select_my_library => 1 ) %]
+                    </select>
+                </li>
+                <li>
+                    <label for="default_category_id">Default category: </label>
+                    [% SET categories = Categories.all() %]
+                    <select name="default_category_id" id="default_category_id">
+                        [% FOREACH category IN categories %]
+                            [% 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>
+                            [% END %]
+                        [% END %]
+                    </select>
+                </li>
+                <li>
+                    <label for="allow_opac">Allow opac: </label>
+                    <select name="allow_opac" id="allow_opac">
+                    [% IF identity_provider_domain.allow_opac == "1" %]
+                        <option value="1" selected="selected">Allow</option>
+                        <option value="0">Don't allow</option>
+                    [% ELSE %]
+                        <option value="1">Allow</option>
+                        <option value="0" selected="selected">Don't allow</option>
+                    [% END %]
+                    </select>
+                    <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 identity_provider_domain.allow_staff == "1" %]
+                        <option value="1" selected="selected">Allow</option>
+                        <option value="0">Don't allow</option>
+                    [% ELSE %]
+                        <option value="1">Allow</option>
+                        <option value="0" selected="selected">Don't allow</option>
+                    [% END %]
+                    </select>
+                    <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/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
+        </fieldset>
+    </form>
+[% END %]
+
+[% IF op == 'list' %]
+
+    <div id="toolbar" class="btn-toolbar">
+        <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>Identity provider domains</h1>
+
+    <table id="identity_provider_domains">
+        <thead>
+            <tr>
+                <th>Domain</th>
+                <th>Update on login</th>
+                <th>Auto register</th>
+                <th>Default library</th>
+                <th>Default category</th>
+                <th>Allow opac</th>
+                <th>Allow staff</th>
+                <th data-class-name="actions noExport">Actions</th>
+            </tr>
+        </thead>
+    </table>
+[% END %]
+
+            <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
+                <div class="modal-dialog">
+                    <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 identity provider domain</h3>
+                        </div>
+                        <div class="modal-body">
+                            <div id="delete_confirm_dialog"></div>
+                        </div>
+                        <div class="modal-footer">
+                            <a href="#" class="btn btn-default" id="delete_confirm_modal_button" role="button" data-toggle="modal">Delete</a>
+                            <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
+                        </div>
+                    </div> <!-- /.modal-content -->
+                </div> <!-- /.modal-dialog -->
+            </div> <!-- #delete_confirm_modal -->
+
+            </main>
+        </div> <!-- /.col-sm-10.col-sm-push-2 -->
+
+        <div class="col-sm-2 col-sm-pull-10">
+            <aside>
+                [% INCLUDE 'admin-menu.inc' %]
+            </aside>
+        </div> <!-- /.col-sm-2.col-sm-pull-10 -->
+     </div> <!-- /.row -->
+
+
+[% MACRO jsinclude BLOCK %]
+    [% Asset.js("js/admin-menu.js") | $raw %]
+    [% INCLUDE 'datatables.inc' %]
+    <script>
+        $(document).ready(function() {
+
+            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 %]
+                "[% category.categorycode | html %]": "[% category.description | html %]",
+            [% END %]
+            };
+            [% SET libraries = Branches.all() %]
+            var libraries = {
+            [% FOREACH library IN libraries %]
+                "[% library.branchcode | html %]": "[% library.branchname | html %]",
+            [% END %]
+            };
+            window.identity_provider_domains = $("#identity_provider_domains").kohaTable({
+                "ajax": {
+                    "url": identity_provider_domains_url
+                },
+                'language': {
+                    'emptyTable': '<div class="dialog message">'+_("There are no identity provider domains defined.")+'</div>'
+                },
+                "columnDefs": [ {
+                    "targets": [1],
+                    "render": function (data, type, row, meta) {
+                        if ( type == 'display' ) {
+                            if ( data != null ) {
+                                return data.escapeHtml();
+                            }
+                            else {
+                                return "";
+                            }
+                        }
+                        return data;
+                    }
+                } ],
+                "columns": [
+                    {
+                        "data": "domain",
+                        "searchable": true,
+                        "orderable": true,
+                        "render": function(data, type, row, meta) {
+                            if ( data != null ) {
+                                return data.escapeHtml();
+                            }
+                            else {
+                                return "*";
+                            }
+                        }
+                    },
+                    {
+                        "data": function( row, type, val, meta ) {
+                            if (row.update_on_auth) {
+                                return _("Yes");
+                            } else {
+                                return _("No");
+                            }
+                        },
+                        "searchable": true,
+                        "orderable": true
+                    },
+                    {
+                        "data": function( row, type, val, meta ) {
+                            if (row.auto_register) {
+                                return _("Yes");
+                            } else {
+                                return _("No");
+                            }
+                        },
+                        "searchable": true,
+                        "orderable": true
+                    },
+                    {
+                        "data": function( row, type, val, meta ) {
+                            return libraries[row.default_library_id] || "";
+                        },
+                        "searchable": true,
+                        "orderable": true
+                    },
+                    {
+                        "data": function( row, type, val, meta ) {
+                            return categories[row.default_category_id] || "";
+                        },
+                        "searchable": true,
+                        "orderable": true
+                    },
+                    {
+                        "data": function( row, type, val, meta ) {
+                            if (row.allow_opac) {
+                                return _("Yes");
+                            } else {
+                                return _("No");
+                            }
+                        },
+                        "searchable": true,
+                        "orderable": true
+                    },
+                    {
+                        "data": function( row, type, val, meta ) {
+                            if (row.allow_staff) {
+                                return _("Yes");
+                            } else {
+                                return _("No");
+                            }
+                        },
+                        "searchable": true,
+                        "orderable": true
+                    },
+                    {
+                        "data": function( row, type, val, meta ) {
+                            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,
+                        "orderable": false
+                    }
+                ],
+                createdRow: function (row, data, dataIndex) {
+                    if ( data.debug ) {
+                        $(row).addClass('debug');
+                    }
+                },
+            });
+
+            $('#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' identity provider domain.").format(identity_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 identity_provider_domain_id   = $(this).data('auth-provider-domain-id');
+                var identity_provider_domain = $(this).data('auth-provider-domain');
+
+                $.ajax({
+                    method: "DELETE",
+                    url: identity_provider_domains_url+"/"+identity_provider_domain_id
+                }).success(function() {
+                    window.identity_provider_domains.api().ajax.reload(function (data) {
+                        $("#smtp_action_result_dialog").hide();
+                        $("#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(identity_provider_domain)).show();
+                }).done(function () {
+                    $("#delete_confirm_modal").modal('hide');
+                });
+            });
+        });
+    </script>
+[% END %]
+
+[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_providers.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_providers.tt
new file mode 100644 (file)
index 0000000..260f3d9
--- /dev/null
@@ -0,0 +1,466 @@
+[% USE raw %]
+[% USE Asset %]
+[% SET footerjs = 1 %]
+[% INCLUDE 'doc-head-open.inc' %]
+<title>
+    [% IF op == 'add_form' %]
+        New identity provider &rsaquo; [% ELSIF op == 'edit_form' %]
+        Edit identity provider &rsaquo; [% END %]
+
+    Identity providers &rsaquo; Administration &rsaquo; Koha
+</title>
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+
+<body id="admin_identity_providers" class="admin">
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'prefs-admin-search.inc' %]
+
+<nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
+    <ol>
+        <li>
+            <a href="/cgi-bin/koha/mainpage.pl">Home</a>
+        </li>
+        <li>
+            <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
+        </li>
+
+        [% IF op == 'add_form' %]
+            <li>
+                <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
+            </li>
+            <li>
+                <a href="#" aria-current="page">
+                    New
+                </a>
+            </li>
+
+        [% ELSIF op == 'edit_form' %]
+            <li>
+                <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
+            </li>
+            <li>
+                <a href="#" aria-current="page">
+                    Edit
+                </a>
+            </li>
+
+        [% ELSE %]
+            <li>
+                <a href="#" aria-current="page">
+                    Identity providers
+                </a>
+            </li>
+        [% END %]
+    </ol>
+</nav>
+
+<div class="main container-fluid">
+    <div class="row">
+        <div class="col-sm-10 col-sm-push-2">
+            <main>
+
+[% FOREACH m IN messages %]
+    <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 identity provider for editing. The passed id is invalid.</span>
+        [% CASE 'error_on_insert' %]
+            <span>An error occurred when adding a new identity provider.</span>
+        [% CASE 'success_on_update' %]
+            <span>Identity provider updated successfully.</span>
+        [% CASE 'success_on_insert' %]
+            <span>Identity provider added successfully.</span>
+        [% CASE %]
+            <span>[% m.code | html %]</span>
+        [% END %]
+    </div>
+[% END %]
+
+    <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 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>
+                <li>
+                    <label for="code" class="required">Code: </label>
+                    <input type="text" name="code" id="code" size="60" class="required" required="required" />
+                    <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" />
+                    <span class="required">Required</span>
+                </li>
+                <li>
+                    <label for="protocol">Protocol: </label>
+                    <select name="protocol" id="protocol">
+                        <option value="OAuth">OAuth</option>
+                        <option value="OIDC">OIDC</option>
+                        <!-- Not implemented yet
+                        <option value="LDAP">LDAP</option>
+                        <option value="CAS">CAS</option>
+                        -->
+                    </select>
+                </li>
+            </ol>
+        </fieldset>
+
+        <fieldset class="rows">
+            <ol>
+                <li>
+                    <div>
+                        <label for="config" class="required json">Configuration: </label>
+                        <textarea name="config" id="config" class="required"></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 OAuth configuration</button>
+                    </div>
+                </li>
+                <li>
+                    <div>
+                        <label for="mapping" class="required json">Mapping: </label>
+                        <textarea name="mapping" id="mapping" class="required"></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 OAuth mapping</button>
+                    </div>
+                </li>
+                <li>
+                    <label for="matchpoint" class="required">Matchpoint: </label>
+                    <select name="matchpoint" id="matchpoint" class="required">
+                        <option value="email">Email</option>
+                        <option value="userid">User id</option>
+                        <option value="cardnumber">Card number</option>
+                    </select>
+                    <span class="required">Required</span>
+                </li>
+                <li>
+                    <label for="icon_url">Icon URL: </label>
+                    <input type="text" name="icon_url" id="icon_url" size="60" />
+                </li>
+            </ol>
+        </fieldset>
+        <fieldset class="action">
+            <input type="submit" value="Submit" />
+            <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
+        </fieldset>
+    </form>
+[% END %]
+
+[% IF op == 'edit_form' %]
+    <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="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="[%- 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="[%- identity_provider.description | html -%]"/>
+                    <span class="required">Required</span>
+                </li>
+                <li>
+                    <label for="protocol">Protocol: </label>
+                    <select name="protocol" id="protocol">
+                    [% IF identity_provider.protocol == 'OAuth' %]
+                        <option value="OAuth" selected="selected">OAuth</option>
+                        <option value="OIDC">OIDC</option>
+                        <!-- Not implemented yet
+                        <option value="LDAP">LDAP</option>
+                        <option value="CAS">CAS</option>
+                        -->
+                    [% ELSE %]
+                        <option value="OAuth">OAuth</option>
+                        <option value="OIDC" selected="selected">OIDC</option>
+                        <!-- Not implemented yet
+                        <option value="LDAP">LDAP</option>
+                        <option value="CAS">CAS</option>
+                        -->
+                    [% END %]
+                    </select>
+                </li>
+            </ol>
+        </fieldset>
+
+        <fieldset class="rows">
+            <ol>
+                <li>
+                    <div>
+                        <label for="config" class="required json">Configuration: </label>
+                        <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 [%- 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">[%- 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 [%- identity_provider.protocol | html -%] mapping</button>
+                    </div>
+                </li>
+                <li>
+                    <label for="matchpoint" class="required">matchpoint: </label>
+                    <select name="matchpoint" id="matchpoint" class="required">
+                        [%- IF identity_provider.matchpoint == 'email'      -%]
+                            <option value="email" selected="selected">Email</option>
+                        [%- ELSE -%]
+                            <option value="email">Email</option>
+                        [%- END -%]
+                        [%- IF identity_provider.matchpoint == 'userid'     -%]
+                            <option value="userid" selected="selected">User id</option>
+                        [%- ELSE -%]
+                            <option value="userid">User id</option>
+                        [%- END -%]
+                        [%- IF identity_provider.matchpoint == 'cardnumber' -%]
+                            <option value="cardnumber" selected="selected">Card number</option>
+                        [%- ELSE -%]
+                            <option value="cardnumber">Card number</option>
+                        [%- END -%]
+                    </select>
+                    <span class="required">Required</span>
+                </li>
+                <li>
+                    <label for="icon_url">Icon URL: </label>
+                    <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/identity_providers.pl">Cancel</a>
+        </fieldset>
+    </form>
+[% END %]
+
+[% IF op == 'list' %]
+
+    <div id="toolbar" class="btn-toolbar">
+        <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>Identity providers</h1>
+
+    <table id="identity_providers">
+        <thead>
+            <tr>
+                <th>Code</th>
+                <th>Description</th>
+                <th>Protocol</th>
+                <th data-class-name="actions noExport">Actions</th>
+            </tr>
+        </thead>
+    </table>
+[% END %]
+
+            <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
+                <div class="modal-dialog">
+                    <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 identity provider</h3>
+                        </div>
+                        <div class="modal-body">
+                            <div id="delete_confirm_dialog"></div>
+                        </div>
+                        <div class="modal-footer">
+                            <a href="#" class="btn btn-default" id="delete_confirm_modal_button" role="button" data-toggle="modal">Delete</a>
+                            <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
+                        </div>
+                    </div> <!-- /.modal-content -->
+                </div> <!-- /.modal-dialog -->
+            </div> <!-- #delete_confirm_modal -->
+
+            </main>
+        </div> <!-- /.col-sm-10.col-sm-push-2 -->
+
+        <div class="col-sm-2 col-sm-pull-10">
+            <aside>
+                [% INCLUDE 'admin-menu.inc' %]
+            </aside>
+        </div> <!-- /.col-sm-2.col-sm-pull-10 -->
+     </div> <!-- /.row -->
+
+
+[% MACRO jsinclude BLOCK %]
+    [% Asset.js("js/admin-menu.js") | $raw %]
+    [% INCLUDE 'datatables.inc' %]
+    <script>
+        $(document).ready(function() {
+
+            var identity_providers_url = '/api/v1/auth/identity_providers';
+            window.identity_providers = $("#identity_providers").kohaTable({
+                "ajax": {
+                    "url": identity_providers_url
+                },
+                'language': {
+                    'emptyTable': '<div class="dialog message">'+_("There are no identity providers defined.")+'</div>'
+                },
+                "columnDefs": [ {
+                    "targets": [0,1,2],
+                    "render": function (data, type, row, meta) {
+                        if ( type == 'display' ) {
+                            if ( data != null ) {
+                                return data.escapeHtml();
+                            }
+                            else {
+                                return "Default";
+                            }
+                        }
+                        return data;
+                    }
+                } ],
+                "columns": [
+                    {
+                        "data": "code",
+                        "searchable": true,
+                        "orderable": true
+                    },
+                    {
+                        "data": "description",
+                        "searchable": true,
+                        "orderable": true
+                    },
+                    {
+                        "data": "protocol",
+                        "searchable": true,
+                        "orderable": true
+                    },
+                    {
+                        "data": function( row, type, val, meta ) {
+                            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,
+                        "orderable": false
+                    }
+                ],
+                createdRow: function (row, data, dataIndex) {
+                    if ( data.debug ) {
+                        $(row).addClass('debug');
+                    }
+                },
+            });
+
+            $('#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' identity provider.").format(identity_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 identity_provider_id   = $(this).data('auth-provider-id');
+                var identity_provider_code = $(this).data('auth-provider-code');
+
+                $.ajax({
+                    method: "DELETE",
+                    url: identity_providers_url+"/"+identity_provider_id
+                }).success(function() {
+                    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 () {
+                    $("#identity_provider_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(identity_provider_code)).show();
+                }).done(function () {
+                    $("#delete_confirm_modal").modal('hide');
+                });
+            });
+
+            $.validator.addMethod('json', function(value, element) {
+                if (this.optional(element)) return true;
+                try {
+                    JSON.parse(value)
+                } catch (error) {
+                    return false;
+                }
+                return true;
+            }, _('Not a valid JSON'));
+
+            $('#config, #mapping').each(function() {
+                $(this).rules('add', {
+                    required: true,
+                    json: true
+                });
+            });
+
+            var defaults = {
+                OIDC: {
+                    config: {
+                        key: "<enter client id>",
+                        secret: "<enter client secret>",
+                        well_known_url: "<enter openid configuration endpoint>",
+                        scope: "openid email"
+                    },
+                    mapping: {
+                        email: "email",
+                        given_name: "firstname",
+                           family_name: "surname"
+                    }
+                },
+                OAuth: {
+                    config: {
+                        key: "<enter client id>",
+                        secret: "<enter client secret>",
+                        authorize_url: "<enter authorization endpoint>",
+                        token_url: "<enter token endpoint>",
+                        userinfo_url: "<enter user info endpoint (optional)>",
+                        scope: "email"
+                    },
+                    mapping: {
+                        email: "email",
+                        firstname: "given_name",
+                           surname: "family_name"
+                    }
+                }
+            };
+
+            $('#protocol').on('change', function() {
+                var protocol = $(this).val();
+                $('#default-config').html(_('Add default %s configuration').format(protocol));
+                $('#default-mapping').html(_('Add default %s mapping').format(protocol));
+            });
+
+            $('button.defaults').on('click', function(event) {
+                event.preventDefault();
+                var target = $(this).data('defaultTarget');
+                if($('#'+target).html() !== '' && !confirm(_('Are you sure you want to replace current %s contents?').format(target))) {
+                    return;
+                }
+                var protocol = $('#protocol').val();
+                $('#'+target).html(JSON.stringify(defaults[protocol][target], null, 2));
+            })
+        });
+    </script>
+[% END %]
+
+[% INCLUDE 'intranet-bottom.inc' %]
index 164ed90..2c9ee57 100644 (file)
@@ -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 %]
         [% 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" />
index f8c97c1..941805f 100644 (file)
                             [% 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 %]
                                 [% 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">
index c9be312..999e6aa 100644 (file)
 
                             [% 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 %]
                                 [% 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 ) %]
index fabd4e8..040ceb0 100644 (file)
                                             <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 %]
                                             [% 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" />
diff --git a/t/db_dependent/Koha/Auth/Client.t b/t/db_dependent/Koha/Auth/Client.t
new file mode 100644 (file)
index 0000000..1739951
--- /dev/null
@@ -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');
+};
\ No newline at end of file
diff --git a/t/db_dependent/Koha/Auth/Identity/Provider.t b/t/db_dependent/Koha/Auth/Identity/Provider.t
new file mode 100755 (executable)
index 0000000..afea2ae
--- /dev/null
@@ -0,0 +1,214 @@
+#!/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 => 6;
+
+use Test::MockModule;
+use Test::Exception;
+
+use JSON qw(encode_json);
+
+use Koha::Auth::Identity::Providers;
+
+use t::lib::TestBuilder;
+use t::lib::Mocks;
+
+my $schema  = Koha::Database->new->schema;
+my $builder = t::lib::TestBuilder->new;
+
+subtest 'domains() tests' => sub {
+
+    plan tests => 3;
+
+    $schema->storage->txn_begin;
+
+    my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers' } );
+    my $domains  = $provider->domains;
+
+    is( ref($domains),   'Koha::Auth::Identity::Provider::Domains', 'Type is correct' );
+    is( $domains->count, 0,                               'No domains defined' );
+
+    $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' );
+
+    $schema->storage->txn_rollback;
+};
+
+subtest 'get_config() tests' => sub {
+
+    plan tests => 2;
+
+    $schema->storage->txn_begin;
+
+    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';
+
+    my $config = { some => 'value', and => 'another' };
+    $provider->config( encode_json($config) )->store;
+
+    is_deeply( $provider->get_config, $config, 'Config correctly retrieved' );
+
+    $schema->storage->txn_rollback;
+};
+
+subtest 'set_config() tests' => sub {
+
+    plan tests => 3;
+
+    $schema->storage->txn_begin;
+
+    subtest 'OIDC protocol tests' => sub {
+
+        plan tests => 4;
+
+        my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { protocol => 'OIDC' } } );
+        $provider = $provider->upgrade_class;
+
+        my $config = {
+            key    => 'key',
+            secret => 'secret',
+        };
+
+        throws_ok { $provider->set_config($config) }
+        'Koha::Exceptions::MissingParameter', 'Exception thrown on missing parameter';
+
+        is( $@->parameter, 'well_known_url', 'Message is correct' );
+
+        $config->{well_known_url} = 'https://koha-community.org/auth';
+
+        my $return = $provider->set_config($config);
+        is( ref($return), 'Koha::Auth::Identity::Provider::OIDC', 'Return type is correct' );
+
+        is_deeply( $provider->get_config, $config, 'Configuration stored correctly' );
+    };
+
+    subtest 'OAuth protocol tests' => sub {
+
+        plan tests => 4;
+
+        my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { protocol => 'OAuth' } } );
+        $provider = $provider->upgrade_class;
+
+        my $config = {
+            key       => 'key',
+            secret    => 'secret',
+            token_url => 'https://koha-community.org/auth/token',
+        };
+
+        throws_ok { $provider->set_config($config) }
+        'Koha::Exceptions::MissingParameter', 'Exception thrown on missing parameter';
+
+        is( $@->parameter, 'authorize_url', 'Message is correct' );
+
+        $config->{authorize_url} = 'https://koha-community.org/auth/authorize';
+
+        my $return = $provider->set_config($config);
+        is( ref($return), 'Koha::Auth::Identity::Provider::OAuth', 'Return type is correct' );
+
+        is_deeply( $provider->get_config, $config, 'Configuration stored correctly' );
+    };
+
+    subtest 'Unsupported protocol tests' => sub {
+
+        plan tests => 2;
+
+        my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { protocol => 'CAS' } } );
+
+        throws_ok { $provider->set_config() }
+        'Koha::Exception', 'Exception thrown on unsupported protocol';
+
+        like( "$@", qr/This method needs to be subclassed/, 'Message is correct' );
+    };
+
+    $schema->storage->txn_rollback;
+};
+
+subtest 'get_mapping() tests' => sub {
+
+    plan tests => 2;
+
+    $schema->storage->txn_begin;
+
+    my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { config => '{' } } );
+
+    throws_ok { $provider->get_mapping() }
+    'Koha::Exceptions::Object::BadValue', 'Expected exception thrown on bad JSON';
+
+    my $mapping = { some => 'value', and => 'another' };
+    $provider->mapping( encode_json($mapping) )->store;
+
+    is_deeply( $provider->get_mapping, $mapping, 'Mapping correctly retrieved' );
+
+    $schema->storage->txn_rollback;
+};
+
+subtest 'set_mapping() tests' => sub {
+
+    plan tests => 1;
+
+    $schema->storage->txn_begin;
+
+    my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers' } );
+
+    my $mapping = { some => 'value', and => 'another' };
+    $provider->set_mapping($mapping)->store;
+
+    is_deeply( $provider->get_mapping, $mapping, 'Mapping correctly retrieved' );
+
+    $schema->storage->txn_rollback;
+};
+
+subtest 'upgrade_class() tests' => sub {
+
+    plan tests => 5;
+
+    $schema->storage->txn_begin;
+
+    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::Identity::Providers',
+                value => { protocol => $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::Identity::Provider->new({ protocol => 'Invalid' });
+    throws_ok
+      { $provider->upgrade }
+      'Koha::Exception',
+      'Exception throw on invalid protocol';
+
+    $schema->storage->txn_rollback;
+};
diff --git a/t/db_dependent/Koha/Auth/Provider.t b/t/db_dependent/Koha/Auth/Provider.t
deleted file mode 100755 (executable)
index 197740b..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/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 => 6;
-
-use Test::MockModule;
-use Test::Exception;
-
-use JSON qw(encode_json);
-
-use Koha::Auth::Providers;
-
-use t::lib::TestBuilder;
-use t::lib::Mocks;
-
-my $schema  = Koha::Database->new->schema;
-my $builder = t::lib::TestBuilder->new;
-
-subtest 'domains() tests' => sub {
-
-    plan tests => 3;
-
-    $schema->storage->txn_begin;
-
-    my $provider = $builder->build_object( { class => 'Koha::Auth::Providers' } );
-    my $domains  = $provider->domains;
-
-    is( ref($domains),   'Koha::Auth::Provider::Domains', 'Type is correct' );
-    is( $domains->count, 0,                               'No domains defined' );
-
-    $builder->build_object( { class => 'Koha::Auth::Provider::Domains', value => { auth_provider_id => $provider->id } } );
-    $builder->build_object( { class => 'Koha::Auth::Provider::Domains', value => { auth_provider_id => $provider->id } } );
-
-    is( $provider->domains->count, 2, 'The provider has 2 domains defined' );
-
-    $schema->storage->txn_rollback;
-};
-
-subtest 'get_config() tests' => sub {
-
-    plan tests => 2;
-
-    $schema->storage->txn_begin;
-
-    my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { config => '{' } } );
-
-    throws_ok { $provider->get_config() }
-    'Koha::Exceptions::Object::BadValue', 'Expected exception thrown on bad JSON';
-
-    my $config = { some => 'value', and => 'another' };
-    $provider->config( encode_json($config) )->store;
-
-    is_deeply( $provider->get_config, $config, 'Config correctly retrieved' );
-
-    $schema->storage->txn_rollback;
-};
-
-subtest 'set_config() tests' => sub {
-
-    plan tests => 3;
-
-    $schema->storage->txn_begin;
-
-    subtest 'OIDC protocol tests' => sub {
-
-        plan tests => 4;
-
-        my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { protocol => 'OIDC' } } );
-        $provider = $provider->upgrade_class;
-
-        my $config = {
-            key    => 'key',
-            secret => 'secret',
-        };
-
-        throws_ok { $provider->set_config($config) }
-        'Koha::Exceptions::MissingParameter', 'Exception thrown on missing parameter';
-
-        is( $@->parameter, 'well_known_url', 'Message is correct' );
-
-        $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_deeply( $provider->get_config, $config, 'Configuration stored correctly' );
-    };
-
-    subtest 'OAuth protocol tests' => sub {
-
-        plan tests => 4;
-
-        my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { protocol => 'OAuth' } } );
-        $provider = $provider->upgrade_class;
-
-        my $config = {
-            key       => 'key',
-            secret    => 'secret',
-            token_url => 'https://koha-community.org/auth/token',
-        };
-
-        throws_ok { $provider->set_config($config) }
-        'Koha::Exceptions::MissingParameter', 'Exception thrown on missing parameter';
-
-        is( $@->parameter, 'authorize_url', 'Message is correct' );
-
-        $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_deeply( $provider->get_config, $config, 'Configuration stored correctly' );
-    };
-
-    subtest 'Unsupported protocol tests' => sub {
-
-        plan tests => 2;
-
-        my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { protocol => 'CAS' } } );
-
-        throws_ok { $provider->set_config() }
-        'Koha::Exception', 'Exception thrown on unsupported protocol';
-
-        like( "$@", qr/This method needs to be subclassed/, 'Message is correct' );
-    };
-
-    $schema->storage->txn_rollback;
-};
-
-subtest 'get_mapping() tests' => sub {
-
-    plan tests => 2;
-
-    $schema->storage->txn_begin;
-
-    my $provider = $builder->build_object( { class => 'Koha::Auth::Providers', value => { config => '{' } } );
-
-    throws_ok { $provider->get_mapping() }
-    'Koha::Exceptions::Object::BadValue', 'Expected exception thrown on bad JSON';
-
-    my $mapping = { some => 'value', and => 'another' };
-    $provider->mapping( encode_json($mapping) )->store;
-
-    is_deeply( $provider->get_mapping, $mapping, 'Mapping correctly retrieved' );
-
-    $schema->storage->txn_rollback;
-};
-
-subtest 'set_mapping() tests' => sub {
-
-    plan tests => 1;
-
-    $schema->storage->txn_begin;
-
-    my $provider = $builder->build_object( { class => 'Koha::Auth::Providers' } );
-
-    my $mapping = { some => 'value', and => 'another' };
-    $provider->set_mapping($mapping)->store;
-
-    is_deeply( $provider->get_mapping, $mapping, 'Mapping correctly retrieved' );
-
-    $schema->storage->txn_rollback;
-};
-
-subtest 'upgrade_class() tests' => sub {
-
-    plan tests => 5;
-
-    $schema->storage->txn_begin;
-
-    my $mapping   = Koha::Auth::Provider::protocol_to_class_mapping;
-    my @protocols = keys %{ $mapping };
-
-    foreach my $protocol (@protocols) {
-
-        my $provider = $builder->build_object(
-            {
-                class => 'Koha::Auth::Providers',
-                value => { protocol => $protocol },
-            }
-        );
-
-        is( ref($provider), 'Koha::Auth::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' });
-    throws_ok
-      { $provider->upgrade }
-      'Koha::Exception',
-      'Exception throw on invalid protocol';
-
-    $schema->storage->txn_rollback;
-};
diff --git a/t/db_dependent/Koha/REST/Plugin/Auth/IdP.t b/t/db_dependent/Koha/REST/Plugin/Auth/IdP.t
new file mode 100644 (file)
index 0000000..0e624bf
--- /dev/null
@@ -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;
\ No newline at end of file
diff --git a/t/db_dependent/api/v1/idp.t b/t/db_dependent/api/v1/idp.t
new file mode 100644 (file)
index 0000000..cf7a310
--- /dev/null
@@ -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;
\ No newline at end of file
diff --git a/t/lib/IdP/ExternalIdP.pm b/t/lib/IdP/ExternalIdP.pm
new file mode 100644 (file)
index 0000000..21bd3a9
--- /dev/null
@@ -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;
\ No newline at end of file