View | Details | Raw Unified | Return to bug 31378
Collapse All | Expand All

(-)a/Koha/Auth/Client.pm (-16 / +18 lines)
Lines 62-77 sub get_user { Link Here
62
62
63
    my ( $mapped_data, $patron ) = $self->_get_data_and_patron({ provider => $provider, data => $data, config => $config });
63
    my ( $mapped_data, $patron ) = $self->_get_data_and_patron({ provider => $provider, data => $data, config => $config });
64
64
65
    if ($mapped_data) {
65
    $mapped_data //= {};
66
        my $domain = $self->has_valid_domain_config({ provider => $provider, email => $mapped_data->{email}, interface => $interface});
67
66
68
        $mapped_data->{categorycode} = $domain->default_category_id;
67
    my $domain = $self->has_valid_domain_config({ provider => $provider, email => $mapped_data->{email}, interface => $interface});
69
        $mapped_data->{branchcode}   = $domain->default_library_id;
70
68
71
        $patron->set($mapped_data)->store if $patron && $domain->update_on_auth;
69
    $patron->set($mapped_data)->store if $patron && $domain->update_on_auth;
72
70
73
        return ( $patron, $mapped_data, $domain );
71
    $mapped_data->{categorycode} = $domain->default_category_id;
74
    }
72
    $mapped_data->{branchcode}   = $domain->default_library_id;
73
74
    return ( $patron, $mapped_data, $domain );
75
}
75
}
76
76
77
=head3 get_valid_domain_config
77
=head3 get_valid_domain_config
Lines 97-111 sub get_valid_domain_config { Link Here
97
    my $domains = $provider->domains;
97
    my $domains = $provider->domains;
98
    my $allow   = "allow_$interface";
98
    my $allow   = "allow_$interface";
99
    my @subdomain_matches;
99
    my @subdomain_matches;
100
    my $default_match;
100
    my $perfect_match;
101
    my $response;
101
102
102
    while ( my $domain = $domains->next ) {
103
    while ( my $domain = $domains->next ) {
103
        next unless $domain->$allow;
104
104
105
        my $pattern = '@';
105
        my $pattern = '@';
106
        my $domain_text = $domain->domain;
106
        my $domain_text = $domain->domain;
107
        unless ( defined $domain_text && $domain_text ne '') {
107
        unless ( defined $domain_text && $domain_text ne '') {
108
            $default_match = $domain;
108
            $response = $domain;
109
            next;
109
            next;
110
        }
110
        }
111
        my ( $asterisk, $domain_name ) = ( $domain_text =~ /^(\*)?(.+)$/ );
111
        my ( $asterisk, $domain_name ) = ( $domain_text =~ /^(\*)?(.+)$/ );
Lines 118-137 sub get_valid_domain_config { Link Here
118
            if ( defined $asterisk && $asterisk eq '*' ) {
118
            if ( defined $asterisk && $asterisk eq '*' ) {
119
                push @subdomain_matches, { domain => $domain, match_length => length $domain_name };
119
                push @subdomain_matches, { domain => $domain, match_length => length $domain_name };
120
            } else {
120
            } else {
121
121
                $perfect_match = $domain;
122
                # Perfect match.. return this one.
123
                return $domain;
124
            }
122
            }
125
        }
123
        }
126
    }
124
    }
127
125
128
    if ( @subdomain_matches ) {
126
    if ( !$perfect_match && @subdomain_matches ) {
129
        @subdomain_matches = sort { $b->{match_length} <=> $a->{match_length} } @subdomain_matches
127
        @subdomain_matches = sort { $b->{match_length} <=> $a->{match_length} } @subdomain_matches
130
          unless scalar @subdomain_matches == 1;
128
          unless scalar @subdomain_matches == 1;
131
        return $subdomain_matches[0]->{domain};
129
        $response = $subdomain_matches[0]->{domain};
130
    } elsif ($perfect_match) {
131
        $response = $perfect_match;
132
    }
132
    }
133
133
134
    return $default_match;
134
    return unless $response && $response->$allow;
135
136
    return $response;
135
}
137
}
136
138
137
=head3 has_valid_domain_config
139
=head3 has_valid_domain_config
(-)a/Koha/Auth/Client/OAuth.pm (-2 / +2 lines)
Lines 65-70 sub _get_data_and_patron { Link Here
65
        my ( $header_part, $claims_part, $footer_part ) = split( /\./, $data->{id_token} );
65
        my ( $header_part, $claims_part, $footer_part ) = split( /\./, $data->{id_token} );
66
66
67
        my $claim = decode_json( decode_base64url($claims_part) );
67
        my $claim = decode_json( decode_base64url($claims_part) );
68
68
        foreach my $key ( keys %$mapping ) {
69
        foreach my $key ( keys %$mapping ) {
69
            my $pkey = $mapping->{$key};
70
            my $pkey = $mapping->{$key};
70
            $mapped_data->{$key} = $claim->{$pkey}
71
            $mapped_data->{$key} = $claim->{$pkey}
Lines 111-118 sub _get_data_and_patron { Link Here
111
112
112
    }
113
    }
113
114
114
    return ( $mapped_data, $patron )
115
    return ( $mapped_data, $patron );
115
          if $patron;
116
}
116
}
117
117
118
1;
118
1;
(-)a/Koha/REST/V1/OAuth/Client.pm (-26 / +23 lines)
Lines 50-71 sub login { Link Here
50
50
51
    my $provider_config = $c->oauth2->providers->{$provider};
51
    my $provider_config = $c->oauth2->providers->{$provider};
52
52
53
    unless ( $provider_config ) {
54
        return $c->render(
55
            status  => 404,
56
            openapi => {
57
                error      => 'Object not found',
58
                error_code => 'not_found',
59
            }
60
        );
61
    }
62
63
    unless ( $provider_config->{authorize_url} =~ /response_type=code/ ) {
64
        my $authorize_url = Mojo::URL->new($provider_config->{authorize_url});
65
        $authorize_url->query->append(response_type => 'code');
66
        $provider_config->{authorize_url} = $authorize_url->to_string;
67
    }
68
69
    my $uri;
53
    my $uri;
70
54
71
    if ( $interface eq 'opac' ) {
55
    if ( $interface eq 'opac' ) {
Lines 78-97 sub login { Link Here
78
        $uri = '/cgi-bin/koha/mainpage.pl';
62
        $uri = '/cgi-bin/koha/mainpage.pl';
79
    }
63
    }
80
64
65
    unless ( $provider_config ) {
66
        my $error = "No configuration found for your provider";
67
        return $c->redirect_to($uri."?auth_error=$error");
68
    }
69
70
    unless ( $provider_config->{authorize_url} =~ /response_type=code/ ) {
71
        my $authorize_url = Mojo::URL->new($provider_config->{authorize_url});
72
        $authorize_url->query->append(response_type => 'code');
73
        $provider_config->{authorize_url} = $authorize_url->to_string;
74
    }
75
81
    return $c->oauth2->get_token_p($provider)->then(
76
    return $c->oauth2->get_token_p($provider)->then(
82
        sub {
77
        sub {
83
            return unless my $response = shift;
78
            return unless my $response = shift;
84
79
85
            my ( $patron, $mapped_data, $domain ) = Koha::Auth::Client::OAuth->new->get_user(
86
                {   provider  => $provider,
87
                    data      => $response,
88
                    interface => $interface,
89
                    config    => $c->oauth2->providers->{$provider}
90
                }
91
            );
92
93
            try {
80
            try {
94
                # FIXME: We could check if the backend allows registering
81
                my ( $patron, $mapped_data, $domain ) = Koha::Auth::Client::OAuth->new->get_user(
82
                    {   provider  => $provider,
83
                        data      => $response,
84
                        interface => $interface,
85
                        config    => $c->oauth2->providers->{$provider}
86
                    }
87
                );
88
95
                if ( !$patron ) {
89
                if ( !$patron ) {
96
                    $patron = $c->auth->register(
90
                    $patron = $c->auth->register(
97
                        {
91
                        {
Lines 113-119 sub login { Link Here
113
                # TODO: Review behavior
107
                # TODO: Review behavior
114
                if ( blessed $error ) {
108
                if ( blessed $error ) {
115
                    if ( $error->isa('Koha::Exceptions::Auth::Unauthorized') ) {
109
                    if ( $error->isa('Koha::Exceptions::Auth::Unauthorized') ) {
116
                        $error = "$error";
110
                        $error = "User cannot access this resource";
111
                    }
112
                    if ( $error->isa('Koha::Exceptions::Auth::NoValidDomain') ) {
113
                        $error = "No configuration found for your email domain";
117
                    }
114
                    }
118
                }
115
                }
119
116
(-)a/Koha/Schema/Result/IdentityProviderDomain.pm (+19 lines)
Lines 209-218 __PACKAGE__->belongs_to( Link Here
209
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-10-20 15:27:55
209
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-10-20 15:27:55
210
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:xTbkigJHktgNYDw1Xx01sw
210
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:xTbkigJHktgNYDw1Xx01sw
211
211
212
__PACKAGE__->add_columns(
213
    '+auto_register'  => { is_boolean => 1 },
214
    '+update_on_auth' => { is_boolean => 1 },
215
    '+allow_opac'     => { is_boolean => 1 },
216
    '+allow_staff'    => { is_boolean => 1 }
217
);
218
219
=head3  koha_object_class
220
221
Koha::Object class
222
223
=cut
212
224
213
sub koha_object_class {
225
sub koha_object_class {
214
    'Koha::Auth::Identity::Provider::Domain';
226
    'Koha::Auth::Identity::Provider::Domain';
215
}
227
}
228
229
=head3  koha_objects_class
230
231
Koha::Objects class
232
233
=cut
234
216
sub koha_objects_class {
235
sub koha_objects_class {
217
    'Koha::Auth::Identity::Provider::Domains';
236
    'Koha::Auth::Identity::Provider::Domains';
218
}
237
}
(-)a/admin/identity_providers.pl (-9 / +9 lines)
Lines 95-108 if ( !$domain_ops && $op eq 'add' ) { Link Here
95
}
95
}
96
elsif ( $domain_ops && $op eq 'add' ) {
96
elsif ( $domain_ops && $op eq 'add' ) {
97
97
98
    my $allow_opac          = $input->param('allow_opac');
98
    my $allow_opac              = $input->param('allow_opac');
99
    my $allow_staff         = $input->param('allow_staff');
99
    my $allow_staff             = $input->param('allow_staff');
100
    my $identity_provider_id    = $input->param('identity_provider_id');
100
    my $identity_provider_id    = $input->param('identity_provider_id');
101
    my $auto_register       = $input->param('auto_register');
101
    my $auto_register           = $input->param('auto_register');
102
    my $default_category_id = $input->param('default_category_id');
102
    my $default_category_id     = $input->param('default_category_id') || undef;
103
    my $default_library_id  = $input->param('default_library_id');
103
    my $default_library_id      = $input->param('default_library_id') || undef;
104
    my $domain              = $input->param('domain');
104
    my $domain                  = $input->param('domain');
105
    my $update_on_auth      = $input->param('update_on_auth');
105
    my $update_on_auth          = $input->param('update_on_auth');
106
106
107
    try {
107
    try {
108
108
Lines 237-244 elsif ( $domain_ops && $op eq 'edit_save' ) { Link Here
237
        my $domain              = $input->param('domain');
237
        my $domain              = $input->param('domain');
238
        my $auto_register       = $input->param('auto_register');
238
        my $auto_register       = $input->param('auto_register');
239
        my $update_on_auth      = $input->param('update_on_auth');
239
        my $update_on_auth      = $input->param('update_on_auth');
240
        my $default_library_id  = $input->param('default_library_id');
240
        my $default_library_id  = $input->param('default_library_id') || undef;
241
        my $default_category_id = $input->param('default_category_id');
241
        my $default_category_id = $input->param('default_category_id') || undef;
242
        my $allow_opac          = $input->param('allow_opac');
242
        my $allow_opac          = $input->param('allow_opac');
243
        my $allow_staff         = $input->param('allow_staff');
243
        my $allow_staff         = $input->param('allow_staff');
244
244
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_provider_domains.tt (-179 / +212 lines)
Lines 33-39 Link Here
33
33
34
        [% IF op == 'add_form' %]
34
        [% IF op == 'add_form' %]
35
            <li>
35
            <li>
36
                <a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_name | html -%]</a>
36
                <a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_code | html -%]</a>
37
            </li>
37
            </li>
38
            <li>
38
            <li>
39
                <a href="#" aria-current="page">
39
                <a href="#" aria-current="page">
Lines 43-49 Link Here
43
43
44
        [% ELSIF op == 'edit_form' %]
44
        [% ELSIF op == 'edit_form' %]
45
            <li>
45
            <li>
46
                <a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_name | html -%]</a>
46
                <a href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | uri -%]">Domains for [%- identity_provider_code | html -%]</a>
47
            </li>
47
            </li>
48
            <li>
48
            <li>
49
                <a href="#" aria-current="page">
49
                <a href="#" aria-current="page">
Lines 87-284 Link Here
87
    <div class="dialog alert"   id="identity_provider_domain_delete_error"   style="display: none;"></div>
87
    <div class="dialog alert"   id="identity_provider_domain_delete_error"   style="display: none;"></div>
88
88
89
[% IF op == 'add_form' %]
89
[% IF op == 'add_form' %]
90
    <h1>New identity provider domain</h1>
90
    <h1>New email domain</h1>
91
    <form action="/cgi-bin/koha/admin/identity_providers.pl" id="add" name="add" class="validated" method="post">
91
    <div class="page-section">
92
        <input type="hidden" name="op" value="add" />
92
        <form action="/cgi-bin/koha/admin/identity_providers.pl" id="add" name="add" class="validated" method="post">
93
        <input type="hidden" name="domain_ops" value="1" />
93
            <input type="hidden" name="op" value="add" />
94
        <input type="hidden" name="identity_provider_id" value="[%- identity_provider_id | html -%]" />
94
            <input type="hidden" name="domain_ops" value="1" />
95
        <fieldset class="rows">
95
            <input type="hidden" name="identity_provider_id" value="[%- identity_provider_id | html -%]" />
96
            <ol>
96
            <fieldset class="rows">
97
                <li>
97
                <ol>
98
                    <label for="domain">Domain: </label>
98
                    <li>
99
                    <input type="text" name="domain" id="domain" size="60" />
99
                        <label for="domain">Domain: </label>
100
                </li>
100
                        <input type="text" name="domain" id="domain" size="60" />
101
            </ol>
101
                        <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>
102
        </fieldset>
102
                        <div class="hint more-domain" style="display: none">
103
                            <div>If this field is empty, or '*' any email domain will match this rule.</div>
104
                            <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>
105
                            <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>
106
                            <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>
107
                        </div>
108
                    </li>
109
                </ol>
110
            </fieldset>
103
111
104
        <fieldset class="rows">
112
            <fieldset class="rows">
105
            <ol>
113
                <ol>
106
                <li>
114
                    <li>
107
                    <label for="update_on_auth">Update on login: </label>
115
                        <label for="update_on_auth">Update on login: </label>
108
                    <select name="update_on_auth" id="update_on_auth">
116
                        <select name="update_on_auth" id="update_on_auth">
109
                        <option value="1">Update</option>
117
                            <option value="1">Update</option>
110
                        <option value="0" selected="selected">Don't update</option>
118
                            <option value="0" selected="selected">Don't update</option>
111
                    </select>
119
                        </select>
112
                    <span>user data on login</span>
120
                        <span>user data on login</span>
113
                </li>
121
                    </li>
114
                <li>
122
                    <li>
115
                    <label for="auto_register">Auto register: </label>
123
                        <label for="auto_register">Auto register: </label>
116
                    <select name="auto_register" id="auto_register">
124
                        <select name="auto_register" id="auto_register">
117
                        <option value="1">Allow</option>
125
                            <option value="1">Allow</option>
118
                        <option value="0" selected="selected">Don't allow</option>
126
                            <option value="0" selected="selected">Don't allow</option>
119
                    </select>
127
                        </select>
120
                    <span>users to auto register on login</span>
128
                        <span>users to auto register on login</span>
121
                </li>
129
                    </li>
122
                <li>
130
                    <li>
123
                    <label for="default_library_id">Default library: </label>
131
                        <label for="default_library_id">Default library: </label>
124
                    <select id="default_library_id" name="default_library_id">
132
                        <select id="default_library_id" name="default_library_id">
125
                        [% PROCESS options_for_libraries libraries => Branches.all( unfiltered => 1, do_not_select_my_library => 1 ) %]
133
                            <option value="">None</option>
126
                    </select>
134
                            [% PROCESS options_for_libraries libraries => Branches.all( unfiltered => 1, do_not_select_my_library => 1 ) %]
127
                </li>
135
                        </select>
128
                <li>
136
                        <div class="hint">Use this library for the patron on auto register</div>
129
                    <label for="default_category_id">Default category: </label>
137
                    </li>
130
                    [% SET categories = Categories.all() %]
138
                    <li>
131
                    <select name="default_category_id" id="default_category_id">
139
                        <label for="default_category_id">Default category: </label>
132
                        [% FOREACH category IN categories %]
140
                        [% SET categories = Categories.all() %]
133
                            <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
141
                        <select name="default_category_id" id="default_category_id">
134
                        [% END %]
142
                            <option value="">None</option>
135
                    </select>
143
                            [% FOREACH category IN categories %]
136
                </li>
144
                                <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
137
                <li>
145
                            [% END %]
138
                    <label for="allow_opac">Allow opac: </label>
146
                        </select>
139
                    <select name="allow_opac" id="allow_opac">
147
                        <div class="hint">Use this category for the patron on auto register</div>
140
                        <option value="1" selected="selected">Allow</option>
148
                    </li>
141
                        <option value="0">Don't allow</option>
149
                    <li>
142
                    </select>
150
                        <label for="allow_opac">Allow opac: </label>
143
                    <span>opac users of this domain to login with this identity provider</span>
151
                        <select name="allow_opac" id="allow_opac">
144
                </li>
152
                            <option value="1" selected="selected">Allow</option>
145
                <li>
153
                            <option value="0">Don't allow</option>
146
                    <label for="allow_opac">Allow staff: </label>
154
                        </select>
147
                    <select name="allow_staff" id="allow_staff">
155
                        <span>opac users of this domain to login with this identity provider</span>
148
                        <option value="1" selected="selected">Allow</option>
156
                    </li>
149
                        <option value="0">Don't allow</option>
157
                    <li>
150
                    </select>
158
                        <label for="allow_opac">Allow staff: </label>
151
                    <span>of this domain </span>
159
                        <select name="allow_staff" id="allow_staff">
152
                </li>
160
                            <option value="1">Allow</option>
153
            </ol>
161
                            <option value="0" selected="selected">Don't allow</option>
154
        </fieldset>
162
                        </select>
155
        <fieldset class="action">
163
                        <span>of this domain to login with this identity provider</span>
156
            <input type="submit" value="Submit" />
164
                    </li>
157
            <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
165
                </ol>
158
        </fieldset>
166
            </fieldset>
159
    </form>
167
            <fieldset class="action">
168
                <input type="submit" value="Submit" />
169
                <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
170
            </fieldset>
171
        </form>
172
    </div>
160
[% END %]
173
[% END %]
161
174
162
[% IF op == 'edit_form' %]
175
[% IF op == 'edit_form' %]
163
    <h1>Edit identity provider domain</h1>
176
    <h1>Edit identity provider domain</h1>
164
    <form action="/cgi-bin/koha/admin/identity_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
177
    <div class="page-section">
165
        <input type="hidden" name="op" value="edit_save" />
178
        <form action="/cgi-bin/koha/admin/identity_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
166
        <input type="hidden" name="domain_ops" value="1" />
179
            <input type="hidden" name="op" value="edit_save" />
167
        <input type="hidden" name="identity_provider_id" value="[%- identity_provider_id | html -%]" />
180
            <input type="hidden" name="domain_ops" value="1" />
168
        <input type="hidden" name="identity_provider_domain_id" value="[%- identity_provider_domain.identity_provider_domain_id | html -%]" />
181
            <input type="hidden" name="identity_provider_id" value="[%- identity_provider_id | html -%]" />
169
        <fieldset class="rows">
182
            <input type="hidden" name="identity_provider_domain_id" value="[%- identity_provider_domain.identity_provider_domain_id | html -%]" />
170
            <ol>
183
            <fieldset class="rows">
171
                <li>
184
                <ol>
172
                    <label for="domain">Domain: </label>
185
                    <li>
173
                    <input type="text" name="domain" id="domain" size="60" value="[%- identity_provider_domain.domain | html -%]"/>
186
                        <label for="domain">Domain: </label>
174
                </li>
187
                        <input type="text" name="domain" id="domain" size="60" value="[%- identity_provider_domain.domain | html -%]"/>
175
            </ol>
188
                        <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>
176
        </fieldset>
189
                        <div class="hint more-domain" style="display: none">
190
                            <div>If this field is empty, or '*' any email domain will match this rule.</div>
191
                            <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>
192
                            <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>
193
                            <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>
194
                        </div>
195
                    </li>
196
                </ol>
197
            </fieldset>
177
198
178
        <fieldset class="rows">
199
            <fieldset class="rows">
179
            <ol>
200
                <ol>
180
                <li>
201
                    <li>
181
                    <label for="update_on_auth">Update on login: </label>
202
                        <label for="update_on_auth">Update on login: </label>
182
                    <select name="update_on_auth" id="update_on_auth">
203
                        <select name="update_on_auth" id="update_on_auth">
183
                    [% IF identity_provider_domain.update_on_auth == "1" %]
204
                        [% IF identity_provider_domain.update_on_auth == "1" %]
184
                        <option value="1" selected="selected">Update</option>
205
                            <option value="1" selected="selected">Update</option>
185
                        <option value="0">Don't update</option>
206
                            <option value="0">Don't update</option>
186
                    [% ELSE %]
207
                        [% ELSE %]
187
                        <option value="1">Update</option>
208
                            <option value="1">Update</option>
188
                        <option value="0" selected="selected">Don't update</option>
209
                            <option value="0" selected="selected">Don't update</option>
189
                    [% END %]
210
                        [% END %]
190
                    </select>
211
                        </select>
191
                    <span>user data on login</span>
212
                        <span>user data on login</span>
192
                </li>
213
                    </li>
193
                <li>
214
                    <li>
194
                    <label for="auto_register">Auto register: </label>
215
                        <label for="auto_register">Auto register: </label>
195
                    <select name="auto_register" id="auto_register">
216
                        <select name="auto_register" id="auto_register">
196
                    [% IF identity_provider_domain.auto_register == "1" %]
217
                        [% IF identity_provider_domain.auto_register == "1" %]
197
                        <option value="1" selected="selected">Allow</option>
218
                            <option value="1" selected="selected">Allow</option>
198
                        <option value="0">Don't allow</option>
219
                            <option value="0">Don't allow</option>
199
                    [% ELSE %]
220
                        [% ELSE %]
200
                        <option value="1">Allow</option>
221
                            <option value="1">Allow</option>
201
                        <option value="0" selected="selected">Don't allow</option>
222
                            <option value="0" selected="selected">Don't allow</option>
202
                    [% END %]
223
                        [% END %]
203
                    </select>
224
                        </select>
204
                    <span>users to auto register on login</span>
225
                        <span>users to auto register on login</span>
205
                </li>
226
                    </li>
206
                <li>
227
                    <li>
207
                    <label for="default_library_id">Default library: </label>
228
                        <label for="default_library_id">Default library: </label>
208
                    <select id="default_library_id" name="default_library_id">
229
                        <select id="default_library_id" name="default_library_id">
209
                        [% PROCESS options_for_libraries libraries => Branches.all( selected => identity_provider_domain.default_library_id, unfiltered => 1, do_not_select_my_library => 1 ) %]
230
                            <option value="">None</option>
210
                    </select>
231
                            [% PROCESS options_for_libraries libraries => Branches.all( selected => identity_provider_domain.default_library_id, unfiltered => 1, do_not_select_my_library => 1 ) %]
211
                </li>
232
                        </select>
212
                <li>
233
                        <div class="hint">Use this library for the patron on auto register</div>
213
                    <label for="default_category_id">Default category: </label>
234
                    </li>
214
                    [% SET categories = Categories.all() %]
235
                    <li>
215
                    <select name="default_category_id" id="default_category_id">
236
                        <label for="default_category_id">Default category: </label>
216
                        [% FOREACH category IN categories %]
237
                        [% SET categories = Categories.all() %]
217
                            [% IF category.categorycode == identity_provider_domain.default_category_id %]
238
                        <select name="default_category_id" id="default_category_id">
218
                                <option value="[% category.categorycode | html %]" selected="selected">[% category.description | html %]</option>
239
                            <option value="">None</option>
219
                            [% ELSE %]
240
                            [% FOREACH category IN categories %]
220
                                <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
241
                                [% IF category.categorycode == identity_provider_domain.default_category_id %]
242
                                    <option value="[% category.categorycode | html %]" selected="selected">[% category.description | html %]</option>
243
                                [% ELSE %]
244
                                    <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
245
                                [% END %]
221
                            [% END %]
246
                            [% END %]
247
                        </select>
248
                        <div class="hint">Use this category for the patron on auto register</div>
249
                    </li>
250
                    <li>
251
                        <label for="allow_opac">Allow opac: </label>
252
                        <select name="allow_opac" id="allow_opac">
253
                        [% IF identity_provider_domain.allow_opac == "1" %]
254
                            <option value="1" selected="selected">Allow</option>
255
                            <option value="0">Don't allow</option>
256
                        [% ELSE %]
257
                            <option value="1">Allow</option>
258
                            <option value="0" selected="selected">Don't allow</option>
259
                        [% END %]
260
                        </select>
261
                        <span>opac users of this domain to login with this identity provider</span>
262
                    </li>
263
                    <li>
264
                        <label for="allow_opac">Allow staff: </label>
265
                        <select name="allow_staff" id="allow_staff">
266
                        [% IF identity_provider_domain.allow_staff == "1" %]
267
                            <option value="1" selected="selected">Allow</option>
268
                            <option value="0">Don't allow</option>
269
                        [% ELSE %]
270
                            <option value="1">Allow</option>
271
                            <option value="0" selected="selected">Don't allow</option>
222
                        [% END %]
272
                        [% END %]
223
                    </select>
273
                        </select>
224
                </li>
274
                        <span>staff users of this domain to login with this identity provider</span>
225
                <li>
275
                    </li>
226
                    <label for="allow_opac">Allow opac: </label>
276
                </ol>
227
                    <select name="allow_opac" id="allow_opac">
277
            </fieldset>
228
                    [% IF identity_provider_domain.allow_opac == "1" %]
278
            <fieldset class="action">
229
                        <option value="1" selected="selected">Allow</option>
279
                <input type="submit" value="Submit" />
230
                        <option value="0">Don't allow</option>
280
                <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
231
                    [% ELSE %]
281
            </fieldset>
232
                        <option value="1">Allow</option>
282
        </form>
233
                        <option value="0" selected="selected">Don't allow</option>
283
    </div>
234
                    [% END %]
235
                    </select>
236
                    <span>opac users of this domain to login with this identity provider</span>
237
                </li>
238
                <li>
239
                    <label for="allow_opac">Allow staff: </label>
240
                    <select name="allow_staff" id="allow_staff">
241
                    [% IF identity_provider_domain.allow_staff == "1" %]
242
                        <option value="1" selected="selected">Allow</option>
243
                        <option value="0">Don't allow</option>
244
                    [% ELSE %]
245
                        <option value="1">Allow</option>
246
                        <option value="0" selected="selected">Don't allow</option>
247
                    [% END %]
248
                    </select>
249
                    <span>staff users of this domain to login with this identity provider</span>
250
                </li>
251
            </ol>
252
        </fieldset>
253
        <fieldset class="action">
254
            <input type="submit" value="Submit" />
255
            <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]">Cancel</a>
256
        </fieldset>
257
    </form>
258
[% END %]
284
[% END %]
259
285
260
[% IF op == 'list' %]
286
[% IF op == 'list' %]
261
287
262
    <div id="toolbar" class="btn-toolbar">
288
    <div id="toolbar" class="btn-toolbar">
263
        <a class="btn btn-default" id="new_identity_provider_domain" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]&amp;op=add_form"><i class="fa fa-plus"></i> New identity provider domain</a>
289
        <a class="btn btn-default" id="new_identity_provider_domain" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id=[%- identity_provider_id | html -%]&amp;op=add_form"><i class="fa fa-plus"></i> New email domain</a>
264
    </div>
290
    </div>
265
291
266
    <h1>Identity provider domains</h1>
292
    <h1>Identity provider email domains</h1>
267
293
    <div class="page-section">
268
    <table id="identity_provider_domains">
294
        <table id="identity_provider_domains">
269
        <thead>
295
            <thead>
270
            <tr>
296
                <tr>
271
                <th>Domain</th>
297
                    <th>Domain</th>
272
                <th>Update on login</th>
298
                    <th>Update on login</th>
273
                <th>Auto register</th>
299
                    <th>Auto register</th>
274
                <th>Default library</th>
300
                    <th>Default library</th>
275
                <th>Default category</th>
301
                    <th>Default category</th>
276
                <th>Allow opac</th>
302
                    <th>Allow opac</th>
277
                <th>Allow staff</th>
303
                    <th>Allow staff</th>
278
                <th data-class-name="actions noExport">Actions</th>
304
                    <th data-class-name="actions noExport">Actions</th>
279
            </tr>
305
                </tr>
280
        </thead>
306
            </thead>
281
    </table>
307
        </table>
308
    </div>
282
[% END %]
309
[% END %]
283
310
284
            <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
311
            <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
Lines 469-474 Link Here
469
                    $("#delete_confirm_modal").modal('hide');
496
                    $("#delete_confirm_modal").modal('hide');
470
                });
497
                });
471
            });
498
            });
499
500
            $('button.more').on('click', function(event) {
501
                event.preventDefault();
502
                var target = $(this).hide().data('target');
503
                $('.more-'+target).show();
504
            });
472
        });
505
        });
473
    </script>
506
    </script>
474
[% END %]
507
[% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/identity_providers.tt (-174 / +218 lines)
Lines 70-76 Link Here
70
        [% CASE 'success_on_update' %]
70
        [% CASE 'success_on_update' %]
71
            <span>Identity provider updated successfully.</span>
71
            <span>Identity provider updated successfully.</span>
72
        [% CASE 'success_on_insert' %]
72
        [% CASE 'success_on_insert' %]
73
            <span>Identity provider added successfully.</span>
73
            <div>Identity provider added successfully.</div>
74
            <div>You will need to restart Koha for the provider to work.</div>
74
        [% CASE %]
75
        [% CASE %]
75
            <span>[% m.code | html %]</span>
76
            <span>[% m.code | html %]</span>
76
        [% END %]
77
        [% END %]
Lines 82-257 Link Here
82
83
83
[% IF op == 'add_form' %]
84
[% IF op == 'add_form' %]
84
    <h1>New identity provider</h1>
85
    <h1>New identity provider</h1>
85
    <form action="/cgi-bin/koha/admin/identity_providers.pl" id="add" name="add" class="validated" method="post">
86
    <div class="page-section">
86
        <input type="hidden" name="op" value="add" />
87
        <form action="/cgi-bin/koha/admin/identity_providers.pl" id="add" name="add" class="validated" method="post">
87
        <fieldset class="rows">
88
            <input type="hidden" name="op" value="add" />
88
            <ol>
89
            <fieldset class="rows">
89
                <li>
90
                <ol>
90
                    <label for="code" class="required">Code: </label>
91
                    <li>
91
                    <input type="text" name="code" id="code" size="60" class="required" required="required" />
92
                        <label for="code" class="required">Code: </label>
92
                    <span class="required">Required</span>
93
                        <input type="text" name="code" id="code" size="60" class="required" required="required" />
93
                </li>
94
                        <span class="required">Required</span>
94
                <li>
95
                        <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
95
                    <label for="description" class="required">Description: </label>
96
                    </li>
96
                    <input type="text" name="description" id="description" size="60" class="required" required="required" />
97
                    <li>
97
                    <span class="required">Required</span>
98
                        <label for="description" class="required">Description: </label>
98
                </li>
99
                        <input type="text" name="description" id="description" size="60" class="required" required="required" />
99
                <li>
100
                        <span class="required">Required</span>
100
                    <label for="protocol">Protocol: </label>
101
                        <div class="hint">User friendly name of this provider</div>
101
                    <select name="protocol" id="protocol">
102
                    </li>
102
                        <option value="OAuth">OAuth</option>
103
                    <li>
103
                        <option value="OIDC">OIDC</option>
104
                        <label for="protocol">Protocol: </label>
104
                        <!-- Not implemented yet
105
                        <select name="protocol" id="protocol">
105
                        <option value="LDAP">LDAP</option>
106
                            <option value="OAuth">OAuth</option>
106
                        <option value="CAS">CAS</option>
107
                            <option value="OIDC">OIDC</option>
107
                        -->
108
                            <!-- Not implemented yet
108
                    </select>
109
                            <option value="LDAP">LDAP</option>
109
                </li>
110
                            <option value="CAS">CAS</option>
110
            </ol>
111
                            -->
111
        </fieldset>
112
                        </select>
112
113
                        <div class="hint">Choose the protocol this external identity provider uses</div>
113
        <fieldset class="rows">
114
                    </li>
114
            <ol>
115
                </ol>
115
                <li>
116
            </fieldset>
116
                    <div>
117
118
            <fieldset class="rows">
119
                <ol>
120
                    <li>
117
                        <label for="config" class="required json">Configuration: </label>
121
                        <label for="config" class="required json">Configuration: </label>
118
                        <textarea name="config" id="config" class="required"></textarea>
122
                        <textarea name="config" id="config" class="required"></textarea>
119
                        <span class="required">Required</span>
123
                        <span class="required">Required</span>
120
                    </div>
124
                        <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>
121
                    <div>
125
                        <div class="hint more-config" style="display: none">
122
                        <label></label>
126
                            <div>This configuration differs for each protocol.</div>
123
                        <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default OAuth configuration</button>
127
                            <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
124
                    </div>
128
                        </div>
125
                </li>
129
                        <div class="hint">
126
                <li>
130
                            <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default OAuth configuration</button>
127
                    <div>
131
                        </div>
132
                    </li>
133
                    <li>
128
                        <label for="mapping" class="required json">Mapping: </label>
134
                        <label for="mapping" class="required json">Mapping: </label>
129
                        <textarea name="mapping" id="mapping" class="required"></textarea>
135
                        <textarea name="mapping" id="mapping" class="required"></textarea>
130
                        <span class="required">Required</span>
136
                        <span class="required">Required</span>
131
                    </div>
137
                        <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>
132
                    <div>
138
                        <div class="hint more-mapping" style="display: none">
133
                        <label></label>
139
                            <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
134
                        <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default OAuth mapping</button>
140
                            <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
135
                    </div>
141
                            <div>For nested values in provider's results, you can use dot separation.</div>
136
                </li>
142
                            <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>
137
                <li>
143
                            <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
138
                    <label for="matchpoint" class="required">Matchpoint: </label>
144
                        </div>
139
                    <select name="matchpoint" id="matchpoint" class="required">
145
                        <div class="hint">
140
                        <option value="email">Email</option>
146
                            <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default OAuth mapping</button>
141
                        <option value="userid">User id</option>
147
                        </div>
142
                        <option value="cardnumber">Card number</option>
148
                    </li>
143
                    </select>
149
                    <li>
144
                    <span class="required">Required</span>
150
                        <label for="matchpoint">Matchpoint: </label>
145
                </li>
151
                        <select name="matchpoint" id="matchpoint">
146
                <li>
152
                            <option value="email">Email</option>
147
                    <label for="icon_url">Icon URL: </label>
153
                            <option value="userid">User id</option>
148
                    <input type="text" name="icon_url" id="icon_url" size="60" />
154
                            <option value="cardnumber">Card number</option>
149
                </li>
155
                        </select>
150
            </ol>
156
                        <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
151
        </fieldset>
157
                        <div class="hint">It must be present in mapping</div>
152
        <fieldset class="action">
158
                    </li>
153
            <input type="submit" value="Submit" />
159
                    <li>
154
            <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
160
                        <label for="icon_url">Icon URL: </label>
155
        </fieldset>
161
                        <input type="text" name="icon_url" id="icon_url" size="60" />
156
    </form>
162
                    </li>
163
                </ol>
164
            </fieldset>
165
            <fieldset class="action">
166
                <input type="submit" value="Submit" />
167
                <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
168
            </fieldset>
169
        </form>
170
    </div>
157
[% END %]
171
[% END %]
158
172
159
[% IF op == 'edit_form' %]
173
[% IF op == 'edit_form' %]
160
    <h1>Edit identity provider</h1>
174
    <h1>Edit identity provider</h1>
161
    <form action="/cgi-bin/koha/admin/identity_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
175
    <div class="page-section">
162
        <input type="hidden" name="op" value="edit_save" />
176
        <form action="/cgi-bin/koha/admin/identity_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
163
        <input type="hidden" name="identity_provider_id" value="[%- identity_provider.identity_provider_id | html -%]" />
177
            <input type="hidden" name="op" value="edit_save" />
164
        <fieldset class="rows">
178
            <input type="hidden" name="identity_provider_id" value="[%- identity_provider.identity_provider_id | html -%]" />
165
            <ol>
179
            <fieldset class="rows">
166
                <li>
180
                <ol>
167
                    <label for="code" class="required">Code: </label>
181
                    <li>
168
                    <input type="text" name="code" id="code" size="60" class="required" required="required" value="[%- identity_provider.code | html -%]"/>
182
                        <label for="code" class="required">Code: </label>
169
                    <span class="required">Required</span>
183
                        <input type="text" name="code" id="code" size="60" class="required" required="required" value="[%- identity_provider.code | html -%]"/>
170
                </li>
184
                        <span class="required">Required</span>
171
                <li>
185
                        <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
172
                    <label for="description" class="required">Description: </label>
186
                    </li>
173
                    <input type="text" name="description" id="description" size="60" class="required" required="required" value="[%- identity_provider.description | html -%]"/>
187
                    <li>
174
                    <span class="required">Required</span>
188
                        <label for="description" class="required">Description: </label>
175
                </li>
189
                        <input type="text" name="description" id="description" size="60" class="required" required="required" value="[%- identity_provider.description | html -%]"/>
176
                <li>
190
                        <span class="required">Required</span>
177
                    <label for="protocol">Protocol: </label>
191
                        <div class="hint">User friendly name of this provider</div>
178
                    <select name="protocol" id="protocol">
192
                    </li>
179
                    [% IF identity_provider.protocol == 'OAuth' %]
193
                    <li>
180
                        <option value="OAuth" selected="selected">OAuth</option>
194
                        <label for="protocol">Protocol: </label>
181
                        <option value="OIDC">OIDC</option>
195
                        <select name="protocol" id="protocol">
182
                        <!-- Not implemented yet
196
                        [% IF identity_provider.protocol == 'OAuth' %]
183
                        <option value="LDAP">LDAP</option>
197
                            <option value="OAuth" selected="selected">OAuth</option>
184
                        <option value="CAS">CAS</option>
198
                            <option value="OIDC">OIDC</option>
185
                        -->
199
                            <!-- Not implemented yet
186
                    [% ELSE %]
200
                            <option value="LDAP">LDAP</option>
187
                        <option value="OAuth">OAuth</option>
201
                            <option value="CAS">CAS</option>
188
                        <option value="OIDC" selected="selected">OIDC</option>
202
                            -->
189
                        <!-- Not implemented yet
203
                        [% ELSE %]
190
                        <option value="LDAP">LDAP</option>
204
                            <option value="OAuth">OAuth</option>
191
                        <option value="CAS">CAS</option>
205
                            <option value="OIDC" selected="selected">OIDC</option>
192
                        -->
206
                            <!-- Not implemented yet
193
                    [% END %]
207
                            <option value="LDAP">LDAP</option>
194
                    </select>
208
                            <option value="CAS">CAS</option>
195
                </li>
209
                            -->
196
            </ol>
210
                        [% END %]
197
        </fieldset>
211
                        </select>
198
212
                        <div class="hint">Choose the protocol this external identity provider uses</div>
199
        <fieldset class="rows">
213
                    </li>
200
            <ol>
214
                </ol>
201
                <li>
215
            </fieldset>
202
                    <div>
216
217
            <fieldset class="rows">
218
                <ol>
219
                    <li>
203
                        <label for="config" class="required json">Configuration: </label>
220
                        <label for="config" class="required json">Configuration: </label>
204
                        <textarea name="config" id="config" class="required">[%- identity_provider.config | html -%]</textarea>
221
                        <textarea name="config" id="config" class="required">[%- identity_provider.config | html -%]</textarea>
205
                        <span class="required">Required</span>
222
                        <span class="required">Required</span>
206
                    </div>
223
                        <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>
207
                    <div>
224
                        <div class="hint more-config" style="display: none">
208
                        <label></label>
225
                            <div>This configuration differs for each protocol.</div>
209
                        <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default [%- identity_provider.protocol | html -%] configuration</button>
226
                            <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
210
                    </div>
227
                        </div>
211
                </li>
228
                        <div class="hint">
212
                <li>
229
                            <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default [%- identity_provider.protocol | html -%] configuration</button>
213
                    <div>
230
                        </div>
231
                    </li>
232
                    <li>
214
                        <label for="mapping" class="required json">Mapping: </label>
233
                        <label for="mapping" class="required json">Mapping: </label>
215
                        <textarea name="mapping" id="mapping" class="required">[%- identity_provider.mapping | html -%]</textarea>
234
                        <textarea name="mapping" id="mapping" class="required">[%- identity_provider.mapping | html -%]</textarea>
216
                        <span class="required">Required</span>
235
                        <span class="required">Required</span>
217
                    </div>
236
                        <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>
218
                    <div>
237
                        <div class="hint more-mapping" style="display: none">
219
                        <label></label>
238
                            <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
220
                        <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default [%- identity_provider.protocol | html -%] mapping</button>
239
                            <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
221
                    </div>
240
                            <div>For nested values in provider's results, you can use dot separation.</div>
222
                </li>
241
                            <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>
223
                <li>
242
                            <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
224
                    <label for="matchpoint" class="required">matchpoint: </label>
243
                        </div>
225
                    <select name="matchpoint" id="matchpoint" class="required">
244
                        <div class="hint">
226
                        [%- IF identity_provider.matchpoint == 'email'      -%]
245
                            <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default [%- identity_provider.protocol | html -%] mapping</button>
227
                            <option value="email" selected="selected">Email</option>
246
                        </div>
228
                        [%- ELSE -%]
247
                    </li>
229
                            <option value="email">Email</option>
248
                    <li>
230
                        [%- END -%]
249
                        <label for="matchpoint">matchpoint: </label>
231
                        [%- IF identity_provider.matchpoint == 'userid'     -%]
250
                        <select name="matchpoint" id="matchpoint">
232
                            <option value="userid" selected="selected">User id</option>
251
                            [%- IF identity_provider.matchpoint == 'email'      -%]
233
                        [%- ELSE -%]
252
                                <option value="email" selected="selected">Email</option>
234
                            <option value="userid">User id</option>
253
                            [%- ELSE -%]
235
                        [%- END -%]
254
                                <option value="email">Email</option>
236
                        [%- IF identity_provider.matchpoint == 'cardnumber' -%]
255
                            [%- END -%]
237
                            <option value="cardnumber" selected="selected">Card number</option>
256
                            [%- IF identity_provider.matchpoint == 'userid'     -%]
238
                        [%- ELSE -%]
257
                                <option value="userid" selected="selected">User id</option>
239
                            <option value="cardnumber">Card number</option>
258
                            [%- ELSE -%]
240
                        [%- END -%]
259
                                <option value="userid">User id</option>
241
                    </select>
260
                            [%- END -%]
242
                    <span class="required">Required</span>
261
                            [%- IF identity_provider.matchpoint == 'cardnumber' -%]
243
                </li>
262
                                <option value="cardnumber" selected="selected">Card number</option>
244
                <li>
263
                            [%- ELSE -%]
245
                    <label for="icon_url">Icon URL: </label>
264
                                <option value="cardnumber">Card number</option>
246
                    <input type="text" name="icon_url" id="icon_url" size="60"  value="[%- identity_provider.icon_url | html -%]"/>
265
                            [%- END -%]
247
                </li>
266
                        </select>
248
            </ol>
267
                        <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
249
        </fieldset>
268
                        <div class="hint">It must be present in mapping</div>
250
        <fieldset class="action">
269
                    </li>
251
            <input type="submit" value="Submit" />
270
                    <li>
252
            <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
271
                        <label for="icon_url">Icon URL: </label>
253
        </fieldset>
272
                        <input type="text" name="icon_url" id="icon_url" size="60"  value="[%- identity_provider.icon_url | html -%]"/>
254
    </form>
273
                    </li>
274
                </ol>
275
            </fieldset>
276
            <fieldset class="action">
277
                <input type="submit" value="Submit" />
278
                <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
279
            </fieldset>
280
        </form>
281
    </div>
255
[% END %]
282
[% END %]
256
283
257
[% IF op == 'list' %]
284
[% IF op == 'list' %]
Lines 261-277 Link Here
261
    </div>
288
    </div>
262
289
263
    <h1>Identity providers</h1>
290
    <h1>Identity providers</h1>
264
291
    <div class="page-section">
265
    <table id="identity_providers">
292
        <table id="identity_providers">
266
        <thead>
293
            <thead>
267
            <tr>
294
                <tr>
268
                <th>Code</th>
295
                    <th>Code</th>
269
                <th>Description</th>
296
                    <th>Description</th>
270
                <th>Protocol</th>
297
                    <th>Protocol</th>
271
                <th data-class-name="actions noExport">Actions</th>
298
                    <th data-class-name="actions noExport">Actions</th>
272
            </tr>
299
                </tr>
273
        </thead>
300
            </thead>
274
    </table>
301
        </table>
302
    </div>
275
[% END %]
303
[% END %]
276
304
277
            <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
305
            <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
Lines 397-410 Link Here
397
            });
425
            });
398
426
399
            $.validator.addMethod('json', function(value, element) {
427
            $.validator.addMethod('json', function(value, element) {
400
                if (this.optional(element)) return true;
428
                if (this.optional(element) && value === '') return true;
401
                try {
429
                try {
402
                    JSON.parse(value)
430
                    JSON.parse(value)
403
                } catch (error) {
431
                } catch (error) {
404
                    return false;
432
                    return false;
405
                }
433
                }
406
                return true;
434
                return true;
407
            }, _('Not a valid JSON'));
435
            }, _("Not a valid JSON"));
436
437
            $.validator.addMethod('alphanum', function(value, element) {
438
                if (this.optional(element) && value === '') return true;
439
                return /^[a-zA-Z0-9_]+$/.test(value);
440
            }, _("Value must have alphanumeric characters or '_'"));
408
441
409
            $('#config, #mapping').each(function() {
442
            $('#config, #mapping').each(function() {
410
                $(this).rules('add', {
443
                $(this).rules('add', {
Lines 413-418 Link Here
413
                });
446
                });
414
            });
447
            });
415
448
449
            $('button.more').on('click', function(event) {
450
                event.preventDefault();
451
                var target = $(this).hide().data('target');
452
                $('.more-'+target).show();
453
            });
454
455
            $('#code').rules('add', {
456
                alphanum: true,
457
                required: true
458
            });
459
416
            var defaults = {
460
            var defaults = {
417
                OIDC: {
461
                OIDC: {
418
                    config: {
462
                    config: {
Lines 424-430 Link Here
424
                    mapping: {
468
                    mapping: {
425
                        email: "email",
469
                        email: "email",
426
                        given_name: "firstname",
470
                        given_name: "firstname",
427
	                    family_name: "surname"
471
                        family_name: "surname"
428
                    }
472
                    }
429
                },
473
                },
430
                OAuth: {
474
                OAuth: {
Lines 439-463 Link Here
439
                    mapping: {
483
                    mapping: {
440
                        email: "email",
484
                        email: "email",
441
                        firstname: "given_name",
485
                        firstname: "given_name",
442
	                    surname: "family_name"
486
                        surname: "family_name"
443
                    }
487
                    }
444
                }
488
                }
445
            };
489
            };
446
490
447
            $('#protocol').on('change', function() {
491
            $('#protocol').on('change', function() {
448
                var protocol = $(this).val();
492
                var protocol = $(this).val();
449
                $('#default-config').html(_('Add default %s configuration').format(protocol));
493
                $('#default-config').html(_("Add default %s configuration").format(protocol));
450
                $('#default-mapping').html(_('Add default %s mapping').format(protocol));
494
                $('#default-mapping').html(_("Add default %s mapping").format(protocol));
451
            });
495
            });
452
496
453
            $('button.defaults').on('click', function(event) {
497
            $('button.defaults').on('click', function(event) {
454
                event.preventDefault();
498
                event.preventDefault();
455
                var target = $(this).data('defaultTarget');
499
                var target = $(this).data('defaultTarget');
456
                if($('#'+target).html() !== '' && !confirm(_('Are you sure you want to replace current %s contents?').format(target))) {
500
                if($('#'+target).val() !== '' && !confirm(_("Are you sure you want to replace current %s contents?").format(target))) {
457
                    return;
501
                    return;
458
                }
502
                }
459
                var protocol = $('#protocol').val();
503
                var protocol = $('#protocol').val();
460
                $('#'+target).html(JSON.stringify(defaults[protocol][target], null, 2));
504
                $('#'+target).val(JSON.stringify(defaults[protocol][target], null, 2));
461
            })
505
            })
462
        });
506
        });
463
    </script>
507
    </script>
(-)a/t/db_dependent/Koha/Auth/Client.t (-3 / +3 lines)
Lines 44-55 subtest 'get_user() tests' => sub { Link Here
44
44
45
  my $client   = Koha::Auth::Client::OAuth->new;
45
  my $client   = Koha::Auth::Client::OAuth->new;
46
  my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { matchpoint => 'email' } } );
46
  my $provider = $builder->build_object( { class => 'Koha::Auth::Identity::Providers', value => { matchpoint => 'email' } } );
47
  my $domain   = $builder->build_object( { class => 'Koha::Auth::Identity::Provider::Domains', value => { identity_provider_id => $provider->id, domain => '', allow_opac => 1, allow_staff => 0 } } );
47
  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 } } );
48
  my $patron   = $builder->build_object( { class => 'Koha::Patrons', value => { email => 'patron@test.com' } } );
48
  my $patron   = $builder->build_object( { class => 'Koha::Patrons', value => { email => 'patron@test.com' } } );
49
  my $mapping = {
49
  my $mapping = {
50
    email     => 'electronic_mail',
50
    email     => 'electronic_mail',
51
    firstname => 'given_name',
51
    firstname => 'given_name',
52
	  surname   => 'family_name'
52
    surname   => 'family_name'
53
  };
53
  };
54
  $provider->set_mapping($mapping)->store;
54
  $provider->set_mapping($mapping)->store;
55
55
Lines 163-169 subtest '_traverse_hash() tests' => sub { Link Here
163
    base => $hash,
163
    base => $hash,
164
    keys => 'a.hash.with'
164
    keys => 'a.hash.with'
165
  });
165
  });
166
  is($first_result, 'complicated structure', 'get the value whithin a hash structure');
166
  is($first_result, 'complicated structure', 'get the value within a hash structure');
167
167
168
  my $second_result = $client->_traverse_hash({
168
  my $second_result = $client->_traverse_hash({
169
    base => $hash,
169
    base => $hash,
(-)a/t/db_dependent/api/v1/idp.t (-42 / +38 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 3;
22
use Test::More tests => 2;
23
use Test::Mojo;
23
use Test::Mojo;
24
use Test::Warn;
24
use Test::Warn;
25
use Mojo::JWT;
25
use Mojo::JWT;
Lines 42-50 t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' ); Link Here
42
42
43
my $remote_address = '127.0.0.1';
43
my $remote_address = '127.0.0.1';
44
44
45
use t::lib::IdP::ExternalIdP;
45
# use t::lib::IdP::ExternalIdP;
46
46
47
my $idp_port = t::lib::IdP::ExternalIdP->start;
47
# my $idp_port = t::lib::IdP::ExternalIdP->start;
48
48
49
49
50
my $oauth_provider_data = {
50
my $oauth_provider_data = {
Lines 59-67 my $oauth_provider_data = { Link Here
59
  },
59
  },
60
  matchpoint  => 'email',
60
  matchpoint  => 'email',
61
  config      => {
61
  config      => {
62
    authorize_url => "http://localhost:$idp_port/idp/test/authorization_endpoint",
62
    authorize_url => "/idp/test/authorization_endpoint",
63
    token_url     => "http://localhost:$idp_port/idp/test/token_endpoint/without_id_token",
63
    token_url     => "/idp/test/token_endpoint/without_id_token",
64
    userinfo_url  => "http://localhost:$idp_port/idp/test/userinfo_endpoint",
64
    userinfo_url  => "/idp/test/userinfo_endpoint",
65
    key           => "client_id",
65
    key           => "client_id",
66
    secret        => "client_secret"
66
    secret        => "client_secret"
67
  }
67
  }
Lines 69-75 my $oauth_provider_data = { Link Here
69
69
70
my $oidc_with_email_provider_data = {
70
my $oidc_with_email_provider_data = {
71
  code => 'oidc_email',
71
  code => 'oidc_email',
72
  description => 'OIDC wiht email provider',
72
  description => 'OIDC with email provider',
73
  protocol => 'OIDC',
73
  protocol => 'OIDC',
74
  mapping => {
74
  mapping => {
75
    email     => 'email',
75
    email     => 'email',
Lines 79-86 my $oidc_with_email_provider_data = { Link Here
79
  },
79
  },
80
  matchpoint => 'email',
80
  matchpoint => 'email',
81
  config => {
81
  config => {
82
    authorize_url  => "http://localhost:$idp_port/idp/test/authorization_endpoint",
82
    authorize_url  => "/idp/test/authorization_endpoint",
83
    well_known_url => "http://localhost:$idp_port/idp/test/with_email/.well_known",
83
    well_known_url => "/idp/test/with_email/.well_known",
84
    key            => "client_id",
84
    key            => "client_id",
85
    secret         => "client_secret"
85
    secret         => "client_secret"
86
  }
86
  }
Lines 88-94 my $oidc_with_email_provider_data = { Link Here
88
88
89
my $oidc_without_email_provider_data = {
89
my $oidc_without_email_provider_data = {
90
  code => 'oidc_no_email',
90
  code => 'oidc_no_email',
91
  description => 'OIDC wihtout email provider',
91
  description => 'OIDC without email provider',
92
  protocol => 'OIDC',
92
  protocol => 'OIDC',
93
  mapping => {
93
  mapping => {
94
    email     => 'users.0.email',
94
    email     => 'users.0.email',
Lines 98-105 my $oidc_without_email_provider_data = { Link Here
98
  },
98
  },
99
  matchpoint => 'email',
99
  matchpoint => 'email',
100
  config => {
100
  config => {
101
    authorize_url  => "http://localhost:$idp_port/idp/test/authorization_endpoint",
101
    authorize_url  => "/idp/test/authorization_endpoint",
102
    well_known_url => "http://localhost:$idp_port/idp/test/without_email/.well_known",
102
    well_known_url => "/idp/test/without_email/.well_known",
103
    key            => "client_id",
103
    key            => "client_id",
104
    secret         => "client_secret"
104
    secret         => "client_secret"
105
  }
105
  }
Lines 272-317 subtest 'domain endpoint tests' => sub { Link Here
272
  $schema->storage->txn_rollback;
272
  $schema->storage->txn_rollback;
273
};
273
};
274
274
275
subtest 'oauth login tests' => sub {
275
# subtest 'oauth login tests' => sub {
276
  plan tests => 4;
276
#   plan tests => 4;
277
277
278
  $schema->storage->txn_begin;
278
#   $schema->storage->txn_begin;
279
279
280
  Koha::Auth::Identity::Provider::Domains->delete;
280
#   Koha::Auth::Identity::Provider::Domains->delete;
281
  Koha::Auth::Identity::Providers->delete;
281
#   Koha::Auth::Identity::Providers->delete;
282
282
283
  my ( $borrowernumber, $session_id ) = create_user_and_session({ authorized => 1 });
283
#   my ( $borrowernumber, $session_id ) = create_user_and_session({ authorized => 1 });
284
284
285
  my $t = Test::Mojo->new('Koha::REST::V1');
285
#   my $t = Test::Mojo->new('Koha::REST::V1');
286
286
287
  # Build provider
287
#   # Build provider
288
  my $tx = $t->ua->build_tx( POST => "/api/v1/auth/identity_providers", json => $oauth_provider_data );
288
#   my $tx = $t->ua->build_tx( POST => "/api/v1/auth/identity_providers", json => $oauth_provider_data );
289
  $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
289
#   $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
290
  $tx->req->env( { REMOTE_ADDR => $remote_address } );
290
#   $tx->req->env( { REMOTE_ADDR => $remote_address } );
291
292
  $t->request_ok($tx);
293
  my $provider_id = $t->tx->res->json->{identity_provider_id};
294
291
295
  # Build domain
292
#   $t->request_ok($tx);
296
  $tx = $t->ua->build_tx( POST => "/api/v1/auth/identity_providers/$provider_id/domains", json => $domain_not_matching );
293
#   my $provider_id = $t->tx->res->json->{identity_provider_id};
297
  $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
298
  $tx->req->env( { REMOTE_ADDR => $remote_address } );
299
294
300
  $t->request_ok($tx);
295
#   # Build domain
296
#   $tx = $t->ua->build_tx( POST => "/api/v1/auth/identity_providers/$provider_id/domains", json => $domain_not_matching );
297
#   $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
298
#   $tx->req->env( { REMOTE_ADDR => $remote_address } );
301
299
302
  t::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 );
300
#   $t->request_ok($tx);
303
301
304
  # Simulate server restart
302
#   t::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 );
305
  $t = Test::Mojo->new('Koha::REST::V1');
306
303
307
  #$t->ua->max_redirects(10);
304
#   # Simulate server restart
308
  $t->get_ok("/api/v1/public/oauth/login/oauth_test/opac")
305
#   $t = Test::Mojo->new('Koha::REST::V1');
309
    ->status_is(302);
310
  use Data::Printer colored => 1;
311
  p $t->tx->res;
312
306
313
  $schema->storage->txn_rollback;
307
#   #$t->ua->max_redirects(10);
314
};
308
#   $t->get_ok("/api/v1/public/oauth/login/oauth_test/opac")
309
#     ->status_is(302);
310
#   $schema->storage->txn_rollback;
311
# };
315
312
316
sub create_user_and_session {
313
sub create_user_and_session {
317
314
318
- 

Return to bug 31378