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