1 /* 2 * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8009977 8186884 8201627 27 * @summary A test to launch multiple Java processes using either Java GSS 28 * or native GSS 29 * @library ../../../../java/security/testlibrary /lib/testlibrary 30 * @compile -XDignore.symbol.file BasicProc.java 31 * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock BasicProc launcher 32 */ 33 34 import java.nio.file.Files; 35 import java.nio.file.Paths; 36 import java.nio.file.attribute.PosixFilePermission; 37 import java.util.Arrays; 38 import java.util.Collections; 39 import java.util.HashSet; 40 import java.util.PropertyPermission; 41 import java.util.Set; 42 43 import jdk.testlibrary.Asserts; 44 import org.ietf.jgss.Oid; 45 import sun.security.krb5.Config; 46 47 import javax.security.auth.PrivateCredentialPermission; 48 49 /** 50 * Run this test automatically and test Java GSS with embedded KDC. 51 * 52 * Run with customized native.krb5.libs to test interop between Java GSS 53 * and native GSS, and native.kdc.path with a native KDC. For example, 54 * run the following command to test interop among Java, default native, 55 * MIT, and Heimdal krb5 libraries with the Heimdal KDC: 56 * 57 * jtreg -Dnative.krb5.libs=j=, 58 * n=, 59 * k=/usr/local/krb5/lib/libgssapi_krb5.so, 60 * h=/space/install/heimdal/lib/libgssapi.so \ 61 * -Dnative.kdc.path=/usr/local/heimdal \ 62 * BasicProc.java 63 * 64 * Note: The first 4 lines should be concatenated to make a long system 65 * property value with no blank around ",". This comma-separated value 66 * has each element being name=libpath. The special name "j" means the 67 * Java library and libpath is ignored. Otherwise it means a native library, 68 * and libpath (can be empty) will be the value for the sun.security.jgss.lib 69 * system property. If this system property is not set, only the Java 70 * library will be tested. 71 */ 72 73 public class BasicProc { 74 75 private static final String CONF = "krb5.conf"; 76 private static final String KTAB_S = "server.ktab"; 77 private static final String KTAB_B = "backend.ktab"; 78 79 private static final String HOST = "localhost"; 80 private static final String SERVER = "server/" + HOST; 81 private static final String BACKEND = "backend/" + HOST; 82 private static final String USER = "user"; 83 private static final char[] PASS = "password".toCharArray(); 84 private static final String REALM = "REALM"; 85 86 private static final int MSGSIZE = 1024; 87 private static final byte[] MSG = new byte[MSGSIZE]; 88 main(String[] args)89 public static void main(String[] args) throws Exception { 90 91 Oid oid = new Oid("1.2.840.113554.1.2.2"); 92 byte[] token, msg; 93 94 switch (args[0]) { 95 case "launcher": 96 KDC kdc = KDC.create(REALM, HOST, 0, true); 97 try { 98 kdc.addPrincipal(USER, PASS); 99 kdc.addPrincipalRandKey("krbtgt/" + REALM); 100 kdc.addPrincipalRandKey(SERVER); 101 kdc.addPrincipalRandKey(BACKEND); 102 103 // Native lib might do some name lookup 104 KDC.saveConfig(CONF, kdc, 105 "dns_lookup_kdc = no", 106 "ticket_lifetime = 1h", 107 "dns_lookup_realm = no", 108 "dns_canonicalize_hostname = false", 109 "forwardable = true"); 110 System.setProperty("java.security.krb5.conf", CONF); 111 Config.refresh(); 112 kdc.writeKtab(KTAB_S, false, SERVER); 113 kdc.writeKtab(KTAB_B, false, BACKEND); 114 115 String[] tmp = System.getProperty("native.krb5.libs", "j=") 116 .split(","); 117 118 // Library paths. The 1st one is always null which means 119 // Java, "" means the default native lib. 120 String[] libs = new String[tmp.length]; 121 122 // Names for each lib above. Use in file names. 123 String[] names = new String[tmp.length]; 124 125 boolean hasNative = false; 126 127 for (int i = 0; i < tmp.length; i++) { 128 if (tmp[i].isEmpty()) { 129 throw new Exception("Invalid native.krb5.libs"); 130 } 131 String[] pair = tmp[i].split("=", 2); 132 names[i] = pair[0]; 133 if (!pair[0].equals("j")) { 134 libs[i] = pair.length > 1 ? pair[1] : ""; 135 hasNative = true; 136 } 137 } 138 139 if (hasNative) { 140 kdc.kinit(USER, "base.ccache"); 141 } 142 143 // Try the same lib first 144 for (int i = 0; i < libs.length; i++) { 145 once(names[i] + names[i] + names[i], 146 libs[i], libs[i], libs[i]); 147 } 148 149 for (int i = 0; i < libs.length; i++) { 150 for (int j = 0; j < libs.length; j++) { 151 for (int k = 0; k < libs.length; k++) { 152 if (i != j || i != k) { 153 once(names[i] + names[j] + names[k], 154 libs[i], libs[j], libs[k]); 155 } 156 } 157 } 158 } 159 } finally { 160 kdc.terminate(); 161 } 162 break; 163 case "client": 164 Context c = args[1].equals("n") ? 165 Context.fromThinAir() : 166 Context.fromUserPass(USER, PASS, false); 167 c.startAsClient(SERVER, oid); 168 c.x().requestCredDeleg(true); 169 c.x().requestMutualAuth(true); 170 Proc.binOut(c.take(new byte[0])); // AP-REQ 171 c.take(Proc.binIn()); // AP-REP 172 Proc.binOut(c.wrap(MSG, true)); 173 Proc.binOut(c.getMic(MSG)); 174 break; 175 case "server": 176 Context s = args[1].equals("n") ? 177 Context.fromThinAir() : 178 Context.fromUserKtab(SERVER, KTAB_S, true); 179 s.startAsServer(oid); 180 token = Proc.binIn(); // AP-REQ 181 Proc.binOut(s.take(token)); // AP-REP 182 msg = s.unwrap(Proc.binIn(), true); 183 Asserts.assertTrue(Arrays.equals(msg, MSG)); 184 s.verifyMic(Proc.binIn(), msg); 185 Context s2 = s.delegated(); 186 s2.startAsClient(BACKEND, oid); 187 s2.x().requestMutualAuth(false); 188 Proc.binOut(s2.take(new byte[0])); // AP-REQ 189 msg = s2.unwrap(Proc.binIn(), true); 190 Asserts.assertTrue(Arrays.equals(msg, MSG)); 191 s2.verifyMic(Proc.binIn(), msg); 192 break; 193 case "backend": 194 Context b = args[1].equals("n") ? 195 Context.fromThinAir() : 196 Context.fromUserKtab(BACKEND, KTAB_B, true); 197 b.startAsServer(oid); 198 token = b.take(Proc.binIn()); // AP-REQ 199 Asserts.assertTrue(token == null); 200 Proc.binOut(b.wrap(MSG, true)); 201 Proc.binOut(b.getMic(MSG)); 202 break; 203 } 204 } 205 206 /** 207 * One test run. 208 * 209 * @param label test label 210 * @param lc lib of client 211 * @param ls lib of server 212 * @param lb lib of backend 213 */ once(String label, String lc, String ls, String lb)214 private static void once(String label, String lc, String ls, String lb) 215 throws Exception { 216 217 Proc pc = proc(lc) 218 .args("client", lc == null ? "j" : "n") 219 .perm(new javax.security.auth.kerberos.ServicePermission( 220 "krbtgt/" + REALM + "@" + REALM, "initiate")) 221 .perm(new javax.security.auth.kerberos.ServicePermission( 222 SERVER + "@" + REALM, "initiate")) 223 .perm(new javax.security.auth.kerberos.DelegationPermission( 224 "\"" + SERVER + "@" + REALM + "\" " + 225 "\"krbtgt/" + REALM + "@" + REALM + "\"")) 226 .debug(label + "-C"); 227 if (lc == null) { 228 // for Krb5LoginModule::promptForName 229 pc.perm(new PropertyPermission("user.name", "read")); 230 } else { 231 Files.copy(Paths.get("base.ccache"), Paths.get(label + ".ccache")); 232 Set<PosixFilePermission> perms = new HashSet<>(); 233 perms.add(PosixFilePermission.OWNER_READ); 234 perms.add(PosixFilePermission.OWNER_WRITE); 235 Files.setPosixFilePermissions(Paths.get(label + ".ccache"), 236 Collections.unmodifiableSet(perms)); 237 pc.env("KRB5CCNAME", label + ".ccache"); 238 // Do not try system ktab if ccache fails 239 pc.env("KRB5_KTNAME", "none"); 240 } 241 pc.start(); 242 243 Proc ps = proc(ls) 244 .args("server", ls == null ? "j" : "n") 245 .perm(new javax.security.auth.kerberos.ServicePermission( 246 SERVER + "@" + REALM, "accept")) 247 .perm(new javax.security.auth.kerberos.ServicePermission( 248 BACKEND + "@" + REALM, "initiate")) 249 .debug(label + "-S"); 250 if (ls == null) { 251 ps.perm(new PrivateCredentialPermission( 252 "javax.security.auth.kerberos.KeyTab * \"*\"", "read")) 253 .perm(new java.io.FilePermission(KTAB_S, "read")); 254 } else { 255 ps.env("KRB5_KTNAME", KTAB_S); 256 } 257 ps.start(); 258 259 Proc pb = proc(lb) 260 .args("backend", lb == null ? "j" : "n") 261 .perm(new javax.security.auth.kerberos.ServicePermission( 262 BACKEND + "@" + REALM, "accept")) 263 .debug(label + "-B"); 264 if (lb == null) { 265 pb.perm(new PrivateCredentialPermission( 266 "javax.security.auth.kerberos.KeyTab * \"*\"", "read")) 267 .perm(new java.io.FilePermission(KTAB_B, "read")); 268 } else { 269 pb.env("KRB5_KTNAME", KTAB_B); 270 } 271 pb.start(); 272 273 // Client and server 274 ps.println(pc.readData()); // AP-REQ 275 pc.println(ps.readData()); // AP-REP 276 277 ps.println(pc.readData()); // KRB-PRIV 278 ps.println(pc.readData()); // KRB-SAFE 279 280 // Server and backend 281 pb.println(ps.readData()); // AP-REQ 282 283 ps.println(pb.readData()); // KRB-PRIV 284 ps.println(pb.readData()); // KRB-SAFE 285 286 if ((pc.waitFor() | ps.waitFor() | pb.waitFor()) != 0) { 287 throw new Exception("Process failed"); 288 } 289 } 290 291 /** 292 * A Proc for a child process. 293 * 294 * @param lib the library. Null is Java. "" is default native lib. 295 */ proc(String lib)296 private static Proc proc(String lib) throws Exception { 297 Proc p = Proc.create("BasicProc") 298 .prop("java.security.manager", "") 299 .prop("sun.net.spi.nameservice.provider.1", "ns,mock") 300 .perm(new javax.security.auth.AuthPermission("doAs")); 301 if (lib != null) { 302 p.env("KRB5_CONFIG", CONF) 303 .env("KRB5_TRACE", "/dev/stderr") 304 .prop("sun.security.jgss.native", "true") 305 .prop("sun.security.jgss.lib", lib) 306 .prop("javax.security.auth.useSubjectCredsOnly", "false") 307 .prop("sun.security.nativegss.debug", "true"); 308 int pos = lib.lastIndexOf('/'); 309 if (pos > 0) { 310 p.env("LD_LIBRARY_PATH", lib.substring(0, pos)); 311 p.env("DYLD_LIBRARY_PATH", lib.substring(0, pos)); 312 } 313 } else { 314 p.perm(new java.util.PropertyPermission( 315 "sun.security.krb5.principal", "read")) 316 // For Krb5LoginModule::login. 317 .perm(new java.lang.RuntimePermission( 318 "accessClassInPackage.sun.net.spi.nameservice")) 319 .perm(new javax.security.auth.AuthPermission( 320 "modifyPrincipals")) 321 .perm(new javax.security.auth.AuthPermission( 322 "modifyPrivateCredentials")) 323 .prop("sun.security.krb5.debug", "true") 324 .prop("java.security.krb5.conf", CONF); 325 } 326 return p; 327 } 328 } 329