1 /*
   2  * Copyright (c) 2014, 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 import java.io.ByteArrayInputStream;
  24 import java.io.FilePermission;
  25 import java.io.IOException;
  26 import java.security.AccessControlException;
  27 import java.security.CodeSource;
  28 import java.security.Permission;
  29 import java.security.PermissionCollection;
  30 import java.security.Permissions;
  31 import java.security.Policy;
  32 import java.security.ProtectionDomain;
  33 import java.util.Enumeration;
  34 import java.util.PropertyPermission;
  35 import java.util.concurrent.atomic.AtomicLong;
  36 import java.util.logging.LogManager;
  37 import java.util.logging.LoggingPermission;
  38 
  39 /**
  40  * @test
  41  * @bug 8043306
  42  * @summary tests LogManager.addConfigurationListener and
  43  *                LogManager.removeConfigurationListener;
  44  * @build TestConfigurationListeners
  45  * @run main/othervm TestConfigurationListeners UNSECURE
  46  * @run main/othervm TestConfigurationListeners PERMISSION
  47  * @run main/othervm TestConfigurationListeners SECURE
  48  * @author danielfuchs
  49  */
  50 public class TestConfigurationListeners {
  51 
  52     /**
  53      * We will test add and remove ConfigurationListeners in 3 configurations.
  54      * UNSECURE: No security manager.
  55      * SECURE: With the security manager present - and the required
  56      *         LoggingPermission("control") granted.
  57      * PERMISSION: With the security manager present - and the required
  58      *         LoggingPermission("control") *not* granted. Here we will
  59      *         test that the expected security permission is thrown.
  60      */
  61     public static enum TestCase {
  62         UNSECURE, SECURE, PERMISSION;
  63         public void run(String name) throws Exception {
  64             System.out.println("Running test case: " + name());
  65             switch (this) {
  66                 case UNSECURE:
  67                     testUnsecure(name);
  68                     break;
  69                 case SECURE:
  70                     testSecure(name);
  71                     break;
  72                 case PERMISSION:
  73                     testPermission(name);
  74                     break;
  75                 default:
  76                     throw new Error("Unknown test case: "+this);
  77             }
  78         }
  79         public String loggerName(String name) {
  80             return name;
  81         }
  82     }
  83 
  84     public static void main(String... args) throws Exception {
  85 
  86  
  87         if (args == null || args.length == 0) {
  88             args = new String[] {
  89                 TestCase.UNSECURE.name(),
  90                 TestCase.SECURE.name(),
  91             };
  92         }
  93 
  94         for (String testName : args) {
  95             TestCase test = TestCase.valueOf(testName);
  96             test.run(test.loggerName("foo.bar"));
  97         }
  98     }
  99 
 100     /**
 101      * Test without security manager.
 102      * @param loggerName The logger to use.
 103      * @throws Exception if the test fails.
 104      */
 105     public static void testUnsecure(String loggerName) throws Exception {
 106         if (System.getSecurityManager() != null) {
 107             throw new Error("Security manager is set");
 108         }
 109         test(loggerName);
 110     }
 111 
 112     /**
 113      * Test with security manager.
 114      * @param loggerName The logger to use.
 115      * @throws Exception if the test fails.
 116      */
 117     public static void testSecure(String loggerName) throws Exception {
 118         if (System.getSecurityManager() != null) {
 119             throw new Error("Security manager is already set");
 120         }
 121         Policy.setPolicy(new SimplePolicy(TestCase.SECURE));
 122         System.setSecurityManager(new SecurityManager());
 123         test(loggerName);
 124     }
 125 
 126     /**
 127      * Test the LoggingPermission("control") is required.
 128      * @param loggerName The logger to use.
 129      */
 130     public static void testPermission(String loggerName) {
 131         TestConfigurationListener run = new TestConfigurationListener(TestCase.PERMISSION.toString());
 132         if (System.getSecurityManager() != null) {
 133             throw new Error("Security manager is already set");
 134         }
 135         Policy.setPolicy(new SimplePolicy(TestCase.PERMISSION));
 136         System.setSecurityManager(new SecurityManager());
 137         
 138         try {
 139             run = new TestConfigurationListener("[Should Be Denied]");
 140             throw new RuntimeException("ConfigurationListener constructor: Permission not checked!");
 141         } catch (AccessControlException x) {
 142             boolean ok = false;
 143             if (x.getPermission() instanceof LoggingPermission) {
 144                 if ("control".equals(x.getPermission().getName())) {
 145                     System.out.println("ConfigurationListener constructor: Got expected exception: " + x);
 146                     ok = true;
 147                 }
 148             }
 149             if (!ok) {
 150                 throw new RuntimeException("ConfigurationListener constructor: Unexpected exception: "+x, x);
 151             }
 152         }
 153         try {
 154             LogManager.getLogManager().addConfigurationListener(run);
 155             throw new RuntimeException("addConfigurationListener: Permission not checked!");
 156         } catch (AccessControlException x) {
 157             boolean ok = false;
 158             if (x.getPermission() instanceof LoggingPermission) {
 159                 if ("control".equals(x.getPermission().getName())) {
 160                     System.out.println("addConfigurationListener: Got expected exception: " + x);
 161                     ok = true;
 162                 }
 163             }
 164             if (!ok) {
 165                 throw new RuntimeException("addConfigurationListener: Unexpected exception: "+x, x);
 166             }
 167         }
 168 
 169         try {
 170             LogManager.getLogManager().removeConfigurationListener(run);
 171             throw new RuntimeException("removeConfigurationListener: Permission not checked!");
 172         } catch (AccessControlException x) {
 173             boolean ok = false;
 174             if (x.getPermission() instanceof LoggingPermission) {
 175                 if ("control".equals(x.getPermission().getName())) {
 176                     System.out.println("removeConfigurationListener: Got expected exception: " + x);
 177                     ok = true;
 178                 }
 179             }
 180             if (!ok) {
 181                 throw new RuntimeException("removeConfigurationListener: Unexpected exception: "+x, x);
 182             }
 183         }
 184 
 185     }
 186 
 187 
 188     static class TestConfigurationListener extends LogManager.ConfigurationListener {
 189         final AtomicLong  count = new AtomicLong(0);
 190         final String name;
 191         TestConfigurationListener(String name) {
 192             this.name = name;
 193         }
 194         @Override
 195         public void configurationLoaded() {
 196             final long times = count.incrementAndGet();
 197             System.out.println("Configured \"" + name + "\": " + times);
 198         }
 199     }
 200 
 201     private static void expect(TestConfigurationListener listener, long value) {
 202         final long got = listener.count.longValue();
 203         if (got != value) {
 204             throw new RuntimeException(listener.name + " expected " + value +", got " + got);
 205         }
 206 
 207     }
 208 
 209     public interface ThrowingConsumer<T, I extends Exception> {
 210         public void accept(T t) throws I;
 211     }
 212 
 213     public static class ReadConfiguration implements ThrowingConsumer<LogManager, IOException> {
 214 
 215         @Override
 216         public void accept(LogManager t) throws IOException {
 217             t.readConfiguration();
 218         }
 219 
 220     }
 221 
 222     public static void test(String loggerName) throws Exception {
 223         System.out.println("Starting test for " + loggerName);
 224         test("m.readConfiguration()", (m) -> m.readConfiguration());
 225         test("m.readConfiguration(new ByteArrayInputStream(new byte[0]))",
 226                 (m) -> m.readConfiguration(new ByteArrayInputStream(new byte[0])));
 227         System.out.println("Test passed for " + loggerName);
 228     }
 229     
 230     public static void test(String testName,
 231             ThrowingConsumer<LogManager, IOException> readConfiguration) throws Exception {
 232 
 233 
 234         System.out.println("\nBEGIN " + testName);
 235         LogManager m = LogManager.getLogManager();
 236 
 237         final TestConfigurationListener l1 = new TestConfigurationListener("l#1");
 238         final TestConfigurationListener l2 = new TestConfigurationListener("l#2");
 239         m.addConfigurationListener(l1);
 240         m.addConfigurationListener(l2);
 241         expect(l1, 0);
 242         expect(l2, 0);
 243 
 244         readConfiguration.accept(m);
 245         expect(l1, 1);
 246         expect(l2, 1);
 247         m.addConfigurationListener(l1);
 248         expect(l1, 1);
 249         expect(l2, 1);
 250         readConfiguration.accept(m);
 251         expect(l1, 3);
 252         expect(l2, 2);
 253         m.removeConfigurationListener(l1);
 254         expect(l1, 3);
 255         expect(l2, 2);
 256         readConfiguration.accept(m);
 257         expect(l1, 4);
 258         expect(l2, 3);
 259         m.removeConfigurationListener(l1);
 260         expect(l1, 4);
 261         expect(l2, 3);
 262         readConfiguration.accept(m);
 263         expect(l1, 4);
 264         expect(l2, 4);
 265         m.removeConfigurationListener(l2);
 266         expect(l1, 4);
 267         expect(l2, 4);
 268         readConfiguration.accept(m);
 269         expect(l1, 4);
 270         expect(l2, 4);
 271 
 272         // l1 and l2 should no longer be present: this should not fail...
 273         m.removeConfigurationListener(l1);
 274         m.removeConfigurationListener(l1);
 275         m.removeConfigurationListener(l2);
 276         m.removeConfigurationListener(l2);
 277         expect(l1, 4);
 278         expect(l2, 4);
 279 
 280         readConfiguration.accept(m);
 281         expect(l1, 4);
 282         expect(l2, 4);
 283 
 284         // add back l1 and l2
 285         m.addConfigurationListener(l1);
 286         m.addConfigurationListener(l2);
 287         expect(l1, 4);
 288         expect(l2, 4);
 289 
 290         readConfiguration.accept(m);
 291         expect(l1, 5);
 292         expect(l2, 5);
 293 
 294         m.removeConfigurationListener(l1);
 295         m.removeConfigurationListener(l2);
 296         expect(l1, 5);
 297         expect(l2, 5);
 298 
 299         readConfiguration.accept(m);
 300         expect(l1, 5);
 301         expect(l2, 5);
 302 
 303         System.out.println("END " + testName+"\n");
 304 
 305     }
 306 
 307 
 308     final static class PermissionsBuilder {
 309         final Permissions perms;
 310         public PermissionsBuilder() {
 311             this(new Permissions());
 312         }
 313         public PermissionsBuilder(Permissions perms) {
 314             this.perms = perms;
 315         }
 316         public PermissionsBuilder add(Permission p) {
 317             perms.add(p);
 318             return this;
 319         }
 320         public PermissionsBuilder addAll(PermissionCollection col) {
 321             if (col != null) {
 322                 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
 323                     perms.add(e.nextElement());
 324                 }
 325             }
 326             return this;
 327         }
 328         public Permissions toPermissions() {
 329             final PermissionsBuilder builder = new PermissionsBuilder();
 330             builder.addAll(perms);
 331             return builder.perms;
 332         }
 333     }
 334 
 335     public static class SimplePolicy extends Policy {
 336 
 337         final Permissions permissions;
 338         public SimplePolicy(TestCase test) {
 339             permissions = new Permissions();
 340             if (test != TestCase.PERMISSION) {
 341                 permissions.add(new LoggingPermission("control", null));
 342                 permissions.add(new PropertyPermission("java.util.logging.config.class", "read"));
 343                 permissions.add(new PropertyPermission("java.util.logging.config.file", "read"));
 344                 permissions.add(new PropertyPermission("java.home", "read"));
 345                 permissions.add(new FilePermission("<<ALL FILES>>", "read"));
 346             }
 347         }
 348 
 349         @Override
 350         public boolean implies(ProtectionDomain domain, Permission permission) {
 351             return permissions.implies(permission);
 352         }
 353 
 354         @Override
 355         public PermissionCollection getPermissions(CodeSource codesource) {
 356             return new PermissionsBuilder().addAll(permissions).toPermissions();
 357         }
 358 
 359         @Override
 360         public PermissionCollection getPermissions(ProtectionDomain domain) {
 361             return new PermissionsBuilder().addAll(permissions).toPermissions();
 362         }
 363     }
 364 
 365 }