// Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
// Written by Gary Benson <gbenson@redhat.com>
// This file is part of Mauve.
// Mauve is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// Mauve 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 for more details.
// You should have received a copy of the GNU General Public License
// along with Mauve; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
// Tags: JDK1.2
package gnu.testlet.java.lang.Class;
import java.io.File;
import java.lang.reflect.Member;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.Permission;
import java.security.Security;
import gnu.testlet.Testlet;
import gnu.testlet.TestHarness;
import gnu.testlet.TestSecurityManager;
public class security implements Testlet
{
public void test(TestHarness harness)
{
try {
harness.checkPoint("setup");
// we need a class with a different loader for most of the
// checks to occur.
Class testClass = new URLClassLoader(new URL[] {
new File(harness.getBuildDirectory()).toURL()}, null).loadClass(
getClass().getName());
harness.check(getClass().getClassLoader() != testClass.getClassLoader());
// Make sure everything's fully resolved, or we'll be loading
// classes during tests and the extra checks will make us fail.
testClass.getDeclaredClasses();
testClass.getDeclaredMethods();
// we need to restrict access to some packages for some of the
// checks to occur.
String oldrestrictions = Security.getProperty("package.access");
Security.setProperty(
"package.access",
"gnu.testlet.java.lang.Class.");
try {
Permission[] noChecks = new Permission[] { };
Permission[] getClassLoader = new Permission[] {
new RuntimePermission("getClassLoader")};
Permission[] accessDeclaredMembers = new Permission[] {
new RuntimePermission("accessDeclaredMembers"),
new RuntimePermission(
"accessClassInPackage.gnu.testlet.java.lang.Class")};
Permission[] accessPublicMembers = new Permission[] {
new RuntimePermission(TestSecurityManager3.publicPerm),
new RuntimePermission(
"accessClassInPackage.gnu.testlet.java.lang.Class")};
Permission[] getProtectionDomain = new Permission[] {
new RuntimePermission("getProtectionDomain")};
TestSecurityManager sm = new TestSecurityManager(harness);
try {
sm.install();
// throwpoint: java.lang.Class-forName
harness.checkPoint("forName");
try {
sm.prepareChecks(getClassLoader);
Class.forName("java.lang.Class", false, null);
sm.checkAllChecked();
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
// throwpoint: java.lang.Class-getClassLoader
harness.checkPoint("getClassLoader");
try {
sm.prepareChecks(getClassLoader);
testClass.getClassLoader();
sm.checkAllChecked();
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
// If it is a bootstrap class, there is a null classloader
// and no checks are necessary.
try {
sm.prepareChecks(noChecks);
Thread.class.getClassLoader();
sm.checkAllChecked();
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
// getDeclaredMember checks
getMemberChecks(harness, sm, testClass, true, accessDeclaredMembers);
// throwpoint: java.lang.Class-getProtectionDomain
harness.checkPoint("getProtectionDomain");
try {
sm.prepareChecks(getProtectionDomain);
testClass.getProtectionDomain();
sm.checkAllChecked();
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
try {
sm.prepareChecks(getProtectionDomain);
getClass().getProtectionDomain();
sm.checkAllChecked();
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
}
finally {
sm.uninstall();
}
// these tests need a modified security manager
sm = new TestSecurityManager3(harness);
try {
sm.install();
// getMember checks
getMemberChecks(harness, sm, testClass, false, accessPublicMembers);
}
finally {
sm.uninstall();
}
}
finally {
Security.setProperty("package.access", oldrestrictions);
}
}
catch (Exception ex) {
harness.debug(ex);
harness.check(false, "Unexpected exception");
}
}
private void getMemberChecks(TestHarness harness, TestSecurityManager sm,
Class testClass, boolean declared,
Permission[] mustCheck)
{
int level;
// throwpoint: java.lang.Class-getClasses
// throwpoint: java.lang.Class-getDeclaredClasses
if (declared)
harness.checkPoint("getDeclaredClasses");
else
harness.checkPoint("getClasses");
try {
sm.prepareChecks(mustCheck);
if (declared)
testClass.getDeclaredClasses();
else
testClass.getClasses();
sm.checkAllChecked();
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
// throwpoint: java.lang.Class-getFields
// throwpoint: java.lang.Class-getDeclaredFields
if (declared)
harness.checkPoint("getDeclaredFields");
else
harness.checkPoint("getFields");
try {
sm.prepareChecks(mustCheck);
if (declared)
testClass.getDeclaredFields();
else
testClass.getFields();
sm.checkAllChecked();
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
// throwpoint: java.lang.Class-getMethods
// throwpoint: java.lang.Class-getDeclaredMethods
if (declared)
harness.checkPoint("getDeclaredMethods");
else
harness.checkPoint("getMethods");
try {
sm.prepareChecks(mustCheck);
if (declared)
testClass.getDeclaredMethods();
else
testClass.getMethods();
sm.checkAllChecked();
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
// throwpoint: java.lang.Class-getConstructors
// throwpoint: java.lang.Class-getDeclaredConstructors
if (declared)
harness.checkPoint("getDeclaredConstructors");
else
harness.checkPoint("getConstructors");
try {
sm.prepareChecks(mustCheck);
if (declared)
testClass.getDeclaredConstructors();
else
testClass.getConstructors();
sm.checkAllChecked();
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
// throwpoint: java.lang.Class-getField
// throwpoint: java.lang.Class-getDeclaredField
if (declared) {
harness.checkPoint("getDeclaredField");
level = 0;
}
else {
harness.checkPoint("getField");
level = 3;
}
try {
for (int i = 0; i < modifiers.length; i++) {
for (int j = 0; j < 5; j++) {
sm.prepareChecks(mustCheck);
boolean exists;
try {
String name = modifiers[i] + "field" + j;
if (declared)
testClass.getDeclaredField(name);
else
testClass.getField(name);
exists = true;
}
catch (NoSuchFieldException e) {
exists = false;
}
sm.checkAllChecked();
harness.check(exists == (j > level));
}
}
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
// throwpoint: java.lang.Class-getMethod
// throwpoint: java.lang.Class-getDeclaredMethod
if (declared)
harness.checkPoint("getDeclaredMethod");
else
harness.checkPoint("getMethod");
try {
for (int i = 0; i < modifiers.length; i++) {
for (int j = 0; j < 5; j++) {
for (int k = 0; k < methodtypes.length; k++) {
sm.prepareChecks(mustCheck);
boolean exists;
try {
String name = modifiers[i] + "method" + j;
if (declared)
testClass.getDeclaredMethod(name, methodtypes[k]);
else
testClass.getMethod(name, methodtypes[k]);
exists = true;
}
catch (NoSuchMethodException e) {
exists = false;
}
sm.checkAllChecked();
harness.check(exists == (j > level && k > 0));
}
}
}
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
// throwpoint: java.lang.Class-getConstructor
// throwpoint: java.lang.Class-getDeclaredConstructor
if (declared) {
harness.checkPoint("getDeclaredConstructor");
level = 0;
}
else {
harness.checkPoint("getConstructor");
level = 6;
}
try {
for (int i = 0; i < constructortypes.length; i++) {
sm.prepareChecks(mustCheck);
boolean exists;
try {
if (declared)
testClass.getDeclaredConstructor(constructortypes[i]);
else
testClass.getConstructor(constructortypes[i]);
exists = true;
}
catch (NoSuchMethodException e) {
exists = false;
}
sm.checkAllChecked();
harness.check(exists == (i > level));
}
}
catch (SecurityException ex) {
harness.debug(ex);
harness.check(false, "unexpected check");
}
}
// Data tables for get{,Declared}{Field,Method,Constructor} checks
private static String[] modifiers = new String[] {"", "static"};
private static Class[][] methodtypes = new Class[][] {
new Class[] {short.class},
new Class[] {},
new Class[] {int.class},
new Class[] {String.class, boolean.class}};
private static Class[][] constructortypes = new Class[][] {
new Class[] {short.class},
new Class[] {int.class},
new Class[] {String.class, int.class},
new Class[] {int.class, int.class},
new Class[] {byte.class},
new Class[] {String.class},
new Class[] {int.class, String.class},
new Class[] {int.class, int.class, int.class},
new Class[] {}};
// Fields for getField and getDeclaredField checks
private boolean field1;
byte field2;
protected int field3;
public String field4;
private static boolean staticfield1;
static byte staticfield2;
protected static int staticfield3;
public static String staticfield4;
// Methods for getMethod and getDeclaredMethod checks
private void method1() {}
private void method1(int a) {}
private void method1(String b, boolean c) {}
char method2() { return 'a'; }
char method2(int a) { return 'b'; }
char method2(String b, boolean c) { return '1'; }
protected String method3() { return "x0x"; }
protected String method3(int a) { return "y"; }
protected String method3(String b, boolean c) { return "z"; }
public int method4() { return 1; }
public int method4(int a) { return 0; }
public int method4(String b, boolean c) { return -5; }
private static void staticmethod1() {}
private static void staticmethod1(int a) {}
private static void staticmethod1(String b, boolean c) {}
static char staticmethod2() { return 'a'; }
static char staticmethod2(int a) { return 'b'; }
static char staticmethod2(String b, boolean c) { return '1'; }
protected static String staticmethod3() { return "x0x"; }
protected static String staticmethod3(int a) { return "y"; }
protected static String staticmethod3(String b, boolean c) { return "z"; }
public static int staticmethod4() { return 1; }
public static int staticmethod4(int a) { return 0; }
public static int staticmethod4(String b, boolean c) { return -5; }
// Constructors for getConstructor and getDeclaredConstructor checks
private security(int a) {}
private security(String a, int b) {}
security(int a, int b) {}
security(byte a) {}
protected security(String a) {}
protected security(int a, String b) {}
public security(int a, int b, int c) {}
public security() {}
// The default implementation of SecurityManager.checkMemberAccess()
// checks no permissions if memberType is Member.PUBLIC. This class
// changes this, allowing us to test get{Field,Method,Constructor}.
// No other tests should use this class.
private static class TestSecurityManager3 extends TestSecurityManager
{
TestSecurityManager3(TestHarness harness)
{
super(harness);
}
static String publicPerm = "gnuAccessPublicMembers";
public void checkMemberAccess(Class c, int memberType)
{
if (c == null)
throw new NullPointerException();
if (memberType == Member.PUBLIC)
checkPermission(new RuntimePermission(publicPerm));
}
}
// Silence compiler warnings
public void shutUp()
{
field1 = staticfield1 = false;
new security(5).method1();
new security("hello", 5).method1(5);
method1("4", field1);
staticmethod1();
staticmethod1(5);
staticmethod1("4", staticfield1);
}
}