diff --git a/src/share/classes/sun/java2d/pipe/BufferedContext.java b/src/share/classes/sun/java2d/pipe/BufferedContext.java index 4513c67090003641df18c02d50af347931280a05..3475c4319ec08374f5ab8c3e7e7c0e1fe06f44fc 100644 --- a/src/share/classes/sun/java2d/pipe/BufferedContext.java +++ b/src/share/classes/sun/java2d/pipe/BufferedContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -38,6 +38,8 @@ import static sun.java2d.pipe.BufferedOpCodes.*; import static sun.java2d.pipe.BufferedRenderPipe.BYTES_PER_SPAN; import java.lang.annotation.Native; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; /** * Base context class for managing state in a single-threaded rendering @@ -87,11 +89,11 @@ public abstract class BufferedContext { */ protected static BufferedContext currentContext; - private AccelSurface validatedSrcData; - private AccelSurface validatedDstData; - private Region validatedClip; - private Composite validatedComp; - private Paint validatedPaint; + private Reference validSrcDataRef = new WeakReference<>(null); + private Reference validDstDataRef = new WeakReference<>(null); + private Reference validClipRef = new WeakReference<>(null); + private Reference validCompRef = new WeakReference<>(null); + private Reference validPaintRef = new WeakReference<>(null); // renamed from isValidatedPaintAColor as part of a work around for 6764257 private boolean isValidatedPaintJustAColor; private int validatedRGB; @@ -127,9 +129,9 @@ public abstract class BufferedContext { int flags) { // assert rq.lock.isHeldByCurrentThread(); - BufferedContext d3dc = dstData.getContext(); - d3dc.validate(srcData, dstData, - clip, comp, xform, paint, sg2d, flags); + BufferedContext context = dstData.getContext(); + context.validate(srcData, dstData, + clip, comp, xform, paint, sg2d, flags); } /** @@ -200,13 +202,15 @@ public abstract class BufferedContext { updatePaint = true; isValidatedPaintJustAColor = true; } - } else if (validatedPaint != paint) { + } else if (validPaintRef.get() != paint) { updatePaint = true; // this should be set when we are switching from paint to color // in which case this condition will be true isValidatedPaintJustAColor = false; } + final AccelSurface validatedSrcData = validSrcDataRef.get(); + final AccelSurface validatedDstData = validDstDataRef.get(); if ((currentContext != this) || (srcData != validatedSrcData) || (dstData != validatedDstData)) @@ -228,11 +232,12 @@ public abstract class BufferedContext { setSurfaces(srcData, dstData); currentContext = this; - validatedSrcData = srcData; - validatedDstData = dstData; + validSrcDataRef = new WeakReference<>(srcData); + validDstDataRef = new WeakReference<>(dstData); } // validate clip + final Region validatedClip = validClipRef.get(); if ((clip != validatedClip) || updateClip) { if (clip != null) { if (updateClip || @@ -248,13 +253,13 @@ public abstract class BufferedContext { } else { resetClip(); } - validatedClip = clip; + validClipRef = new WeakReference<>(clip); } // validate composite (note that a change in the context flags // may require us to update the composite state, even if the // composite has not changed) - if ((comp != validatedComp) || (flags != validatedFlags)) { + if ((comp != validCompRef.get()) || (flags != validatedFlags)) { if (comp != null) { setComposite(comp, flags); } else { @@ -263,7 +268,7 @@ public abstract class BufferedContext { // the paint state is dependent on the composite state, so make // sure we update the color below updatePaint = true; - validatedComp = comp; + validCompRef = new WeakReference<>(comp); validatedFlags = flags; } @@ -297,7 +302,7 @@ public abstract class BufferedContext { } else { BufferedPaints.resetPaint(rq); } - validatedPaint = paint; + validPaintRef = new WeakReference<>(paint); } // mark dstData dirty @@ -315,9 +320,9 @@ public abstract class BufferedContext { * @see RenderQueue#lock * @see RenderQueue#unlock */ - public void invalidateSurfaces() { - validatedSrcData = null; - validatedDstData = null; + private void invalidateSurfaces() { + validSrcDataRef.clear(); + validDstDataRef.clear(); } private void setSurfaces(AccelSurface srcData, @@ -434,9 +439,9 @@ public abstract class BufferedContext { resetClip(); BufferedPaints.resetPaint(rq); invalidateSurfaces(); - validatedComp = null; - validatedClip = null; - validatedPaint = null; + validCompRef.clear(); + validClipRef.clear(); + validPaintRef.clear(); isValidatedPaintJustAColor = false; xformInUse = false; } diff --git a/src/share/classes/sun/security/krb5/KrbKdcRep.java b/src/share/classes/sun/security/krb5/KrbKdcRep.java index dd0e951028db2a6f13e39e3224dca76aa1d75dad..66ce73a32050bdf4e93830a65b6719dddeb7bf58 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 798b78d3e6365ea5e2d431b38ecf91114248c63e..85b7cb2e05c5703c041f417125ecfbf616b0cd35 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 b6a367775994081fc1e7f48f62b6f90201f587a1..14620e94483ece9940deaeaaa9ce4c58c6b8bdc4 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/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp index 825a69c8c424ebd8bf1447c851b5865149fbc941..b7ab7e00d6b6b5d42abadef66446346e514465e3 100644 --- a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp +++ b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp @@ -875,6 +875,9 @@ Java_sun_awt_Win32GraphicsDevice_initIDs(JNIEnv *env, jclass cls) // Only want to call this once per session make_uns_ordered_dither_array(img_oda_alpha, 256); + // workaround JDK-6477756, ignore return value to keep dll in memory + JDK_LoadSystemLibrary("opengl32.dll"); + CATCH_BAD_ALLOC; } diff --git a/test/java/awt/Window/WindowsLeak/WindowsLeak.java b/test/java/awt/Window/WindowsLeak/WindowsLeak.java index dd776a8d299d1eb7a49293dd808b969e880aa6f4..3f44687251b0fd7fce68e52fed0145b87f5fbcd2 100644 --- a/test/java/awt/Window/WindowsLeak/WindowsLeak.java +++ b/test/java/awt/Window/WindowsLeak/WindowsLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, 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 @@ -23,41 +23,40 @@ /* * @test - * @bug 8013563 + * @bug 8013563 8028486 * @summary Tests that windows are removed from windows list + * @library /javax/swing/regtesthelpers + * @build Util * @run main/othervm -Xms32M -Xmx32M WindowsLeak */ -import java.awt.*; -import sun.awt.AppContext; - +import java.awt.Frame; +import java.awt.Robot; +import java.awt.Window; import java.lang.ref.WeakReference; - import java.util.Vector; +import sun.awt.AppContext; +import sun.java2d.Disposer; + public class WindowsLeak { - public static void main(String[] args) { - for (int i = 0; i < 100; i++) - { + private static volatile boolean disposerPhantomComplete; + + public static void main(String[] args) throws Exception { + Robot r = new Robot(); + for (int i = 0; i < 100; i++) { Frame f = new Frame(); f.pack(); f.dispose(); } + r.waitForIdle(); + + Disposer.addRecord(new Object(), () -> disposerPhantomComplete = true); - Vector garbage = new Vector(); - while (true) - { - try - { - garbage.add(new byte[1000]); - } - catch (OutOfMemoryError e) - { - break; - } + while (!disposerPhantomComplete) { + Util.generateOOME(); } - garbage = null; Vector> windowList = (Vector>) AppContext.getAppContext().get(Window.class); diff --git a/test/sun/security/krb5/auto/Context.java b/test/sun/security/krb5/auto/Context.java index 715a1ad59788fea9c818fde03cc51f4522c2644e..f6646055aea3f1d54a1344ee04fbcda63d66b6bc 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 0000000000000000000000000000000000000000..df6e49ec66b458bb34eff33759488ca50e71dd44 --- /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 e3d63d08f0548346e9216bd3d2394d90651976e3..15b161200cc109a4eedb6dbe8004f6c4543d22ee 100644 --- a/test/sun/security/krb5/auto/KDC.java +++ b/test/sun/security/krb5/auto/KDC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, 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 @@ -145,6 +145,9 @@ public class KDC { private List conf = new ArrayList<>(); private Thread thread1, thread2, thread3; + private volatile boolean udpConsumerReady = false; + private volatile boolean tcpConsumerReady = false; + private volatile boolean dispatcherReady = false; DatagramSocket u1 = null; ServerSocket t1 = null; @@ -194,6 +197,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 +645,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 +721,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 +832,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 +879,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 +922,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 +1104,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, @@ -1192,6 +1213,7 @@ public class KDC { // The UDP consumer thread1 = new Thread() { public void run() { + udpConsumerReady = true; while (true) { try { byte[] inbuf = new byte[8192]; @@ -1212,6 +1234,7 @@ public class KDC { // The TCP consumer thread2 = new Thread() { public void run() { + tcpConsumerReady = true; while (true) { try { Socket socket = tcp.accept(); @@ -1234,6 +1257,7 @@ public class KDC { // The dispatcher thread3 = new Thread() { public void run() { + dispatcherReady = true; while (true) { try { q.take().send(); @@ -1244,6 +1268,19 @@ public class KDC { }; thread3.setDaemon(true); thread3.start(); + + // wait for the KDC is ready + try { + while (!isReady()) { + Thread.sleep(100); + } + } catch(InterruptedException e) { + throw new IOException(e); + } + } + + boolean isReady() { + return udpConsumerReady && tcpConsumerReady && dispatcherReady; } public void terminate() { diff --git a/test/sun/security/krb5/auto/UnboundSSL.java b/test/sun/security/krb5/auto/UnboundSSL.java new file mode 100644 index 0000000000000000000000000000000000000000..0862f072f04b986ecbc6f76d1aa1cc73d3a17bfa --- /dev/null +++ b/test/sun/security/krb5/auto/UnboundSSL.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedActionException; +import java.util.HashMap; +import java.util.Map; +import javax.security.auth.login.LoginException; + +/* + * @test + * @bug 8025123 + * @summary Checks if an unbound server can handle connections + * only for allowed service principals + * @run main/othervm/policy=unbound.ssl.policy UnboundSSL + * unbound.ssl.jaas.conf server_star + * @run main/othervm/policy=unbound.ssl.policy UnboundSSL + * unbound.ssl.jaas.conf server_multiple_principals + */ +public class UnboundSSL { + + public static void main(String[] args) throws IOException, + NoSuchAlgorithmException,LoginException, PrivilegedActionException, + InterruptedException { + UnboundSSL test = new UnboundSSL(); + test.start(args[0], args[1]); + } + + private void start(String jaacConfigFile, String serverJaasConfig) + throws IOException, NoSuchAlgorithmException,LoginException, + PrivilegedActionException, InterruptedException { + + // define principals + String service1host = "service1." + UnboundSSLUtils.HOST; + String service2host = "service2." + UnboundSSLUtils.HOST; + String service3host = "service3." + UnboundSSLUtils.HOST; + String service1Principal = "host/" + service1host + "@" + + UnboundSSLUtils.REALM; + String service2Principal = "host/" + service2host + "@" + + UnboundSSLUtils.REALM; + String service3Principal = "host/" + service3host + "@" + + UnboundSSLUtils.REALM; + + Map principals = new HashMap<>(); + principals.put(UnboundSSLUtils.USER_PRINCIPAL, + UnboundSSLUtils.USER_PASSWORD); + principals.put(UnboundSSLUtils.KRBTGT_PRINCIPAL, null); + principals.put(service1Principal, null); + principals.put(service2Principal, null); + principals.put(service3Principal, null); + + System.setProperty("java.security.krb5.conf", + UnboundSSLUtils.KRB5_CONF_FILENAME); + + // start a local KDC instance + UnboundSSLUtils.startKDC(UnboundSSLUtils.REALM, principals, + UnboundSSLUtils.KTAB_FILENAME, UnboundSSLUtils.KtabMode.APPEND); + + System.setProperty("java.security.auth.login.config", + UnboundSSLUtils.TEST_SRC + UnboundSSLUtils.FS + jaacConfigFile); + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + + try (final SSLEchoServer server = SSLEchoServer.init( + UnboundSSLUtils.TLS_KRB5_FILTER, UnboundSSLUtils.SNI_PATTERN)) { + + // start a server instance + UnboundSSLUtils.startServerWithJaas(server, serverJaasConfig); + + // wait for the server is ready + while (!server.isReady()) { + Thread.sleep(UnboundSSLUtils.DELAY); + } + + int port = server.getPort(); + + // run clients + + // the server should have a permission to handle a request + // with this service principal (there should be an appropriate + // javax.security.auth.kerberos.ServicePermission in policy file) + System.out.println("Connect: SNI hostname = " + service1host + + ", successful connection is expected"); + SSLClient.init(UnboundSSLUtils.HOST, port, + UnboundSSLUtils.TLS_KRB5_FILTER, service1host).connect(); + + // the server should NOT have a permission to handle a request + // with this service principal (there should be an appropriate + // javax.security.auth.kerberos.ServicePermission in policy file) + // handshake failures is expected + System.out.println("Connect: SNI hostname = " + service2host + + ", connection failure is expected"); + try { + SSLClient.init(UnboundSSLUtils.HOST, port, + UnboundSSLUtils.TLS_KRB5_FILTER, service2host) + .connect(); + throw new RuntimeException("Test failed: " + + "expected IOException not thrown"); + } catch (IOException e) { + System.out.println("Expected exception: " + e); + } + + // the server should have a permission to handle a request + // with this service principal (there should be an appropriate + // javax.security.auth.kerberos.ServicePermission in policy file) + System.out.println("Connect: SNI hostname = " + service3host + + ", successful connection is expected"); + SSLClient.init(UnboundSSLUtils.HOST, port, + UnboundSSLUtils.TLS_KRB5_FILTER, service3host).connect(); + } + + System.out.println("Test passed"); + } +} diff --git a/test/sun/security/krb5/auto/UnboundSSLMultipleKeys.java b/test/sun/security/krb5/auto/UnboundSSLMultipleKeys.java new file mode 100644 index 0000000000000000000000000000000000000000..255a40ca10617c6b000e8eda8cd5f7f811decce3 --- /dev/null +++ b/test/sun/security/krb5/auto/UnboundSSLMultipleKeys.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedActionException; +import java.util.HashMap; +import java.util.Map; +import javax.security.auth.login.LoginException; + +/* + * @test + * @bug 8025123 + * @summary Checks if an unbound server pick up a correct key from keytab + * @run main/othervm UnboundSSLMultipleKeys + * unbound.ssl.jaas.conf server_star + * @run main/othervm UnboundSSLMultipleKeys + * unbound.ssl.jaas.conf server_multiple_principals + */ +public class UnboundSSLMultipleKeys { + + public static void main(String[] args) + throws IOException, NoSuchAlgorithmException, LoginException, + PrivilegedActionException, InterruptedException { + UnboundSSLMultipleKeys test = new UnboundSSLMultipleKeys(); + test.start(args[0], args[1]); + } + + private void start(String jaacConfigFile, String serverJaasConfig) + throws IOException, NoSuchAlgorithmException, LoginException, + PrivilegedActionException, InterruptedException { + + // define service principals + String service1host = "service1." + UnboundSSLUtils.HOST; + String service2host = "service2." + UnboundSSLUtils.HOST; + String service3host = "service3." + UnboundSSLUtils.HOST; + String service1Principal = "host/" + service1host + "@" + + UnboundSSLUtils.REALM; + String service2Principal = "host/" + service2host + "@" + + UnboundSSLUtils.REALM; + String service3Principal = "host/" + service3host + "@" + + UnboundSSLUtils.REALM; + + Map principals = new HashMap<>(); + principals.put(UnboundSSLUtils.USER_PRINCIPAL, + UnboundSSLUtils.USER_PASSWORD); + principals.put(UnboundSSLUtils.KRBTGT_PRINCIPAL, "pass"); + principals.put(service1Principal, "pass0"); + principals.put(service1Principal, "pass1"); + principals.put(service1Principal, "pass2"); + principals.put(service2Principal, "pass"); + principals.put(service3Principal, "pass"); + + System.setProperty("java.security.krb5.conf", + UnboundSSLUtils.KRB5_CONF_FILENAME); + + /* + * Start a local KDC instance + * + * Keytab file contains 3 keys (with different KVNO) for service1 + * principal, but password for only one key is the same with the record + * for service1 principal in KDC. + */ + UnboundSSLUtils.startKDC(UnboundSSLUtils.REALM, principals, + UnboundSSLUtils.KTAB_FILENAME, UnboundSSLUtils.KtabMode.APPEND); + + System.setProperty("java.security.auth.login.config", + UnboundSSLUtils.TEST_SRC + UnboundSSLUtils.FS + jaacConfigFile); + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + + // start an SSL server instance + try (SSLEchoServer server = SSLEchoServer.init( + UnboundSSLUtils.TLS_KRB5_FILTER, UnboundSSLUtils.SNI_PATTERN)) { + + UnboundSSLUtils.startServerWithJaas(server, serverJaasConfig); + + // wait for the server is ready + while (!server.isReady()) { + Thread.sleep(UnboundSSLUtils.DELAY); + } + + // run a client + System.out.println("Successful connection is expected"); + SSLClient.init(UnboundSSLUtils.HOST, server.getPort(), + UnboundSSLUtils.TLS_KRB5_FILTER, service1host).connect(); + } + + System.out.println("Test passed"); + } + +} diff --git a/test/sun/security/krb5/auto/UnboundSSLPrincipalProperty.java b/test/sun/security/krb5/auto/UnboundSSLPrincipalProperty.java new file mode 100644 index 0000000000000000000000000000000000000000..3ccb4bf604a08afeb94786e0308f4469c61ea08f --- /dev/null +++ b/test/sun/security/krb5/auto/UnboundSSLPrincipalProperty.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedActionException; +import java.util.HashMap; +import java.util.Map; +import javax.security.auth.login.LoginException; + +/* + * @test + * @bug 8025123 + * @summary Checks if an unbound server uses a service principal + * from sun.security.krb5.principal system property if specified + * @run main/othervm UnboundSSLPrincipalProperty + * unbound.ssl.jaas.conf server_star + * @run main/othervm UnboundSSLPrincipalProperty + * unbound.ssl.jaas.conf server_multiple_principals + */ +public class UnboundSSLPrincipalProperty { + + public static void main(String[] args) throws IOException, + NoSuchAlgorithmException,LoginException, PrivilegedActionException, + InterruptedException { + UnboundSSLPrincipalProperty test = new UnboundSSLPrincipalProperty(); + test.start(args[0], args[1]); + } + + public void start(String jaacConfigFile, String serverJaasConfig) + throws IOException, NoSuchAlgorithmException,LoginException, + PrivilegedActionException, InterruptedException { + + // define principals + String service1host = "service1." + UnboundSSLUtils.HOST; + String service3host = "service3." + UnboundSSLUtils.HOST; + String service1Principal = "host/" + service1host + "@" + + UnboundSSLUtils.REALM; + String service3Principal = "host/" + service3host + + "@" + UnboundSSLUtils.REALM; + + Map principals = new HashMap<>(); + principals.put(UnboundSSLUtils.USER_PRINCIPAL, + UnboundSSLUtils.USER_PASSWORD); + principals.put(UnboundSSLUtils.KRBTGT_PRINCIPAL, null); + principals.put(service1Principal, null); + principals.put(service3Principal, null); + + System.setProperty("java.security.krb5.conf", + UnboundSSLUtils.KRB5_CONF_FILENAME); + + // start a local KDC instance + UnboundSSLUtils.startKDC(UnboundSSLUtils.REALM, principals, + UnboundSSLUtils.KTAB_FILENAME, UnboundSSLUtils.KtabMode.APPEND); + + System.setProperty("java.security.auth.login.config", + UnboundSSLUtils.TEST_SRC + UnboundSSLUtils.FS + jaacConfigFile); + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + + // start an SSL server instance + try (final SSLEchoServer server = SSLEchoServer.init( + UnboundSSLUtils.TLS_KRB5_FILTER, UnboundSSLUtils.SNI_PATTERN)) { + + // specify a service principal for the server + System.setProperty("sun.security.krb5.principal", + service3Principal); + + UnboundSSLUtils.startServerWithJaas(server, serverJaasConfig); + + // wait for the server is ready + while (!server.isReady()) { + Thread.sleep(UnboundSSLUtils.DELAY); + } + + int port = server.getPort(); + + // connetion failure is expected + // since service3 principal was specified to use by the server + System.out.println("Connect: SNI hostname = " + service1host + + ", connection failure is expected"); + try { + SSLClient.init(UnboundSSLUtils.HOST, port, + UnboundSSLUtils.TLS_KRB5_FILTER, service1host) + .connect(); + throw new RuntimeException("Test failed: " + + "expected IOException not thrown"); + } catch (IOException e) { + System.out.println("Expected exception: " + e); + } + + System.out.println("Connect: SNI hostname = " + service3host + + ", successful connection is expected"); + SSLClient.init(UnboundSSLUtils.HOST, port, + UnboundSSLUtils.TLS_KRB5_FILTER, service3host).connect(); + } + + System.out.println("Test passed"); + } +} diff --git a/test/sun/security/krb5/auto/UnboundSSLUtils.java b/test/sun/security/krb5/auto/UnboundSSLUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..ab55e1fa184e86369b43a3b78756ef9af48480af --- /dev/null +++ b/test/sun/security/krb5/auto/UnboundSSLUtils.java @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIMatcher; +import javax.net.ssl.SNIServerName; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.security.auth.Subject; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; + +/* + * Helper class for unbound krb5 tests. + */ +class UnboundSSLUtils { + + static enum KtabMode { APPEND, EXISTING }; + + static final String KTAB_FILENAME = "krb5.keytab.data"; + static final String HOST = "localhost"; + static final String REALM = "TEST.REALM"; + static final String KRBTGT_PRINCIPAL = "krbtgt/" + REALM; + static final String TEST_SRC = System.getProperty("test.src", "."); + static final String TLS_KRB5_FILTER = "TLS_KRB5"; + static final String USER = "USER"; + static final String USER_PASSWORD = "password"; + static final String FS = System.getProperty("file.separator"); + static final String SNI_PATTERN = ".*"; + static final String USER_PRINCIPAL = USER + "@" + REALM; + static final String KRB5_CONF_FILENAME = "krb5.conf"; + static final int DELAY = 1000; + + static String[] filterStringArray(String[] src, String filter) { + return Arrays.stream(src).filter((item) -> item.startsWith(filter)) + .toArray(size -> new String[size]); + } + + /* + * The method does JAAS login, + * and runs an SSL server in the JAAS context. + */ + static void startServerWithJaas(final SSLEchoServer server, + String config) throws LoginException, PrivilegedActionException { + LoginContext context = new LoginContext(config); + context.login(); + System.out.println("Server: successful authentication"); + Subject.doAs(context.getSubject(), + (PrivilegedExceptionAction) () -> { + SSLEchoServer.startServer(server); + return null; + }); + } + + /* + * Start a KDC server: + * - create a KDC instance + * - create Kerberos principals + * - save Kerberos configuration + * - save keys to keytab file + * - no pre-auth required + */ + static void startKDC(String realm, Map principals, + String ktab, KtabMode mode) { + try { + KDC kdc = KDC.create(realm, HOST, 0, true); + kdc.setOption(KDC.Option.PREAUTH_REQUIRED, Boolean.FALSE); + if (principals != null) { + for (Map.Entry entry : principals.entrySet()) { + String name = entry.getKey(); + String password = entry.getValue(); + if (password == null || password.isEmpty()) { + System.out.println("KDC: add a principal '" + name + + "' with a random password"); + kdc.addPrincipalRandKey(name); + } else { + System.out.println("KDC: add a principal '" + name + + "' with '" + password + "' password"); + kdc.addPrincipal(name, password.toCharArray()); + } + } + } + + KDC.saveConfig(KRB5_CONF_FILENAME, kdc); + + if (ktab != null) { + File ktabFile = new File(ktab); + if (mode == KtabMode.APPEND) { + if (ktabFile.exists()) { + System.out.println("KDC: append keys to an exising " + + "keytab file " + ktab); + kdc.appendKtab(ktab); + } else { + System.out.println("KDC: create a new keytab file " + + ktab); + kdc.writeKtab(ktab); + } + } else if (mode == KtabMode.EXISTING) { + System.out.println("KDC: use an existing keytab file " + + ktab); + } else { + throw new RuntimeException("KDC: unsupported keytab mode: " + + mode); + } + } + + System.out.println("KDC: started on " + HOST + ":" + kdc.getPort() + + " with '" + realm + "' realm"); + } catch (Exception e) { + throw new RuntimeException("KDC: unexpected exception", e); + } + } + +} + +class SSLClient { + + private final static byte[][] arrays = { + new byte[] {-1, 0, 2}, + new byte[] {} + }; + + private final SSLSocket socket; + + private SSLClient(SSLSocket socket) { + this.socket = socket; + } + + void connect() throws IOException { + System.out.println("Client: connect to server"); + try (BufferedInputStream bis = new BufferedInputStream( + socket.getInputStream()); + BufferedOutputStream bos = new BufferedOutputStream( + socket.getOutputStream())) { + + for (byte[] bytes : arrays) { + System.out.println("Client: send byte array: " + + Arrays.toString(bytes)); + + bos.write(bytes); + bos.flush(); + + byte[] recieved = new byte[bytes.length]; + int read = bis.read(recieved, 0, bytes.length); + if (read < 0) { + throw new IOException("Client: couldn't read a response"); + } + + System.out.println("Client: recieved byte array: " + + Arrays.toString(recieved)); + + if (!Arrays.equals(bytes, recieved)) { + throw new IOException("Client: sent byte array " + + "is not equal with recieved byte array"); + } + } + socket.getSession().invalidate(); + } finally { + if (!socket.isClosed()) { + socket.close(); + } + } + } + + static SSLClient init(String host, int port, String cipherSuiteFilter, + String sniHostName) throws NoSuchAlgorithmException, IOException { + SSLContext sslContext = SSLContext.getDefault(); + SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory(); + SSLSocket socket = (SSLSocket) ssf.createSocket(host, port); + SSLParameters params = new SSLParameters(); + + if (cipherSuiteFilter != null) { + String[] cipherSuites = UnboundSSLUtils.filterStringArray( + ssf.getSupportedCipherSuites(), cipherSuiteFilter); + System.out.println("Client: enabled cipher suites: " + + Arrays.toString(cipherSuites)); + params.setCipherSuites(cipherSuites); + } + + if (sniHostName != null) { + System.out.println("Client: set SNI hostname: " + sniHostName); + SNIHostName serverName = new SNIHostName(sniHostName); + List serverNames = new ArrayList<>(); + serverNames.add(serverName); + params.setServerNames(serverNames); + } + + socket.setSSLParameters(params); + + return new SSLClient(socket); + } + +} + +class SSLEchoServer implements Runnable, AutoCloseable { + + private final SSLServerSocket ssocket; + private volatile boolean stopped = false; + private volatile boolean ready = false; + + /* + * Starts the server in a separate thread. + */ + static void startServer(SSLEchoServer server) { + Thread serverThread = new Thread(server, "SSL echo server thread"); + serverThread.setDaemon(true); + serverThread.start(); + } + + private SSLEchoServer(SSLServerSocket ssocket) { + this.ssocket = ssocket; + } + + /* + * Main server loop. + */ + @Override + public void run() { + System.out.println("Server: started"); + while (!stopped) { + ready = true; + try (SSLSocket socket = (SSLSocket) ssocket.accept()) { + System.out.println("Server: client connection accepted"); + try ( + BufferedInputStream bis = new BufferedInputStream( + socket.getInputStream()); + BufferedOutputStream bos = new BufferedOutputStream( + socket.getOutputStream()) + ) { + byte[] buffer = new byte[1024]; + int read; + while ((read = bis.read(buffer)) > 0) { + bos.write(buffer, 0, read); + System.out.println("Server: recieved " + read + + " bytes: " + + Arrays.toString(Arrays.copyOf(buffer, read))); + bos.flush(); + } + } + } catch (IOException e) { + if (stopped) { + // stopped == true means that stop() method was called, + // so just ignore the exception, and finish the loop + break; + } + System.out.println("Server: couldn't accept client connection: " + + e); + } + } + System.out.println("Server: finished"); + } + + boolean isReady() { + return ready; + } + + void stop() { + stopped = true; + ready = false; + + // close the server socket to interupt accept() method + try { + if (!ssocket.isClosed()) { + ssocket.close(); + } + } catch (IOException e) { + throw new RuntimeException("Unexpected exception: " + e); + } + } + + @Override + public void close() { + stop(); + } + + int getPort() { + return ssocket.getLocalPort(); + } + + /* + * Creates server instance. + * + * @param cipherSuiteFilter Filter for enabled cipher suites + * @param sniMatcherPattern Pattern for SNI server hame + */ + static SSLEchoServer init(String cipherSuiteFilter, + String sniPattern) throws NoSuchAlgorithmException, IOException { + SSLContext context = SSLContext.getDefault(); + SSLServerSocketFactory ssf = + (SSLServerSocketFactory) context.getServerSocketFactory(); + SSLServerSocket ssocket = + (SSLServerSocket) ssf.createServerSocket(0); + + // specify enabled cipher suites + if (cipherSuiteFilter != null) { + String[] ciphersuites = UnboundSSLUtils.filterStringArray( + ssf.getSupportedCipherSuites(), cipherSuiteFilter); + System.out.println("Server: enabled cipher suites: " + + Arrays.toString(ciphersuites)); + ssocket.setEnabledCipherSuites(ciphersuites); + } + + // specify SNI matcher pattern + if (sniPattern != null) { + System.out.println("Server: set SNI matcher: " + sniPattern); + SNIMatcher matcher = SNIHostName.createSNIMatcher(sniPattern); + List matchers = new ArrayList<>(); + matchers.add(matcher); + SSLParameters params = ssocket.getSSLParameters(); + params.setSNIMatchers(matchers); + ssocket.setSSLParameters(params); + } + + return new SSLEchoServer(ssocket); + } + +} + diff --git a/test/sun/security/krb5/auto/unbound.ssl.jaas.conf b/test/sun/security/krb5/auto/unbound.ssl.jaas.conf new file mode 100644 index 0000000000000000000000000000000000000000..bee0a670c4b6c52c521e0392c469fbaa56088472 --- /dev/null +++ b/test/sun/security/krb5/auto/unbound.ssl.jaas.conf @@ -0,0 +1,40 @@ +com.sun.net.ssl.client { + com.sun.security.auth.module.Krb5LoginModule required + principal="USER@TEST.REALM" + doNotPrompt=true + useKeyTab=true + keyTab="krb5.keytab.data"; +}; + +server_star { + com.sun.security.auth.module.Krb5LoginModule required + principal="*" + isInitiator=false + useKeyTab=true + keyTab="krb5.keytab.data" + storeKey=true; +}; + +server_multiple_principals { + com.sun.security.auth.module.Krb5LoginModule required + principal="host/service1.localhost@TEST.REALM" + isInitiator=false + useKeyTab=true + keyTab="krb5.keytab.data" + storeKey=true; + + com.sun.security.auth.module.Krb5LoginModule required + principal="host/service2.localhost@TEST.REALM" + isInitiator=false + useKeyTab=true + keyTab="krb5.keytab.data" + storeKey=true; + + com.sun.security.auth.module.Krb5LoginModule required + principal="host/service3.localhost@TEST.REALM" + isInitiator=false + useKeyTab=true + keyTab="krb5.keytab.data" + storeKey=true; +}; + diff --git a/test/sun/security/krb5/auto/unbound.ssl.policy b/test/sun/security/krb5/auto/unbound.ssl.policy new file mode 100644 index 0000000000000000000000000000000000000000..0df839c2e7e80a174a04bfe275882bdb9b0e3191 --- /dev/null +++ b/test/sun/security/krb5/auto/unbound.ssl.policy @@ -0,0 +1,29 @@ +grant { + permission java.util.PropertyPermission "*", "read,write"; + permission java.net.SocketPermission "*:*", "listen,resolve,accept,connect"; + permission java.io.FilePermission "*", "read,write,delete"; + permission java.lang.RuntimePermission "accessDeclaredMembers"; + permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + permission java.lang.RuntimePermission "accessClassInPackage.*"; + permission javax.security.auth.AuthPermission "doAs"; + permission javax.security.auth.AuthPermission "getSubject"; + permission javax.security.auth.AuthPermission + "createLoginContext.server_star"; + permission javax.security.auth.AuthPermission + "createLoginContext.server_multiple_principals"; + permission javax.security.auth.AuthPermission "modifyPrincipals"; + permission javax.security.auth.PrivateCredentialPermission "javax.security.auth.kerberos.KeyTab java.security.Principal \"krb5.keytab.data\"", "read"; + + // clients have a permission to use all service principals + permission javax.security.auth.kerberos.ServicePermission "*", "initiate"; + + // server has a service permission + // to accept only service1 and service3 principals + permission javax.security.auth.kerberos.ServicePermission + "host/service1.localhost@TEST.REALM", "accept"; + permission javax.security.auth.kerberos.ServicePermission + "host/service3.localhost@TEST.REALM", "accept"; + + // permission to use SunJCE provider + permission java.security.SecurityPermission "putProviderProperty.SunJCE"; +};