Bug 31378: Add domain settings to IdP add page
[koha.git] / koha-tmpl / intranet-tmpl / prog / en / modules / admin / identity_providers.tt
1 [% USE raw %]
2 [% USE Asset %]
3 [% USE Branches %]
4 [% USE Categories %]
5 [% SET footerjs = 1 %]
6 [% INCLUDE 'doc-head-open.inc' %]
7 <title>
8     [% IF op == 'add_form' %]
9         New identity provider &rsaquo; [% ELSIF op == 'edit_form' %]
10         Edit identity provider &rsaquo; [% END %]
11
12     Identity providers &rsaquo; Administration &rsaquo; Koha
13 </title>
14 [% INCLUDE 'doc-head-close.inc' %]
15 </head>
16
17 <body id="admin_identity_providers" class="admin">
18 [% INCLUDE 'header.inc' %]
19 [% INCLUDE 'prefs-admin-search.inc' %]
20
21 <nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
22     <ol>
23         <li>
24             <a href="/cgi-bin/koha/mainpage.pl">Home</a>
25         </li>
26         <li>
27             <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
28         </li>
29
30         [% IF op == 'add_form' %]
31             <li>
32                 <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
33             </li>
34             <li>
35                 <a href="#" aria-current="page">
36                     New
37                 </a>
38             </li>
39
40         [% ELSIF op == 'edit_form' %]
41             <li>
42                 <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
43             </li>
44             <li>
45                 <a href="#" aria-current="page">
46                     Edit
47                 </a>
48             </li>
49
50         [% ELSE %]
51             <li>
52                 <a href="#" aria-current="page">
53                     Identity providers
54                 </a>
55             </li>
56         [% END %]
57     </ol>
58 </nav>
59
60 <div class="main container-fluid">
61     <div class="row">
62         <div class="col-sm-10 col-sm-push-2">
63             <main>
64
65 [% FOREACH m IN messages %]
66     <div class="dialog [% m.type | html %]" id="identity_provider_action_result_dialog">
67         [% SWITCH m.code %]
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>
77         [% CASE %]
78             <span>[% m.code | html %]</span>
79         [% END %]
80     </div>
81 [% END %]
82
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>
85
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>
93                 <ol>
94                     <li>
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>
99                     </li>
100                     <li>
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>
105                     </li>
106                     <li>
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>
114                             -->
115                         </select>
116                         <div class="hint">Choose the protocol this external identity provider uses</div>
117                     </li>
118                 </ol>
119             </fieldset>
120
121             <fieldset class="rows">
122                 <legend id="identity_provider_advanced">Advanced configuration</legend>
123                 <ol>
124                     <li>
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>
132                         </div>
133                         <div class="hint">
134                             <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default OAuth configuration</button>
135                         </div>
136                     </li>
137                     <li>
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>
148                         </div>
149                         <div class="hint">
150                             <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default OAuth mapping</button>
151                         </div>
152                     </li>
153                     <li>
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>
159                         </select>
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>
162                     </li>
163                     <li>
164                         <label for="icon_url">Icon URL: </label>
165                         <input type="text" name="icon_url" id="icon_url" size="60" />
166                     </li>
167                 </ol>
168             </fieldset>
169
170             <fieldset class="rows">
171                 <legend id="identity_provider_domain">Domain configuration</legend>
172                 <ol>
173                     <li>
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 &ast; for any domain. You can add new domains later on the dedicated admin page.</div>
178                     </li>
179                     <li>
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 ) %]
183                         </select>
184                         <span class="required">Required</span>
185                         <div class="hint">Use this library for the patron on auto register</div>
186                     </li>
187                     <li>
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>
193                             [% END %]
194                         </select>
195                         <span class="required">Required</span>
196                         <div class="hint">Use this category for the patron on auto register</div>
197                     </li>
198                     <li>
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>
203                         </select>
204                         <div class="hint">Allow OPAC access to users from this domain to login with this identity provider.</div>
205                     </li>
206                     <li>
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>
211                         </select>
212                         <div class="hint">Allow staff access to users from this domain to login with this identity provider.</div>
213                     </li>
214                     <li>
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>
219                         </select>
220                         <div class="hint">Allow users to auto register on login.</div>
221                     </li>
222                     <li>
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>
227                         </select>
228                         <div class="hint">Update user data on login.</div>
229                 </ol>
230             </fieldset>
231
232             <fieldset class="action">
233                 <input type="submit" value="Submit" />
234                 <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
235             </fieldset>
236         </form>
237     </div>
238 [% END %]
239
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">
247                 <ol>
248                     <li>
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>
253                     </li>
254                     <li>
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>
259                     </li>
260                     <li>
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>
269                             -->
270                         [% ELSE %]
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>
276                             -->
277                         [% END %]
278                         </select>
279                         <div class="hint">Choose the protocol this external identity provider uses</div>
280                     </li>
281                 </ol>
282             </fieldset>
283
284             <fieldset class="rows">
285                 <ol>
286                     <li>
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>
294                         </div>
295                         <div class="hint">
296                             <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default [%- identity_provider.protocol | html -%] configuration</button>
297                         </div>
298                     </li>
299                     <li>
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>
310                         </div>
311                         <div class="hint">
312                             <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default [%- identity_provider.protocol | html -%] mapping</button>
313                         </div>
314                     </li>
315                     <li>
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>
320                             [%- ELSE -%]
321                                 <option value="email">Email</option>
322                             [%- END -%]
323                             [%- IF identity_provider.matchpoint == 'userid'     -%]
324                                 <option value="userid" selected="selected">User id</option>
325                             [%- ELSE -%]
326                                 <option value="userid">User id</option>
327                             [%- END -%]
328                             [%- IF identity_provider.matchpoint == 'cardnumber' -%]
329                                 <option value="cardnumber" selected="selected">Card number</option>
330                             [%- ELSE -%]
331                                 <option value="cardnumber">Card number</option>
332                             [%- END -%]
333                         </select>
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>
336                     </li>
337                     <li>
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 -%]"/>
340                     </li>
341                 </ol>
342             </fieldset>
343             <fieldset class="action">
344                 <input type="submit" value="Submit" />
345                 <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
346             </fieldset>
347         </form>
348     </div>
349 [% END %]
350
351 [% IF op == 'list' %]
352
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>
355     </div>
356
357     <h1>Identity providers</h1>
358     <div class="page-section">
359         <table id="identity_providers">
360             <thead>
361                 <tr>
362                     <th>Code</th>
363                     <th>Description</th>
364                     <th>Protocol</th>
365                     <th data-class-name="actions noExport">Actions</th>
366                 </tr>
367             </thead>
368         </table>
369     </div>
370 [% END %]
371
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>
378                         </div>
379                         <div class="modal-body">
380                             <div id="delete_confirm_dialog"></div>
381                         </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>
385                         </div>
386                     </div> <!-- /.modal-content -->
387                 </div> <!-- /.modal-dialog -->
388             </div> <!-- #delete_confirm_modal -->
389
390             </main>
391         </div> <!-- /.col-sm-10.col-sm-push-2 -->
392
393         <div class="col-sm-2 col-sm-pull-10">
394             <aside>
395                 [% INCLUDE 'admin-menu.inc' %]
396             </aside>
397         </div> <!-- /.col-sm-2.col-sm-pull-10 -->
398      </div> <!-- /.row -->
399
400
401 [% MACRO jsinclude BLOCK %]
402     [% Asset.js("js/admin-menu.js") | $raw %]
403     [% INCLUDE 'datatables.inc' %]
404     <script>
405         $(document).ready(function() {
406
407             var identity_providers_url = '/api/v1/auth/identity_providers';
408             window.identity_providers = $("#identity_providers").kohaTable({
409                 "ajax": {
410                     "url": identity_providers_url
411                 },
412                 'language': {
413                     'emptyTable': '<div class="dialog message">'+_("There are no identity providers defined.")+'</div>'
414                 },
415                 "columnDefs": [ {
416                     "targets": [0,1,2],
417                     "render": function (data, type, row, meta) {
418                         if ( type == 'display' ) {
419                             if ( data != null ) {
420                                 return data.escapeHtml();
421                             }
422                             else {
423                                 return "Default";
424                             }
425                         }
426                         return data;
427                     }
428                 } ],
429                 "columns": [
430                     {
431                         "data": "code",
432                         "searchable": true,
433                         "orderable": true
434                     },
435                     {
436                         "data": "description",
437                         "searchable": true,
438                         "orderable": true
439                     },
440                     {
441                         "data": "protocol",
442                         "searchable": true,
443                         "orderable": true
444                     },
445                     {
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&amp;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&amp;identity_provider_id='+ encodeURIComponent(row.identity_provider_id) +'"><i class="fa fa-cog" aria-hidden="true"></i> '+_("Manage Domains")+'</a>';
450                             return result;
451                         },
452                         "searchable": false,
453                         "orderable": false
454                     }
455                 ],
456                 createdRow: function (row, data, dataIndex) {
457                     if ( data.debug ) {
458                         $(row).addClass('debug');
459                     }
460                 },
461             });
462
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'));
466
467                 $("#delete_confirm_dialog").html(
468                     _("You are about to delete the '%s' identity provider.").format(identity_provider_code)
469                 );
470                 $("#delete_confirm_modal_button").data('auth-provider-id', identity_provider_id);
471                 $("#delete_confirm_modal_button").data('auth-provider-code', identity_provider_code);
472             });
473
474             $("#delete_confirm_modal_button").on( "click", function () {
475
476                 var identity_provider_id   = $(this).data('auth-provider-id');
477                 var identity_provider_code = $(this).data('auth-provider-code');
478
479                 $.ajax({
480                     method: "DELETE",
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();
486                     });
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');
491                 });
492             });
493
494             $.validator.addMethod('json', function(value, element) {
495                 if (this.optional(element) && value === '') return true;
496                 try {
497                     JSON.parse(value)
498                 } catch (error) {
499                     return false;
500                 }
501                 return true;
502             }, _("Not a valid JSON"));
503
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 '_'"));
508
509             $('#config, #mapping').each(function() {
510                 $(this).rules('add', {
511                     required: true,
512                     json: true
513                 });
514             });
515
516             $('button.more').on('click', function(event) {
517                 event.preventDefault();
518                 var target = $(this).hide().data('target');
519                 $('.more-'+target).show();
520             });
521
522             $('#code').rules('add', {
523                 alphanum: true,
524                 required: true
525             });
526
527             var defaults = {
528                 OIDC: {
529                     config: {
530                         key: "<enter client id>",
531                         secret: "<enter client secret>",
532                         well_known_url: "<enter openid configuration endpoint>",
533                         scope: "openid email"
534                     },
535                     mapping: {
536                         email: "email",
537                         given_name: "firstname",
538                         family_name: "surname"
539                     }
540                 },
541                 OAuth: {
542                     config: {
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)>",
548                         scope: "email"
549                     },
550                     mapping: {
551                         email: "email",
552                         firstname: "given_name",
553                         surname: "family_name"
554                     }
555                 }
556             };
557
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));
562             });
563
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))) {
568                     return;
569                 }
570                 var protocol = $('#protocol').val();
571                 $('#'+target).val(JSON.stringify(defaults[protocol][target], null, 2));
572             })
573         });
574     </script>
575 [% END %]
576
577 [% INCLUDE 'intranet-bottom.inc' %]