< prev index next >
src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java
Print this page
rev 54745 : 8215032: Support Kerberos cross-realm referrals (RFC 6806)
Reviewed-by: weijun
@@ -1,7 +1,7 @@
/*
- * 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
@@ -260,29 +260,40 @@
* @param key null (initial AS-REQ) or pakey (with preauth)
* @return the KrbAsReq object
* @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");
} else {
EncryptionKey[] ks = Krb5Util.keysFromJavaxKeyTab(ktab, cname);
eTypes = EType.getDefaults("default_tkt_enctypes",
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,
sname,
from,
till,
rtime,
eTypes,
- addresses);
+ addresses,
+ extraPAs);
}
/**
* Parses AS-REP, decrypts enc-part, retrieves ticket and session key
* @throws KrbException
@@ -316,15 +327,19 @@
* @throws KrbException
* @throws IOException
*/
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) {
if (!preAuthFailedOnce && (
ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED ||
@@ -349,16 +364,75 @@
PAData.getSaltAndParams(
paEType, kerr.getPA()));
}
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.getNameString().replaceAll(
+ PrincipalName.NAME_REALM_SEPARATOR + "", "\\\\" +
+ PrincipalName.NAME_REALM_SEPARATOR), cname.getNameType(),
+ referredRealm.toString());
+ 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.
* @throws KrbException
* @throws Asn1Exception
< prev index next >