Skip to content

Commit a253964

Browse files
jborean93frozencemetery
authored andcommitted
Support for running tests against Heimdal in CI
Signed-off-by: Jordan Borean <[email protected]>
1 parent 97c0466 commit a253964

File tree

5 files changed

+275
-79
lines changed

5 files changed

+275
-79
lines changed

Diff for: ci/build.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ if [ $BUILD_RES -ne 0 ]; then
3636
fi
3737

3838
# Only call exit on failures so we can source this script
39-
if [ x"$KRB5_VER" = "xheimdal" ] || [ "$OS_NAME" = "windows" ]; then
40-
# heimdal/Windows can't run the tests yet, so just make sure it imports and exit
39+
if [ "$OS_NAME" = "windows" ]; then
40+
# Windows can't run the tests yet, so just make sure it imports and exit
4141
python -c "import gssapi" || exit $?
4242
else
4343
python setup.py nosetests --verbosity=3 || exit $?

Diff for: ci/lib-setup.sh

+11-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ setup::debian::install() {
88
apt-get update
99

1010
if [ x"$KRB5_VER" = "xheimdal" ]; then
11-
apt-get -y install heimdal-dev
11+
apt-get -y install heimdal-{clients,dev,kdc}
12+
13+
export GSSAPI_KRB5_MAIN_LIB="/usr/lib/x86_64-linux-gnu/libkrb5.so.26"
14+
export PATH="/usr/lib/heimdal-servers:${PATH}"
1215
else
1316
apt-get -y install krb5-{user,kdc,admin-server,multidev} libkrb5-dev \
1417
gss-ntlmssp
@@ -62,6 +65,13 @@ setup::macos::install() {
6265
python3 -m virtualenv -p $(which python3) .venv
6366
source .venv/bin/activate
6467
pip install --install-option='--no-cython-compile' cython
68+
69+
export GSSAPI_KRB5_MAIN_LIB="/System/Library/PrivateFrameworks/Heimdal.framework/Heimdal"
70+
71+
# macOS's Heimdal version is buggy, it will only use KRB5_KTNAME if the
72+
# env var was set when GSSAPI creates the context. Setting it here to any
73+
# value solves that problem for CI.
74+
export KRB5_KTNAME=initial
6575
}
6676

6777
setup::windows::install() {

Diff for: ci/run-on-linux.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# If we try to use a normal Github Actions container with
44
# github-pages-deploy-action, it will fail due to inability to find git.
55

6-
docker run -h test.box \
6+
docker run -h test.krbtest.com \
77
-v `pwd`:/tmp/build -w /tmp/build \
88
-e KRB5_VER=${KRB5_VER:-mit} \
99
-e FLAKE=${FLAKE:no} \

Diff for: gssapi/tests/test_high_level.py

+119-30
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919

2020
TARGET_SERVICE_NAME = b'host'
21-
FQDN = socket.getfqdn().encode('utf-8')
21+
FQDN = (
22+
'localhost' if sys.platform == 'darwin' else socket.getfqdn()
23+
).encode('utf-8')
2224
SERVICE_PRINCIPAL = TARGET_SERVICE_NAME + b'/' + FQDN
2325

2426
# disable error deferring to catch errors immediately
@@ -124,7 +126,8 @@ def setUp(self):
124126
usage='both')
125127
def test_acquire_by_init(self, str_name, kwargs):
126128
creds = gsscreds.Credentials(name=self.name, **kwargs)
127-
self.assertIsInstance(creds.lifetime, int)
129+
if sys.platform != 'darwin':
130+
self.assertIsInstance(creds.lifetime, int)
128131
del creds
129132

130133
@exist_perms(lifetime=30, mechs=[gb.MechType.kerberos],
@@ -137,7 +140,8 @@ def test_acquire_by_method(self, str_name, kwargs):
137140
creds, actual_mechs, ttl = cred_resp
138141
self.assertIsInstance(creds, gsscreds.Credentials)
139142
self.assertIn(gb.MechType.kerberos, actual_mechs)
140-
self.assertIsInstance(ttl, int)
143+
if sys.platform != 'darwin':
144+
self.assertIsInstance(ttl, int)
141145

142146
del creds
143147

@@ -165,9 +169,12 @@ def test_store_acquire(self):
165169
self.assertIsNotNone(deleg_creds)
166170

167171
store_res = deleg_creds.store(usage='initiate', set_default=True,
172+
mech=gb.MechType.kerberos,
168173
overwrite=True)
169-
self.assertEqual(store_res.usage, "initiate")
170-
self.assertIn(gb.MechType.kerberos, store_res.mechs)
174+
# While Heimdal doesn't fail it doesn't set the return values as exp.
175+
if self.realm.provider.lower() != 'heimdal':
176+
self.assertEqual(store_res.usage, "initiate")
177+
self.assertIn(gb.MechType.kerberos, store_res.mechs)
171178

172179
reacquired_creds = gsscreds.Credentials(name=deleg_creds.name,
173180
usage='initiate')
@@ -187,10 +194,18 @@ def test_store_into_acquire_from(self):
187194
initial_creds = gsscreds.Credentials(name=None,
188195
usage='initiate')
189196

190-
store_res = initial_creds.store(store, overwrite=True)
197+
acquire_kwargs = {}
198+
expected_usage = 'initiate'
199+
if self.realm.provider.lower() == 'heimdal':
200+
acquire_kwargs['usage'] = 'initiate'
201+
acquire_kwargs['mech'] = gb.MechType.kerberos
202+
expected_usage = 'both'
203+
204+
store_res = initial_creds.store(store, overwrite=True,
205+
**acquire_kwargs)
191206
self.assertIsNotNone(store_res.mechs)
192207
self.assertGreater(len(store_res.mechs), 0)
193-
self.assertEqual(store_res.usage, "initiate")
208+
self.assertEqual(store_res.usage, expected_usage)
194209

195210
name = gssnames.Name(princ_name)
196211
retrieved_creds = gsscreds.Credentials(name=name, store=store)
@@ -212,13 +227,14 @@ def test_inquire(self, str_name, kwargs):
212227
else:
213228
self.assertIsNone(resp.name)
214229

215-
if kwargs['lifetime']:
230+
if kwargs['lifetime'] and sys.platform != 'darwin':
216231
self.assertIsInstance(resp.lifetime, int)
217232
else:
218233
self.assertIsNone(resp.lifetime)
219234

220235
if kwargs['usage']:
221-
self.assertEqual(resp.usage, "both")
236+
expected = "accept" if sys.platform == "darwin" else "both"
237+
self.assertEqual(resp.usage, expected)
222238
else:
223239
self.assertIsNone(resp.usage)
224240

@@ -242,17 +258,21 @@ def test_inquire_by_mech(self, str_name, kwargs):
242258
else:
243259
self.assertIsNone(resp.init_lifetime)
244260

245-
if kwargs['accept_lifetime']:
261+
if kwargs['accept_lifetime'] and sys.platform != "darwin":
246262
self.assertIsInstance(resp.accept_lifetime, int)
247263
else:
248264
self.assertIsNone(resp.accept_lifetime)
249265

250266
if kwargs['usage']:
251-
self.assertEqual(resp.usage, "both")
267+
expected = "accept" if sys.platform == "darwin" else "both"
268+
self.assertEqual(resp.usage, expected)
252269
else:
253270
self.assertIsNone(resp.usage)
254271

255272
def test_add(self):
273+
if sys.platform == 'darwin':
274+
self.skipTest("macOS Heimdal broken")
275+
256276
input_creds = gsscreds.Credentials(gb.Creds())
257277
name = gssnames.Name(SERVICE_PRINCIPAL)
258278
new_creds = input_creds.add(name, gb.MechType.kerberos,
@@ -265,18 +285,25 @@ def test_store_into_add_from(self):
265285
KT = '{tmpdir}/other_keytab'.format(tmpdir=self.realm.tmpdir)
266286
store = {'ccache': CCACHE, 'keytab': KT}
267287

268-
princ_name = 'service/cs@' + self.realm.realm
288+
princ_name = 'service_add_from/cs@' + self.realm.realm
269289
self.realm.addprinc(princ_name)
270290
self.realm.extract_keytab(princ_name, KT)
271291
self.realm.kinit(princ_name, None, ['-k', '-t', KT])
272292

273293
initial_creds = gsscreds.Credentials(name=None,
274294
usage='initiate')
275295

276-
store_res = initial_creds.store(store, overwrite=True)
296+
store_kwargs = {}
297+
expected_usage = 'initiate'
298+
if self.realm.provider.lower() == 'heimdal':
299+
store_kwargs['usage'] = 'initiate'
300+
store_kwargs['mech'] = gb.MechType.kerberos
301+
expected_usage = 'both'
302+
303+
store_res = initial_creds.store(store, overwrite=True, **store_kwargs)
277304
self.assertIsNotNone(store_res.mechs)
278305
self.assertGreater(len(store_res.mechs), 0)
279-
self.assertEqual(store_res.usage, "initiate")
306+
self.assertEqual(store_res.usage, expected_usage)
280307

281308
name = gssnames.Name(princ_name)
282309
input_creds = gsscreds.Credentials(gb.Creds())
@@ -286,26 +313,34 @@ def test_store_into_add_from(self):
286313

287314
@ktu.gssapi_extension_test('cred_imp_exp', 'credentials import-export')
288315
def test_export(self):
289-
creds = gsscreds.Credentials(name=self.name)
316+
creds = gsscreds.Credentials(name=self.name,
317+
mechs=[gb.MechType.kerberos])
290318
token = creds.export()
291319
self.assertIsInstance(token, bytes)
292320

293321
@ktu.gssapi_extension_test('cred_imp_exp', 'credentials import-export')
294322
def test_import_by_init(self):
295-
creds = gsscreds.Credentials(name=self.name)
323+
creds = gsscreds.Credentials(name=self.name,
324+
mechs=[gb.MechType.kerberos])
296325
token = creds.export()
297326
imported_creds = gsscreds.Credentials(token=token)
298327

299-
self.assertEqual(imported_creds.lifetime, creds.lifetime)
328+
# lifetime seems to be None in Heimdal
329+
if self.realm.provider.lower() != 'heimdal':
330+
self.assertEqual(imported_creds.lifetime, creds.lifetime)
331+
300332
self.assertEqual(imported_creds.name, creds.name)
301333

302334
@ktu.gssapi_extension_test('cred_imp_exp', 'credentials import-export')
303335
def test_pickle_unpickle(self):
304-
creds = gsscreds.Credentials(name=self.name)
336+
creds = gsscreds.Credentials(name=self.name,
337+
mechs=[gb.MechType.kerberos])
305338
pickled_creds = pickle.dumps(creds)
306339
unpickled_creds = pickle.loads(pickled_creds)
307340

308-
self.assertEqual(unpickled_creds.lifetime, creds.lifetime)
341+
# lifetime seems to be None in Heimdal
342+
if self.realm.provider.lower() != 'heimdal':
343+
self.assertEqual(unpickled_creds.lifetime, creds.lifetime)
309344
self.assertEqual(unpickled_creds.name, creds.name)
310345

311346
@exist_perms(lifetime=30, mechs=[gb.MechType.kerberos],
@@ -381,8 +416,15 @@ def test_sasl_properties(self):
381416
if mech.description:
382417
self.assertIsInstance(mech.description, str)
383418

384-
cmp_mech = gssmechs.Mechanism.from_sasl_name(mech.sasl_name)
385-
self.assertEqual(str(cmp_mech), str(mech))
419+
# Heimdal fails with Unknown mech-code on sanon
420+
if not (self.realm.provider.lower() == "heimdal" and
421+
s == '1.3.6.1.4.1.5322.26.1.110'):
422+
cmp_mech = gssmechs.Mechanism.from_sasl_name(mech.sasl_name)
423+
424+
# For some reason macOS sometimes returns this for mechs
425+
if not (sys.platform == 'darwin' and
426+
str(cmp_mech) == '1.2.752.43.14.2'):
427+
self.assertEqual(str(cmp_mech), str(mech))
386428

387429
@ktu.gssapi_extension_test('rfc5587', 'RFC 5587: Mech Inquiry')
388430
def test_mech_inquiry(self):
@@ -441,6 +483,8 @@ def test_create_from_token(self):
441483
self.assertEqual(name2.name_type, gb.NameType.kerberos_principal)
442484

443485
@ktu.gssapi_extension_test('rfc6680', 'RFC 6680')
486+
@ktu.krb_provider_test(['mit'], 'gss_display_name_ext as it is not '
487+
'implemented for krb5')
444488
def test_display_as(self):
445489
name = gssnames.Name(TARGET_SERVICE_NAME,
446490
gb.NameType.hostbased_service)
@@ -457,6 +501,8 @@ def test_display_as(self):
457501
self.assertEqual(krb_name, princ_str)
458502

459503
@ktu.gssapi_extension_test('rfc6680', 'RFC 6680')
504+
@ktu.krb_provider_test(['mit'], 'gss_canonicalize_name as it is not '
505+
'implemented for krb5')
460506
def test_create_from_composite_token_no_attrs(self):
461507
name1 = gssnames.Name(TARGET_SERVICE_NAME,
462508
gb.NameType.hostbased_service)
@@ -539,7 +585,16 @@ def test_canonicalize(self):
539585

540586
canonicalized_name = name.canonicalize(gb.MechType.kerberos)
541587
self.assertIsInstance(canonicalized_name, gssnames.Name)
542-
self.assertEqual(bytes(canonicalized_name), SERVICE_PRINCIPAL + b"@")
588+
589+
expected = SERVICE_PRINCIPAL + b"@"
590+
if sys.platform == 'darwin':
591+
# No idea - just go with it
592+
expected = b"host/wellknown:org.h5l.hostbased-service@" \
593+
b"H5L.HOSTBASED-SERVICE"
594+
elif self.realm.provider.lower() == 'heimdal':
595+
expected += self.realm.realm.encode('utf-8')
596+
597+
self.assertEqual(bytes(canonicalized_name), expected)
543598

544599
def test_copy(self):
545600
name1 = gssnames.Name(SERVICE_PRINCIPAL)
@@ -551,6 +606,7 @@ def test_copy(self):
551606
# doesn't actually implement it
552607

553608
@ktu.gssapi_extension_test('rfc6680', 'RFC 6680')
609+
@ktu.krb_provider_test(['mit'], 'Heimdal does not implemented for krb5')
554610
def test_is_mech_name(self):
555611
name = gssnames.Name(TARGET_SERVICE_NAME,
556612
gb.NameType.hostbased_service)
@@ -562,6 +618,7 @@ def test_is_mech_name(self):
562618
self.assertEqual(canon_name.mech, gb.MechType.kerberos)
563619

564620
@ktu.gssapi_extension_test('rfc6680', 'RFC 6680')
621+
@ktu.krb_provider_test(['mit'], 'Heimdal does not implemented for krb5')
565622
def test_export_name_composite_no_attrs(self):
566623
name = gssnames.Name(TARGET_SERVICE_NAME,
567624
gb.NameType.hostbased_service)
@@ -611,8 +668,13 @@ def setUp(self):
611668
self.client_creds = gsscreds.Credentials(name=None,
612669
usage='initiate')
613670

614-
self.target_name = gssnames.Name(TARGET_SERVICE_NAME,
615-
gb.NameType.hostbased_service)
671+
if sys.platform == "darwin":
672+
spn = TARGET_SERVICE_NAME + b"@" + FQDN
673+
self.target_name = gssnames.Name(spn,
674+
gb.NameType.hostbased_service)
675+
else:
676+
self.target_name = gssnames.Name(TARGET_SERVICE_NAME,
677+
gb.NameType.hostbased_service)
616678

617679
self.server_name = gssnames.Name(SERVICE_PRINCIPAL)
618680
self.server_creds = gsscreds.Credentials(name=self.server_name,
@@ -628,7 +690,12 @@ def _create_client_ctx(self, **kwargs):
628690
def test_create_from_other(self):
629691
raw_client_ctx, raw_server_ctx = self._create_completed_contexts()
630692
high_level_ctx = gssctx.SecurityContext(raw_client_ctx)
631-
self.assertEqual(high_level_ctx.target_name, self.target_name)
693+
694+
expected = self.target_name
695+
if self.realm.provider.lower() == "heimdal":
696+
expected = gssnames.Name(self.realm.host_princ.encode('utf-8'),
697+
name_type=gb.NameType.kerberos_principal)
698+
self.assertEqual(high_level_ctx.target_name, expected)
632699

633700
@exist_perms(lifetime=30, flags=[],
634701
mech=gb.MechType.kerberos,
@@ -688,7 +755,13 @@ def test_initiate_accept_steps(self):
688755
self.assertTrue(server_ctx.complete)
689756

690757
self.assertLessEqual(client_ctx.lifetime, 400)
691-
self.assertEqual(client_ctx.target_name, self.target_name)
758+
759+
expected = self.target_name
760+
if self.realm.provider.lower() == "heimdal":
761+
expected = gssnames.Name(self.realm.host_princ.encode('utf-8'),
762+
name_type=gb.NameType.kerberos_principal)
763+
self.assertEqual(client_ctx.target_name, expected)
764+
692765
self.assertIsInstance(client_ctx.mech, gb.OID)
693766
self.assertIsInstance(client_ctx.actual_flags, gb.IntEnumFlagSet)
694767
self.assertTrue(client_ctx.locally_initiated)
@@ -714,6 +787,9 @@ def test_channel_bindings(self):
714787
client_ctx.step(server_token)
715788

716789
def test_bad_channel_bindings_raises_error(self):
790+
if sys.platform == "darwin":
791+
self.skipTest("macOS Heimdal doesn't fail as expected")
792+
717793
bdgs = gb.ChannelBindings(application_data=b'abcxyz',
718794
initiator_address_type=gb.AddressType.ip,
719795
initiator_address=b'127.0.0.1',
@@ -738,7 +814,13 @@ def test_export_create_from_token(self):
738814

739815
imported_ctx = gssctx.SecurityContext(token=token)
740816
self.assertEqual(imported_ctx.usage, "initiate")
741-
self.assertEqual(imported_ctx.target_name, self.target_name)
817+
818+
expected = self.target_name
819+
if self.realm.provider.lower() == "heimdal":
820+
expected = gssnames.Name(self.realm.host_princ.encode('utf-8'),
821+
name_type=gb.NameType.kerberos_principal)
822+
823+
self.assertEqual(imported_ctx.target_name, expected)
742824

743825
def test_pickle_unpickle(self):
744826
client_ctx, server_ctx = self._create_completed_contexts()
@@ -747,7 +829,12 @@ def test_pickle_unpickle(self):
747829
unpickled_ctx = pickle.loads(pickled_ctx)
748830
self.assertIsInstance(unpickled_ctx, gssctx.SecurityContext)
749831
self.assertEqual(unpickled_ctx.usage, "initiate")
750-
self.assertEqual(unpickled_ctx.target_name, self.target_name)
832+
833+
expected = self.target_name
834+
if self.realm.provider.lower() == "heimdal":
835+
expected = gssnames.Name(self.realm.host_princ.encode('utf-8'),
836+
name_type=gb.NameType.kerberos_principal)
837+
self.assertEqual(unpickled_ctx.target_name, expected)
751838

752839
def test_encrypt_decrypt(self):
753840
client_ctx, server_ctx = self._create_completed_contexts()
@@ -810,7 +897,8 @@ def test_verify_signature_raise(self):
810897
self.assertRaises(gb.GSSError, server_ctx.verify_signature,
811898
b"other message", mic_token)
812899

813-
@ktu.krb_minversion_test("1.11", "returning tokens")
900+
@ktu.krb_minversion_test("1.11", "returning tokens", provider="mit")
901+
@ktu.krb_provider_test(["mit"], "returning tokens")
814902
def test_defer_step_error_on_method(self):
815903
gssctx.SecurityContext.__DEFER_STEP_ERRORS__ = True
816904
bdgs = gb.ChannelBindings(application_data=b'abcxyz')
@@ -827,7 +915,8 @@ def test_defer_step_error_on_method(self):
827915
self.assertRaises(gb.BadChannelBindingsError, server_ctx.encrypt,
828916
b"test")
829917

830-
@ktu.krb_minversion_test("1.11", "returning tokens")
918+
@ktu.krb_minversion_test("1.11", "returning tokens", provider="mit")
919+
@ktu.krb_provider_test(["mit"], "returning tokens")
831920
def test_defer_step_error_on_complete_property_access(self):
832921
gssctx.SecurityContext.__DEFER_STEP_ERRORS__ = True
833922
bdgs = gb.ChannelBindings(application_data=b'abcxyz')

0 commit comments

Comments
 (0)