1 /*
   2  * Copyright (c) 2001, 2015, 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 import java.io.BufferedOutputStream;
  25 import java.io.File;
  26 import java.io.FileInputStream;
  27 import java.io.FileOutputStream;
  28 import java.io.IOException;
  29 import java.security.AccessControlContext;
  30 import java.security.AccessControlException;
  31 import java.security.AccessController;
  32 import java.security.PrivilegedAction;
  33 import java.security.PrivilegedActionException;
  34 import java.security.PrivilegedExceptionAction;
  35 import java.util.ArrayList;
  36 import java.util.Arrays;
  37 import java.util.List;
  38 import java.util.jar.JarEntry;
  39 import java.util.jar.JarOutputStream;
  40 import java.util.jar.Manifest;
  41 import javax.security.auth.Subject;
  42 import javax.security.auth.x500.X500Principal;
  43 import jdk.testlibrary.ProcessTools;
  44 
  45 /**
  46  * @test
  47  * @bug 8048147
  48  * @summary Check if proper AccessControlException is thrown
  49  *          in case of nested Subject.doAs() invocations
  50  *          when one of protection domains doesn't have permissions
  51  *
  52  * @library /lib/testlibrary
  53  *
  54  * @run main NestedActions jar NestedActionsACE.jar
  55  *              NestedActionsACE.class Utils.class
  56  * @run main NestedActions jar NestedActionsPAE.jar
  57  *              NestedActionsPAE.class Utils.class
  58  * @run main NestedActions jar NestedActionsOnePrincipal.jar
  59  *              NestedActionsOnePrincipal.class Utils.class
  60  * @run main NestedActions jar NestedActionsTwoPrincipals.jar
  61  *              NestedActionsTwoPrincipals.class Utils.class
  62  * @run main NestedActions jar WriteToFileAction.jar
  63  *              WriteToFileAction.class
  64  * @run main NestedActions jar WriteToFileNegativeAction.jar
  65  *              WriteToFileNegativeAction.class
  66  * @run main NestedActions jar WriteToFileExceptionAction.jar
  67  *              WriteToFileExceptionAction.class
  68  * @run main NestedActions jar ReadFromFileAction.jar
  69  *              ReadFromFileAction.class
  70  * @run main NestedActions jar ReadFromFileNegativeAction.jar
  71  *              ReadFromFileNegativeAction.class
  72  * @run main NestedActions jar ReadFromFileExceptionAction.jar
  73  *              ReadFromFileExceptionAction.class
  74  * @run main NestedActions jar ReadPropertyAction.jar
  75  *              ReadPropertyAction.class
  76  * @run main NestedActions jar ReadPropertyNegativeAction.jar
  77  *              ReadPropertyNegativeAction.class
  78  * @run main NestedActions jar ReadPropertyExceptionAction.jar
  79  *              ReadPropertyExceptionAction.class ReadPropertyException.class
  80  *
  81  * @run main NestedActions NestedActionsACE policy.expect.ace
  82  *              NestedActionsACE.jar WriteToFileNegativeAction.jar
  83  *              ReadFromFileNegativeAction.jar ReadPropertyNegativeAction.jar
  84  * @run main NestedActions NestedActionsPAE policy.expect.pae
  85  *              NestedActionsPAE.jar WriteToFileExceptionAction.jar
  86  *              ReadFromFileExceptionAction.jar ReadPropertyExceptionAction.jar
  87  * @run main NestedActions NestedActionsOnePrincipal policy.one.principal
  88  *              NestedActionsOnePrincipal.jar WriteToFileAction.jar
  89  *              ReadFromFileAction.jar ReadPropertyAction.jar
  90  * @run main NestedActions NestedActionsTwoPrincipals policy.two.principals
  91  *              NestedActionsTwoPrincipals.jar WriteToFileAction.jar
  92  *              ReadFromFileAction.jar ReadPropertyAction.jar
  93  */
  94 public class NestedActions {
  95 
  96     static final String file = "NestedActions.tmp";
  97     static final String PS = System.getProperty("path.separator");
  98     static final String FS = System.getProperty("file.separator");
  99     static final String TEST_CLASSES = System.getProperty("test.classes");
 100     static final String TEST_SOURCES = System.getProperty("test.src");
 101     static final String JAVA_OPTS = System.getProperty("test.java.opts");
 102     static final String JAVA = System.getProperty("java.home")
 103             + FS + "bin" + FS + "java";
 104 
 105     public static void main(String[] args) throws IOException {
 106         if (args.length > 0) {
 107             if ("jar".equals(args[0]) && args.length > 2) {
 108                 createJar(args[1],
 109                     Arrays.copyOfRange(args, 2, args.length));
 110             } else {
 111                 runJava(args);
 112             }
 113         } else {
 114             throw new RuntimeException("Wrong parameters");
 115         }
 116     }
 117 
 118     static void createJar(String dest, String... files) throws IOException {
 119         System.out.println("Create " + dest + " with the following content:");
 120         try (JarOutputStream jos = new JarOutputStream(
 121                 new FileOutputStream(dest), new Manifest())) {
 122             for (String file : files) {
 123                 System.out.println("  " + file);
 124                 jos.putNextEntry(new JarEntry(file));
 125                 try (FileInputStream fis = new FileInputStream(
 126                         TEST_CLASSES + FS + file)) {
 127                     fis.transferTo(jos);
 128                 }
 129             }
 130         }
 131     }
 132 
 133     static void runJava(String[] args) {
 134         if (args == null || args.length < 3) {
 135             throw new IllegalArgumentException("wrong parameters");
 136         }
 137 
 138         List<String> cmds = new ArrayList<>();
 139         cmds.add(JAVA);
 140         StringBuilder sb = new StringBuilder();
 141         cmds.add("-classpath");
 142         for (int i=2; i<args.length; i++) {
 143             sb.append(args[i]).append(PS);
 144         }
 145         cmds.add(sb.toString());
 146         if (JAVA_OPTS != null && !JAVA_OPTS.isEmpty()) {
 147             Arrays.stream(JAVA_OPTS.split(" "))
 148                 .filter(str -> !str.trim().isEmpty())
 149                     .forEach(opt -> cmds.add(opt));
 150         }
 151         cmds.add("-Djava.security.manager");
 152         cmds.add("-Djava.security.policy=" + TEST_SOURCES + FS + args[1]);
 153         cmds.add(args[0]);
 154         try {
 155             ProcessTools.executeCommand(cmds.toArray(new String[cmds.size()]))
 156                     .shouldHaveExitValue(0);
 157         } catch (Throwable e) {
 158             throw new RuntimeException(e);
 159         }
 160     }
 161 }
 162 
 163 /**
 164  * Test for nested Subject.doAs() invocation:
 165  *
 166  * WriteToFileAction (CN=Duke principal) ->
 167  *      ReadFromFileAction (CN=Duke principal) ->
 168  *          ReadPropertyAction (CN=Duke principal)
 169  *
 170  * The test expects AccessControllException.
 171  */
 172 class NestedActionsACE {
 173 
 174     public static void main(String args[]) {
 175         Subject subject = new Subject();
 176         subject.getPrincipals().add(new X500Principal("CN=Duke"));
 177         WriteToFileNegativeAction writeToFile
 178                 = new WriteToFileNegativeAction(NestedActions.file);
 179         Subject.doAs(subject, writeToFile);
 180     }
 181 }
 182 
 183 /**
 184  * Test for nested Subject.doAs() invocation:
 185  *
 186  * WriteToFileAction (CN=Duke principal) ->
 187  *      ReadFromFileAction (CN=Duke principal) ->
 188  *          ReadPropertyAction (CN=Duke principal)
 189  *
 190  * The test expects PrivilegedActionException
 191  * that caused by AccessControlEception.
 192  */
 193 class NestedActionsPAE {
 194 
 195     public static void main(String args[]) {
 196         Subject subject = new Subject();
 197         subject.getPrincipals().add(new X500Principal("CN=Duke"));
 198         try {
 199             WriteToFileExceptionAction writeToFile =
 200                     new WriteToFileExceptionAction(NestedActions.file);
 201             Subject.doAs(subject, writeToFile);
 202             throw new RuntimeException(
 203                     "Test failed: no PrivilegedActionException thrown");
 204         } catch (PrivilegedActionException pae) {
 205             System.out.println(
 206                     "PrivilegedActionException thrown as expected: "
 207                     + pae);
 208 
 209             // check if AccessControlException caused PrivilegedActionException
 210             Throwable exception = pae.getException();
 211             do {
 212                 if (!(exception instanceof PrivilegedActionException)) {
 213                     break;
 214                 }
 215                 exception = ((PrivilegedActionException) exception).
 216                         getException();
 217             } while (true);
 218 
 219             if (!(exception instanceof ReadPropertyException)) {
 220                 throw new RuntimeException(
 221                         "Test failed: PrivilegedActionException "
 222                         + "was not caused by ReadPropertyException");
 223             }
 224 
 225             exception = exception.getCause();
 226             if (!(exception instanceof AccessControlException)) {
 227                 throw new RuntimeException(
 228                         "Test failed: PrivilegedActionException "
 229                         + "was not caused by ReadPropertyException");
 230             }
 231 
 232             System.out.println(
 233                     "Test passed: PrivilegedActionException "
 234                     + "was caused by AccessControlException");
 235         }
 236     }
 237 }
 238 
 239 /**
 240  * Test for nested Subject.doAs() invocation:
 241  *
 242  * WriteToFileAction (CN=Duke principal) ->
 243  *      ReadFromFileAction (CN=Duke principal) ->
 244  *          ReadPropertyAction (CN=Duke principal)
 245  */
 246 class NestedActionsOnePrincipal {
 247 
 248     public static void main(String args[]) {
 249         Subject subject = new Subject();
 250         subject.getPrincipals().add(new X500Principal("CN=Duke"));
 251         WriteToFileAction writeToFile =
 252                 new WriteToFileAction(NestedActions.file);
 253         Subject.doAs(subject, writeToFile);
 254     }
 255 }
 256 
 257 /**
 258  * Test for nested Subject.doAs() invocation:
 259  *
 260  * WriteToFileAction (CN=Duke principal) ->
 261  *      ReadFromFileAction (CN=Duke principal) ->
 262  *          ReadPropertyAction (CN=Java principal)
 263  */
 264 class NestedActionsTwoPrincipals {
 265 
 266     public static void main(String args[]) {
 267         Subject subject = new Subject();
 268         subject.getPrincipals().add(new X500Principal("CN=Duke"));
 269         Subject anotherSubject = new Subject();
 270         anotherSubject.getPrincipals().add(new X500Principal("CN=Java"));
 271         ReadFromFileAction readFromFile
 272                 = new ReadFromFileAction(NestedActions.file, anotherSubject);
 273         WriteToFileAction writeToFile
 274                 = new WriteToFileAction(NestedActions.file, readFromFile);
 275         Subject.doAs(subject, writeToFile);
 276     }
 277 }
 278 
 279 /**
 280  * Helper class.
 281  */
 282 class Utils {
 283 
 284     static void readFile(String filename) {
 285         System.out.println("ReadFromFileAction: try to read " + filename);
 286         AccessControlContext acc = AccessController.getContext();
 287         Subject subject = Subject.getSubject(acc);
 288         System.out.println("principals = " + subject.getPrincipals());
 289         try (FileInputStream fis = new FileInputStream(filename)) {
 290             // do nothing
 291         } catch (IOException e) {
 292             throw new RuntimeException("Unexpected IOException", e);
 293         }
 294     }
 295 
 296     static void writeFile(String filename) {
 297         System.out.println("WriteToFileAction: try to write to " + filename);
 298         AccessControlContext acc = AccessController.getContext();
 299         Subject subject = Subject.getSubject(acc);
 300         System.out.println("principals = " + subject.getPrincipals());
 301         try (BufferedOutputStream bos = new BufferedOutputStream(
 302                 new FileOutputStream(filename))) {
 303             bos.write(0);
 304             bos.flush();
 305         } catch (IOException e) {
 306             throw new RuntimeException("Unexpected IOException", e);
 307         }
 308     }
 309 
 310 }
 311 
 312 class WriteToFileAction implements PrivilegedAction {
 313 
 314     private final String filename;
 315     private final PrivilegedAction nextAction;
 316 
 317     WriteToFileAction(String filename, PrivilegedAction nextAction) {
 318         this.filename = filename;
 319         this.nextAction = nextAction;
 320     }
 321 
 322     WriteToFileAction(String filename) {
 323         this(filename, new ReadFromFileAction(filename));
 324     }
 325 
 326     @Override
 327     public Object run() {
 328         Utils.writeFile(filename);
 329         AccessControlContext acc = AccessController.getContext();
 330         Subject subject = Subject.getSubject(acc);
 331         return Subject.doAs(subject, nextAction);
 332     }
 333 
 334 }
 335 
 336 class ReadFromFileAction implements PrivilegedAction {
 337 
 338     private final String filename;
 339     private final Subject anotherSubject;
 340 
 341     ReadFromFileAction(String filename) {
 342         this(filename, null);
 343     }
 344 
 345     ReadFromFileAction(String filename, Subject anotherSubject) {
 346         this.filename = filename;
 347         this.anotherSubject = anotherSubject;
 348     }
 349 
 350     @Override
 351     public Object run() {
 352         Utils.readFile(filename);
 353 
 354         AccessControlContext acc = AccessController.getContext();
 355         Subject subject = Subject.getSubject(acc);
 356         ReadPropertyAction readProperty = new ReadPropertyAction();
 357         if (anotherSubject != null) {
 358             return Subject.doAs(anotherSubject, readProperty);
 359         } else {
 360             return Subject.doAs(subject, readProperty);
 361         }
 362     }
 363 
 364 }
 365 
 366 class ReadPropertyAction implements PrivilegedAction {
 367 
 368     @Override
 369     public java.lang.Object run() {
 370         System.out.println("ReadPropertyAction: "
 371                 + "try to read 'java.class.path' property");
 372 
 373         AccessControlContext acc = AccessController.getContext();
 374         Subject s = Subject.getSubject(acc);
 375         System.out.println("principals = " + s.getPrincipals());
 376         System.out.println("java.class.path = "
 377                 + System.getProperty("java.class.path"));
 378 
 379         return null;
 380     }
 381 
 382 }
 383 
 384 class WriteToFileNegativeAction implements PrivilegedAction {
 385 
 386     private final String filename;
 387 
 388     public WriteToFileNegativeAction(String filename) {
 389         this.filename = filename;
 390     }
 391 
 392     @Override
 393     public Object run() {
 394         AccessControlContext acc = AccessController.getContext();
 395         Subject subject = Subject.getSubject(acc);
 396         System.out.println("principals = " + subject.getPrincipals());
 397 
 398         try {
 399             Utils.writeFile(filename);
 400             new File(filename).delete();
 401             throw new RuntimeException(
 402                     "Test failed: no AccessControlException thrown");
 403         } catch (AccessControlException ace) {
 404             System.out.println(
 405                     "AccessControlException thrown as expected: "
 406                     + ace.getMessage());
 407         }
 408 
 409         ReadFromFileNegativeAction readFromFile
 410                 = new ReadFromFileNegativeAction(filename);
 411         return Subject.doAs(subject, readFromFile);
 412     }
 413 
 414 }
 415 
 416 class ReadFromFileNegativeAction implements PrivilegedAction {
 417 
 418     private final String filename;
 419 
 420     public ReadFromFileNegativeAction(String filename) {
 421         this.filename = filename;
 422     }
 423 
 424     @Override
 425     public Object run() {
 426         AccessControlContext acc = AccessController.getContext();
 427         Subject subject = Subject.getSubject(acc);
 428         System.out.println("principals = " + subject.getPrincipals());
 429 
 430         try {
 431             Utils.readFile(filename);
 432             throw new RuntimeException(
 433                     "Test failed: no AccessControlException thrown");
 434         } catch (AccessControlException ace) {
 435             System.out.println(
 436                     "AccessControlException thrown as expected: "
 437                     + ace.getMessage());
 438         }
 439 
 440         ReadPropertyNegativeAction readProperty =
 441                 new ReadPropertyNegativeAction();
 442         return Subject.doAs(subject, readProperty);
 443     }
 444 
 445 }
 446 
 447 class ReadPropertyNegativeAction implements PrivilegedAction {
 448 
 449     @Override
 450     public java.lang.Object run() {
 451         System.out.println("Try to read 'java.class.path' property");
 452 
 453         AccessControlContext acc = AccessController.getContext();
 454         Subject s = Subject.getSubject(acc);
 455         System.out.println("principals = " + s.getPrincipals());
 456 
 457         try {
 458             System.out.println("java.class.path = "
 459                     + System.getProperty("java.class.path"));
 460             throw new RuntimeException(
 461                     "Test failed: no AccessControlException thrown");
 462         } catch (AccessControlException ace) {
 463             System.out.println(
 464                     "AccessControlException thrown as expected: "
 465                     + ace.getMessage());
 466         }
 467 
 468         return null;
 469     }
 470 
 471 }
 472 
 473 class WriteToFileExceptionAction implements PrivilegedExceptionAction {
 474 
 475     private final String filename;
 476 
 477     WriteToFileExceptionAction(String filename) {
 478         this.filename = filename;
 479     }
 480 
 481     @Override
 482     public Object run() throws Exception {
 483         Utils.writeFile(filename);
 484         AccessControlContext acc = AccessController.getContext();
 485         Subject subject = Subject.getSubject(acc);
 486         ReadFromFileExceptionAction readFromFile =
 487                 new ReadFromFileExceptionAction(filename);
 488         return Subject.doAs(subject, readFromFile);
 489     }
 490 
 491 }
 492 
 493 class ReadFromFileExceptionAction implements PrivilegedExceptionAction {
 494 
 495     private final String filename;
 496 
 497     ReadFromFileExceptionAction(String filename) {
 498         this.filename = filename;
 499     }
 500 
 501     @Override
 502     public Object run() throws Exception {
 503         Utils.readFile(filename);
 504         AccessControlContext acc = AccessController.getContext();
 505         Subject subject = Subject.getSubject(acc);
 506         ReadPropertyExceptionAction readProperty =
 507                 new ReadPropertyExceptionAction();
 508         return Subject.doAs(subject, readProperty);
 509     }
 510 
 511 }
 512 
 513 class ReadPropertyExceptionAction implements PrivilegedExceptionAction {
 514 
 515     @Override
 516     public java.lang.Object run() throws Exception {
 517         System.out.println("Try to read 'java.class.path' property");
 518 
 519         AccessControlContext acc = AccessController.getContext();
 520         Subject s = Subject.getSubject(acc);
 521         System.out.println("principals = " + s.getPrincipals());
 522 
 523         try {
 524             System.out.println("java.class.path = "
 525                     + System.getProperty("java.class.path"));
 526             throw new RuntimeException(
 527                     "Test failed: no AccessControlException thrown");
 528         } catch (AccessControlException ace) {
 529             System.out.println(
 530                     "AccessControlException thrown as expected: "
 531                     + ace.getMessage());
 532             throw new ReadPropertyException(ace);
 533         }
 534     }
 535 
 536 }
 537 
 538 class ReadPropertyException extends Exception {
 539 
 540     ReadPropertyException(Throwable cause) {
 541         super(cause);
 542     }
 543 }