|
Packit |
fd8b60 |
import os
|
|
Packit |
fd8b60 |
import re
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
from k5test import *
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# On macOS with System Integrity Protection enabled, this script hangs
|
|
Packit |
fd8b60 |
# in the wait_for_prop() call after starting the first kpropd process,
|
|
Packit |
fd8b60 |
# most likely due to signal restrictions preventing the listening
|
|
Packit |
fd8b60 |
# child from informing the parent that a full resync was processed.
|
|
Packit |
fd8b60 |
if which('csrutil'):
|
|
Packit |
fd8b60 |
out = subprocess.check_output(['csrutil', 'status'],
|
|
Packit |
fd8b60 |
universal_newlines=True)
|
|
Packit |
fd8b60 |
if 'status: enabled' in out:
|
|
Packit |
fd8b60 |
skip_rest('iprop tests', 'System Integrity Protection is enabled')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Read lines from kpropd output until we are synchronized. Error if
|
|
Packit |
fd8b60 |
# full_expected is true and we didn't see a full propagation or vice
|
|
Packit |
fd8b60 |
# versa.
|
|
Packit |
fd8b60 |
def wait_for_prop(kpropd, full_expected, expected_old, expected_new):
|
|
Packit |
fd8b60 |
output('*** Waiting for sync from kpropd\n')
|
|
Packit |
fd8b60 |
full_seen = sleep_seen = False
|
|
Packit |
fd8b60 |
old_sno = new_sno = -1
|
|
Packit |
fd8b60 |
while True:
|
|
Packit |
fd8b60 |
line = kpropd.stdout.readline()
|
|
Packit |
fd8b60 |
if line == '':
|
|
Packit |
fd8b60 |
fail('kpropd process exited unexpectedly')
|
|
Packit |
fd8b60 |
output('kpropd: ' + line)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
m = re.match(r'Calling iprop_get_updates_1 \(sno=(\d+) ', line)
|
|
Packit |
fd8b60 |
if m:
|
|
Packit |
fd8b60 |
if not full_seen:
|
|
Packit |
fd8b60 |
old_sno = int(m.group(1))
|
|
Packit |
fd8b60 |
# Also record this as the new sno, in case we get back
|
|
Packit |
fd8b60 |
# UPDATE_NIL.
|
|
Packit |
fd8b60 |
new_sno = int(m.group(1))
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
m = re.match(r'Got incremental updates \(sno=(\d+) ', line)
|
|
Packit |
fd8b60 |
if m:
|
|
Packit |
fd8b60 |
new_sno = int(m.group(1))
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if 'KDC is synchronized' in line or 'Incremental updates:' in line:
|
|
Packit |
fd8b60 |
break
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# After a full resync request, these lines could appear in
|
|
Packit |
fd8b60 |
# either order.
|
|
Packit |
fd8b60 |
if 'Waiting for' in line:
|
|
Packit |
fd8b60 |
sleep_seen = True
|
|
Packit |
fd8b60 |
if 'load process for full propagation completed' in line:
|
|
Packit |
fd8b60 |
full_seen = True
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Detect some failure conditions.
|
|
Packit |
fd8b60 |
if 'Still waiting for full resync' in line:
|
|
Packit |
fd8b60 |
fail('kadmind gave consecutive full resyncs')
|
|
Packit |
fd8b60 |
if 'Rejected connection' in line:
|
|
Packit |
fd8b60 |
fail('kpropd rejected kprop connection')
|
|
Packit |
fd8b60 |
if 'get updates failed' in line:
|
|
Packit |
fd8b60 |
fail('iprop_get_updates failed')
|
|
Packit |
fd8b60 |
if 'permission denied' in line:
|
|
Packit |
fd8b60 |
fail('kadmind denied update')
|
|
Packit |
fd8b60 |
if 'error from master' in line or 'error returned from master' in line:
|
|
Packit |
fd8b60 |
fail('kadmind reported error')
|
|
Packit |
fd8b60 |
if 'invalid return' in line:
|
|
Packit |
fd8b60 |
fail('kadmind returned invalid result')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if full_expected and not full_seen:
|
|
Packit |
fd8b60 |
fail('Expected full dump but saw only incremental')
|
|
Packit |
fd8b60 |
if full_seen and not full_expected:
|
|
Packit |
fd8b60 |
fail('Expected incremental prop but saw full dump')
|
|
Packit |
fd8b60 |
if old_sno != expected_old:
|
|
Packit |
fd8b60 |
fail('Expected old serial %d from kpropd sync' % expected_old)
|
|
Packit |
fd8b60 |
if new_sno != expected_new:
|
|
Packit |
fd8b60 |
fail('Expected new serial %d from kpropd sync' % expected_new)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Wait until kpropd is sleeping before continuing, to avoid races.
|
|
Packit |
fd8b60 |
# (This is imperfect since there's there is a short window between
|
|
Packit |
fd8b60 |
# the fprintf and the sleep; kpropd will need design changes to
|
|
Packit |
fd8b60 |
# fix that.)
|
|
Packit |
fd8b60 |
while True:
|
|
Packit |
fd8b60 |
line = kpropd.stdout.readline()
|
|
Packit |
fd8b60 |
output('kpropd: ' + line)
|
|
Packit |
fd8b60 |
if 'Waiting for' in line:
|
|
Packit |
fd8b60 |
break
|
|
Packit |
fd8b60 |
output('*** Sync complete\n')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Verify the output of kproplog against the expected number of
|
|
Packit |
fd8b60 |
# entries, first and last serial number, and a list of principal names
|
|
Packit |
fd8b60 |
# for the update entrires.
|
|
Packit |
fd8b60 |
def check_ulog(num, first, last, entries, env=None):
|
|
Packit |
fd8b60 |
out = realm.run([kproplog], env=env)
|
|
Packit |
fd8b60 |
if 'Number of entries : ' + str(num) + '\n' not in out:
|
|
Packit |
fd8b60 |
fail('Expected %d entries' % num)
|
|
Packit |
fd8b60 |
if last:
|
|
Packit |
fd8b60 |
firststr = first and str(first) or 'None'
|
|
Packit |
fd8b60 |
if 'First serial # : ' + firststr + '\n' not in out:
|
|
Packit |
fd8b60 |
fail('Expected first serial number %d' % first)
|
|
Packit |
fd8b60 |
laststr = last and str(last) or 'None'
|
|
Packit |
fd8b60 |
if 'Last serial # : ' + laststr + '\n' not in out:
|
|
Packit |
fd8b60 |
fail('Expected last serial number %d' % last)
|
|
Packit |
fd8b60 |
assert(len(entries) == num)
|
|
Packit |
fd8b60 |
ser = first - 1
|
|
Packit |
fd8b60 |
entindex = 0
|
|
Packit |
fd8b60 |
for line in out.splitlines():
|
|
Packit |
fd8b60 |
m = re.match(r'\tUpdate serial # : (\d+)$', line)
|
|
Packit |
fd8b60 |
if m:
|
|
Packit |
fd8b60 |
ser = ser + 1
|
|
Packit |
fd8b60 |
if m.group(1) != str(ser):
|
|
Packit |
fd8b60 |
fail('Expected serial number %d in update entry' % ser)
|
|
Packit |
fd8b60 |
m = re.match(r'\tUpdate principal : (.*)$', line)
|
|
Packit |
fd8b60 |
if m:
|
|
Packit |
fd8b60 |
eprinc = entries[ser - first]
|
|
Packit |
fd8b60 |
if eprinc == None:
|
|
Packit |
fd8b60 |
fail('Expected dummy update entry %d' % ser)
|
|
Packit |
fd8b60 |
elif m.group(1) != eprinc:
|
|
Packit |
fd8b60 |
fail('Expected princ %s in update entry %d' % (eprinc, ser))
|
|
Packit |
fd8b60 |
if line == '\tDummy entry':
|
|
Packit |
fd8b60 |
eprinc = entries[ser - first]
|
|
Packit |
fd8b60 |
if eprinc != None:
|
|
Packit |
fd8b60 |
fail('Expected princ %s in update entry %d' % (eprinc, ser))
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# replica1 will receive updates from master, and replica2 will receive
|
|
Packit |
fd8b60 |
# updates from replica1. Because of the awkward way iprop and kprop
|
|
Packit |
fd8b60 |
# port configuration currently works, we need separate config files
|
|
Packit |
fd8b60 |
# for the replica and master sides of replica1, but they use the same
|
|
Packit |
fd8b60 |
# DB and ulog file.
|
|
Packit |
fd8b60 |
conf = {'realms': {'$realm': {'iprop_enable': 'true',
|
|
Packit |
fd8b60 |
'iprop_logfile': '$testdir/db.ulog'}}}
|
|
Packit |
fd8b60 |
conf_rep1 = {'realms': {'$realm': {'iprop_replica_poll': '600',
|
|
Packit |
fd8b60 |
'iprop_logfile': '$testdir/ulog.replica1'}},
|
|
Packit |
fd8b60 |
'dbmodules': {'db': {'database_name': '$testdir/db.replica1'}}}
|
|
Packit |
fd8b60 |
conf_rep1m = {'realms': {'$realm': {'iprop_logfile': '$testdir/ulog.replica1',
|
|
Packit |
fd8b60 |
'iprop_port': '$port8'}},
|
|
Packit |
fd8b60 |
'dbmodules': {'db': {'database_name': '$testdir/db.replica1'}}}
|
|
Packit |
fd8b60 |
conf_rep2 = {'realms': {'$realm': {'iprop_replica_poll': '600',
|
|
Packit |
fd8b60 |
'iprop_logfile': '$testdir/ulog.replica2',
|
|
Packit |
fd8b60 |
'iprop_port': '$port8'}},
|
|
Packit |
fd8b60 |
'dbmodules': {'db': {'database_name': '$testdir/db.replica2'}}}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
conf_foo = {'libdefaults': {'default_realm': 'FOO'},
|
|
Packit |
fd8b60 |
'domain_realm': {hostname: 'FOO'}}
|
|
Packit |
fd8b60 |
conf_rep3 = {'realms': {'$realm': {'iprop_replica_poll': '600',
|
|
Packit |
fd8b60 |
'iprop_logfile': '$testdir/ulog.replica3',
|
|
Packit |
fd8b60 |
'iprop_port': '$port8'},
|
|
Packit |
fd8b60 |
'FOO': {'iprop_logfile': '$testdir/ulog.replica3'}},
|
|
Packit |
fd8b60 |
'dbmodules': {'db': {'database_name': '$testdir/db.replica3'}}}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_conf_rep4 = {'domain_realm': {hostname: 'FOO'}}
|
|
Packit |
fd8b60 |
conf_rep4 = {'realms': {'$realm': {'iprop_replica_poll': '600',
|
|
Packit |
fd8b60 |
'iprop_logfile': '$testdir/ulog.replica4',
|
|
Packit |
fd8b60 |
'iprop_port': '$port8'}},
|
|
Packit |
fd8b60 |
'dbmodules': {'db': {'database_name': '$testdir/db.replica4'}}}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for realm in multidb_realms(kdc_conf=conf, create_user=False,
|
|
Packit |
fd8b60 |
start_kadmind=True):
|
|
Packit |
fd8b60 |
replica1 = realm.special_env('replica1', True, kdc_conf=conf_rep1)
|
|
Packit |
fd8b60 |
replica1m = realm.special_env('replica1m', True, krb5_conf=conf_foo,
|
|
Packit |
fd8b60 |
kdc_conf=conf_rep1m)
|
|
Packit |
fd8b60 |
replica2 = realm.special_env('replica2', True, kdc_conf=conf_rep2)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# A default_realm and domain_realm that do not match the KDC's
|
|
Packit |
fd8b60 |
# realm. The FOO realm iprop_logfile setting is needed to run
|
|
Packit |
fd8b60 |
# kproplog during a replica3 test, since kproplog has no realm
|
|
Packit |
fd8b60 |
# option.
|
|
Packit |
fd8b60 |
replica3 = realm.special_env('replica3', True, krb5_conf=conf_foo,
|
|
Packit |
fd8b60 |
kdc_conf=conf_rep3)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# A default realm and a domain realm map that differ.
|
|
Packit |
fd8b60 |
replica4 = realm.special_env('replica4', True, krb5_conf=krb5_conf_rep4,
|
|
Packit |
fd8b60 |
kdc_conf=conf_rep4)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Define some principal names. pr3 is long enough to cause internal
|
|
Packit |
fd8b60 |
# reallocs, but not long enough to grow the basic ulog entry size.
|
|
Packit |
fd8b60 |
pr1 = 'wakawaka@' + realm.realm
|
|
Packit |
fd8b60 |
pr2 = 'w@' + realm.realm
|
|
Packit |
fd8b60 |
c = 'chocolate-flavored-school-bus'
|
|
Packit |
fd8b60 |
cs = c + '/'
|
|
Packit |
fd8b60 |
pr3 = (cs + cs + cs + cs + cs + cs + cs + cs + cs + cs + cs + cs + c +
|
|
Packit |
fd8b60 |
'@' + realm.realm)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Create the kpropd ACL file.
|
|
Packit |
fd8b60 |
acl_file = os.path.join(realm.testdir, 'kpropd-acl')
|
|
Packit |
fd8b60 |
acl = open(acl_file, 'w')
|
|
Packit |
fd8b60 |
acl.write(realm.host_princ + '\n')
|
|
Packit |
fd8b60 |
acl.close()
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
ulog = os.path.join(realm.testdir, 'db.ulog')
|
|
Packit |
fd8b60 |
if not os.path.exists(ulog):
|
|
Packit |
fd8b60 |
fail('update log not created: ' + ulog)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Create the principal used to authenticate kpropd to kadmind.
|
|
Packit |
fd8b60 |
kiprop_princ = 'kiprop/' + hostname
|
|
Packit |
fd8b60 |
realm.extract_keytab(kiprop_princ, realm.keytab)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Create the initial replica databases.
|
|
Packit |
fd8b60 |
dumpfile = os.path.join(realm.testdir, 'dump')
|
|
Packit |
fd8b60 |
realm.run([kdb5_util, 'dump', dumpfile])
|
|
Packit |
fd8b60 |
realm.run([kdb5_util, 'load', dumpfile], replica1)
|
|
Packit |
fd8b60 |
realm.run([kdb5_util, 'load', dumpfile], replica2)
|
|
Packit |
fd8b60 |
realm.run([kdb5_util, '-r', realm.realm, 'load', dumpfile], replica3)
|
|
Packit |
fd8b60 |
realm.run([kdb5_util, 'load', dumpfile], replica4)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Reinitialize the master ulog so we know exactly what to expect in
|
|
Packit |
fd8b60 |
# it.
|
|
Packit |
fd8b60 |
realm.run([kproplog, '-R'])
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None])
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Make some changes to the master DB.
|
|
Packit |
fd8b60 |
realm.addprinc(pr1)
|
|
Packit |
fd8b60 |
realm.addprinc(pr3)
|
|
Packit |
fd8b60 |
realm.addprinc(pr2)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'modprinc', '-allow_tix', pr2])
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'modprinc', '+allow_tix', pr2])
|
|
Packit |
fd8b60 |
check_ulog(6, 1, 6, [None, pr1, pr3, pr2, pr2, pr2])
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Start kpropd for replica1 and get a full dump from master.
|
|
Packit |
fd8b60 |
mark('propagate M->1 full')
|
|
Packit |
fd8b60 |
kpropd1 = realm.start_kpropd(replica1, ['-d'])
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, True, 1, 6)
|
|
Packit |
fd8b60 |
out = realm.run([kadminl, 'listprincs'], env=replica1)
|
|
Packit |
fd8b60 |
if pr1 not in out or pr2 not in out or pr3 not in out:
|
|
Packit |
fd8b60 |
fail('replica1 does not have all principals from master')
|
|
Packit |
fd8b60 |
check_ulog(1, 6, 6, [None], replica1)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Make a change and check that it propagates incrementally.
|
|
Packit |
fd8b60 |
mark('propagate M->1 incremental')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'modprinc', '-allow_tix', pr2])
|
|
Packit |
fd8b60 |
check_ulog(7, 1, 7, [None, pr1, pr3, pr2, pr2, pr2, pr2])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, False, 6, 7)
|
|
Packit |
fd8b60 |
check_ulog(2, 6, 7, [None, pr2], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr2], env=replica1,
|
|
Packit |
fd8b60 |
expected_msg='Attributes: DISALLOW_ALL_TIX')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Start kadmind -proponly for replica1. (Use the replica1m
|
|
Packit |
fd8b60 |
# environment which defines iprop_port to $port8.)
|
|
Packit |
fd8b60 |
replica1_out_dump_path = os.path.join(realm.testdir, 'dump.replica1.out')
|
|
Packit |
fd8b60 |
replica2_in_dump_path = os.path.join(realm.testdir, 'dump.replica2.in')
|
|
Packit |
fd8b60 |
replica2_kprop_port = str(realm.portbase + 9)
|
|
Packit |
fd8b60 |
kadmind_proponly = realm.start_server([kadmind, '-r', realm.realm,
|
|
Packit |
fd8b60 |
'-nofork', '-proponly',
|
|
Packit |
fd8b60 |
'-W', '-p', kdb5_util,
|
|
Packit |
fd8b60 |
'-K', kprop, '-k',
|
|
Packit |
fd8b60 |
replica2_kprop_port,
|
|
Packit |
fd8b60 |
'-F', replica1_out_dump_path],
|
|
Packit |
fd8b60 |
'starting...', replica1m)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Test similar default_realm and domain_realm map settings with -r realm.
|
|
Packit |
fd8b60 |
mark('propagate 1->3 full')
|
|
Packit |
fd8b60 |
replica3_in_dump_path = os.path.join(realm.testdir, 'dump.replica3.in')
|
|
Packit |
fd8b60 |
kpropd3 = realm.start_server([kpropd, '-d', '-D', '-r', realm.realm, '-P',
|
|
Packit |
fd8b60 |
replica2_kprop_port, '-f',
|
|
Packit |
fd8b60 |
replica3_in_dump_path, '-p', kdb5_util, '-a',
|
|
Packit |
fd8b60 |
acl_file, '-A', hostname], 'ready', replica3)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd3, True, 1, 7)
|
|
Packit |
fd8b60 |
out = realm.run([kadminl, '-r', realm.realm, 'listprincs'], env=replica3)
|
|
Packit |
fd8b60 |
if pr1 not in out or pr2 not in out or pr3 not in out:
|
|
Packit |
fd8b60 |
fail('replica3 does not have all principals from replica1')
|
|
Packit |
fd8b60 |
check_ulog(1, 7, 7, [None], env=replica3)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Test an incremental propagation for the kpropd -r case.
|
|
Packit |
fd8b60 |
mark('propagate M->1->3 incremental')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'modprinc', '-maxlife', '20 minutes', pr1])
|
|
Packit |
fd8b60 |
check_ulog(8, 1, 8, [None, pr1, pr3, pr2, pr2, pr2, pr2, pr1])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, False, 7, 8)
|
|
Packit |
fd8b60 |
check_ulog(3, 6, 8, [None, pr2, pr1], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr1], env=replica1,
|
|
Packit |
fd8b60 |
expected_msg='Maximum ticket life: 0 days 00:20:00')
|
|
Packit |
fd8b60 |
kpropd3.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd3, False, 7, 8)
|
|
Packit |
fd8b60 |
check_ulog(2, 7, 8, [None, pr1], replica3)
|
|
Packit |
fd8b60 |
realm.run([kadminl, '-r', realm.realm, 'getprinc', pr1], env=replica3,
|
|
Packit |
fd8b60 |
expected_msg='Maximum ticket life: 0 days 00:20:00')
|
|
Packit |
fd8b60 |
stop_daemon(kpropd3)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Test dissimilar default_realm and domain_realm map settings (no
|
|
Packit |
fd8b60 |
# -r realm).
|
|
Packit |
fd8b60 |
mark('propagate 1->4 full')
|
|
Packit |
fd8b60 |
replica4_in_dump_path = os.path.join(realm.testdir, 'dump.replica4.in')
|
|
Packit |
fd8b60 |
kpropd4 = realm.start_server([kpropd, '-d', '-D', '-P',
|
|
Packit |
fd8b60 |
replica2_kprop_port, '-f',
|
|
Packit |
fd8b60 |
replica4_in_dump_path, '-p', kdb5_util,
|
|
Packit |
fd8b60 |
'-a', acl_file, '-A', hostname], 'ready',
|
|
Packit |
fd8b60 |
replica4)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd4, True, 1, 8)
|
|
Packit |
fd8b60 |
out = realm.run([kadminl, 'listprincs'], env=replica4)
|
|
Packit |
fd8b60 |
if pr1 not in out or pr2 not in out or pr3 not in out:
|
|
Packit |
fd8b60 |
fail('replica4 does not have all principals from replica1')
|
|
Packit |
fd8b60 |
stop_daemon(kpropd4)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Start kpropd for replica2. The -A option isn't needed since
|
|
Packit |
fd8b60 |
# we're talking to the same host as master (we specify it anyway
|
|
Packit |
fd8b60 |
# to exercise the code), but replica2 defines iprop_port to $port8
|
|
Packit |
fd8b60 |
# so it will talk to replica1. Get a full dump from replica1.
|
|
Packit |
fd8b60 |
mark('propagate 1->2 full')
|
|
Packit |
fd8b60 |
kpropd2 = realm.start_server([kpropd, '-d', '-D', '-P',
|
|
Packit |
fd8b60 |
replica2_kprop_port, '-f',
|
|
Packit |
fd8b60 |
replica2_in_dump_path, '-p', kdb5_util,
|
|
Packit |
fd8b60 |
'-a', acl_file, '-A', hostname], 'ready',
|
|
Packit |
fd8b60 |
replica2)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, True, 1, 8)
|
|
Packit |
fd8b60 |
check_ulog(2, 7, 8, [None, pr1], replica2)
|
|
Packit |
fd8b60 |
out = realm.run([kadminl, 'listprincs'], env=replica1)
|
|
Packit |
fd8b60 |
if pr1 not in out or pr2 not in out or pr3 not in out:
|
|
Packit |
fd8b60 |
fail('replica2 does not have all principals from replica1')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Make another change and check that it propagates incrementally
|
|
Packit |
fd8b60 |
# to both replicas.
|
|
Packit |
fd8b60 |
mark('propagate M->1->2 incremental')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'modprinc', '-maxrenewlife', '22 hours', pr1])
|
|
Packit |
fd8b60 |
check_ulog(9, 1, 9, [None, pr1, pr3, pr2, pr2, pr2, pr2, pr1, pr1])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, False, 8, 9)
|
|
Packit |
fd8b60 |
check_ulog(4, 6, 9, [None, pr2, pr1, pr1], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr1], env=replica1,
|
|
Packit |
fd8b60 |
expected_msg='Maximum renewable life: 0 days 22:00:00\n')
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, False, 8, 9)
|
|
Packit |
fd8b60 |
check_ulog(3, 7, 9, [None, pr1, pr1], replica2)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr1], env=replica2,
|
|
Packit |
fd8b60 |
expected_msg='Maximum renewable life: 0 days 22:00:00\n')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Reset the ulog on replica1 to force a full resync from master.
|
|
Packit |
fd8b60 |
# The resync will use the old dump file and then propagate
|
|
Packit |
fd8b60 |
# changes. replica2 should still be in sync with replica1 after
|
|
Packit |
fd8b60 |
# the resync, so make sure it doesn't take a full resync.
|
|
Packit |
fd8b60 |
mark('propagate M->1->2 full')
|
|
Packit |
fd8b60 |
realm.run([kproplog, '-R'], replica1)
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica1)
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, True, 1, 9)
|
|
Packit |
fd8b60 |
check_ulog(4, 6, 9, [None, pr2, pr1, pr1], replica1)
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, False, 9, 9)
|
|
Packit |
fd8b60 |
check_ulog(3, 7, 9, [None, pr1, pr1], replica2)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Make another change and check that it propagates incrementally to
|
|
Packit |
fd8b60 |
# both replicas.
|
|
Packit |
fd8b60 |
mark('propagate M->1->2 incremental (after reset)')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'modprinc', '+allow_tix', pr2])
|
|
Packit |
fd8b60 |
check_ulog(10, 1, 10, [None, pr1, pr3, pr2, pr2, pr2, pr2, pr1, pr1, pr2])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, False, 9, 10)
|
|
Packit |
fd8b60 |
check_ulog(5, 6, 10, [None, pr2, pr1, pr1, pr2], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr2], env=replica1,
|
|
Packit |
fd8b60 |
expected_msg='Attributes:\n')
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, False, 9, 10)
|
|
Packit |
fd8b60 |
check_ulog(4, 7, 10, [None, pr1, pr1, pr2], replica2)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr2], env=replica2,
|
|
Packit |
fd8b60 |
expected_msg='Attributes:\n')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Create a policy and check that it propagates via full resync.
|
|
Packit |
fd8b60 |
mark('propagate M->1->2 full (new policy)')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'addpol', '-minclasses', '2', 'testpol'])
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, True, 10, 1)
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getpol', 'testpol'], env=replica1,
|
|
Packit |
fd8b60 |
expected_msg='Minimum number of password character classes: 2')
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, True, 10, 1)
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica2)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getpol', 'testpol'], env=replica2,
|
|
Packit |
fd8b60 |
expected_msg='Minimum number of password character classes: 2')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Modify the policy and test that it also propagates via full resync.
|
|
Packit |
fd8b60 |
mark('propagate M->1->2 full (policy change)')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'modpol', '-minlength', '17', 'testpol'])
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, True, 1, 1)
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getpol', 'testpol'], env=replica1,
|
|
Packit |
fd8b60 |
expected_msg='Minimum password length: 17')
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, True, 1, 1)
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica2)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getpol', 'testpol'], env=replica2,
|
|
Packit |
fd8b60 |
expected_msg='Minimum password length: 17')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Delete the policy and test that it propagates via full resync.
|
|
Packit |
fd8b60 |
mark('propgate M->1->2 full (policy delete)')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'delpol', 'testpol'])
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, True, 1, 1)
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getpol', 'testpol'], env=replica1, expected_code=1,
|
|
Packit |
fd8b60 |
expected_msg='Policy does not exist')
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, True, 1, 1)
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica2)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getpol', 'testpol'], env=replica2, expected_code=1,
|
|
Packit |
fd8b60 |
expected_msg='Policy does not exist')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Modify a principal on the master and test that it propagates
|
|
Packit |
fd8b60 |
# incrementally.
|
|
Packit |
fd8b60 |
mark('propagate M->1->2 incremental (after policy changes)')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'modprinc', '-maxlife', '10 minutes', pr1])
|
|
Packit |
fd8b60 |
check_ulog(2, 1, 2, [None, pr1])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, False, 1, 2)
|
|
Packit |
fd8b60 |
check_ulog(2, 1, 2, [None, pr1], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr1], env=replica1,
|
|
Packit |
fd8b60 |
expected_msg='Maximum ticket life: 0 days 00:10:00')
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, False, 1, 2)
|
|
Packit |
fd8b60 |
check_ulog(2, 1, 2, [None, pr1], replica2)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr1], env=replica2,
|
|
Packit |
fd8b60 |
expected_msg='Maximum ticket life: 0 days 00:10:00')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Delete a principal and test that it propagates incrementally.
|
|
Packit |
fd8b60 |
mark('propagate M->1->2 incremental (princ delete)')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'delprinc', pr3])
|
|
Packit |
fd8b60 |
check_ulog(3, 1, 3, [None, pr1, pr3])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, False, 2, 3)
|
|
Packit |
fd8b60 |
check_ulog(3, 1, 3, [None, pr1, pr3], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr3], env=replica1, expected_code=1,
|
|
Packit |
fd8b60 |
expected_msg='Principal does not exist')
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, False, 2, 3)
|
|
Packit |
fd8b60 |
check_ulog(3, 1, 3, [None, pr1, pr3], replica2)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr3], env=replica2, expected_code=1,
|
|
Packit |
fd8b60 |
expected_msg='Principal does not exist')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Rename a principal and test that it propagates incrementally.
|
|
Packit |
fd8b60 |
mark('propagate M->1->2 incremental (princ rename)')
|
|
Packit |
fd8b60 |
renpr = "quacked@" + realm.realm
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'renprinc', pr1, renpr])
|
|
Packit |
fd8b60 |
check_ulog(6, 1, 6, [None, pr1, pr3, renpr, pr1, renpr])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, False, 3, 6)
|
|
Packit |
fd8b60 |
check_ulog(6, 1, 6, [None, pr1, pr3, renpr, pr1, renpr], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr1], env=replica1, expected_code=1,
|
|
Packit |
fd8b60 |
expected_msg='Principal does not exist')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', renpr], env=replica1)
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, False, 3, 6)
|
|
Packit |
fd8b60 |
check_ulog(6, 1, 6, [None, pr1, pr3, renpr, pr1, renpr], replica2)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr1], env=replica2, expected_code=1,
|
|
Packit |
fd8b60 |
expected_msg='Principal does not exist')
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', renpr], env=replica2)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
pr1 = renpr
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Reset the ulog on the master to force a full resync.
|
|
Packit |
fd8b60 |
mark('propagate M->1->2 full (ulog reset)')
|
|
Packit |
fd8b60 |
realm.run([kproplog, '-R'])
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None])
|
|
Packit |
fd8b60 |
kpropd1.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd1, True, 6, 1)
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica1)
|
|
Packit |
fd8b60 |
kpropd2.send_signal(signal.SIGUSR1)
|
|
Packit |
fd8b60 |
wait_for_prop(kpropd2, True, 6, 1)
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica2)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Stop the kprop daemons so we can test kpropd -t.
|
|
Packit |
fd8b60 |
realm.stop_kpropd(kpropd1)
|
|
Packit |
fd8b60 |
stop_daemon(kpropd2)
|
|
Packit |
fd8b60 |
stop_daemon(kadmind_proponly)
|
|
Packit |
fd8b60 |
mark('kpropd -t')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Test the case where no updates are needed.
|
|
Packit |
fd8b60 |
out = realm.run_kpropd_once(replica1, ['-d'])
|
|
Packit |
fd8b60 |
if 'KDC is synchronized' not in out:
|
|
Packit |
fd8b60 |
fail('Expected synchronized from kpropd -t')
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica1)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Make a change on the master and fetch it incrementally.
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'modprinc', '-maxlife', '5 minutes', pr1])
|
|
Packit |
fd8b60 |
check_ulog(2, 1, 2, [None, pr1])
|
|
Packit |
fd8b60 |
out = realm.run_kpropd_once(replica1, ['-d'])
|
|
Packit |
fd8b60 |
if 'Got incremental updates (sno=2 ' not in out:
|
|
Packit |
fd8b60 |
fail('Expected full dump and synchronized from kpropd -t')
|
|
Packit |
fd8b60 |
check_ulog(2, 1, 2, [None, pr1], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getprinc', pr1], env=replica1,
|
|
Packit |
fd8b60 |
expected_msg='Maximum ticket life: 0 days 00:05:00')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# Propagate a policy change via full resync.
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'addpol', '-minclasses', '3', 'testpol'])
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None])
|
|
Packit |
fd8b60 |
out = realm.run_kpropd_once(replica1, ['-d'])
|
|
Packit |
fd8b60 |
if ('Full propagation transfer finished' not in out or
|
|
Packit |
fd8b60 |
'KDC is synchronized' not in out):
|
|
Packit |
fd8b60 |
fail('Expected full dump and synchronized from kpropd -t')
|
|
Packit |
fd8b60 |
check_ulog(1, 1, 1, [None], replica1)
|
|
Packit |
fd8b60 |
realm.run([kadminl, 'getpol', 'testpol'], env=replica1,
|
|
Packit |
fd8b60 |
expected_msg='Minimum number of password character classes: 3')
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
success('iprop tests')
|