httpkadmind: Make more like bx509d internally
[heimdal.git] / tests / kdc / check-httpkadmind.in
blob816f753d0792176f23646dfe323fdde3b9dd1a6c
1 #!/bin/sh
3 # Copyright (c) 2020 Kungliga Tekniska Högskolan
4 # (Royal Institute of Technology, Stockholm, Sweden).
5 # All rights reserved.
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
11 # 1. Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
18 # 3. Neither the name of the Institute nor the names of its contributors
19 # may be used to endorse or promote products derived from this software
20 # without specific prior written permission.
22 # THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 # ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 # SUCH DAMAGE.
34 top_builddir="@top_builddir@"
35 env_setup="@env_setup@"
36 objdir="@objdir@"
38 testfailed="echo test failed; cat messages.log; exit 1"
40 . ${env_setup}
42 # If there is no useful db support compiled in, disable test
43 ${have_db} || exit 77
45 if ! which curl > /dev/null; then
46 echo "curl is not available -- not testing httpkadmind"
47 exit 77
49 if ! test -x ${objdir}/../../kdc/httpkadmind; then
50 echo "Configured w/o libmicrohttpd -- not testing httpkadmind"
51 exit 77
54 R=TEST.H5L.SE
55 domain=test.h5l.se
57 port=@port@
58 admport=@admport@
59 admport1=@admport@
60 admport2=@admport2@
61 restport=@restport@
62 restport1=@restport@
63 restport2=@restport2@
65 server=datan.test.h5l.se
66 otherserver=other.test.h5l.se
67 cache="FILE:${objdir}/cache.krb5"
68 cache2="FILE:${objdir}/cache2.krb5"
69 admincache="FILE:${objdir}/cache3.krb5"
70 keyfile="${hx509_data}/key.der"
71 keyfile2="${hx509_data}/key2.der"
72 kt=${objdir}/kt
73 keytab=FILE:${kt}
74 ukt=${objdir}/ukt
75 ukeytab=FILE:${ukt}
77 kdc="${kdc} --addresses=localhost -P $port"
78 kadminr="${kadmin} -r $R -a $(uname -n)"
79 kadmin="${kadmin} -l -r $R"
80 kadmind2="${kadmind} --keytab=${keytab} --detach -p $admport2 --read-only"
81 kadmind="${kadmind} --keytab=${keytab} --detach -p $admport"
82 httpkadmind2="${httpkadmind} --reverse-proxied -T Negotiate -p $restport2"
83 httpkadmind="${httpkadmind} --reverse-proxied -T Negotiate -p $restport1"
85 kinit2="${kinit} -c $cache2 ${afs_no_afslog}"
86 kinit="${kinit} -c $cache ${afs_no_afslog}"
87 adminklist="${klist} --hidden -v -c $admincache"
88 klist2="${klist} --hidden -v -c $cache2"
89 klist="${klist} --hidden -v -c $cache"
90 kgetcred2="${kgetcred} -c $cache2"
91 kgetcred="${kgetcred} -c $cache"
92 kdestroy2="${kdestroy} -c $cache2 ${afs_no_unlog}"
93 kdestroy="${kdestroy} -c $cache ${afs_no_unlog}"
94 kx509="${kx509} -c $cache"
96 KRB5_CONFIG="${objdir}/krb5-httpkadmind.conf"
97 export KRB5_CONFIG
98 KRB5CCNAME=$cache
99 export KRB5CCNAME
101 rm -f current-db*
102 rm -f out-*
103 rm -f mkey.file*
104 rm -f *.pem *.crt *.der
105 rm -rf simple_csr_authz
106 rm -f extracted_keytab*
108 mkdir -p simple_csr_authz
110 > messages.log
112 # We'll avoid using a KDC for now. For testing /httpkadmind we only need keys
113 # for Negotiate tokens, and we'll use ktutil and kimpersonate to make it
114 # possible to create and accept those without a KDC.
116 # grant ext-type value grantee_principal
117 grant() {
118 mkdir -p "${objdir}/simple_csr_authz/${3}"
119 touch "${objdir}/simple_csr_authz/${3}/${1}-${2}"
122 revoke() {
123 rm -rf "${objdir}/simple_csr_authz"
124 mkdir -p "${objdir}/simple_csr_authz"
127 if set -o|grep 'verbose.*on' > /dev/null ||
128 set -o|grep 'xtrace.*on' > /dev/null; then
129 verbose=-vvv
130 else
131 verbose=
134 # HTTP curl-opts
135 HTTP() {
136 curl -g --resolve ${server}:${restport2}:127.0.0.1 \
137 --resolve ${server}:${restport}:127.0.0.1 \
138 -u: --negotiate $verbose \
139 -D response-headers \
140 "$@"
143 # get_config QPARAMS curl-opts
144 get_config() {
145 url="http://${server}:${restport}/get-config?$1"
146 shift
147 HTTP $verbose "$@" "$url"
150 check_age() {
151 set -- $(grep -i ^Cache-Control: response-headers)
152 if [ $# -eq 0 ]; then
153 return 1
155 shift
156 for param in "$@"; do
157 case "$param" in
158 no-store) true;;
159 max-age=0) return 1;;
160 max-age=*) true;;
161 *) return 1;;
162 esac
163 done
164 return 0;
167 # get_keytab QPARAMS curl-opts
168 get_keytab() {
169 url="http://${server}:${restport}/get-keys?$1"
170 shift
171 HTTP $verbose "$@" "$url"
174 # get_keytab_POST QPARAMS curl-opts
175 get_keytab_POST() {
176 # Curl is awful, so if you don't use -f, you don't get non-zero exit codes on
177 # error responses, but if you do use -f then -D doesn't work. Ugh.
179 # So first we check that POST w/o CSRF token fails:
180 q=$1
181 shift
183 get_keytab "$q" -X POST --data-binary @/dev/null -f "$@" &&
184 { echo "POST succeeded w/o CSRF token!"; return 1; }
185 get_keytab "$q" -X POST --data-binary @/dev/null "$@"
186 grep ^X-CSRF-Token: response-headers >/dev/null || return 1
187 get_keytab "$q" -X POST --data-binary @/dev/null \
188 -H "$(sed -e 's/\r//' response-headers | grep ^X-CSRF-Token:)" "$@"
189 grep '^HTTP/1.1 200' response-headers >/dev/null || return $?
190 return 0
193 get_keytab_POST_redir() {
194 url="http://${server}:${restport}/get-keys?$1"
195 shift
196 HTTP -X POST --data-binary @/dev/null "$@" "$url"
197 grep ^X-CSRF-Token: response-headers >/dev/null ||
198 { echo "POST w/o CSRF token had response w/o CSRF token!"; return 1; }
199 HTTP -X POST --data-binary @/dev/null -f \
200 -H "$(sed -e 's/\r//' response-headers | grep ^X-CSRF-Token:)" \
201 --location --location-trusted "$@" "$url"
204 kdcpid=
205 httpkadmindpid=
206 httpkadmind2pid=
207 kadmindpid=
208 kadmind2pid=
209 cleanup() {
210 test -n "$kdcpid" &&
211 { echo signal killing kdc; kill -9 "$kdcpid"; }
212 test -n "$httpkadmindpid" &&
213 { echo signal killing httpkadmind; kill -9 "$httpkadmindpid"; }
214 test -n "$httpkadmind2pid" &&
215 { echo signal killing httpkadmind; kill -9 "$httpkadmind2pid"; }
216 test -n "$kadmindpid" &&
217 { echo signal killing kadmind; kill -9 "$kadmindpid"; }
218 test -n "$kadmind2pid" &&
219 { echo signal killing kadmind; kill -9 "$kadmind2pid"; }
221 trap cleanup EXIT
223 rm -f extracted_keytab
225 echo "Creating database"
226 rm -f $kt $ukt
227 ${kadmin} init \
228 --realm-max-ticket-life=1day \
229 --realm-max-renewable-life=1month \
230 ${R} || exit 1
231 ${kadmin} add -r --use-defaults foo@${R} || exit 1
232 ${kadmin} add -r --use-defaults httpkadmind/admin@${R} || exit 1
233 ${kadmin} add -r --use-defaults WELLKNOWN/CSRFTOKEN@${R} || exit 1
234 ${kadmin} add -r --use-defaults HTTP/localhost@${R} || exit 1
235 ${kadmin} add -r --use-defaults host/xyz.${domain}@${R} || exit 1
236 ${kadmin} add -r --use-defaults HTTP/xyz.${domain}@${R} || exit 1
237 ${kadmin} add_ns --key-rotation-epoch=-1d --key-rotation-period=5m \
238 --max-ticket-life=1d --max-renewable-life=5d \
239 --attributes= HTTP/ns.${domain}@${R} || exit 1
240 ${kadmin} add_ns --key-rotation-epoch=-1d --key-rotation-period=5m \
241 --max-ticket-life=1d --max-renewable-life=5d \
242 --attributes=ok-as-delegate host/.ns2.${domain}@${R} || exit 1
243 ${kadmin} add -r --use-defaults HTTP/${server}@${R} || exit 1
244 ${kadmin} ext_keytab -r -k $keytab kadmin/admin@${R} || exit 1
245 ${kadmin} ext_keytab -r -k $keytab httpkadmind/admin@${R} || exit 1
246 ${kadmin} ext_keytab -r -k $keytab HTTP/${server}@${R} || exit 1
247 ${kadmin} ext_keytab -r -k $keytab HTTP/localhost@${R} || exit 1
248 ${kadmin} add -r --use-defaults HTTP/${otherserver}@${R} || exit 1
249 ${kadmin} ext_keytab -r -k $ukeytab foo@${R} || exit 1
250 ${kdestroy}
252 # For a while let's not bother with a KDC
253 $kimpersonate --ccache=$cache -k $keytab -R -t aes128-cts-hmac-sha1-96 \
254 -c foo@${R} -s HTTP/datan.test.h5l.se@${R} ||
255 { echo "failed to setup kimpersonate credentials"; exit 2; }
256 $kimpersonate -A --ccache=$cache -k $keytab -R -t aes128-cts-hmac-sha1-96 \
257 -c foo@${R} -s HTTP/localhost@${R} ||
258 { echo "failed to setup kimpersonate credentials"; exit 2; }
259 $klist -t >/dev/null ||
260 { echo "failed to setup kimpersonate credentials"; exit 2; }
262 echo "Starting httpkadmind"
263 ${httpkadmind} -H $server -H localhost --local -t --daemon ||
264 { echo "httpkadmind failed to start"; exit 2; }
265 httpkadmindpid=`getpid httpkadmind`
266 ec=0
268 echo "Checking that concrete principal exists"
269 ${kadmin} get HTTP/xyz.${domain} > /dev/null ||
270 { echo "Failed to create HTTP/xyz.${domain}"; exit 1; }
271 echo "Checking that virtual principal exists"
272 ${kadmin} get HTTP/foo.ns.${domain} > /dev/null ||
273 { echo "Virtual principals not working"; exit 1; }
275 hn=xyz.${domain}
276 p=HTTP/$hn
277 echo "Fetching krb5.conf for $p"
278 get_config "princ=$p" -sf -o "${objdir}/extracted_config" ||
279 { echo "Failed to get config for $p"; exit 1; }
280 read config < "${objdir}/extracted_config"
281 test "$config" = "include /etc/krb5.conf" ||
282 { echo "Got unexpected default config for $p"; exit 1; }
283 ${kadmin} mod --krb5-config-file="$KRB5_CONFIG" $p ||
284 { echo "Failed to set config for $p"; exit 1; }
285 get_config "princ=$p" -sf -o "${objdir}/extracted_config" ||
286 { echo "Failed to get config for $p"; exit 1; }
287 cmp "${objdir}/extracted_config" "$KRB5_CONFIG" ||
288 { echo "Got unexpected config for $p"; exit 1; }
290 hn=xyz.${domain}
291 p=HTTP/$hn
292 echo "Fetching keytab for concrete principal $p"
293 rm -f extracted_keytab*
294 grant dnsname $hn foo@${R}
295 ${kadmin} ext_keytab -k extracted_keytab $p ||
296 { echo "Failed to get a keytab for $p with kadmin"; exit 1; }
297 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin ||
298 { echo "Failed to list keytab for $p"; exit 1; }
299 get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" ||
300 { echo "Failed to get a keytab for $p with curl"; exit 1; }
301 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest ||
302 { echo "Failed to list keytab for $p"; exit 1; }
303 cmp extracted_keytab.kadmin extracted_keytab.rest ||
304 { echo "Keytabs for $p don't match!"; exit 1; }
306 hn=foo.ns.${domain}
307 p=HTTP/$hn
308 echo "Fetching keytab for virtual principal $p"
309 rm -f extracted_keytab*
310 grant dnsname $hn foo@${R}
311 ${kadmin} ext_keytab -k extracted_keytab $p ||
312 { echo "Failed to get a keytab for $p with kadmin"; exit 1; }
313 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin ||
314 { echo "Failed to list keytab for $p"; exit 1; }
315 get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" ||
316 { echo "Failed to get a keytab for $p with curl"; exit 1; }
317 check_age
318 grep -i ^Cache-Control response-headers
319 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest ||
320 { echo "Failed to list keytab for $p"; exit 1; }
321 cmp extracted_keytab.kadmin extracted_keytab.rest ||
322 { echo "Keytabs for $p don't match!"; exit 1; }
324 hn1=foo.ns.${domain}
325 hn2=foobar.ns.${domain}
326 hn3=xyz.${domain}
327 p1=HTTP/$hn1
328 p2=HTTP/$hn2
329 p3=HTTP/$hn3
330 echo "Fetching keytabs for more than one principal"
331 rm -f extracted_keytab*
332 grant dnsname $hn1 foo@${R}
333 grant dnsname $hn2 foo@${R}
334 grant dnsname $hn3 foo@${R}
335 # Note that httpkadmind will first process dNSName q-params, then the spn
336 # q-params.
337 ${kadmin} ext_keytab -k extracted_keytab $p1 ||
338 { echo "Failed to get a keytab for $p1 with kadmin"; exit 1; }
339 ${kadmin} ext_keytab -k extracted_keytab $p3 ||
340 { echo "Failed to get a keytab for $p3 with kadmin"; exit 1; }
341 ${kadmin} ext_keytab -k extracted_keytab $p2 ||
342 { echo "Failed to get a keytab for $p2 with kadmin"; exit 1; }
343 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin ||
344 { echo "Failed to list keytab for multiple principals"; exit 1; }
345 get_keytab "dNSName=${hn1}&spn=${p2}&dNSName=${hn3}" -sf -o "${objdir}/extracted_keytab" ||
346 { echo "Failed to get a keytab for multiple principals with curl"; exit 1; }
347 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest ||
348 { echo "Failed to list keytab for $p"; exit 1; }
349 cmp extracted_keytab.kadmin extracted_keytab.rest ||
350 { echo "Keytabs for $p don't match!"; exit 1; }
351 grep $hn1 extracted_keytab.rest > /dev/null ||
352 { echo "Keytab does not include keys for $p1"; exit 1; }
353 grep $hn2 extracted_keytab.rest > /dev/null ||
354 { echo "Keytab does not include keys for $p2"; exit 1; }
355 grep $hn3 extracted_keytab.rest > /dev/null ||
356 { echo "Keytab does not include keys for $p3"; exit 1; }
358 p=host/foo.ns.${domain}
359 echo "Checking that $p doesn't exist (no namespace for host service)"
360 get_keytab "svc=host&dNSName=foo.ns.${domain}" -sf -o "${objdir}/extracted_keytab.rest" &&
361 { echo "Got a keytab for host/foo.ns.${domain} when not namespaced!"; }
363 echo "Checking that authorization is enforced"
364 revoke
365 get_keytab "dNSName=xyz.${domain}" -sf -o "${objdir}/extracted_keytab" &&
366 { echo "Got a keytab for HTTP/xyz.${domain} when not authorized!"; exit 1; }
367 get_keytab "dNSName=foo.ns.${domain}" -sf -o "${objdir}/extracted_keytab" &&
368 { echo "Got a keytab for HTTP/foo.ns.${domain} when not authorized!"; exit 1; }
370 echo "Checking that host service keys are not served"
371 hn=xyz.${domain}
372 p=host/$hn
373 echo "Fetching keytab for virtual principal $p"
374 rm -f extracted_keytab*
375 grant dnsname $hn foo@${R}
376 get_keytab "service=host&dNSName=xyz.${domain}" -sf -o "${objdir}/extracted_keytab" &&
377 { echo "Got a keytab for $p even though it is a host service!"; exit 1; }
378 get_keytab "spn=host/xyz.${domain}" -sf -o "${objdir}/extracted_keytab" &&
379 { echo "Got a keytab for $p even though it is a host service!"; exit 1; }
380 revoke
382 hn=xyz.${domain}
383 p=HTTP/$hn
384 echo "Checking key rotation for concrete principal $p"
385 rm -f extracted_keytab*
386 grant dnsname $hn foo@${R}
387 get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" ||
388 { echo "Failed to get a keytab for $p with curl"; exit 1; }
389 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest1 ||
390 { echo "Failed to list keytab for $p"; exit 1; }
391 test "$(grep $p extracted_keytab.rest1 | wc -l)" -eq 1 ||
392 { echo "Wrong number of new keys!"; exit 1; }
393 get_keytab "dNSName=${hn}&rotate=true" -sf -o "${objdir}/extracted_keytab" &&
394 { echo "GET succeeded for write operation!"; exit 1; }
395 get_keytab_POST "dNSName=${hn}&rotate=true" -s -o "${objdir}/extracted_keytab" ||
396 { echo "Failed to rotate keys for $p"; exit 1; }
397 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest2 ||
398 { echo "Failed to list keytab for $p"; exit 1; }
399 cmp extracted_keytab.rest1 extracted_keytab.rest2 > /dev/null &&
400 { echo "Keys for $p did not change!"; exit 1; }
401 test "$(grep $p extracted_keytab.rest2 | wc -l)" -eq 2 ||
402 { echo "Wrong number of new keys!"; exit 1; }
404 hn=xyz.${domain}
405 p=HTTP/$hn
406 echo "Checking key rotation w/ revocation for concrete principal $p"
407 rm -f extracted_keytab*
408 grant dnsname $hn foo@${R}
409 get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" ||
410 { echo "Failed to get a keytab for $p with curl"; exit 1; }
411 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest1 ||
412 { echo "Failed to list keytab for $p"; exit 1; }
413 get_keytab "dNSName=${hn}&revoke=true" -sf -o "${objdir}/extracted_keytab" &&
414 { echo "GET succeeded for write operation!"; exit 1; }
415 get_keytab_POST "dNSName=${hn}&revoke=true" -s -o "${objdir}/extracted_keytab" ||
416 { echo "Failed to get a keytab for $p with curl"; exit 1; }
417 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest2 ||
418 { echo "Failed to list keytab for $p"; exit 1; }
419 cmp extracted_keytab.rest1 extracted_keytab.rest2 > /dev/null &&
420 { echo "Keys for $p did not change!"; exit 1; }
421 test "$(grep $p extracted_keytab.rest2 | wc -l)" -eq 1 ||
422 { echo "Wrong number of new keys!"; exit 1; }
424 hn=abc.${domain}
425 p=HTTP/$hn
426 echo "Checking concrete principal creation ($p)"
427 rm -f extracted_keytab
428 grant dnsname $hn foo@${R}
429 get_keytab "dNSName=${hn}&create=true" -sf -o "${objdir}/extracted_keytab" &&
430 { echo "GET succeeded for write operation!"; exit 1; }
431 get_keytab_POST "dNSName=${hn}&create=true" -s -o "${objdir}/extracted_keytab" ||
432 { echo "Failed to get a keytab for $p with curl"; exit 1; }
433 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest ||
434 { echo "Failed to list keytab for $p"; exit 1; }
435 rm -f extracted_keytab
436 ${kadmin} ext_keytab -k extracted_keytab $p ||
437 { echo "Failed to get a keytab for $p with kadmin"; exit 1; }
438 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin ||
439 { echo "Failed to list keytab for $p"; exit 1; }
440 cmp extracted_keytab.kadmin extracted_keytab.rest ||
441 { echo "Keytabs for $p don't match!"; exit 1; }
443 hn=bar.ns.${domain}
444 p=HTTP/$hn
445 echo "Checking materialization of virtual principal ($p)"
446 rm -f extracted_keytab
447 grant dnsname $hn foo@${R}
448 get_keytab "dNSName=${hn}&materialize=true" -sf -o "${objdir}/extracted_keytab" &&
449 { echo "GET succeeded for write operation!"; exit 1; }
450 get_keytab_POST "dNSName=${hn}&materialize=true" -s -o "${objdir}/extracted_keytab" ||
451 { echo "Failed to materialize and get a keytab for $p with curl"; exit 1; }
452 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest ||
453 { echo "Failed to list keytab for $p"; exit 1; }
454 rm -f extracted_keytab
455 ${kadmin} ext_keytab -k extracted_keytab $p ||
456 { echo "Failed to get a keytab for $p with kadmin"; exit 1; }
457 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin ||
458 { echo "Failed to list keytab for $p"; exit 1; }
459 cmp extracted_keytab.kadmin extracted_keytab.rest ||
460 { echo "Keytabs for $p don't match!"; exit 1; }
462 echo "Starting secondary httpkadmind to test HTTP redirection"
463 ${httpkadmind2} --primary-server-uri=http://localhost:$restport \
464 -H $server --local --local-read-only -t --daemon ||
465 { echo "httpkadmind failed to start"; exit 2; }
466 httpkadmind2pid=`getpid httpkadmind`
467 ec=0
469 hn=def.${domain}
470 p=HTTP/$hn
471 restport=$restport2
472 echo "Checking principal creation at secondary yields redirect"
473 rm -f extracted_keytab
474 grant dnsname $hn foo@${R}
475 get_keytab_POST_redir "dNSName=${hn}&create=true" \
476 -s -o "${objdir}/extracted_keytab"
477 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest ||
478 { echo "Failed to list keytab for $p"; exit 1; }
479 rm -f extracted_keytab
480 ${kadmin} ext_keytab -k extracted_keytab $p ||
481 { echo "Failed to get a keytab for $p with kadmin"; exit 1; }
482 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin ||
483 { echo "Failed to list keytab for $p"; exit 1; }
484 cmp extracted_keytab.kadmin extracted_keytab.rest ||
485 { echo "Keytabs for $p don't match!"; exit 1; }
487 echo "killing httpkadmind (${httpkadmindpid} ${httpkadmind2pid})"
488 sh ${leaks_kill} httpkadmind $httpkadmindpid || ec=1
489 sh ${leaks_kill} httpkadmind $httpkadmind2pid || ec=1
490 httpkadmindpid=
491 httpkadmind2pid=
492 test $ec = 1 &&
493 { echo "Error killing httpkadmind instances or memory errors found"; exit 1; }
495 echo "Starting primary kadmind for testing httpkadmind with remote HDB"
496 ${kadmind} ||
497 { echo "Read-write kadmind failed to start"; exit 2; }
498 kadmindpid=`getpid kadmind`
499 echo "Starting secondray (read-only) kadmind for testing httpkadmind with remote HDB"
500 ${kadmind2} ||
501 { echo "Read-only kadmind failed to start"; exit 2; }
502 kadmind2pid=`getpid kadmind`
504 # Make a ccache for use with kadmin(1)
505 $kimpersonate --ticket-flags=initial --ccache=$admincache -k $keytab -t aes128-cts-hmac-sha1-96 \
506 -c httpkadmind/admin@${R} -s kadmin/admin@${R} ||
507 { echo "failed to setup kimpersonate credentials"; exit 2; }
508 $adminklist -t >/dev/null ||
509 { echo "failed to setup kimpersonate credentials"; exit 2; }
512 echo "Making PKINIT certs for KDC"
513 ${hxtool} issue-certificate \
514 --self-signed \
515 --issue-ca \
516 --ca-private-key=FILE:${keyfile} \
517 --subject="CN=CA,DC=test,DC=h5l,DC=se" \
518 --certificate="FILE:ca.crt" || exit 1
519 ${hxtool} request-create \
520 --subject="CN=kdc,DC=test,DC=h5l,DC=se" \
521 --key=FILE:${keyfile2} \
522 req-kdc.der || exit 1
523 ${hxtool} issue-certificate \
524 --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \
525 --type="pkinit-kdc" \
526 --pk-init-principal="krbtgt/TEST.H5L.SE@TEST.H5L.SE" \
527 --req="PKCS10:req-kdc.der" \
528 --certificate="FILE:kdc.crt" || exit 1
529 ${hxtool} request-create \
530 --subject="CN=bar,DC=test,DC=h5l,DC=se" \
531 --key=FILE:${keyfile2} \
532 req-pkinit.der ||
533 { echo "Failed to make CSR for PKINIT client cert"; exit 1; }
534 ${hxtool} issue-certificate \
535 --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \
536 --type="pkinit-client" \
537 --pk-init-principal="host/synthesized.${domain}@$R" \
538 --req="PKCS10:req-pkinit.der" \
539 --lifetime=7d \
540 --certificate="FILE:pkinit-synthetic.crt" ||
541 { echo "Failed to make PKINIT client cert"; exit 1; }
543 echo "Starting kdc needed for httpkadmind authentication to kadmind"
544 ${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; }
545 kdcpid=`getpid kdc`
547 echo "Starting httpkadmind with remote HDBs only"
548 restport=$restport1
549 ${httpkadmind} -H $server -H localhost -t --daemon \
550 --writable-admin-server=$(uname -n):$admport \
551 --read-only-admin-server=$(uname -n):$admport2 \
552 --kadmin-client-name=httpkadmind/admin@${R} \
553 --kadmin-client-keytab=$keytab ||
554 { echo "httpkadmind failed to start"; exit 2; }
555 httpkadmindpid=`getpid httpkadmind`
556 ec=0
558 hn=xyz.${domain}
559 p=HTTP/$hn
560 echo "Fetching keytab for concrete principal $p using remote HDB"
561 rm -f extracted_keytab*
562 grant dnsname $hn httpkadmind/admin@${R}
563 KRB5CCNAME=$admincache ${kadmin} ext_keytab -k extracted_keytab $p ||
564 { echo "Failed to get a keytab for $p with kadmin"; exit 1; }
565 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin ||
566 { echo "Failed to list keytab for $p"; exit 1; }
567 get_keytab "spn=${p}" -sf -o "${objdir}/extracted_keytab" ||
568 { echo "Failed to get a keytab for $p with curl"; exit 1; }
569 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest ||
570 { echo "Failed to list keytab for $p"; exit 1; }
571 cmp extracted_keytab.kadmin extracted_keytab.rest ||
572 { echo "Keytabs for $p don't match!"; exit 1; }
574 hn=xyz.${domain}
575 p=HTTP/$hn
576 echo "Checking key rotation for concrete principal $p using remote HDB"
577 rm -f extracted_keytab*
578 grant dnsname $hn foo@${R}
579 get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" ||
580 { echo "Failed to get a keytab for $p with curl"; exit 1; }
581 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest1 ||
582 { echo "Failed to list keytab for $p"; exit 1; }
583 test "$(grep $p extracted_keytab.rest1 | wc -l)" -eq 1 ||
584 { echo "Wrong number of new keys!"; exit 1; }
585 get_keytab "dNSName=${hn}&rotate=true" -sf -o "${objdir}/extracted_keytab" &&
586 { echo "GET succeeded for write operation!"; exit 1; }
587 get_keytab_POST "dNSName=${hn}&rotate=true" -s -o "${objdir}/extracted_keytab" ||
588 { echo "Failed to rotate keys for $p"; exit 1; }
589 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest2 ||
590 { echo "Failed to list keytab for $p"; exit 1; }
591 cmp extracted_keytab.rest1 extracted_keytab.rest2 > /dev/null &&
592 { echo "Keys for $p did not change!"; exit 1; }
593 test "$(grep $p extracted_keytab.rest2 | wc -l)" -eq 2 ||
594 { echo "Wrong number of new keys!"; exit 1; }
596 sh ${leaks_kill} httpkadmind $httpkadmindpid || ec=1
597 httpkadmindpid=
599 echo "Starting httpkadmind with local read-only HDB and remote read-write HDB"
600 ${httpkadmind} -H $server -H localhost -t --daemon \
601 --local-read-only \
602 --writable-admin-server=$(uname -n):$admport \
603 --kadmin-client-name=httpkadmind/admin@${R} \
604 --kadmin-client-keytab=$keytab ||
605 { echo "httpkadmind failed to start"; exit 2; }
606 httpkadmindpid=`getpid httpkadmind`
607 ec=0
609 hn=xyz.${domain}
610 p=HTTP/$hn
611 echo "Fetching keytab for concrete principal $p using local read-only HDB"
612 rm -f extracted_keytab*
613 grant dnsname $hn httpkadmind/admin@${R}
614 KRB5CCNAME=$admincache ${kadmin} ext_keytab -k extracted_keytab $p ||
615 { echo "Failed to get a keytab for $p with kadmin"; exit 1; }
616 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.kadmin ||
617 { echo "Failed to list keytab for $p"; exit 1; }
618 get_keytab "spn=${p}" -sf -o "${objdir}/extracted_keytab" ||
619 { echo "Failed to get a keytab for $p with curl"; exit 1; }
620 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest ||
621 { echo "Failed to list keytab for $p"; exit 1; }
622 cmp extracted_keytab.kadmin extracted_keytab.rest ||
623 { echo "Keytabs for $p don't match!"; exit 1; }
625 hn=xyz.${domain}
626 p=HTTP/$hn
627 echo "Checking key rotation for concrete principal $p using local read-only HDB and remote HDB"
628 rm -f extracted_keytab*
629 grant dnsname $hn foo@${R}
630 get_keytab "dNSName=${hn}" -sf -o "${objdir}/extracted_keytab" ||
631 { echo "Failed to get a keytab for $p with curl"; exit 1; }
632 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest1 ||
633 { echo "Failed to list keytab for $p"; exit 1; }
634 test "$(grep $p extracted_keytab.rest1 | wc -l)" -eq 2 ||
635 { echo "Wrong number of new keys!"; exit 1; }
636 get_keytab "dNSName=${hn}&rotate=true" -sf -o "${objdir}/extracted_keytab" &&
637 { echo "GET succeeded for write operation!"; exit 1; }
638 get_keytab_POST "dNSName=${hn}&rotate=true" -s -o "${objdir}/extracted_keytab" ||
639 { echo "Failed to rotate keys for $p"; exit 1; }
640 ${ktutil} -k "${objdir}/extracted_keytab" list --keys > extracted_keytab.rest2 ||
641 { echo "Failed to list keytab for $p"; exit 1; }
642 cmp extracted_keytab.rest1 extracted_keytab.rest2 > /dev/null &&
643 { echo "Keys for $p did not change!"; exit 1; }
644 test "$(grep $p extracted_keytab.rest2 | wc -l)" -eq 3 ||
645 { echo "Wrong number of new keys!"; exit 1; }
647 echo "Checking that host services as clients can self-create"
648 hn=synthesized.${domain}
649 p=host/$hn
650 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null &&
651 { echo "Internal error -- $p exists too soon"; exit 1; }
652 ${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \
653 { echo "Failed to kinit with PKINIT client cert"; exit 1; }
654 ${kgetcred2} HTTP/localhost@$R || echo WAT
655 rm -f extracted_keytab*
656 KRB5CCNAME=$cache2 \
657 get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" ||
658 { echo "Failed to create and extract host keys for self"; exit 1; }
659 ${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null ||
660 { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; }
661 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null ||
662 { echo "Failed to create and extract host keys for self"; exit 1; }
664 echo "Checking that host services can't get other host service principals"
665 hn=nonexistent.${domain}
666 p=host/$hn
667 KRB5CCNAME=$cache2 \
668 get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab2" &&
669 { echo "Failed to fail to create and extract host keys for other!"; exit 1; }
670 ${ktutil} -k "${objdir}/extracted_keytab2" list > /dev/null || true
671 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null &&
672 { echo "Failed to fail to create and extract host keys for other!"; exit 1; }
674 echo "Checking that host services can't get keys for themselves and others"
675 hn=synthesized.${domain}
676 p=host/$hn
677 p2=host/nonexistent.${domain}
678 ${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \
679 { echo "Failed to kinit with PKINIT client cert"; exit 1; }
680 ${kgetcred2} HTTP/localhost@$R || echo WAT
681 rm -f extracted_keytab*
682 KRB5CCNAME=$cache2 \
683 get_keytab_POST "spn=$p&spn=$p2&create=true" -s -o "${objdir}/extracted_keytab" &&
684 { echo "Failed to fail to create and extract host keys for other!"; exit 1; }
685 ${ktutil} -k "${objdir}/extracted_keytab2" list > /dev/null || true
686 KRB5CCNAME=$admincache ${kadmin} get -s $p2 >/dev/null &&
687 { echo "Failed to fail to create and extract host keys for other!"; exit 1; }
689 echo "Checking that attributes for new principals can be configured"
690 hn=a-particular-hostname.test.h5l.se
691 p=host/$hn
692 ${hxtool} issue-certificate \
693 --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \
694 --type="pkinit-client" \
695 --pk-init-principal="$p@$R" \
696 --req="PKCS10:req-pkinit.der" \
697 --lifetime=7d \
698 --certificate="FILE:pkinit-synthetic.crt" ||
699 { echo "Failed to make PKINIT client cert"; exit 1; }
700 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null 2>&1 &&
701 { echo "Internal error -- $p exists too soon"; exit 1; }
702 ${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \
703 { echo "Failed to kinit with PKINIT client cert"; exit 1; }
704 ${kgetcred2} HTTP/localhost@$R || echo WAT
705 rm -f extracted_keytab*
706 KRB5CCNAME=$cache2 \
707 get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" ||
708 { echo "Failed to create and extract host keys for self"; exit 1; }
709 ${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null ||
710 { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; }
711 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null ||
712 { echo "Failed to create and extract host keys for self"; exit 1; }
713 KRB5CCNAME=$admincache ${kadmin} get $p |
714 grep 'Attributes:.*ok-as-delegate' > /dev/null ||
715 { echo "Failed to create with configured attributes"; exit 1; }
716 KRB5CCNAME=$admincache ${kadmin} get $p |
717 grep 'Attributes:.*no-auth-data-reqd' > /dev/null ||
718 { echo "Failed to create with configured attributes"; exit 1; }
720 hn=other-hostname.test.h5l.se
721 p=host/$hn
722 ${hxtool} issue-certificate \
723 --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \
724 --type="pkinit-client" \
725 --pk-init-principal="$p@$R" \
726 --req="PKCS10:req-pkinit.der" \
727 --lifetime=7d \
728 --certificate="FILE:pkinit-synthetic.crt" ||
729 { echo "Failed to make PKINIT client cert"; exit 1; }
730 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null 2>&1 &&
731 { echo "Internal error -- $p exists too soon"; exit 1; }
732 ${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \
733 { echo "Failed to kinit with PKINIT client cert"; exit 1; }
734 ${kgetcred2} HTTP/localhost@$R || echo WAT
735 rm -f extracted_keytab*
736 KRB5CCNAME=$cache2 \
737 get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" ||
738 { echo "Failed to create and extract host keys for self"; exit 1; }
739 ${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null ||
740 { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; }
741 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null ||
742 { echo "Failed to create and extract host keys for self"; exit 1; }
743 KRB5CCNAME=$admincache ${kadmin} get $p |
744 grep 'Attributes:.*ok-as-delegate' > /dev/null &&
745 { echo "Create with unexpected attributes"; exit 1; }
746 KRB5CCNAME=$admincache ${kadmin} get $p |
747 grep 'Attributes:.*no-auth-data-reqd' > /dev/null &&
748 { echo "Create with unexpected attributes"; exit 1; }
750 hn=a-server.prod.test.h5l.se
751 p=host/$hn
752 ${hxtool} issue-certificate \
753 --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \
754 --type="pkinit-client" \
755 --pk-init-principal="$p@$R" \
756 --req="PKCS10:req-pkinit.der" \
757 --lifetime=7d \
758 --certificate="FILE:pkinit-synthetic.crt" ||
759 { echo "Failed to make PKINIT client cert"; exit 1; }
760 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null 2>&1 &&
761 { echo "Internal error -- $p exists too soon"; exit 1; }
762 ${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \
763 { echo "Failed to kinit with PKINIT client cert"; exit 1; }
764 ${kgetcred2} HTTP/localhost@$R || echo WAT
765 rm -f extracted_keytab*
766 KRB5CCNAME=$cache2 \
767 get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" ||
768 { echo "Failed to create and extract host keys for self"; exit 1; }
769 ${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null ||
770 { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; }
771 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null ||
772 { echo "Failed to create and extract host keys for self"; exit 1; }
773 KRB5CCNAME=$admincache ${kadmin} get $p |
774 grep 'Attributes:.*ok-as-delegate' > /dev/null ||
775 { echo "Failed to create with configured attributes"; exit 1; }
776 KRB5CCNAME=$admincache ${kadmin} get $p |
777 grep 'Attributes:.*no-auth-data-reqd' > /dev/null ||
778 { echo "Failed to create with configured attributes"; exit 1; }
780 hn=a-host.ns2.test.h5l.se
781 p=host/$hn
782 ${hxtool} issue-certificate \
783 --ca-certificate=FILE:$objdir/ca.crt,${keyfile} \
784 --type="pkinit-client" \
785 --pk-init-principal="$p@$R" \
786 --req="PKCS10:req-pkinit.der" \
787 --lifetime=7d \
788 --certificate="FILE:pkinit-synthetic.crt" ||
789 { echo "Failed to make PKINIT client cert"; exit 1; }
790 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null 2>&1 &&
791 { echo "Internal error -- $p exists too soon"; exit 1; }
792 ${kinit2} -C "FILE:${objdir}/pkinit-synthetic.crt,${keyfile2}" ${p}@${R} || \
793 { echo "Failed to kinit with PKINIT client cert"; exit 1; }
794 ${kgetcred2} HTTP/localhost@$R || echo WAT
795 rm -f extracted_keytab*
796 KRB5CCNAME=$cache2 \
797 get_keytab_POST "spn=$p&create=true" -s -o "${objdir}/extracted_keytab" ||
798 { echo "Failed to create and extract host keys for self"; exit 1; }
799 ${ktutil} -k "${objdir}/extracted_keytab" list > /dev/null ||
800 { echo "Failed to create and extract host keys for self (bogus keytab)"; exit 1; }
801 KRB5CCNAME=$admincache ${kadmin} get -s $p >/dev/null ||
802 { echo "Failed to create and extract host keys for self"; exit 1; }
803 KRB5CCNAME=$admincache ${kadmin} get $p |
804 grep 'Attributes:.*ok-as-delegate' > /dev/null ||
805 { echo "Failed to create with namespace attributes"; exit 1; }
806 KRB5CCNAME=$admincache ${kadmin} get $p |
807 grep 'Attributes:.*no-auth-data-reqd' > /dev/null &&
808 { echo "Create with unexpected attributes"; exit 1; }
810 grep 'Internal error' messages.log &&
811 { echo "Internal errors in log"; exit 1; }
813 sh ${leaks_kill} httpkadmind $httpkadmindpid || ec=1
814 sh ${leaks_kill} kadmind $kadmindpid || ec=1
815 sh ${leaks_kill} kadmind $kadmind2pid || ec=1
816 sh ${leaks_kill} kdc $kdcpid || ec=1
818 if [ $ec = 0 ]; then
819 trap "" EXIT
820 echo "Success"
823 # TODO
825 # - implement and test that we can materialize a principal yet leave it with
826 # virtual keys
827 # - test new key delay? this one is tricky
829 exit $ec