Security Considerations

   

Reflection involves substantial discovery at runtime about code that has been loaded into the virtual machine. For an application such as an integrated development environment (IDE), virtually every aspect of a class must be accessible through Reflection to satisfy the needs of the program. However, from earlier chapters, you have seen that access to, and knowledge of, the methods and fields of a class are restricted through the use of access specifiers. Some of the uses of Reflection require that these restrictions be suspended , but this is done in a secure way.

The Java 2 security mechanisms are central to allowing or disallowing Reflection access to a requestor .

The Java 2 security model prevents classes that don't have access to methods, fields, constructors, and so on from being able to see them. In particular, the checkMemberAccess method of SecurityManager has the capability to grant or refuse access to the nonpublic members of a class. For example, when a method is called on a class that would cause an instance of the Method class to be created (the Method, Field, and Constructor classes do not have public constructors and can only be instantiated by java.lang.Class ), it first queries the SecurityManager to determine if providing the requesting class what it is asking for is allowed. Say you have a scenario in which the object Requestor wants to know what constructors are available in the class Provider. To do this, you might create two classes like those in Listing 28.1.

Listing 28.1 Requestor Class Requests Constructor Information from the Provider Class
 /* * Requestor */ import java.lang.reflect.*; public class Requestor {   public void requestConstuctors() {     try {       // load the Provider class and use Reflection       // to get an array of constructor information       Constructor con[]= Class.forName("Provider").getDeclaredConstructors();       for (int x=0; x<con.length; x++)         System.out.println("Constructor " + x + " = " + con[x]);     }     catch (ClassNotFoundException ce) {       // Class.forName was unable to load Provider.class       System.out.println("Could not locate class");     }     catch (SecurityException se) {       // Reflection permission was not granted       System.out.println("Not allowed to get class info");     }   }   public static void main(String args[]) {      // construct a Requestor and ask it for the      // constructors declared by Provider      Requestor req = new Requestor();      req.requestConstuctors();   } } /*  *  Provider */ class Provider {   public Provider(String s) {   }   private Provider(int i) {   } } 

After you compile these classes, which should be placed in a source file named Requestor.java, you can then run the Requestor program. The output you get looks like this:

 Constructor 0 = private Provider(int) Constructor 1 = public Provider(java.lang.String) 

The implementation of requestConstructors in Listing 28.1 introduces the static forName method of Class. This method instructs the class loader to load the class or interface with the name given by its argument and then returns a corresponding Class object. As shown here, the getDeclaredConstructors method of Class returns all constructors declared in a class, regardless of access restriction. This assumes of course that the required permissions exist.

Note

Class is not restricted to representing only classes. One of its instances could also represent an interface, an array, a primitive type, or the keyword void. Every class must have at least one constructor, so if getDeclaredConstructors returns an empty array as its result, the Class instance being used must be associated with one of the other supported entities. To determine this at runtime, you can call the isInterface, isArray, and isPrimitive methods of Class that each return a boolean result.


Troubleshooting Tip

If you have trouble inspecting the characteristics of a Class instance, see "No Class Members Reflected" in the "Troubleshooting" section at the end of this chapter.


This type of information about a class could not be retrieved in Java without Reflection. Under other languages, such as C/C++, access to methods can be accomplished using method pointers. Because Java has no pointers, it's necessary to have the Reflection model to gain access to methods at runtime.

The example in Listing 28.1 shows a catch clause for a SecurityException. This is not a checked exception, so this catch is not required, but it's included to illustrate what is happening. Notice that Requestor was able to access a private constructor. This requires the approval of the SecurityManager. If this request had been denied , a SecurityException would have been thrown.

The complete details of the Java 2 security model are beyond the scope of this chapter, but some of the details here do illustrate some of the core concepts. Java security is largely permissions based. The access a class has to a particular method of another class is determined by the permissions it has.

The permission suppressAccessChecks of the ReflectPermission class is the one that is most interesting within this discussion. A class that has this permission grants Reflection privileges to classes that would not have them by default. Classes are given this permission through the use of a policy file. The other key class related to Reflection and security is AccessibleObject, which is the superclass of Field, Method, and Constructor. This class allows a reflected object to be used in a manner that suppresses all normal access checks. For more information on the Java 2 security model, refer to Sun's documentation available at http://java.sun.com/security/.

   


Special Edition Using Java 2 Standard Edition
Special Edition Using Java 2, Standard Edition (Special Edition Using...)
ISBN: 0789724685
EAN: 2147483647
Year: 1999
Pages: 353

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net