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 [% WRAPPER 'sub-header.inc' %]
22 [% WRAPPER breadcrumbs %]
23 [% WRAPPER breadcrumb_item %]
24 <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
27 [% IF op == 'add_form' %]
28 [% WRAPPER breadcrumb_item %]
29 <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
31 [% WRAPPER breadcrumb_item bc_active= 1 %]
32 <span>New identity provider</span>
35 [% ELSIF op == 'edit_form' %]
36 [% WRAPPER breadcrumb_item %]
37 <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
39 [% WRAPPER breadcrumb_item bc_active= 1 %]
40 <span>Edit identity provider</span>
44 [% WRAPPER breadcrumb_item bc_active= 1 %]
45 <span>Identity providers</span>
48 [% END #/ WRAPPER breadcrumbs %]
49 [% END #/ WRAPPER sub-header.inc %]
51 <div class="main container-fluid">
53 <div class="col-sm-10 col-sm-push-2">
56 [% FOREACH m IN messages %]
57 <div class="dialog [% m.type | html %]" id="identity_provider_action_result_dialog">
59 [% CASE 'error_on_update' %]
60 <span>An error occurred trying to open the identity provider for editing. The passed ID is invalid.</span>
61 [% CASE 'error_on_insert' %]
62 <span>An error occurred when adding a new identity provider.</span>
63 [% CASE 'success_on_update' %]
64 <span>Identity provider updated successfully.</span>
65 [% CASE 'success_on_insert' %]
66 <div>Identity provider added successfully.</div>
67 <div>You will need to restart Koha for the provider to work.</div>
69 <span>[% m.code | html %]</span>
74 <div class="dialog message" id="identity_provider_delete_success" style="display: none;"></div>
75 <div class="dialog alert" id="identity_provider_delete_error" style="display: none;"></div>
77 [% IF op == 'add_form' %]
78 <h1>New identity provider</h1>
79 <div class="page-section">
80 <form action="/cgi-bin/koha/admin/identity_providers.pl" id="add" name="add" class="validated" method="post">
81 <input type="hidden" name="op" value="add" />
82 <fieldset class="rows">
83 <legend id="identity_provider_basic">Basic configuration</legend>
86 <label for="code" class="required">Code: </label>
87 <input type="text" name="code" id="code" size="60" class="required" required="required" />
88 <span class="required">Required</span>
89 <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
92 <label for="description" class="required">Description: </label>
93 <input type="text" name="description" id="description" size="60" class="required" required="required" />
94 <span class="required">Required</span>
95 <div class="hint">User friendly name of this provider</div>
98 <label for="protocol">Protocol: </label>
99 <select name="protocol" id="protocol">
100 <option value="OAuth">OAuth</option>
101 <option value="OIDC">OIDC</option>
102 <!-- Not implemented yet
103 <option value="LDAP">LDAP</option>
104 <option value="CAS">CAS</option>
107 <div class="hint">Choose the protocol this external identity provider uses</div>
112 <fieldset class="rows">
113 <legend id="identity_provider_advanced">Advanced configuration</legend>
116 <label for="config" class="required json">Configuration: </label>
117 <textarea name="config" id="config" class="required" cols="75" rows="10"></textarea>
118 <span class="required">Required</span>
119 <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>
120 <div class="hint more-config" style="display: none">
121 <div>This configuration differs for each protocol.</div>
122 <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
125 <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default OAuth configuration</button>
129 <label for="mapping" class="required json">Mapping: </label>
130 <textarea name="mapping" id="mapping" class="required" cols="75" rows="10"></textarea>
131 <span class="required">Required</span>
132 <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>
133 <div class="hint more-mapping" style="display: none">
134 <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
135 <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
136 <div>For nested values in provider's results, you can use dot separation.</div>
137 <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>
138 <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
141 <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default OAuth mapping</button>
145 <label for="matchpoint">Matchpoint: </label>
146 <select name="matchpoint" id="matchpoint">
147 <option value="email">Email</option>
148 <option value="userid">User ID</option>
149 <option value="cardnumber">Card number</option>
151 <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
152 <div class="hint">It must be present in mapping</div>
155 <label for="icon_url">Icon URL: </label>
156 <input type="text" name="icon_url" id="icon_url" size="60" />
161 <fieldset class="rows">
162 <legend id="identity_provider_domain">Domain configuration</legend>
165 <label for="domain" class="required">Domain: </label>
166 <input type="text" name="domain" id="domain" class="required" size="60" />
167 <span class="required">Required</span>
168 <div class="hint">Use * for any domain. You can add new domains later on the dedicated admin page.</div>
171 <label for="default_library_id">Default library: </label>
172 <select id="default_library_id" name="default_library_id" class="mandatory">
173 [% PROCESS options_for_libraries libraries => Branches.all( unfiltered => 1, do_not_select_my_library => 1 ) %]
175 <span class="required">Required</span>
176 <div class="hint">Use this library for the patron on auto register</div>
179 <label for="default_category_id">Default category: </label>
180 [% SET categories = Categories.all() %]
181 <select name="default_category_id" id="default_category_id" class="mandatory">
182 [% FOREACH category IN categories %]
183 <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
186 <span class="required">Required</span>
187 <div class="hint">Use this category for the patron on auto register</div>
190 <label for="allow_opac">Allow OPAC: </label>
191 <select name="allow_opac" id="allow_opac">
192 <option value="1">Yes</option>
193 <option value="0" selected="selected">No</option>
195 <div class="hint">Allow OPAC access to users from this domain to login with this identity provider.</div>
198 <label for="allow_opac">Allow staff: </label>
199 <select name="allow_staff" id="allow_staff">
200 <option value="1">Yes</option>
201 <option value="0" selected="selected">No</option>
203 <div class="hint">Allow staff access to users from this domain to login with this identity provider.</div>
206 <label for="auto_register">Auto register: </label>
207 <select name="auto_register" id="auto_register">
208 <option value="1">Yes</option>
209 <option value="0" selected="selected">No</option>
211 <div class="hint">Allow users to auto register on login.</div>
214 <label for="update_on_auth">Update on login: </label>
215 <select name="update_on_auth" id="update_on_auth">
216 <option value="1">Yes</option>
217 <option value="0" selected="selected">No</option>
219 <div class="hint">Update user data on login.</div>
223 <fieldset class="action">
224 <input type="submit" value="Submit" />
225 <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
231 [% IF op == 'edit_form' %]
232 <h1>Edit identity provider</h1>
233 <div class="page-section">
234 <form action="/cgi-bin/koha/admin/identity_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
235 <input type="hidden" name="op" value="edit_save" />
236 <input type="hidden" name="identity_provider_id" value="[%- identity_provider.identity_provider_id | html -%]" />
237 <fieldset class="rows">
238 <legend id="identity_provider_basic">Basic configuration</legend>
241 <label for="code" class="required">Code: </label>
242 <input type="text" name="code" id="code" size="60" class="required" required="required" value="[%- identity_provider.code | html -%]"/>
243 <span class="required">Required</span>
244 <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
247 <label for="description" class="required">Description: </label>
248 <input type="text" name="description" id="description" size="60" class="required" required="required" value="[%- identity_provider.description | html -%]"/>
249 <span class="required">Required</span>
250 <div class="hint">User friendly name of this provider</div>
253 <label for="protocol">Protocol: </label>
254 <select name="protocol" id="protocol">
255 [% IF identity_provider.protocol == 'OAuth' %]
256 <option value="OAuth" selected="selected">OAuth</option>
257 <option value="OIDC">OIDC</option>
258 <!-- Not implemented yet
259 <option value="LDAP">LDAP</option>
260 <option value="CAS">CAS</option>
263 <option value="OAuth">OAuth</option>
264 <option value="OIDC" selected="selected">OIDC</option>
265 <!-- Not implemented yet
266 <option value="LDAP">LDAP</option>
267 <option value="CAS">CAS</option>
271 <div class="hint">Choose the protocol this external identity provider uses</div>
276 <fieldset class="rows">
277 <legend id="identity_provider_advanced">Advanced configuration</legend>
280 <label for="config" class="required json">Configuration: </label>
281 <textarea name="config" id="config" class="required" cols="75" rows="10">[%- identity_provider.config | html -%]</textarea>
282 <span class="required">Required</span>
283 <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>
284 <div class="hint more-config" style="display: none">
285 <div>This configuration differs for each protocol.</div>
286 <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
289 <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default [%- identity_provider.protocol | html -%] configuration</button>
293 <label for="mapping" class="required json">Mapping: </label>
294 <textarea name="mapping" id="mapping" class="required" cols="75" rows="10">[%- identity_provider.mapping | html -%]</textarea>
295 <span class="required">Required</span>
296 <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>
297 <div class="hint more-mapping" style="display: none">
298 <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
299 <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
300 <div>For nested values in provider's results, you can use dot separation.</div>
301 <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>
302 <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
305 <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default [%- identity_provider.protocol | html -%] mapping</button>
309 <label for="matchpoint">Matchpoint: </label>
310 <select name="matchpoint" id="matchpoint">
311 [%- IF identity_provider.matchpoint == 'email' -%]
312 <option value="email" selected="selected">Email</option>
314 <option value="email">Email</option>
316 [%- IF identity_provider.matchpoint == 'userid' -%]
317 <option value="userid" selected="selected">User id</option>
319 <option value="userid">User id</option>
321 [%- IF identity_provider.matchpoint == 'cardnumber' -%]
322 <option value="cardnumber" selected="selected">Card number</option>
324 <option value="cardnumber">Card number</option>
327 <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
328 <div class="hint">It must be present in mapping</div>
331 <label for="icon_url">Icon URL: </label>
332 <input type="text" name="icon_url" id="icon_url" size="60" value="[%- identity_provider.icon_url | html -%]"/>
336 <fieldset class="action">
337 <input type="submit" value="Submit" />
338 <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
344 [% IF op == 'list' %]
346 <div id="toolbar" class="btn-toolbar">
347 <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>
350 <h1>Identity providers</h1>
351 <div class="page-section">
352 <table id="identity_providers">
358 <th data-class-name="actions noExport">Actions</th>
365 <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
366 <div class="modal-dialog">
367 <div class="modal-content">
368 <div class="modal-header">
369 <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
370 <h3 id="delete_confirm_modal_label">Delete identity provider</h3>
372 <div class="modal-body">
373 <div id="delete_confirm_dialog"></div>
375 <div class="modal-footer">
376 <a href="#" class="btn btn-default" id="delete_confirm_modal_button" role="button" data-toggle="modal">Delete</a>
377 <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
379 </div> <!-- /.modal-content -->
380 </div> <!-- /.modal-dialog -->
381 </div> <!-- #delete_confirm_modal -->
384 </div> <!-- /.col-sm-10.col-sm-push-2 -->
386 <div class="col-sm-2 col-sm-pull-10">
388 [% INCLUDE 'admin-menu.inc' %]
390 </div> <!-- /.col-sm-2.col-sm-pull-10 -->
391 </div> <!-- /.row -->
394 [% MACRO jsinclude BLOCK %]
395 [% Asset.js("js/admin-menu.js") | $raw %]
396 [% INCLUDE 'datatables.inc' %]
398 $(document).ready(function() {
400 var identity_providers_url = '/api/v1/auth/identity_providers';
401 window.identity_providers = $("#identity_providers").kohaTable({
403 "url": identity_providers_url
406 'emptyTable': '<div class="dialog message">'+_("There are no identity providers defined.")+'</div>'
410 "render": function (data, type, row, meta) {
411 if ( type == 'display' ) {
412 if ( data != null ) {
413 return data.escapeHtml();
429 "data": "description",
439 "data": function( row, type, val, meta ) {
440 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";
441 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";
442 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>';
449 createdRow: function (row, data, dataIndex) {
451 $(row).addClass('debug');
456 $('#identity_providers').on( "click", '.delete_identity_provider', function () {
457 var identity_provider_id = $(this).data('auth-provider-id');
458 var identity_provider_code = decodeURIComponent($(this).data('auth-provider-code'));
460 $("#delete_confirm_dialog").html(
461 _("You are about to delete the '%s' identity provider.").format(identity_provider_code)
463 $("#delete_confirm_modal_button").data('auth-provider-id', identity_provider_id);
464 $("#delete_confirm_modal_button").data('auth-provider-code', identity_provider_code);
467 $("#delete_confirm_modal_button").on( "click", function () {
469 var identity_provider_id = $(this).data('auth-provider-id');
470 var identity_provider_code = $(this).data('auth-provider-code');
474 url: identity_providers_url+"/"+identity_provider_id
475 }).success(function() {
476 window.identity_providers.api().ajax.reload(function (data) {
477 $("#identity_provider_action_result_dialog").hide();
478 $("#identity_provider_delete_success").html(_("Server '%s' deleted successfully.").format(identity_provider_code)).show();
480 }).fail(function () {
481 $("#identity_provider_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(identity_provider_code)).show();
482 }).done(function () {
483 $("#delete_confirm_modal").modal('hide');
487 $.validator.addMethod('json', function(value, element) {
488 if (this.optional(element) && value === '') return true;
495 }, _("Not a valid JSON"));
497 $.validator.addMethod('alphanum', function(value, element) {
498 if (this.optional(element) && value === '') return true;
499 return /^[a-zA-Z0-9_]+$/.test(value);
500 }, _("Value must have alphanumeric characters or '_'"));
502 $('#config, #mapping').each(function() {
503 $(this).rules('add', {
509 $('button.more').on('click', function(event) {
510 event.preventDefault();
511 var target = $(this).hide().data('target');
512 $('.more-'+target).show();
515 $('#code').rules('add', {
523 key: "<enter client id>",
524 secret: "<enter client secret>",
525 well_known_url: "<enter openid configuration endpoint>",
526 scope: "openid email"
530 firstname: "given_name",
531 surname: "family_name"
536 key: "<enter client id>",
537 secret: "<enter client secret>",
538 authorize_url: "<enter authorization endpoint>",
539 token_url: "<enter token endpoint>",
540 userinfo_url: "<enter user info endpoint (optional)>",
545 firstname: "given_name",
546 surname: "family_name"
551 $('#protocol').on('change', function() {
552 var protocol = $(this).val();
553 $('#default-config').html(_("Add default %s configuration").format(protocol));
554 $('#default-mapping').html(_("Add default %s mapping").format(protocol));
557 $('button.defaults').on('click', function(event) {
558 event.preventDefault();
559 var target = $(this).data('defaultTarget');
560 if($('#'+target).val() !== '' && !confirm(_("Are you sure you want to replace current %s contents?").format(target))) {
563 var protocol = $('#protocol').val();
564 $('#'+target).val(JSON.stringify(defaults[protocol][target], null, 2));
570 [% INCLUDE 'intranet-bottom.inc' %]