From fd79580b340684dc6ec4753caca177e862d102c0 Mon Sep 17 00:00:00 2001 From: weijun Date: Tue, 31 May 2016 16:24:47 +0300 Subject: [PATCH] 8022582: Relax response flags checking in sun.security.krb5.KrbKdcRep.check. Reviewed-by: mullan --- .../classes/sun/security/krb5/KrbKdcRep.java | 3 +- .../classes/sun/security/krb5/KrbTgsReq.java | 12 +-- .../krb5/internal/CredentialsUtil.java | 6 ++ test/sun/security/krb5/auto/Context.java | 8 +- .../security/krb5/auto/ForwardableCheck.java | 81 +++++++++++++++++++ test/sun/security/krb5/auto/KDC.java | 30 +++++-- 6 files changed, 122 insertions(+), 18 deletions(-) create mode 100644 test/sun/security/krb5/auto/ForwardableCheck.java diff --git a/src/share/classes/sun/security/krb5/KrbKdcRep.java b/src/share/classes/sun/security/krb5/KrbKdcRep.java index dd0e95102..66ce73a32 100644 --- a/src/share/classes/sun/security/krb5/KrbKdcRep.java +++ b/src/share/classes/sun/security/krb5/KrbKdcRep.java @@ -62,7 +62,8 @@ abstract class KrbKdcRep { throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); } - for (int i = 1; i < 6; i++) { + // We allow KDC to return a non-forwardable ticket if request has -f + for (int i = 2; i < 6; i++) { if (req.reqBody.kdcOptions.get(i) != rep.encKDCRepPart.flags.get(i)) { if (Krb5.DEBUG) { diff --git a/src/share/classes/sun/security/krb5/KrbTgsReq.java b/src/share/classes/sun/security/krb5/KrbTgsReq.java index 798b78d3e..85b7cb2e0 100644 --- a/src/share/classes/sun/security/krb5/KrbTgsReq.java +++ b/src/share/classes/sun/security/krb5/KrbTgsReq.java @@ -150,19 +150,11 @@ public class KrbTgsReq { ctime = KerberosTime.now(); // check if they are valid arguments. The optional fields - // should be consistent with settings in KDCOptions. - - // TODO: Is this necessary? If the TGT is not FORWARDABLE, - // you can still request for a FORWARDABLE ticket, just the - // KDC will give you a non-FORWARDABLE one. Even if you - // cannot use the ticket expected, it still contains info. - // This means there will be problem later. We already have - // flags check in KrbTgsRep. Of course, sometimes the KDC - // will not issue the ticket at all. + // should be consistent with settings in KDCOptions. if (options.get(KDCOptions.FORWARDABLE) && (!(asCreds.flags.get(Krb5.TKT_OPTS_FORWARDABLE)))) { - throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); + options.set(KDCOptions.FORWARDABLE, false); } if (options.get(KDCOptions.FORWARDED)) { if (!(asCreds.flags.get(KDCOptions.FORWARDABLE))) diff --git a/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java b/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java index b6a367775..14620e944 100644 --- a/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java +++ b/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java @@ -58,6 +58,9 @@ public class CredentialsUtil { // TODO: we do not support kerberos referral now throw new KrbException("Cross realm impersonation not supported"); } + if (!ccreds.isForwardable()) { + throw new KrbException("S4U2self needs a FORWARDABLE ticket"); + } KrbTgsReq req = new KrbTgsReq( ccreds, ccreds.getClient(), @@ -68,6 +71,9 @@ public class CredentialsUtil { if (!creds.getClient().equals(client)) { throw new KrbException("S4U2self request not honored by KDC"); } + if (!creds.isForwardable()) { + throw new KrbException("S4U2self ticket must be FORWARDABLE"); + } return creds; } diff --git a/test/sun/security/krb5/auto/Context.java b/test/sun/security/krb5/auto/Context.java index 715a1ad59..f6646055a 100644 --- a/test/sun/security/krb5/auto/Context.java +++ b/test/sun/security/krb5/auto/Context.java @@ -23,6 +23,7 @@ import com.sun.security.auth.module.Krb5LoginModule; import java.security.Key; +import java.lang.reflect.InvocationTargetException; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Arrays; @@ -581,7 +582,12 @@ public class Context { out.name = name + " as " + out.cred.getName().toString(); return out; } catch (PrivilegedActionException pae) { - throw pae.getException(); + Exception e = pae.getException(); + if (e instanceof InvocationTargetException) { + throw (Exception)((InvocationTargetException) e).getTargetException(); + } else { + throw e; + } } } diff --git a/test/sun/security/krb5/auto/ForwardableCheck.java b/test/sun/security/krb5/auto/ForwardableCheck.java new file mode 100644 index 000000000..df6e49ec6 --- /dev/null +++ b/test/sun/security/krb5/auto/ForwardableCheck.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8022582 + * @summary Relax response flags checking in sun.security.krb5.KrbKdcRep.check. + * @compile -XDignore.symbol.file ForwardableCheck.java + * @run main/othervm ForwardableCheck + */ + +import org.ietf.jgss.GSSException; +import sun.security.jgss.GSSUtil; + +import java.util.Arrays; + +public class ForwardableCheck { + + public static void main(String[] args) throws Exception { + OneKDC kdc = new OneKDC(null); + kdc.writeJAASConf(); + + // USER can impersonate someone else + kdc.setOption(KDC.Option.ALLOW_S4U2SELF, + Arrays.asList(OneKDC.USER + "@" + OneKDC.REALM)); + // USER2 is sensitive + kdc.setOption(KDC.Option.SENSITIVE_ACCOUNTS, + Arrays.asList(OneKDC.USER2 + "@" + OneKDC.REALM)); + + Context c; + + // USER2 is sensitive but it's still able to get a normal ticket + c = Context.fromUserPass(OneKDC.USER2, OneKDC.PASS2, false); + + // ... and connect to another account + c.startAsClient(OneKDC.USER, GSSUtil.GSS_KRB5_MECH_OID); + c.x().requestCredDeleg(true); + c.x().requestMutualAuth(false); + + c.take(new byte[0]); + + if (!c.x().isEstablished()) { + throw new Exception("Context should have been established"); + } + + // ... but will not be able to delegate itself + if (c.x().getCredDelegState()) { + throw new Exception("Impossible"); + } + + // Although USER is allowed to impersonate other people, + // it cannot impersonate USER2 coz it's sensitive. + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + try { + c.impersonate(OneKDC.USER2); + throw new Exception("Should fail"); + } catch (GSSException e) { + e.printStackTrace(); + } + } +} diff --git a/test/sun/security/krb5/auto/KDC.java b/test/sun/security/krb5/auto/KDC.java index e3d63d08f..f21860ba4 100644 --- a/test/sun/security/krb5/auto/KDC.java +++ b/test/sun/security/krb5/auto/KDC.java @@ -194,6 +194,10 @@ public class KDC { * Krb5.KDC_ERR_POLICY will be send for S4U2proxy request. */ ALLOW_S4U2PROXY, + /** + * Sensitive accounts can never be delegated. + */ + SENSITIVE_ACCOUNTS, }; static { @@ -638,7 +642,7 @@ public class KDC { try { System.out.println(realm + "> " + tgsReq.reqBody.cname + " sends TGS-REQ for " + - service); + service + ", " + tgsReq.reqBody.kdcOptions); KDCReqBody body = tgsReq.reqBody; int[] eTypes = KDCReqBodyDotEType(body); int e2 = eTypes[0]; // etype for outgoing session key @@ -714,7 +718,13 @@ public class KDC { boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; if (body.kdcOptions.get(KDCOptions.FORWARDABLE) && allowForwardable) { - bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + List sensitives = (List) + options.get(Option.SENSITIVE_ACCOUNTS); + if (sensitives != null && sensitives.contains(cname.toString())) { + // Cannot make FORWARDABLE + } else { + bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + } } if (body.kdcOptions.get(KDCOptions.FORWARDED) || etp.flags.get(Krb5.TKT_OPTS_FORWARDED)) { @@ -819,7 +829,8 @@ public class KDC { t, edata); System.out.println(" Return " + tgsRep.cname - + " ticket for " + tgsRep.ticket.sname); + + " ticket for " + tgsRep.ticket.sname + ", flags " + + tFlags); DerOutputStream out = new DerOutputStream(); out.write(DerValue.createTag(DerValue.TAG_APPLICATION, @@ -865,7 +876,7 @@ public class KDC { try { System.out.println(realm + "> " + asReq.reqBody.cname + " sends AS-REQ for " + - service); + service + ", " + asReq.reqBody.kdcOptions); KDCReqBody body = asReq.reqBody; @@ -908,7 +919,13 @@ public class KDC { //body.from boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; if (body.kdcOptions.get(KDCOptions.FORWARDABLE)) { - bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + List sensitives = (List) + options.get(Option.SENSITIVE_ACCOUNTS); + if (sensitives != null && sensitives.contains(body.cname.toString())) { + // Cannot make FORWARDABLE + } else { + bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + } } if (body.kdcOptions.get(KDCOptions.RENEWABLE)) { bFlags[Krb5.TKT_OPTS_RENEWABLE] = true; @@ -1084,7 +1101,8 @@ public class KDC { edata); System.out.println(" Return " + asRep.cname - + " ticket for " + asRep.ticket.sname); + + " ticket for " + asRep.ticket.sname + ", flags " + + tFlags); DerOutputStream out = new DerOutputStream(); out.write(DerValue.createTag(DerValue.TAG_APPLICATION, -- GitLab