1
1
/*
2
- * Copyright (c) 2010, 2012 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2010, 2019 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
@@ -262,7 +262,9 @@ public void setAddresses(HostAddresses addresses) {
262
262
* @throws KrbException
263
263
* @throws IOException
264
264
*/
265
- private KrbAsReq build (EncryptionKey key ) throws KrbException , IOException {
265
+ private KrbAsReq build (EncryptionKey key , ReferralsState referralsState )
266
+ throws KrbException , IOException {
267
+ PAData [] extraPAs = null ;
266
268
int [] eTypes ;
267
269
if (password != null ) {
268
270
eTypes = EType .getDefaults ("default_tkt_enctypes" );
@@ -272,6 +274,14 @@ private KrbAsReq build(EncryptionKey key) throws KrbException, IOException {
272
274
ks );
273
275
for (EncryptionKey k : ks ) k .destroy ();
274
276
}
277
+ options = (options == null ) ? new KDCOptions () : options ;
278
+ if (referralsState .isEnabled ()) {
279
+ options .set (KDCOptions .CANONICALIZE , true );
280
+ extraPAs = new PAData []{ new PAData (Krb5 .PA_REQ_ENC_PA_REP ,
281
+ new byte []{}) };
282
+ } else {
283
+ options .set (KDCOptions .CANONICALIZE , false );
284
+ }
275
285
return new KrbAsReq (key ,
276
286
options ,
277
287
cname ,
@@ -280,7 +290,8 @@ private KrbAsReq build(EncryptionKey key) throws KrbException, IOException {
280
290
till ,
281
291
rtime ,
282
292
eTypes ,
283
- addresses );
293
+ addresses ,
294
+ extraPAs );
284
295
}
285
296
286
297
/**
@@ -318,11 +329,15 @@ private KrbAsReqBuilder resolve()
318
329
*/
319
330
private KrbAsReqBuilder send () throws KrbException , IOException {
320
331
boolean preAuthFailedOnce = false ;
321
- KdcComm comm = new KdcComm ( cname . getRealmAsString ()) ;
332
+ KdcComm comm = null ;
322
333
EncryptionKey pakey = null ;
334
+ ReferralsState referralsState = new ReferralsState ();
323
335
while (true ) {
336
+ if (referralsState .refreshComm ()) {
337
+ comm = new KdcComm (cname .getRealmAsString ());
338
+ }
324
339
try {
325
- req = build (pakey );
340
+ req = build (pakey , referralsState );
326
341
rep = new KrbAsRep (comm .send (req .encoding ()));
327
342
return this ;
328
343
} catch (KrbException ke ) {
@@ -351,12 +366,69 @@ private KrbAsReqBuilder send() throws KrbException, IOException {
351
366
}
352
367
paList = kerr .getPA (); // Update current paList
353
368
} else {
369
+ if (referralsState .handleError (ke )) {
370
+ continue ;
371
+ }
354
372
throw ke ;
355
373
}
356
374
}
357
375
}
358
376
}
359
377
378
+ private final class ReferralsState {
379
+ private boolean enabled ;
380
+ private int count ;
381
+ private boolean refreshComm ;
382
+
383
+ ReferralsState () throws KrbException {
384
+ if (Config .DISABLE_REFERRALS ) {
385
+ if (cname .getNameType () == PrincipalName .KRB_NT_ENTERPRISE ) {
386
+ throw new KrbException ("NT-ENTERPRISE principals only allowed" +
387
+ " when referrals are enabled." );
388
+ }
389
+ enabled = false ;
390
+ } else {
391
+ enabled = true ;
392
+ }
393
+ refreshComm = true ;
394
+ }
395
+
396
+ boolean handleError (KrbException ke ) throws RealmException {
397
+ if (enabled ) {
398
+ if (ke .returnCode () == Krb5 .KRB_ERR_WRONG_REALM ) {
399
+ Realm referredRealm = ke .getError ().getClientRealm ();
400
+ if (req .getMessage ().reqBody .kdcOptions .get (KDCOptions .CANONICALIZE ) &&
401
+ referredRealm != null && referredRealm .toString ().length () > 0 &&
402
+ count < Config .MAX_REFERRALS ) {
403
+ cname = new PrincipalName (cname .getNameType (),
404
+ cname .getNameStrings (), referredRealm );
405
+ refreshComm = true ;
406
+ count ++;
407
+ return true ;
408
+ }
409
+ }
410
+ if (count < Config .MAX_REFERRALS &&
411
+ cname .getNameType () != PrincipalName .KRB_NT_ENTERPRISE ) {
412
+ // Server may raise an error if CANONICALIZE is true.
413
+ // Try CANONICALIZE false.
414
+ enabled = false ;
415
+ return true ;
416
+ }
417
+ }
418
+ return false ;
419
+ }
420
+
421
+ boolean refreshComm () {
422
+ boolean retRefreshComm = refreshComm ;
423
+ refreshComm = false ;
424
+ return retRefreshComm ;
425
+ }
426
+
427
+ boolean isEnabled () {
428
+ return enabled ;
429
+ }
430
+ }
431
+
360
432
/**
361
433
* Performs AS-REQ send and AS-REP receive.
362
434
* Maybe a state is needed here, to divide prepare process and getCreds.
0 commit comments