1from k5test import * 2import os 3 4realm = K5Realm(create_host=False, create_user=False) 5 6def make_client(name): 7 global realm 8 realm.addprinc(name, password(name)) 9 ccache = os.path.join(realm.testdir, 10 'kadmin_ccache_' + name.replace('/', '_')) 11 realm.kinit(name, password(name), 12 flags=['-S', 'kadmin/admin', '-c', ccache]) 13 return ccache 14 15def kadmin_as(client, query, **kwargs): 16 global realm 17 return realm.run([kadmin, '-c', client] + query, **kwargs) 18 19all_add = make_client('all_add') 20all_changepw = make_client('all_changepw') 21all_delete = make_client('all_delete') 22all_inquire = make_client('all_inquire') 23all_list = make_client('all_list') 24all_modify = make_client('all_modify') 25all_rename = make_client('all_rename') 26all_wildcard = make_client('all_wildcard') 27all_extract = make_client('all_extract') 28all_alias = make_client('all_alias') 29some_add = make_client('some_add') 30some_changepw = make_client('some_changepw') 31some_delete = make_client('some_delete') 32some_inquire = make_client('some_inquire') 33some_modify = make_client('some_modify') 34some_rename = make_client('some_rename') 35some_extract = make_client('some_extract') 36some_alias = make_client('some_alias') 37restricted_add = make_client('restricted_add') 38restricted_modify = make_client('restricted_modify') 39restricted_rename = make_client('restricted_rename') 40restricted_alias = make_client('restricted_alias') 41wctarget = make_client('wctarget') 42admin = make_client('user/admin') 43none = make_client('none') 44restrictions = make_client('restrictions') 45onetwothreefour = make_client('one/two/three/four') 46 47realm.run([kadminl, 'alias', 'aliastonone', 'none']) 48aliastonone = os.path.join(realm.testdir, 'kadmin_ccache_aliastonone') 49realm.kinit('aliastonone', password('none'), 50 flags=['-S', 'kadmin/admin', '-c', aliastonone]) 51 52realm.run([kadminl, 'alias', 'aliastounselected', 'unselected']) 53realm.run([kadminl, 'alias', 'aliastoselected', 'selected']) 54 55realm.run([kadminl, 'addpol', '-minlife', '1 day', 'minlife']) 56 57f = open(os.path.join(realm.testdir, 'acl'), 'w') 58f.write(''' 59all_add a 60all_changepw c 61all_delete d 62all_inquire i 63all_list l 64all_modify im 65all_rename ad 66all_wildcard x 67all_extract ie 68all_alias am 69some_add a selected 70some_add a aliastounselected 71some_changepw c selected 72some_changepw c aliastounselected 73some_delete d selected 74some_delete d aliastounselected 75some_inquire i selected 76some_inquire i aliastounselected 77some_modify im selected 78some_modify im aliastounselected 79some_extract ie selected 80some_extract ie aliastounselected 81some_rename d from 82some_rename a to 83some_alias a aliasname 84some_alias m canon 85restricted_add a * +preauth 86restricted_modify im * +preauth 87restricted_rename ad * +preauth 88restricted_alias ai * +preauth 89 90*/* d *2/*1 91# The next line is a regression test for #8154; it is not used directly. 92one/*/*/five l 93*/two/*/* d *3/*1/*2 94*/admin a 95wctarget a wild/* 96restrictions a type1 -policy minlife 97restrictions a type2 -clearpolicy 98restrictions a type3 -maxlife 1h -maxrenewlife 2h 99''') 100f.close() 101 102realm.start_kadmind() 103 104# cpw can generate four different RPC calls depending on options. 105realm.addprinc('selected', 'oldpw') 106realm.addprinc('unselected', 'oldpw') 107for pw in (['-pw', 'newpw'], ['-randkey']): 108 for ks in ([], ['-e', 'aes256-cts']): 109 mark('cpw: %s %s' % (repr(pw), repr(ks))) 110 args = pw + ks 111 kadmin_as(all_changepw, ['cpw'] + args + ['unselected']) 112 kadmin_as(some_changepw, ['cpw'] + args + ['selected']) 113 msg = "Operation requires ``change-password'' privilege" 114 kadmin_as(none, ['cpw'] + args + ['selected'], expected_code=1, 115 expected_msg=msg) 116 kadmin_as(some_changepw, ['cpw'] + args + ['unselected'], 117 expected_code=1, expected_msg=msg) 118 # Verify that the ACL check is canonicalized. 119 kadmin_as(some_changepw, ['cpw'] + args + ['aliastounselected'], 120 expected_code=1, expected_msg=msg) 121 kadmin_as(some_changepw, ['cpw'] + args + ['aliastoselected']) 122 kadmin_as(none, ['cpw'] + args + ['none']) 123 kadmin_as(aliastonone, ['cpw'] + args + ['none'], 124 expected_code=1, expected_msg=msg) 125 realm.run([kadminl, 'modprinc', '-policy', 'minlife', 'none']) 126 msg = "Current password's minimum life has not expired" 127 kadmin_as(none, ['cpw'] + args + ['none'], expected_code=1, 128 expected_msg=msg) 129 realm.run([kadminl, 'modprinc', '-clearpolicy', 'none']) 130realm.run([kadminl, 'delprinc', 'selected']) 131realm.run([kadminl, 'delprinc', 'unselected']) 132 133mark('addpol') 134kadmin_as(all_add, ['addpol', 'policy']) 135realm.run([kadminl, 'delpol', 'policy']) 136kadmin_as(none, ['addpol', 'policy'], expected_code=1, 137 expected_msg="Operation requires ``add'' privilege") 138 139# addprinc can generate two different RPC calls depending on options. 140for ks in ([], ['-e', 'aes256-cts']): 141 mark('addprinc: %s' % repr(ks)) 142 args = ['-pw', 'pw'] + ks 143 kadmin_as(all_add, ['addprinc'] + args + ['unselected']) 144 realm.run([kadminl, 'delprinc', 'unselected']) 145 kadmin_as(some_add, ['addprinc'] + args + ['selected']) 146 realm.run([kadminl, 'delprinc', 'selected']) 147 kadmin_as(restricted_add, ['addprinc'] + args + ['unselected']) 148 realm.run([kadminl, 'getprinc', 'unselected'], 149 expected_msg='REQUIRES_PRE_AUTH') 150 realm.run([kadminl, 'delprinc', 'unselected']) 151 kadmin_as(none, ['addprinc'] + args + ['selected'], expected_code=1, 152 expected_msg="Operation requires ``add'' privilege") 153 kadmin_as(some_add, ['addprinc'] + args + ['unselected'], expected_code=1, 154 expected_msg="Operation requires ``add'' privilege") 155 # Verify that the ACL check isn't canonicalized. (We need the alias 156 # to resolve or we will overwrite it, currently.) 157 realm.addprinc('unselected') 158 kadmin_as(some_add, ['addprinc'] + args + ['aliastounselected'], 159 expected_code=1, expected_msg='already exists') 160 realm.run([kadminl, 'delprinc', 'unselected']) 161 162mark('delprinc') 163realm.addprinc('unselected', 'pw') 164kadmin_as(all_delete, ['delprinc', 'unselected']) 165realm.addprinc('selected', 'pw') 166kadmin_as(some_delete, ['delprinc', 'selected']) 167realm.addprinc('unselected', 'pw') 168kadmin_as(none, ['delprinc', 'unselected'], expected_code=1, 169 expected_msg="Operation requires ``delete'' privilege") 170kadmin_as(some_delete, ['delprinc', 'unselected'], expected_code=1, 171 expected_msg="Operation requires ``delete'' privilege") 172# Verify that the ACL check isn't canonicalized. 173kadmin_as(some_delete, ['delprinc', 'aliastounselected']) 174realm.run([kadminl, 'alias', 'aliastounselected', 'unselected']) 175kadmin_as(some_delete, ['delprinc', 'aliastoselected'], expected_code=1, 176 expected_msg="Operation requires ``delete'' privilege") 177realm.run([kadminl, 'delprinc', 'unselected']) 178 179mark('getpol') 180kadmin_as(all_inquire, ['getpol', 'minlife'], expected_msg='Policy: minlife') 181kadmin_as(none, ['getpol', 'minlife'], expected_code=1, 182 expected_msg="Operation requires ``get'' privilege") 183realm.run([kadminl, 'modprinc', '-policy', 'minlife', 'none']) 184kadmin_as(none, ['getpol', 'minlife'], expected_msg='Policy: minlife') 185realm.run([kadminl, 'modprinc', '-clearpolicy', 'none']) 186 187mark('getprinc') 188realm.addprinc('selected', 'pw') 189realm.addprinc('unselected', 'pw') 190kadmin_as(all_inquire, ['getprinc', 'unselected'], 191 expected_msg='Principal: unselected@KRBTEST.COM') 192kadmin_as(some_inquire, ['getprinc', 'selected'], 193 expected_msg='Principal: selected@KRBTEST.COM') 194kadmin_as(none, ['getprinc', 'selected'], expected_code=1, 195 expected_msg="Operation requires ``get'' privilege") 196kadmin_as(some_inquire, ['getprinc', 'unselected'], expected_code=1, 197 expected_msg="Operation requires ``get'' privilege") 198# Verify that the ACL check is canonicalized. 199kadmin_as(some_inquire, ['getprinc', 'aliastounselected'], expected_code=1, 200 expected_msg="Operation requires ``get'' privilege") 201kadmin_as(some_inquire, ['getprinc', 'aliastoselected'], 202 expected_msg='Principal: selected@KRBTEST.COM') 203kadmin_as(none, ['getprinc', 'none'], 204 expected_msg='Principal: none@KRBTEST.COM') 205realm.run([kadminl, 'delprinc', 'selected']) 206realm.run([kadminl, 'delprinc', 'unselected']) 207 208mark('listprincs') 209kadmin_as(all_list, ['listprincs'], expected_msg='K/M@KRBTEST.COM') 210kadmin_as(none, ['listprincs'], expected_code=1, 211 expected_msg="Operation requires ``list'' privilege") 212 213mark('getstrs') 214realm.addprinc('selected', 'pw') 215realm.addprinc('unselected', 'pw') 216realm.run([kadminl, 'setstr', 'selected', 'key', 'value']) 217realm.run([kadminl, 'setstr', 'unselected', 'key', 'value']) 218kadmin_as(all_inquire, ['getstrs', 'unselected'], expected_msg='key: value') 219kadmin_as(some_inquire, ['getstrs', 'selected'], expected_msg='key: value') 220kadmin_as(none, ['getstrs', 'selected'], expected_code=1, 221 expected_msg="Operation requires ``get'' privilege") 222kadmin_as(some_inquire, ['getstrs', 'unselected'], expected_code=1, 223 expected_msg="Operation requires ``get'' privilege") 224# Verify that the ACL check is canonicalized. 225kadmin_as(some_inquire, ['getstrs', 'aliastounselected'], expected_code=1, 226 expected_msg="Operation requires ``get'' privilege") 227kadmin_as(some_inquire, ['getstrs', 'aliastoselected'], 228 expected_msg='key: value') 229kadmin_as(none, ['getstrs', 'none'], expected_msg='(No string attributes.)') 230realm.run([kadminl, 'delprinc', 'selected']) 231realm.run([kadminl, 'delprinc', 'unselected']) 232 233mark('modpol') 234out = kadmin_as(all_modify, ['modpol', '-maxlife', '1 hour', 'policy'], 235 expected_code=1) 236if 'Operation requires' in out: 237 fail('modpol success (acl)') 238kadmin_as(none, ['modpol', '-maxlife', '1 hour', 'policy'], expected_code=1, 239 expected_msg="Operation requires ``modify'' privilege") 240 241mark('modprinc') 242realm.addprinc('selected', 'pw') 243realm.addprinc('unselected', 'pw') 244kadmin_as(all_modify, ['modprinc', '-maxlife', '1 hour', 'unselected']) 245kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'selected']) 246kadmin_as(restricted_modify, ['modprinc', '-maxlife', '1 hour', 'unselected']) 247realm.run([kadminl, 'getprinc', 'unselected'], 248 expected_msg='REQUIRES_PRE_AUTH') 249kadmin_as(all_inquire, ['modprinc', '-maxlife', '1 hour', 'selected'], 250 expected_code=1, 251 expected_msg="Operation requires ``modify'' privilege") 252kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'unselected'], 253 expected_code=1, expected_msg='Operation requires') 254# Verify that the ACL check is canonicalized. 255kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'aliastounselected'], 256 expected_code=1, expected_msg='Operation requires') 257kadmin_as(some_modify, ['modprinc', '-maxlife', '2 hours', 'aliastoselected']) 258realm.run([kadminl, 'delprinc', 'selected']) 259realm.run([kadminl, 'delprinc', 'unselected']) 260 261mark('purgekeys') 262realm.addprinc('selected', 'pw') 263realm.addprinc('unselected', 'pw') 264kadmin_as(all_modify, ['purgekeys', 'unselected']) 265kadmin_as(some_modify, ['purgekeys', 'selected']) 266kadmin_as(none, ['purgekeys', 'selected'], expected_code=1, 267 expected_msg="Operation requires ``modify'' privilege") 268kadmin_as(some_modify, ['purgekeys', 'unselected'], expected_code=1, 269 expected_msg="Operation requires ``modify'' privilege") 270# Verify that the ACL check is canonicalized. 271kadmin_as(some_modify, ['purgekeys', 'aliastounselected'], expected_code=1, 272 expected_msg="Operation requires ``modify'' privilege") 273kadmin_as(some_modify, ['purgekeys', 'aliastoselected']) 274kadmin_as(none, ['purgekeys', 'none']) 275realm.run([kadminl, 'delprinc', 'selected']) 276realm.run([kadminl, 'delprinc', 'unselected']) 277 278mark('renprinc') 279realm.addprinc('from', 'pw') 280kadmin_as(all_rename, ['renprinc', 'from', 'to']) 281realm.run([kadminl, 'renprinc', 'to', 'from']) 282kadmin_as(some_rename, ['renprinc', 'from', 'to']) 283realm.run([kadminl, 'renprinc', 'to', 'from']) 284kadmin_as(all_add, ['renprinc', 'from', 'to'], expected_code=1, 285 expected_msg="Insufficient authorization for operation") 286kadmin_as(all_delete, ['renprinc', 'from', 'to'], expected_code=1, 287 expected_msg="Insufficient authorization for operation") 288kadmin_as(some_rename, ['renprinc', 'from', 'notto'], expected_code=1, 289 expected_msg="Insufficient authorization for operation") 290realm.run([kadminl, 'renprinc', 'from', 'notfrom']) 291kadmin_as(some_rename, ['renprinc', 'notfrom', 'to'], expected_code=1, 292 expected_msg="Insufficient authorization for operation") 293# Verify that the ACL check isn't canonicalized. 294realm.run([kadminl, 'alias', 'aliastofrom', 'from']) 295realm.run([kadminl, 'alias', 'aliastoto', 'to']) 296kadmin_as(some_rename, ['renprinc', 'aliastofrom', 'to'], expected_code=1, 297 expected_msg="Insufficient authorization for operation") 298kadmin_as(some_rename, ['renprinc', 'from', 'aliastoto'], expected_code=1, 299 expected_msg="Insufficient authorization for operation") 300realm.run([kadminl, 'delprinc', 'aliastofrom']) 301realm.run([kadminl, 'delprinc', 'aliastoto']) 302kadmin_as(restricted_rename, ['renprinc', 'notfrom', 'to'], expected_code=1, 303 expected_msg="Insufficient authorization for operation") 304realm.run([kadminl, 'delprinc', 'notfrom']) 305 306mark('setstr') 307realm.addprinc('selected', 'pw') 308realm.addprinc('unselected', 'pw') 309kadmin_as(all_modify, ['setstr', 'unselected', 'key', 'value']) 310kadmin_as(some_modify, ['setstr', 'selected', 'key', 'value']) 311kadmin_as(none, ['setstr', 'selected', 'key', 'value'], expected_code=1, 312 expected_msg="Operation requires ``modify'' privilege") 313kadmin_as(some_modify, ['setstr', 'unselected', 'key', 'value'], 314 expected_code=1, expected_msg='Operation requires') 315# Verify that the ACL check is canonicalized. 316kadmin_as(some_modify, ['setstr', 'aliastounselected', 'key', 'value'], 317 expected_code=1, expected_msg='Operation requires') 318kadmin_as(some_modify, ['setstr', 'aliastoselected', 'key', 'value']) 319realm.run([kadminl, 'delprinc', 'selected']) 320realm.run([kadminl, 'delprinc', 'unselected']) 321 322mark('addprinc/delprinc (wildcard)') 323kadmin_as(admin, ['addprinc', '-pw', 'pw', 'anytarget']) 324realm.run([kadminl, 'delprinc', 'anytarget']) 325kadmin_as(wctarget, ['addprinc', '-pw', 'pw', 'wild/card']) 326realm.run([kadminl, 'delprinc', 'wild/card']) 327kadmin_as(wctarget, ['addprinc', '-pw', 'pw', 'wild/card/extra'], 328 expected_code=1, expected_msg='Operation requires') 329realm.addprinc('admin/user', 'pw') 330kadmin_as(admin, ['delprinc', 'admin/user']) 331kadmin_as(admin, ['delprinc', 'none'], expected_code=1, 332 expected_msg='Operation requires') 333realm.addprinc('four/one/three', 'pw') 334kadmin_as(onetwothreefour, ['delprinc', 'four/one/three']) 335 336mark('addprinc (restrictions)') 337kadmin_as(restrictions, ['addprinc', '-pw', 'pw', 'type1']) 338realm.run([kadminl, 'getprinc', 'type1'], expected_msg='Policy: minlife') 339realm.run([kadminl, 'delprinc', 'type1']) 340kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-policy', 'minlife', 341 'type2']) 342realm.run([kadminl, 'getprinc', 'type2'], expected_msg='Policy: [none]') 343realm.run([kadminl, 'delprinc', 'type2']) 344kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-maxlife', '1 minute', 345 'type3']) 346out = realm.run([kadminl, 'getprinc', 'type3']) 347if ('Maximum ticket life: 0 days 00:01:00' not in out or 348 'Maximum renewable life: 0 days 02:00:00' not in out): 349 fail('restriction (maxlife low, maxrenewlife unspec)') 350realm.run([kadminl, 'delprinc', 'type3']) 351kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-maxrenewlife', '1 day', 352 'type3']) 353realm.run([kadminl, 'getprinc', 'type3'], 354 expected_msg='Maximum renewable life: 0 days 02:00:00') 355 356mark('extract') 357realm.addprinc('selected') 358realm.addprinc('unselected') 359realm.run([kadminl, 'addprinc', '-pw', 'pw', 'extractkeys']) 360msg = "Operation requires ``extract-keys'' privilege" 361kadmin_as(all_wildcard, ['ktadd', '-norandkey', 'extractkeys'], 362 expected_code=1, expected_msg=msg) 363kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys']) 364realm.kinit('extractkeys', flags=['-k']) 365kadmin_as(some_extract, ['ktadd', '-norandkey', 'selected']) 366kadmin_as(some_extract, ['ktadd', '-norandkey', 'unselected'], expected_code=1, 367 expected_msg=msg) 368# Verify that the ACL check is canonicalized. 369kadmin_as(some_extract, ['ktadd', '-norandkey', 'aliastounselected'], 370 expected_code=1, expected_msg=msg) 371kadmin_as(some_extract, ['ktadd', '-norandkey', 'aliastoselected']) 372os.remove(realm.keytab) 373realm.run([kadminl, 'delprinc', 'selected']) 374realm.run([kadminl, 'delprinc', 'unselected']) 375 376mark('lockdown_keys') 377kadmin_as(all_modify, ['modprinc', '+lockdown_keys', 'extractkeys']) 378kadmin_as(all_changepw, ['cpw', '-pw', 'newpw', 'extractkeys'], 379 expected_code=1, 380 expected_msg="Operation requires ``change-password'' privilege") 381kadmin_as(all_changepw, ['cpw', '-randkey', 'extractkeys']) 382kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'], expected_code=1, 383 expected_msg="Operation requires ``extract-keys'' privilege") 384kadmin_as(all_delete, ['delprinc', 'extractkeys'], expected_code=1, 385 expected_msg="Operation requires ``delete'' privilege") 386kadmin_as(all_rename, ['renprinc', 'extractkeys', 'renamedprinc'], 387 expected_code=1, 388 expected_msg="Operation requires ``delete'' privilege") 389kadmin_as(all_modify, ['modprinc', '-lockdown_keys', 'extractkeys'], 390 expected_code=1, 391 expected_msg="Operation requires ``modify'' privilege") 392realm.run([kadminl, 'modprinc', '-lockdown_keys', 'extractkeys']) 393kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys']) 394realm.kinit('extractkeys', flags=['-k']) 395os.remove(realm.keytab) 396 397mark('alias') 398kadmin_as(all_alias, ['alias', 'aliasname', 'canon']) 399realm.run([kadminl, 'delprinc', 'aliasname']) 400kadmin_as(some_alias, ['alias', 'aliasname', 'canon']) 401realm.run([kadminl, 'delprinc', 'aliasname']) 402kadmin_as(all_add, ['alias', 'aliasname', 'canon'], expected_code=1, 403 expected_msg="Insufficient authorization for operation") 404kadmin_as(all_inquire, ['alias', 'aliasname', 'canon'], expected_code=1, 405 expected_msg="Insufficient authorization for operation") 406kadmin_as(some_alias, ['alias', 'aliasname', 'notcanon'], expected_code=1, 407 expected_msg="Insufficient authorization for operation") 408kadmin_as(some_alias, ['alias', 'notaliasname', 'canon'], expected_code=1, 409 expected_msg="Insufficient authorization for operation") 410kadmin_as(restricted_alias, ['alias', 'aliasname', 'canon'], expected_code=1, 411 expected_msg="Insufficient authorization for operation") 412 413# Verify that self-service key changes require an initial ticket. 414mark('self-service initial ticket') 415realm.run([kadminl, 'cpw', '-pw', password('none'), 'none']) 416realm.run([kadminl, 'modprinc', '+allow_tgs_req', 'kadmin/admin']) 417realm.kinit('none', password('none')) 418realm.run([kvno, 'kadmin/admin']) 419msg = 'Operation requires initial ticket' 420realm.run([kadmin, '-c', realm.ccache, 'cpw', '-pw', 'newpw', 'none'], 421 expected_code=1, expected_msg=msg) 422realm.run([kadmin, '-c', realm.ccache, 'cpw', '-pw', 'newpw', 423 '-e', 'aes256-cts', 'none'], expected_code=1, expected_msg=msg) 424realm.run([kadmin, '-c', realm.ccache, 'cpw', '-randkey', 'none'], 425 expected_code=1, expected_msg=msg) 426realm.run([kadmin, '-c', realm.ccache, 'cpw', '-randkey', '-e', 'aes256-cts', 427 'none'], expected_code=1, expected_msg=msg) 428 429# Test authentication to kadmin/hostname. 430mark('authentication to kadmin/hostname') 431kadmin_hostname = 'kadmin/' + hostname 432realm.addprinc(kadmin_hostname) 433realm.run([kadminl, 'delprinc', 'kadmin/admin']) 434msgs = ('Getting initial credentials for user/admin@KRBTEST.COM', 435 'Setting initial creds service to kadmin/admin', 436 '/Server not found in Kerberos database', 437 'Getting initial credentials for user/admin@KRBTEST.COM', 438 'Setting initial creds service to ' + kadmin_hostname, 439 'Decrypted AS reply') 440realm.run([kadmin, '-p', 'user/admin', 'listprincs'], expected_code=1, 441 expected_msg="Operation requires ``list'' privilege", 442 input=password('user/admin'), expected_trace=msgs) 443 444# Test operations disallowed at the libkadm5 layer. 445realm.run([kadminl, 'delprinc', 'K/M'], 446 expected_code=1, expected_msg='Cannot change protected principal') 447realm.run([kadminl, 'cpw', '-pw', 'pw', 'kadmin/history'], 448 expected_code=1, expected_msg='Cannot change protected principal') 449 450success('kadmin ACL enforcement') 451