Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional Java.JDK.5.Edition (Wrox)

.pdf
Скачиваний:
31
Добавлен:
29.02.2016
Размер:
12.07 Mб
Скачать

Chapter 13

NAME {

LoginModuleClass FLAG ModuleOptions;

LoginModuleClass FLAG ModuleOptions;

}

The LoginModuleClass is the fully qualified name of a LoginModule. The FLAG can be one of the values in the following table.

Flag Name

Description

 

 

Required

The LoginModule is required to succeed; however, if it fails, LoginModules

 

specified after the current one still execute.

Requisite

The LoginModule is required to succeed. If it fails, control returns to the appli-

 

cation. No further LoginModules are executed.

Sufficient

The LoginModule is not required to succeed. If the LoginModule succeeds,

 

control is immediately returned to the application. Control passes down the

 

list of LoginModules even if this one fails.

Optional

The LoginModule is not required to succeed, and control passes down the list

 

if this one succeeds or fails.

 

 

The ModuleOptions is a space-separated list of login module-specific name=value pairs.

LoginContext

The LoginContext class provides a clean approach to authenticating subjects while leaving the authentication details to LoginModules. This makes it easy to change the configuration for an application by adding or removing a LoginModule. The LoginContext class provides the following constructors:

public LoginContext(String name) throws LoginException

public LoginContext(String name, Subject subject) throws LoginException public LoginContext(String name, CallbackHandler callbackHandler)

throws LoginException

public LoginContext(String name, Subject subject, CallbackHandler callbackHandler)

throws LoginException

The name parameter corresponds to an entry in the configuration used for the application. The first and third forms of the constructor create an empty subject because one isn’t passed in. If a LoginModule has to communicate with the user, it can do so through a CallbackHandler. For example, if a username and password are required, a class can inherit from javax.security.auth.callback.CallbackHandler and retrieve the information from the user. The CallbackHandler interface defines a single method:

void handle(Callback[] callbacks)

throws java.io.IOException, UnsupportedCallbackException

One or more callbacks can be specified, allowing you to separate username and password entries into two separate callbacks all managed by a single CallbackHandler.

616

Java Security

The LoginContext also provides login and logout methods:

public void login() throws LoginException

This method causes all configured LoginModules to authenticate the subject. If authentication succeeds, you can retrieve the subject via getSubject(). The subject may have revised credentials and principals after all authentication is performed:

public void logout() throws LoginException

The logout method removes credentials/principals from the authenticated subject.

Essentially, the code used for an application to log in, obtain an authenticated subject, and then log out looks like the following snippet of code:

LoginContext loginContext = new LoginContext(“BasicConsoleLogin”);

try {

loginContext.login(); // utilizes callbacks Subject subject = loginContext.getSubject();

// ... execute specific application code here ...

loginContext.logout();

}catch(LoginException le) {

//authentication failed

The LoginContext retrieves the set of LoginModules to execute from the configuration under the name BasicConsoleLogin.

Authorization

Authentication provides for more of a black-and-white approach to security. The user (or other entity) is either authenticated or not. JAAS provides authorization for granting degrees of access to an entity. Each application can use a policy file that contains a list of permissions for various targets. The policy file provides a way to grant permissions to both code and principals.

The javax.security.auth.AuthPermission class exists to guard access to the Policy, Subject, LoginContext, and Configuration objects, providing a layer of security on these classes as well. Consult the documentation for this class for a full list of permissions that it provides.

The policy file contains a list of grant sections that grant permissions to code or principals. The grant keyword is used to start a grant section, followed by zero or more optional elements: signedBy, codeBase, and principal. The basic format looks like the following:

grant signedBy “signer_names”, codeBase “URL”,

principal principal_class_name “principal_name”, principal principal_class_name “principal_name”,

617

Chapter 13

... {

permission permission_class_name “target_name”, “action”, signedBy “signer_names”;

permission permission_class_name “target_name”, “action”, signedBy “signer_names”;

...

};

You can only specify signedBy and codeBase a maximum of one time, but the principal element can be specified more than once. All of these are optional elements. By not specifying any at all, the permissions specified apply to all executing code, regardless of its source.

As one example of a policy file, the java.policy that is located in the jre/lib/security directory that comes with JDK 5 has a policy that opens permissions wide to Java extensions:

grant codeBase “file:${{java.ext.dirs}}/*” {

permission java.security.AllPermission;

};

The codeBase element is used to specify all code that is located in the java.ext.dirs (a system property) directory, which hence grants AllPermission to all code in the Java extensions directory.

The signedBy element is used to grant permissions only when the code is signed by the specified entity.

There are many available permissions in the Java API, such as java.io.FilePermission, java.net

.NetPermission, and java.security.AllPermission. Each permission has its own set of actions, such as FilePermission, needing to know which operations are valid on a particular file (read, write, and so forth). Consult the online documentation for specific details on each permission.

Summar y

In this chapter, you learned about Java Cryptography and Security. Security is very important in online systems and systems that have multiple users. You now know some of the basics of security, such as generating and using keys, including digital signing and key management. You have seen how Java supports a variety of security mechanisms from data encryption to access control, and you have an overview of how to go about securing your application.

618

Packaging and Deploying

Your Java Applications

This chapter describes how to package and deploy your Java applications including client-side and server-side applications. It discusses technologies like Java Web Start, JAR packaging, JAR signing, building WAR files, and CLASSPATH manipulation. You’ll walk through the different types of Java applications and get a brief introduction to each as well as information on a few useful utilities that you can use when creating, configuring, and deploying your own applications.

Examining Java CLASSPATHs

One of the most potentially frustrating aspects of Java is the classpath. If you have coded in Java even for a short length of time, you’re already familiar with the classpath. It is a system environment variable that directs the Java Virtual Machine (VM) to a set of classes and/or JAR files. This is how the VM knows where code used by the program resides.

At times, you wind up needing a class and have no idea which JAR file has this class. You might add a bunch of JAR files to your classpath, hoping you’ll accidentally add the right one in, never truly knowing which JAR files are not needed. Many people complain about DLL Hell on Windows, but a similar mismanagement of the classpath and the many files it points to can create the same situation with Java. If you use a development environment such as Eclipse, you are somewhat insulated from this problem because it is easy to manage your classpath through the GUI. However, in a deployment scenario, you may not have the luxury of a graphical tool to help manage the classpath. A seemingly small problem (one JAR left off the classpath, for example) may take seconds to fix if you know where the class is, or — if you don’t know — much longer.

Another problem with classpaths is length limits on the classpath environment variable imposed by the environment. I’ve seen more than one project with an insane number of JAR files (each with a long path) specified within the classpath. Sometimes, there is no great solution to this problem.

Chapter 14

If the classpath works and nobody needs to tweak it after deployment, you should be fine. However, long classpaths are troublesome during development and might even grow too long for the environment space after deployment.

Here are a few suggestions to attempt to manage long classpaths. First, know where your application is executing from and utilize relative paths instead of absolute paths. Second, attempt to group your application and its libraries into as few JAR files as possible. A more complicated but useful solution is grouping the common utility JAR files (perhaps third-party JAR files used by your application) and placing these in the extensions directory within the installed JRE. By default, this extensions directory is lib/ext beneath the JRE directory. By installing a JAR file as an extension, it no longer needs to appear on the classpath. You must ensure that the JAR file is placed within the correct JRE though. This might entail you installing your own JRE with your application, but this too cannot be done lightly. Utilizing the extensions directory is not a great idea because you are technically not extending the Java environment, but it is one solution to consider in managing a classpath that is too long.

In hoping to alleviate your burden a little, here are a couple of utility programs that may help you in managing your classpath. The first class is a straightforward utility that accepts a list of classes stored inside a file and verifies that each class is present somewhere within the classpath (or in one of the JAR files in the classpath). The file containing the class list is passed in on the command line. Each line in the file contains a single fully qualified class name:

import java.io.*;

public class ClassPathVerifier {

public static void main(String args[])

{

try {

BufferedReader br = new BufferedReader(

new InputStreamReader(

new FileInputStream(args[0])));

String clsName=””;

while( (clsName = br.readLine()) != null) { try {

Class.forName(clsName);

System.out.print(“.”); } catch(Exception e) {

System.out.println(“\nNOT FOUND: “ + clsName);

}

}

br.close();

} catch(IOException ioe) { System.out.println(“IOException: “ + ioe); ioe.printStackTrace();

}

}

}

This class uses the simple technique of passing a class name into the Class.forName method. If no exception is thrown, the class is found. In order to show progress, a single period is printed for each class that is successfully loaded. If you manage multiple classpaths, this utility can be used to ensure that a set of classes is always available.

620

Packaging and Deploying Your Java Applications

A utility that packs more of a punch is listed next. The purpose of this next utility is to find which JAR file(s) a class is inside. You need not specify a fully qualified class name — any portion of the class name and package will do. This means that you can even search for a package instead of a particular class:

import java.io.*; import java.util.zip.*;

import java.util.StringTokenizer;

public class ClassSearch {

private String m_baseDirectory; private String m_classToFind; private int m_resultsCount=0;

A very interesting method that uses a bit more complex code is the searchJarFile. This method, shown in the following example, actually opens a JAR file and searches inside it for a given class name:

public void searchJarFile(String filePath)

{

try {

FileInputStream fis = new FileInputStream(filePath); BufferedInputStream bis = new BufferedInputStream(fis); ZipInputStream zis = new ZipInputStream(bis);

ZipEntry ze = null;

while((ze=zis.getNextEntry()) != null) { if(ze.isDirectory()) {

continue;

}

if(ze.getName().indexOf(m_classToFind) != -1) {

System.out.println(“

“ + ze.getName() +

“\n

(inside “ + filePath + “)”);

m_resultsCount++;

 

}

 

}

} catch(Exception e) { System.out.println(“Exception: “ + e); e.printStackTrace();

}

}

The findHelper method searches directories and subdirectories for JAR files:

public void findHelper(File dir, int level)

{

int i;

File[] subFiles;

subFiles = dir.listFiles();

for(i=0; i<subFiles.length; i++) { if(subFiles[i].isFile()) {

if(subFiles[i].getName().toLowerCase().indexOf(“.jar”) != -1) { // found a jar file, process it

621

Chapter 14

searchJarFile(subFiles[i].getAbsolutePath());

}

}else {

//directory, so recur

findHelper(subFiles[i], level+1);

}

}

}

The method searchClassPath is used to find a class in the JAR files specified in the given classpath:

public void searchClassPath(String classToFind)

{

String classPath = System.getProperty(“java.class.path”); System.out.println(“Searching classpath: “ + classPath); StringTokenizer st = new StringTokenizer(classPath, “;”);

m_classToFind = classToFind;

while(st.hasMoreTokens()) {

String jarFileName = st.nextToken(); if(jarFileName != null &&

jarFileName.toLowerCase().indexOf(“.jar”) != -1) { searchJarFile(jarFileName);

}

}

}

The findClass method is kicked off from the main method and takes two parameters. One parameter is the base directory that will be used as a starting point to begin the class search. The second parameter is the class name that you are looking for. If the class name is found in any JAR files that exist in the base directory or its subdirectories, the JAR filename and location are printed out to the console:

public void findClass(String baseDir, String classToFind)

{

System.out.println(“SEARCHING IN: “ + baseDir); m_baseDirectory = baseDir;

m_classToFind = classToFind;

m_classToFind = m_classToFind.replaceAll(“\\.”, “/”);

File start = new File(m_baseDirectory);

System.out.println(“SEARCHING FOR: “ + m_classToFind);

System.out.println(“\nSEARCH RESULTS:”);

findHelper(start, 1);

if(m_resultsCount == 0) { System.out.println(“No results.”);

}

}

622

Packaging and Deploying Your Java Applications

The main method shown in the following example is the driver method of the utility class and takes a base directory and class name for which to search:

public static void main(String args[])

{

if(args.length < 1 || args.length > 2) { System.out.println(“Incorrect program usage”);

System.out.println(“

java ClassSearch <base directory>” +

“ <class to find>\n”);

System.out.println(“

searches all jar files beneath base” +

“ directory for class\n”); System.out.println(“”);

System.out.println(“

java ClassSearch <class to find>\n”);

System.out.println(“

searches all jar files in classpath” +

“ for class\n”);

System.exit(1);

}

ClassSearch cs = new ClassSearch();

if(args.length == 1) { cs.searchClassPath(args[0]);

} else if(args.length == 2) { cs.findClass(args[0], args[1]);

}

}

}

This class uses the zip library in Java along with the directory search facilities of the File class to search for a class/package specified on the command line. An alternate usage allows you to search for a class within the JAR files listed in the classpath. This allows you to find every JAR file that has a class, which thus resolves a mess in the classpath. Here’s an example usage of the program. This assumes that the JDK is installed in D:\j2sdk1.5.0:

D:\writing\code>java ClassSearch d:\j2sdk1.5.0 ArrayList

SEARCHING IN: d:\j2sdk1.5.0

SEARCHING FOR: ArrayList

SEARCH RESULTS: java/util/Arrays$ArrayList.class

(inside d:\j2sdk1.5.0\jre\lib\rt.jar) java/util/concurrent/CopyOnWriteArrayList$1.class

(inside d:\j2sdk1.5.0\jre\lib\rt.jar) java/util/concurrent/CopyOnWriteArrayList$COWIterator.class

(inside d:\j2sdk1.5.0\jre\lib\rt.jar) java/util/concurrent/CopyOnWriteArrayList$COWSubList.class

(inside d:\j2sdk1.5.0\jre\lib\rt.jar) java/util/concurrent/CopyOnWriteArrayList$COWSubListIterator.class

(inside d:\j2sdk1.5.0\jre\lib\rt.jar) java/util/concurrent/CopyOnWriteArrayList.class

(inside d:\j2sdk1.5.0\jre\lib\rt.jar) sun/swing/BakedArrayList.class

(inside d:\j2sdk1.5.0\jre\lib\rt.jar) java/util/ArrayList.class

(inside d:\j2sdk1.5.0\jre\lib\rt.jar)

623

Chapter 14

This execution of the utility shows the various ArrayList classes in the various packages inside the core runtime JAR that comes with every JRE. If you search for a more obscure class, such as

ByteToCharDBCS_EBCDIC, you’ll find the charsets.jar file in your search results. This utility can be used to find which JAR file a class is in but also every JAR file that contains this class. You can find a class you need or resolve classpath confusion if the same class is in a number of JAR files and an older version of a class you developed is being used although you’ve specified the newer version on the command line.

Investigating the Endorsed Director y

In an installation of a Java Runtime Environment, there are packages that are not part of the standard Java API. These packages are common third-party libraries and are considered endorsed, which means they are distributed as an extension to the Java API. One example of an endorsed package is the org.omg.CORBA package providing CORBA functionality. Because these packages are available to Java programs, it is possible that there is a conflict when you distribute third-party libraries that already exist in the endorsed directory. Java provides a mechanism called the Endorsed Standard Override Mechanism, which gives you a way to install newer versions of libraries in the endorsed directory.

In order to override the endorsed standards, place JAR files in the endorsed directory within the JRE. This directory is named endorsed and is located in the JRE installation beneath the lib directory, both on Windows and on Unix. If you have multiple JREs or JDKs installed, make sure you place the JAR files in the correct endorsed directory such that the VM that executes will recognize these JAR files. If you want to use a different directory for overriding the endorsed standards, specify it in the java.endorsed.dirs system property. In this property, you can list one or more directories that have JAR files you wish to use. These directories are delimited by the value of the File.pathSeparatorChar, which is system-specific.

There is a fixed list of standard API’s that you can override, shown in the following table. Note that you cannot arbitrarily override a package in the standard Java API.

Packages that Can Be Overridden

Packages that Can Be Overridden

 

 

javax.rmi.CORBA

org.omg.DynamicAny

org.omg.CORBA

org.omg.DynamicAny.DynAnyFactoryPackage

org.omg.CORBA.DynAnyPackage

org.omg.DynamicAny.DynAnyPackage

org.omg.CORBA.ORBPackage

org.omg.IOP

org.omg.CORBA.portable

org.omg.IOP.CodecFactoryPackage

org.omg.CORBA.TypeCodePackage

org.omg.IOP.CodecPackage

org.omg.CORBA_2_3

org.omg.Messaging

org.omg.CORBA_2_3.portable

org.omg.PortableInterceptor

org.omg.CosNaming

org.omg.PortableInterceptor.ORBInitInfoPackage

org.omg.CosNaming.NamingContextExtPackage

org.omg.PortableServer

org.omg.CosNaming.NamingContextPackage

org.omg.PortableServer.CurrentPackage

org.omg.Dynamic

 

 

 

624

Packaging and Deploying Your Java Applications

Exploring Java Archives

Java wouldn’t be where it is today without the creation of its archive file format. The JAVA archive, which programmers generally refer to as a JAR file, is a way to bundle multiple files, including other JARs, into a single file that is suffixed with the .jar extension. JAR files use the same format to compress their files as those of the zip format. So, you can open a JAR file in a program that understands the normal zip compression and edit away. This makes the format of JAR files very portable across different operating systems because most operating systems understand the zip format or have utilities that were created for them to manipulate zip files. JAR files can greatly reduce the download time of classes, images, audio, and other large files by compressing them. Applets and their resources can be compressed into a JAR file, significantly reducing the amount of time it takes to download the applet.

JAR files can also be digitally signed for architectures that require a substantial amount of security requirements to be imposed on the applications being constructed. By digitally signing a JAR file, you can always tell who the author of the JAR file was and if it has been tampered with. In Java 5, there have been two new enhancements of the JAR format:

Faster access to the contents of JAR files has been accomplished with a new parameter addition, -i, to the command-line JAR tool that allows you to create a JAR file index.

A new API has been added for the delete-on-close mode that is used when opening JAR files.

The major feature that separates the JAR file from a normal zip file is that of its manifest file that is contained in the JAR files META-INF directory. The manifest file allows you to invoke special features like package sealing and the ability to specify the JAR as an executable JAR file. The manifest file is similar to the format of a properties file in that it accepts NAME-VALUE pair entries that are used for changing specific settings about the JAR file. Along with the manifest file, there are also other files that can be created in the META-INF directory of a JAR file. More about this subject will be discussed subsequently. The new Java 5 allows you to include an INDEX.LIST in the META-INF directory, which is automatically generated when you invoke the JAR tool and specify the -i option. This allows for quicker class loading times.

Manipulating JAR files

The Java Development Kit (JDK) contains a command-line tool called the Java Archive Tool that is used to create JAR files via the command line. You execute the JAR tool by simply typing jar at a console window. If you can’t get the tool to run, it’s most likely that you don’t have Java set up correctly for your environment. Reread the install instructions for your environment that comes with your JDK. You can always run the tool from the JDK/BIN directory, but it is highly recommended that you adjust your environment so that you can run the tool from almost anywhere. The correct syntax for executing the JAR tool is shown in the following example:

jar {ctxu}[vfm0Mi] [jar-file] [manifest-file] [-C dir] files ...

Before you create your first JAR file, it is important to understand the options that can be used to create a JAR file. Otherwise, it will seem like a big mystery as to why certain options were chosen to create the JAR file. The following table lists the options and a description of the options for the JAR tool.

625

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]