--- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java Thu Jun 06 10:03:22 2019 -0400
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java Wed Jun 05 01:42:11 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -262,7 +262,9 @@
* @throws KrbException
* @throws IOException
*/
- private KrbAsReq build(EncryptionKey key) throws KrbException, IOException {
+ private KrbAsReq build(EncryptionKey key, ReferralsState referralsState)
+ throws KrbException, IOException {
+ PAData[] extraPAs = null;
int[] eTypes;
if (password != null) {
eTypes = EType.getDefaults("default_tkt_enctypes");
@@ -272,6 +274,14 @@
ks);
for (EncryptionKey k: ks) k.destroy();
}
+ options = (options == null) ? new KDCOptions() : options;
+ if (referralsState.isEnabled()) {
+ options.set(KDCOptions.CANONICALIZE, true);
+ extraPAs = new PAData[]{ new PAData(Krb5.PA_REQ_ENC_PA_REP,
+ new byte[]{}) };
+ } else {
+ options.set(KDCOptions.CANONICALIZE, false);
+ }
return new KrbAsReq(key,
options,
cname,
@@ -280,7 +290,8 @@
till,
rtime,
eTypes,
- addresses);
+ addresses,
+ extraPAs);
}
/**
@@ -318,11 +329,15 @@
*/
private KrbAsReqBuilder send() throws KrbException, IOException {
boolean preAuthFailedOnce = false;
- KdcComm comm = new KdcComm(cname.getRealmAsString());
+ KdcComm comm = null;
EncryptionKey pakey = null;
+ ReferralsState referralsState = new ReferralsState();
while (true) {
+ if (referralsState.refreshComm()) {
+ comm = new KdcComm(cname.getRealmAsString());
+ }
try {
- req = build(pakey);
+ req = build(pakey, referralsState);
rep = new KrbAsRep(comm.send(req.encoding()));
return this;
} catch (KrbException ke) {
@@ -351,12 +366,69 @@
}
paList = kerr.getPA(); // Update current paList
} else {
+ if (referralsState.handleError(ke)) {
+ continue;
+ }
throw ke;
}
}
}
}
+ private final class ReferralsState {
+ private boolean enabled;
+ private int count;
+ private boolean refreshComm;
+
+ ReferralsState() throws KrbException {
+ if (Config.DISABLE_REFERRALS) {
+ if (cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) {
+ throw new KrbException("NT-ENTERPRISE principals only allowed" +
+ " when referrals are enabled.");
+ }
+ enabled = false;
+ } else {
+ enabled = true;
+ }
+ refreshComm = true;
+ }
+
+ boolean handleError(KrbException ke) throws RealmException {
+ if (enabled) {
+ if (ke.returnCode() == Krb5.KRB_ERR_WRONG_REALM) {
+ Realm referredRealm = ke.getError().getClientRealm();
+ if (req.getMessage().reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) &&
+ referredRealm != null && referredRealm.toString().length() > 0 &&
+ count < Config.MAX_REFERRALS) {
+ cname = new PrincipalName(cname.getNameType(),
+ cname.getNameStrings(), referredRealm);
+ refreshComm = true;
+ count++;
+ return true;
+ }
+ }
+ if (count < Config.MAX_REFERRALS &&
+ cname.getNameType() != PrincipalName.KRB_NT_ENTERPRISE) {
+ // Server may raise an error if CANONICALIZE is true.
+ // Try CANONICALIZE false.
+ enabled = false;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean refreshComm() {
+ boolean retRefreshComm = refreshComm;
+ refreshComm = false;
+ return retRefreshComm;
+ }
+
+ boolean isEnabled() {
+ return enabled;
+ }
+ }
+
/**
* Performs AS-REQ send and AS-REP receive.
* Maybe a state is needed here, to divide prepare process and getCreds.