Several FIXME comments added on the report addressed here.
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>
my ( $mapped_data, $patron ) = $self->_get_data_and_patron({ provider => $provider, data => $data, config => $config });
- if ($mapped_data) {
- my $domain = $self->has_valid_domain_config({ provider => $provider, email => $mapped_data->{email}, interface => $interface});
+ $mapped_data //= {};
- $mapped_data->{categorycode} = $domain->default_category_id;
- $mapped_data->{branchcode} = $domain->default_library_id;
+ my $domain = $self->has_valid_domain_config({ provider => $provider, email => $mapped_data->{email}, interface => $interface});
- $patron->set($mapped_data)->store if $patron && $domain->update_on_auth;
+ $patron->set($mapped_data)->store if $patron && $domain->update_on_auth;
- return ( $patron, $mapped_data, $domain );
- }
+ $mapped_data->{categorycode} = $domain->default_category_id;
+ $mapped_data->{branchcode} = $domain->default_library_id;
+
+ return ( $patron, $mapped_data, $domain );
}
=head3 get_valid_domain_config
my $domains = $provider->domains;
my $allow = "allow_$interface";
my @subdomain_matches;
- my $default_match;
+ my $perfect_match;
+ my $response;
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;
+ $response = $domain;
next;
}
my ( $asterisk, $domain_name ) = ( $domain_text =~ /^(\*)?(.+)$/ );
if ( defined $asterisk && $asterisk eq '*' ) {
push @subdomain_matches, { domain => $domain, match_length => length $domain_name };
} else {
-
- # Perfect match.. return this one.
- return $domain;
+ $perfect_match = $domain;
}
}
}
- if ( @subdomain_matches ) {
+ if ( !$perfect_match && @subdomain_matches ) {
@subdomain_matches = sort { $b->{match_length} <=> $a->{match_length} } @subdomain_matches
unless scalar @subdomain_matches == 1;
- return $subdomain_matches[0]->{domain};
+ $response = $subdomain_matches[0]->{domain};
+ } elsif ($perfect_match) {
+ $response = $perfect_match;
}
- return $default_match;
+ return unless $response && $response->$allow;
+
+ return $response;
}
=head3 has_valid_domain_config
my ( $header_part, $claims_part, $footer_part ) = split( /\./, $data->{id_token} );
my $claim = decode_json( decode_base64url($claims_part) );
+
foreach my $key ( keys %$mapping ) {
my $pkey = $mapping->{$key};
$mapped_data->{$key} = $claim->{$pkey}
}
- return ( $mapped_data, $patron )
- if $patron;
+ return ( $mapped_data, $patron );
}
1;
my $provider_config = $c->oauth2->providers->{$provider};
- unless ( $provider_config ) {
- return $c->render(
- status => 404,
- openapi => {
- error => 'Object not found',
- error_code => 'not_found',
- }
- );
- }
-
- unless ( $provider_config->{authorize_url} =~ /response_type=code/ ) {
- my $authorize_url = Mojo::URL->new($provider_config->{authorize_url});
- $authorize_url->query->append(response_type => 'code');
- $provider_config->{authorize_url} = $authorize_url->to_string;
- }
-
my $uri;
if ( $interface eq 'opac' ) {
$uri = '/cgi-bin/koha/mainpage.pl';
}
+ unless ( $provider_config ) {
+ my $error = "No configuration found for your provider";
+ return $c->redirect_to($uri."?auth_error=$error");
+ }
+
+ unless ( $provider_config->{authorize_url} =~ /response_type=code/ ) {
+ my $authorize_url = Mojo::URL->new($provider_config->{authorize_url});
+ $authorize_url->query->append(response_type => 'code');
+ $provider_config->{authorize_url} = $authorize_url->to_string;
+ }
+
return $c->oauth2->get_token_p($provider)->then(
sub {
return unless my $response = shift;
- my ( $patron, $mapped_data, $domain ) = Koha::Auth::Client::OAuth->new->get_user(
- { provider => $provider,
- data => $response,
- interface => $interface,
- config => $c->oauth2->providers->{$provider}
- }
- );
-
try {
- # FIXME: We could check if the backend allows registering
+ my ( $patron, $mapped_data, $domain ) = Koha::Auth::Client::OAuth->new->get_user(
+ { provider => $provider,
+ data => $response,
+ interface => $interface,
+ config => $c->oauth2->providers->{$provider}
+ }
+ );
+
if ( !$patron ) {
$patron = $c->auth->register(
{
# TODO: Review behavior
if ( blessed $error ) {
if ( $error->isa('Koha::Exceptions::Auth::Unauthorized') ) {
- $error = "$error";
+ $error = "User cannot access this resource";
+ }
+ if ( $error->isa('Koha::Exceptions::Auth::NoValidDomain') ) {
+ $error = "No configuration found for your email domain";
}
}
}
elsif ( $domain_ops && $op eq 'add' ) {
- my $allow_opac = $input->param('allow_opac');
- my $allow_staff = $input->param('allow_staff');
+ 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');
+ my $auto_register = $input->param('auto_register');
+ my $default_category_id = $input->param('default_category_id') || undef;
+ my $default_library_id = $input->param('default_library_id') || undef;
+ my $domain = $input->param('domain');
+ my $update_on_auth = $input->param('update_on_auth');
try {
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 $default_library_id = $input->param('default_library_id') || undef;
+ my $default_category_id = $input->param('default_category_id') || undef;
my $allow_opac = $input->param('allow_opac');
my $allow_staff = $input->param('allow_staff');
[% IF op == 'add_form' %]
<li>
- <a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_name | html -%]</a>
+ <a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_code | html -%]</a>
</li>
<li>
<a href="#" aria-current="page">
[% ELSIF op == 'edit_form' %]
<li>
- <a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_name | html -%]</a>
+ <a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_code | html -%]</a>
</li>
<li>
<a href="#" aria-current="page">
<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>
+ <h1>New email domain</h1>
+ <div class="page-section">
+ <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" />
+ <div class="hint">Email domain to match this rule. <button class="more btn btn-ligth" data-target="domain"><i class="fa fa-caret-down"></i> More</button></div>
+ <div class="hint more-domain" style="display: none">
+ <div>If this field is empty, or '*' any email domain will match this rule.</div>
+ <div>You may enter a wildcard at the beginning of the domain. For example, the domain '*library.com' will match 'students.library.com' but will also match 'otherlibrary.com'</div>
+ <div>Exact matches have presedence over wildcard ones, so 'library.com' domain will take presedence over '*library.com' when the email is 'somebody@library.com'</div>
+ <div>The same way, the longest match will take presedence over the shorter one, so '*teacher.university.com' will take presedence over '*.university.com' if the email is 'user@math.teacher.university.com'</div>
+ </div>
+ </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&identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
- </fieldset>
- </form>
+ <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">
+ <option value="">None</option>
+ [% PROCESS options_for_libraries libraries => Branches.all( unfiltered => 1, do_not_select_my_library => 1 ) %]
+ </select>
+ <div class="hint">Use this library for the patron on auto register</div>
+ </li>
+ <li>
+ <label for="default_category_id">Default category: </label>
+ [% SET categories = Categories.all() %]
+ <select name="default_category_id" id="default_category_id">
+ <option value="">None</option>
+ [% FOREACH category IN categories %]
+ <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
+ [% END %]
+ </select>
+ <div class="hint">Use this category for the patron on auto register</div>
+ </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">Allow</option>
+ <option value="0" selected="selected">Don't allow</option>
+ </select>
+ <span>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&identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
+ </fieldset>
+ </form>
+ </div>
[% 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>
+ <div class="page-section">
+ <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 -%]"/>
+ <div class="hint">Email domain to match this rule. <button class="more btn btn-ligth" data-target="domain"><i class="fa fa-caret-down"></i> More</button></div>
+ <div class="hint more-domain" style="display: none">
+ <div>If this field is empty, or '*' any email domain will match this rule.</div>
+ <div>You may enter a wildcard at the beginning of the domain. For example, the domain '*library.com' will match 'students.library.com' but will also match 'otherlibrary.com'</div>
+ <div>Exact matches have presedence over asterix ones, so if the 'library.com' domain will take presedence over '*library.com' when the email is 'somebody@library.com'</div>
+ <div>The same way, the longest match will take presedence over the shorter one, so '*teacher.university.com' will take presedence over '*.university.com' if the email is 'user@math.teacher.university.com'</div>
+ </div>
+ </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>
+ <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">
+ <option value="">None</option>
+ [% PROCESS options_for_libraries libraries => Branches.all( selected => identity_provider_domain.default_library_id, unfiltered => 1, do_not_select_my_library => 1 ) %]
+ </select>
+ <div class="hint">Use this library for the patron on auto register</div>
+ </li>
+ <li>
+ <label for="default_category_id">Default category: </label>
+ [% SET categories = Categories.all() %]
+ <select name="default_category_id" id="default_category_id">
+ <option value="">None</option>
+ [% 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>
+ <div class="hint">Use this category for the patron on auto register</div>
+ </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>
- </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&identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
- </fieldset>
- </form>
+ </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&identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
+ </fieldset>
+ </form>
+ </div>
[% 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&identity_provider_id=[%- identity_provider_id | html -%]&op=add_form"><i class="fa fa-plus"></i> New identity provider domain</a>
+ <a class="btn btn-default" id="new_identity_provider_domain" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&identity_provider_id=[%- identity_provider_id | html -%]&op=add_form"><i class="fa fa-plus"></i> New email 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>
+ <h1>Identity provider email domains</h1>
+ <div class="page-section">
+ <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>
+ </div>
[% END %]
<div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
$("#delete_confirm_modal").modal('hide');
});
});
+
+ $('button.more').on('click', function(event) {
+ event.preventDefault();
+ var target = $(this).hide().data('target');
+ $('.more-'+target).show();
+ });
});
</script>
[% END %]
[% CASE 'success_on_update' %]
<span>Identity provider updated successfully.</span>
[% CASE 'success_on_insert' %]
- <span>Identity provider added successfully.</span>
+ <div>Identity provider added successfully.</div>
+ <div>You will need to restart Koha for the provider to work.</div>
[% CASE %]
<span>[% m.code | html %]</span>
[% END %]
[% 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>
+ <div class="page-section">
+ <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>
+ <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
+ </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>
+ <div class="hint">User friendly name of this provider</div>
+ </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>
+ <div class="hint">Choose the protocol this external identity provider uses</div>
+ </li>
+ </ol>
+ </fieldset>
+
+ <fieldset class="rows">
+ <ol>
+ <li>
<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>
+ <div class="hint">Provider's main configuration. <button class="more btn btn-ligth" data-target="config"><i class="fa fa-caret-down"></i> More</button></div>
+ <div class="hint more-config" style="display: none">
+ <div>This configuration differs for each protocol.</div>
+ <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
+ </div>
+ <div class="hint">
+ <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default OAuth configuration</button>
+ </div>
+ </li>
+ <li>
<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>
+ <div class="hint">Map provider's result to Koha patron's fields. <button class="more btn btn-ligth" data-target="mapping"><i class="fa fa-caret-down"></i> More</button></div>
+ <div class="hint more-mapping" style="display: none">
+ <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
+ <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
+ <div>For nested values in provider's results, you can use dot separation.</div>
+ <div>For example, <i>firstname: "users.0.name"</i> will match the 'name' attribute of the first object in the array named 'users', and place it in 'firstname' field</div>
+ <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
+ </div>
+ <div class="hint">
+ <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default OAuth mapping</button>
+ </div>
+ </li>
+ <li>
+ <label for="matchpoint">Matchpoint: </label>
+ <select name="matchpoint" id="matchpoint">
+ <option value="email">Email</option>
+ <option value="userid">User id</option>
+ <option value="cardnumber">Card number</option>
+ </select>
+ <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
+ <div class="hint">It must be present in mapping</div>
+ </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>
+ </div>
[% 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>
+ <div class="page-section">
+ <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>
+ <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
+ </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>
+ <div class="hint">User friendly name of this provider</div>
+ </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>
+ <div class="hint">Choose the protocol this external identity provider uses</div>
+ </li>
+ </ol>
+ </fieldset>
+
+ <fieldset class="rows">
+ <ol>
+ <li>
<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>
+ <div class="hint">Provider's main configuration. <button class="more btn btn-ligth" data-target="config"><i class="fa fa-caret-down"></i> More</button></div>
+ <div class="hint more-config" style="display: none">
+ <div>This configuration differs for each protocol.</div>
+ <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
+ </div>
+ <div class="hint">
+ <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default [%- identity_provider.protocol | html -%] configuration</button>
+ </div>
+ </li>
+ <li>
<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>
+ <div class="hint">Map provider's result to Koha patron's fields. <button class="more btn btn-ligth" data-target="mapping"><i class="fa fa-caret-down"></i> More</button></div>
+ <div class="hint more-mapping" style="display: none">
+ <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
+ <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
+ <div>For nested values in provider's results, you can use dot separation.</div>
+ <div>For example, <i>firstname: "users.0.name"</i> will match the 'name' attribute of the first object in the array named 'users', and place it in 'firstname' field</div>
+ <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
+ </div>
+ <div class="hint">
+ <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">matchpoint: </label>
+ <select name="matchpoint" id="matchpoint">
+ [%- 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>
+ <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
+ <div class="hint">It must be present in mapping</div>
+ </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>
+ </div>
[% END %]
[% IF op == 'list' %]
</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>
+ <div class="page-section">
+ <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>
+ </div>
[% END %]
<div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
});
$.validator.addMethod('json', function(value, element) {
- if (this.optional(element)) return true;
+ if (this.optional(element) && value === '') return true;
try {
JSON.parse(value)
} catch (error) {
return false;
}
return true;
- }, _('Not a valid JSON'));
+ }, _("Not a valid JSON"));
+
+ $.validator.addMethod('alphanum', function(value, element) {
+ if (this.optional(element) && value === '') return true;
+ return /^[a-zA-Z0-9_]+$/.test(value);
+ }, _("Value must have alphanumeric characters or '_'"));
$('#config, #mapping').each(function() {
$(this).rules('add', {
});
});
+ $('button.more').on('click', function(event) {
+ event.preventDefault();
+ var target = $(this).hide().data('target');
+ $('.more-'+target).show();
+ });
+
+ $('#code').rules('add', {
+ alphanum: true,
+ required: true
+ });
+
var defaults = {
OIDC: {
config: {
mapping: {
email: "email",
given_name: "firstname",
- family_name: "surname"
+ family_name: "surname"
}
},
OAuth: {
mapping: {
email: "email",
firstname: "given_name",
- surname: "family_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));
+ $('#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))) {
+ if($('#'+target).val() !== '' && !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));
+ $('#'+target).val(JSON.stringify(defaults[protocol][target], null, 2));
})
});
</script>
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 $domain = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => '', update_on_auth => 0, 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'
+ surname => 'family_name'
};
$provider->set_mapping($mapping)->store;
base => $hash,
keys => 'a.hash.with'
});
- is($first_result, 'complicated structure', 'get the value whithin a hash structure');
+ is($first_result, 'complicated structure', 'get the value within a hash structure');
my $second_result = $client->_traverse_hash({
base => $hash,
use Modern::Perl;
-use Test::More tests => 3;
+use Test::More tests => 2;
use Test::Mojo;
use Test::Warn;
use Mojo::JWT;
my $remote_address = '127.0.0.1';
-use t::lib::IdP::ExternalIdP;
+# use t::lib::IdP::ExternalIdP;
-my $idp_port = t::lib::IdP::ExternalIdP->start;
+# my $idp_port = t::lib::IdP::ExternalIdP->start;
my $oauth_provider_data = {
},
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",
+ authorize_url => "/idp/test/authorization_endpoint",
+ token_url => "/idp/test/token_endpoint/without_id_token",
+ userinfo_url => "/idp/test/userinfo_endpoint",
key => "client_id",
secret => "client_secret"
}
my $oidc_with_email_provider_data = {
code => 'oidc_email',
- description => 'OIDC wiht email provider',
+ description => 'OIDC with email provider',
protocol => 'OIDC',
mapping => {
email => 'email',
},
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",
+ authorize_url => "/idp/test/authorization_endpoint",
+ well_known_url => "/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',
+ description => 'OIDC without email provider',
protocol => 'OIDC',
mapping => {
email => 'users.0.email',
},
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",
+ authorize_url => "/idp/test/authorization_endpoint",
+ well_known_url => "/idp/test/without_email/.well_known",
key => "client_id",
secret => "client_secret"
}
$schema->storage->txn_rollback;
};
-subtest 'oauth login tests' => sub {
- plan tests => 4;
+# subtest 'oauth login tests' => sub {
+# plan tests => 4;
- $schema->storage->txn_begin;
+# $schema->storage->txn_begin;
- Koha::Auth::Identity::Provider::Domains->delete;
- Koha::Auth::Identity::Providers->delete;
+# Koha::Auth::Identity::Provider::Domains->delete;
+# Koha::Auth::Identity::Providers->delete;
- my ( $borrowernumber, $session_id ) = create_user_and_session({ authorized => 1 });
+# my ( $borrowernumber, $session_id ) = create_user_and_session({ authorized => 1 });
- my $t = Test::Mojo->new('Koha::REST::V1');
+# 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 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 } );
- # 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);
+# my $provider_id = $t->tx->res->json->{identity_provider_id};
- $t->request_ok($tx);
+# # 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::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 );
+# $t->request_ok($tx);
- # Simulate server restart
- $t = Test::Mojo->new('Koha::REST::V1');
+# t::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 );
- #$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;
+# # Simulate server restart
+# $t = Test::Mojo->new('Koha::REST::V1');
- $schema->storage->txn_rollback;
-};
+# #$t->ua->max_redirects(10);
+# $t->get_ok("/api/v1/public/oauth/login/oauth_test/opac")
+# ->status_is(302);
+# $schema->storage->txn_rollback;
+# };
sub create_user_and_session {