6 [% INCLUDE 'doc-head-open.inc' %]
8 [% IF op == 'add_form' %]
9 New identity provider › [% ELSIF op == 'edit_form' %]
10 Edit identity provider › [% END %]
12 Identity providers › Administration › Koha
14 [% INCLUDE 'doc-head-close.inc' %]
17 <body id="admin_identity_providers" class="admin">
18 [% INCLUDE 'header.inc' %]
19 [% INCLUDE 'prefs-admin-search.inc' %]
21 <nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
24 <a href="/cgi-bin/koha/mainpage.pl">Home</a>
27 <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
30 [% IF op == 'add_form' %]
32 <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
35 <a href="#" aria-current="page">
40 [% ELSIF op == 'edit_form' %]
42 <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
45 <a href="#" aria-current="page">
52 <a href="#" aria-current="page">
60 <div class="main container-fluid">
62 <div class="col-sm-10 col-sm-push-2">
65 [% FOREACH m IN messages %]
66 <div class="dialog [% m.type | html %]" id="identity_provider_action_result_dialog">
68 [% CASE 'error_on_update' %]
69 <span>An error occurred trying to open the identity provider for editing. The passed id is invalid.</span>
70 [% CASE 'error_on_insert' %]
71 <span>An error occurred when adding a new identity provider.</span>
72 [% CASE 'success_on_update' %]
73 <span>Identity provider updated successfully.</span>
74 [% CASE 'success_on_insert' %]
75 <div>Identity provider added successfully.</div>
76 <div>You will need to restart Koha for the provider to work.</div>
78 <span>[% m.code | html %]</span>
83 <div class="dialog message" id="identity_provider_delete_success" style="display: none;"></div>
84 <div class="dialog alert" id="identity_provider_delete_error" style="display: none;"></div>
86 [% IF op == 'add_form' %]
87 <h1>New identity provider</h1>
88 <div class="page-section">
89 <form action="/cgi-bin/koha/admin/identity_providers.pl" id="add" name="add" class="validated" method="post">
90 <input type="hidden" name="op" value="add" />
91 <fieldset class="rows">
92 <legend id="identity_provider_basic">Basic configuration</legend>
95 <label for="code" class="required">Code: </label>
96 <input type="text" name="code" id="code" size="60" class="required" required="required" />
97 <span class="required">Required</span>
98 <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
101 <label for="description" class="required">Description: </label>
102 <input type="text" name="description" id="description" size="60" class="required" required="required" />
103 <span class="required">Required</span>
104 <div class="hint">User friendly name of this provider</div>
107 <label for="protocol">Protocol: </label>
108 <select name="protocol" id="protocol">
109 <option value="OAuth">OAuth</option>
110 <option value="OIDC">OIDC</option>
111 <!-- Not implemented yet
112 <option value="LDAP">LDAP</option>
113 <option value="CAS">CAS</option>
116 <div class="hint">Choose the protocol this external identity provider uses</div>
121 <fieldset class="rows">
122 <legend id="identity_provider_advanced">Advanced configuration</legend>
125 <label for="config" class="required json">Configuration: </label>
126 <textarea name="config" id="config" class="required" cols="75" rows="10"></textarea>
127 <span class="required">Required</span>
128 <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>
129 <div class="hint more-config" style="display: none">
130 <div>This configuration differs for each protocol.</div>
131 <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
134 <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default OAuth configuration</button>
138 <label for="mapping" class="required json">Mapping: </label>
139 <textarea name="mapping" id="mapping" class="required" cols="75" rows="10"></textarea>
140 <span class="required">Required</span>
141 <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>
142 <div class="hint more-mapping" style="display: none">
143 <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
144 <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
145 <div>For nested values in provider's results, you can use dot separation.</div>
146 <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>
147 <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
150 <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default OAuth mapping</button>
154 <label for="matchpoint">Matchpoint: </label>
155 <select name="matchpoint" id="matchpoint">
156 <option value="email">Email</option>
157 <option value="userid">User id</option>
158 <option value="cardnumber">Card number</option>
160 <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
161 <div class="hint">It must be present in mapping</div>
164 <label for="icon_url">Icon URL: </label>
165 <input type="text" name="icon_url" id="icon_url" size="60" />
170 <fieldset class="rows">
171 <legend id="identity_provider_domain">Domain configuration</legend>
174 <label for="domain" class="required">Domain: </label>
175 <input type="text" name="domain" id="domain" class="required" size="60" />
176 <span class="required">Required</span>
177 <div class="hint">Use * for any domain. You can add new domains later on the dedicated admin page.</div>
180 <label for="default_library_id">Default library: </label>
181 <select id="default_library_id" name="default_library_id" class="mandatory">
182 [% PROCESS options_for_libraries libraries => Branches.all( unfiltered => 1, do_not_select_my_library => 1 ) %]
184 <span class="required">Required</span>
185 <div class="hint">Use this library for the patron on auto register</div>
188 <label for="default_category_id">Default category: </label>
189 [% SET categories = Categories.all() %]
190 <select name="default_category_id" id="default_category_id" class="mandatory">
191 [% FOREACH category IN categories %]
192 <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
195 <span class="required">Required</span>
196 <div class="hint">Use this category for the patron on auto register</div>
199 <label for="allow_opac">Allow OPAC: </label>
200 <select name="allow_opac" id="allow_opac">
201 <option value="1">Yes</option>
202 <option value="0" selected="selected">No</option>
204 <div class="hint">Allow OPAC access to users from this domain to login with this identity provider.</div>
207 <label for="allow_opac">Allow staff: </label>
208 <select name="allow_staff" id="allow_staff">
209 <option value="1">Yes</option>
210 <option value="0" selected="selected">No</option>
212 <div class="hint">Allow staff access to users from this domain to login with this identity provider.</div>
215 <label for="auto_register">Auto register: </label>
216 <select name="auto_register" id="auto_register">
217 <option value="1">Yes</option>
218 <option value="0" selected="selected">No</option>
220 <div class="hint">Allow users to auto register on login.</div>
223 <label for="update_on_auth">Update on login: </label>
224 <select name="update_on_auth" id="update_on_auth">
225 <option value="1">Yes</option>
226 <option value="0" selected="selected">No</option>
228 <div class="hint">Update user data on login.</div>
232 <fieldset class="action">
233 <input type="submit" value="Submit" />
234 <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
240 [% IF op == 'edit_form' %]
241 <h1>Edit identity provider</h1>
242 <div class="page-section">
243 <form action="/cgi-bin/koha/admin/identity_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
244 <input type="hidden" name="op" value="edit_save" />
245 <input type="hidden" name="identity_provider_id" value="[%- identity_provider.identity_provider_id | html -%]" />
246 <fieldset class="rows">
249 <label for="code" class="required">Code: </label>
250 <input type="text" name="code" id="code" size="60" class="required" required="required" value="[%- identity_provider.code | html -%]"/>
251 <span class="required">Required</span>
252 <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
255 <label for="description" class="required">Description: </label>
256 <input type="text" name="description" id="description" size="60" class="required" required="required" value="[%- identity_provider.description | html -%]"/>
257 <span class="required">Required</span>
258 <div class="hint">User friendly name of this provider</div>
261 <label for="protocol">Protocol: </label>
262 <select name="protocol" id="protocol">
263 [% IF identity_provider.protocol == 'OAuth' %]
264 <option value="OAuth" selected="selected">OAuth</option>
265 <option value="OIDC">OIDC</option>
266 <!-- Not implemented yet
267 <option value="LDAP">LDAP</option>
268 <option value="CAS">CAS</option>
271 <option value="OAuth">OAuth</option>
272 <option value="OIDC" selected="selected">OIDC</option>
273 <!-- Not implemented yet
274 <option value="LDAP">LDAP</option>
275 <option value="CAS">CAS</option>
279 <div class="hint">Choose the protocol this external identity provider uses</div>
284 <fieldset class="rows">
287 <label for="config" class="required json">Configuration: </label>
288 <textarea name="config" id="config" class="required">[%- identity_provider.config | html -%]</textarea>
289 <span class="required">Required</span>
290 <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>
291 <div class="hint more-config" style="display: none">
292 <div>This configuration differs for each protocol.</div>
293 <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
296 <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default [%- identity_provider.protocol | html -%] configuration</button>
300 <label for="mapping" class="required json">Mapping: </label>
301 <textarea name="mapping" id="mapping" class="required">[%- identity_provider.mapping | html -%]</textarea>
302 <span class="required">Required</span>
303 <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>
304 <div class="hint more-mapping" style="display: none">
305 <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
306 <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
307 <div>For nested values in provider's results, you can use dot separation.</div>
308 <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>
309 <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
312 <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default [%- identity_provider.protocol | html -%] mapping</button>
316 <label for="matchpoint">matchpoint: </label>
317 <select name="matchpoint" id="matchpoint">
318 [%- IF identity_provider.matchpoint == 'email' -%]
319 <option value="email" selected="selected">Email</option>
321 <option value="email">Email</option>
323 [%- IF identity_provider.matchpoint == 'userid' -%]
324 <option value="userid" selected="selected">User id</option>
326 <option value="userid">User id</option>
328 [%- IF identity_provider.matchpoint == 'cardnumber' -%]
329 <option value="cardnumber" selected="selected">Card number</option>
331 <option value="cardnumber">Card number</option>
334 <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
335 <div class="hint">It must be present in mapping</div>
338 <label for="icon_url">Icon URL: </label>
339 <input type="text" name="icon_url" id="icon_url" size="60" value="[%- identity_provider.icon_url | html -%]"/>
343 <fieldset class="action">
344 <input type="submit" value="Submit" />
345 <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
351 [% IF op == 'list' %]
353 <div id="toolbar" class="btn-toolbar">
354 <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>
357 <h1>Identity providers</h1>
358 <div class="page-section">
359 <table id="identity_providers">
365 <th data-class-name="actions noExport">Actions</th>
372 <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
373 <div class="modal-dialog">
374 <div class="modal-content">
375 <div class="modal-header">
376 <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
377 <h3 id="delete_confirm_modal_label">Delete identity provider</h3>
379 <div class="modal-body">
380 <div id="delete_confirm_dialog"></div>
382 <div class="modal-footer">
383 <a href="#" class="btn btn-default" id="delete_confirm_modal_button" role="button" data-toggle="modal">Delete</a>
384 <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
386 </div> <!-- /.modal-content -->
387 </div> <!-- /.modal-dialog -->
388 </div> <!-- #delete_confirm_modal -->
391 </div> <!-- /.col-sm-10.col-sm-push-2 -->
393 <div class="col-sm-2 col-sm-pull-10">
395 [% INCLUDE 'admin-menu.inc' %]
397 </div> <!-- /.col-sm-2.col-sm-pull-10 -->
398 </div> <!-- /.row -->
401 [% MACRO jsinclude BLOCK %]
402 [% Asset.js("js/admin-menu.js") | $raw %]
403 [% INCLUDE 'datatables.inc' %]
405 $(document).ready(function() {
407 var identity_providers_url = '/api/v1/auth/identity_providers';
408 window.identity_providers = $("#identity_providers").kohaTable({
410 "url": identity_providers_url
413 'emptyTable': '<div class="dialog message">'+_("There are no identity providers defined.")+'</div>'
417 "render": function (data, type, row, meta) {
418 if ( type == 'display' ) {
419 if ( data != null ) {
420 return data.escapeHtml();
436 "data": "description",
446 "data": function( row, type, val, meta ) {
447 var result = '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/admin/identity_providers.pl?op=edit_form&identity_provider_id='+ encodeURIComponent(row.identity_provider_id) +'"><i class="fa fa-pencil" aria-hidden="true"></i> '+_("Edit")+'</a>'+"\n";
448 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";
449 result += '<a class="btn btn-default btn-xs edit_domains" role="button" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&identity_provider_id='+ encodeURIComponent(row.identity_provider_id) +'"><i class="fa fa-cog" aria-hidden="true"></i> '+_("Manage Domains")+'</a>';
456 createdRow: function (row, data, dataIndex) {
458 $(row).addClass('debug');
463 $('#identity_providers').on( "click", '.delete_identity_provider', function () {
464 var identity_provider_id = $(this).data('auth-provider-id');
465 var identity_provider_code = decodeURIComponent($(this).data('auth-provider-code'));
467 $("#delete_confirm_dialog").html(
468 _("You are about to delete the '%s' identity provider.").format(identity_provider_code)
470 $("#delete_confirm_modal_button").data('auth-provider-id', identity_provider_id);
471 $("#delete_confirm_modal_button").data('auth-provider-code', identity_provider_code);
474 $("#delete_confirm_modal_button").on( "click", function () {
476 var identity_provider_id = $(this).data('auth-provider-id');
477 var identity_provider_code = $(this).data('auth-provider-code');
481 url: identity_providers_url+"/"+identity_provider_id
482 }).success(function() {
483 window.identity_providers.api().ajax.reload(function (data) {
484 $("#identity_provider_action_result_dialog").hide();
485 $("#identity_provider_delete_success").html(_("Server '%s' deleted successfully.").format(identity_provider_code)).show();
487 }).fail(function () {
488 $("#identity_provider_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(identity_provider_code)).show();
489 }).done(function () {
490 $("#delete_confirm_modal").modal('hide');
494 $.validator.addMethod('json', function(value, element) {
495 if (this.optional(element) && value === '') return true;
502 }, _("Not a valid JSON"));
504 $.validator.addMethod('alphanum', function(value, element) {
505 if (this.optional(element) && value === '') return true;
506 return /^[a-zA-Z0-9_]+$/.test(value);
507 }, _("Value must have alphanumeric characters or '_'"));
509 $('#config, #mapping').each(function() {
510 $(this).rules('add', {
516 $('button.more').on('click', function(event) {
517 event.preventDefault();
518 var target = $(this).hide().data('target');
519 $('.more-'+target).show();
522 $('#code').rules('add', {
530 key: "<enter client id>",
531 secret: "<enter client secret>",
532 well_known_url: "<enter openid configuration endpoint>",
533 scope: "openid email"
537 given_name: "firstname",
538 family_name: "surname"
543 key: "<enter client id>",
544 secret: "<enter client secret>",
545 authorize_url: "<enter authorization endpoint>",
546 token_url: "<enter token endpoint>",
547 userinfo_url: "<enter user info endpoint (optional)>",
552 firstname: "given_name",
553 surname: "family_name"
558 $('#protocol').on('change', function() {
559 var protocol = $(this).val();
560 $('#default-config').html(_("Add default %s configuration").format(protocol));
561 $('#default-mapping').html(_("Add default %s mapping").format(protocol));
564 $('button.defaults').on('click', function(event) {
565 event.preventDefault();
566 var target = $(this).data('defaultTarget');
567 if($('#'+target).val() !== '' && !confirm(_("Are you sure you want to replace current %s contents?").format(target))) {
570 var protocol = $('#protocol').val();
571 $('#'+target).val(JSON.stringify(defaults[protocol][target], null, 2));
577 [% INCLUDE 'intranet-bottom.inc' %]