Java security evolution and concepts, Part 4

Learn how optional packages extend and enhance Java security

Early on, Java security focused on resisting executable content threats -- security risks caused by malicious or poorly programmed code. In this series's previous articles, we saw how Java security evolved to provide security based on the code's origination and who had signed it. Java security has since evolved further.

Java security evolution and concepts: Read the whole series!

In this article, the fourth and last in the series, I will cover Java's optional security packages, which focus on resisting distributed system threats. I will show how to use a strong encryption framework, even outside the US thanks to recent favorable changes in US export control laws. I'll also discuss Pluggable Authentication Modules (PAM) for custom authentication, as well as communicating with confidentiality and integrity using the Secure Socket Layer (SSL).

Further, we'll see simple code samples and follow through with the example we looked at in Part 3. We will enhance that example to also read from an SSL socket, not necessarily from the same system to which it made an HTTP connection.

The optional packages we will discuss comprise:

  • Java Authentication and Authorization Service (JAAS): A framework for user-based authentication
  • Java Cryptography Extension (JCE): A framework for using strong ciphers on a global basis
  • Java Secure Socket Extension (JSSE): An extension for SSL and Transport Layer Security (TLS) support

See "Sidebar 1: Install the Optional Java Security Packages" for general guidelines to install JAAS, JCE, and JSSE. This security series does not intend to provide a comprehensive guide to computer security. Computer security is a multifaceted issue touching several disciplines, departments, and cultures. Investments in technologies should be followed up with investments in personnel training, strict policy enforcement, and periodic review of the overall security policy.

So, let's get to it.

Note: This article features a running Java applet designed to demonstrate applet security issues. Read below for more details.

Java Authentication and Authorization Service (JAAS)

In the earlier articles we examined Java security as focused on the CodeSource property, which is a combination of where the code originated (URL) and who signed it (certificates). This CodeSource-based access control lacks the ability to enforce access based on who is running the code. JAAS supplements the Java 2 security architecture by providing a framework to do so, as illustrated in Figure 1.

Figure 1. JAAS: User-based authentication framework. (Source: Sun Microsystems)

We will examine JAAS's common classes, as well as classes from its two main components: authentication and authorization.

JAAS authentication

JAAS authentication is performed in a pluggable fashion -- illustrated in Figure 2 -- permitting Java applications to remain independent from underlying authentication technologies. Applications enable the authentication process by instantiating a LoginContext object, which in turn references a Configuration to determine the authentication technology, or LoginModule, to perform the authentication. Typical LoginModules may prompt for and verify a username and password. More sophisticated authentication schemes may read and verify a voice or a fingerprint, for example. Later we will examine how multiple authentication schemes can also provide for stack-based authentication.

Figure 2. JAAS: Pluggable authentication. (Source: Sun Microsystems)

Modules can be configured via configuration files. A sample entry might look like:

Login1 {
    sample.SampleLoginModule required debug=true;
};

In this case, only one module performs the authentication. An attempt by Login1 to authenticate a Subject will succeed if and only if the SampleLoginModule succeeds.

In the code above, required represents a LoginModuleControlFlag. Let's look at required and its fellow LoginModuleControlFlags in more detail:

  • required: In this case, the login module must succeed. Regardless of whether it succeeds or fails, however, authentication still proceeds down the login module list.
  • requisite: The login module must succeed. If login succeeds, authentication continues down. However, if it fails, control returns immediately to the application.
  • sufficient: The module doesn't have to succeed. If it does succeed, control immediately returns to the application.
  • optional: This login module doesn't have to succeed. Whether it succeeds or fails, authentication still proceeds down the login module list.

Stacked authentication can be achieved by a configuration policy containing multiple modules. Here's an example:

Login2 {
    sample.SampleLoginModule required;
    com.sun.security.auth.module.NTLoginModule sufficient;
    com.foo.SmartCard requisite debug=true;
    com.foo.Kerberos optional debug=true;
};

Overall authentication is governed by the individual modules and their LoginModuleControlFlag entry, as illustrated in Table 1. In the figure, p indicates pass, f indicates fail, and * indicates don't care entries.

Table 1. Overall authentication for a stack-based authentication policy
ModuleCriterionPass/Fail
SampleLoginModuleRequiredp p p p f f f f
NTLoginModuleSufficientp f f f p f f f
SmartCardRequisite* p p f * p p f
KerberosOptional* p f * * p f *

Overall

authentication

p p p f f f f f

JAAS authorization

Once the user executing the code has been authenticated, the JAAS authorization component works in conjunction with the existing Java 2 CodeSource-based access control model. JAAS policy extends the Java 2 policy with the relevant Subject-based information. Therefore, permissions recognized and understood in Java 2 (java.io.FilePermission and java.net.SocketPermission, for example) are equally understood and recognized by JAAS. Although the JAAS security policy physically resides separately from the existing Java 2 security policy, the two policies should be treated as one logical policy.

A policy file syntax -- an extension to the Java 2 policy file -- looks like:

grant signedBy "alias", codeBase "URL",
    principal principalClass "principalName",
    principal principalClass "principalName",
    ... {
    permission Type "name "action", 
        signedBy "alias";
    permission Type "name "action",
        signedBy "alias";
    ....
    };

Here's an example entry:

    grant CodeBase "http://foo.com",
        Signedby "foo",
        Principal com.sun.security.auth.NTPrincipal "admin" {
            permission java.io.FilePermission "c:/user/admin", "read, write";
    };

Notice that the policy file entries include a Principal entry, the basis for user-based authentication.

JAAS classes

The JAAS classes and interfaces reside in the following packages:

  • javax.security.auth
  • javax.security.auth.callback
  • javax.security.auth.login
  • javax.security.auth.spi

The classes and interfaces can be categorized as:

  • Common classes:
    • Subject
    • Principal
    • Credential
  • Authentication classes:
    • LoginContext
    • LoginModule interface
    • Callback
    • CallbackHandler
  • Authorization classes:
    • Policy
    • AuthPermission
    • PrivateCredentialPermission

Let's examine a few of the important classes and interfaces in more detail.

A Subject may be any entity, such as a person or service. Once authenticated, a Subject is populated with associated identities, or Principals. A Subject may have many Principals. For example, a person may have a name Principal ("Jane Doe") and a Social Security Number Principal ("111-22-3333"), that distinguish it from other Subjects. The getPrincipals() method retrieves the Principals associated with a Subject. The static method doAs() in Subject achieves the effect of having an action run as the subject. Based on whether this action is authorized, the action completes successfully or generates an exception.

The LoginContext class provides the basic methods to authenticate Subjects and a way to develop an application independent of the underlying authentication technology using a configuration file (which we studied above). Actual authentication occurs with a call to the login() method.

Moving on, the LoginModule interface allows you to implement various authentication technologies that can be plugged under an application. Its important methods include:

  • login()
  • commit()
  • abort()
  • logout()

Next, the CallbackHandler communicates with the user to obtain authentication information using callbacks.

Finally, the abstract Policy class represents the system-wide JAAS access-control policy.

JAAS programming model

Having looked at the JAAS classes briefly, let's try to build a LoginModule.

To authenticate and authorize a Subject, these steps are performed:

  • An application instantiates a LoginContext.
  • The LoginContext consults a Configuration file, along the lines of ones discussed above, to load the LoginModules configured for that application.
  • The application invokes the LoginContext's login() method.
  • The login() method invokes the loaded LoginModules. Each LoginModule attempts to authenticate the Subject. Upon success, LoginModules associate relevant Principals and credentials with the Subject.
  • The LoginContext returns the authentication status to the application.
  • If authentication succeeds, the application retrieves the authenticated Subject from the LoginContext.
  • Upon successful authentication of a Subject, fine-grained access controls can be placed upon that Subject by invoking the Subject.doAs() methods. The permissions granted to that Subject are configured in a JAAS policy.

The following code outline illustrates how application code uses the JAAS framework:

    // Instantiate a login context
    LoginContext context = new LoginContext("name", CallbackHandler);
    // Authenticate the subject
    context.login();
    // Retrieve the authenticated subject
    Subject subject = context.getSubject();
    // Enforce Access Controls
    Subject.doAs(subject, action);

To implement a new login module, follow these suggested steps:

  • Understand the authentication technology
  • Name the LoginModule implementation
  • Implement the abstract LoginModule method
  • Compile the LoginModule
  • Configure and test the LoginModule
  • Document and package the LoginModule implementation

JAAS example program

The JAAS 1.0 kit includes a sample program. We will discuss the program without including the code. To run the sample, refer to the kit's policy files, command lines, and other relevant material.

The sample program first instantiates a LoginContext. The LoginContext consults the login configuration, which in this example points to a single module: SampleLoginModule. The SampleLoginModule, loaded to perform the authentication, prompts for a username and password. Entering "testUser" for the username and "testPassword" for the password, the SampleLoginModule associates a SamplePrincipal (with "testUser" as its name) with the current Subject, and then executes the SampleAction as that Subject (by calling Subject.doAs).

The SampleAction, a privileged action, attempts to access two System properties (java.home and user.home), and also attempts to access the file foo.txt in the current working directory. This process will succeed only for the appropriate users, thereby accomplishing user-based authentication.

Java Cryptography Extension (JCE)

As we saw in the previous section, JAAS supplements Java core security by providing a framework for user-based authentication and authorization. Along the same lines, JCE enhances core security by adding support for encryption, key generation and key agreement, and Message Authentication Code (MAC) algorithms. JCE supplements the algorithms available in core Java security such as digital signatures or one-way hash functions. JCE extends the Java Cryptography Architecture (JCA), with which it is possible to use multiple CSPs (Cryptography Service Provider), thereby promoting implementation independence, as seen in Figure 3.

Figure 3. Java Cryptography Extension. (Source: Sun Microsystems)

The reference implementation, SunJCE provider, supports the following ciphers and MACs:

  • DES
  • DESede
  • Blowfish
  • PBEWithMD5AndDES
  • PBEWithMD5AndTripleDES
  • Diffie-Hellman key agreement among multiple parties
  • HMACMD5
  • HMACSHA1

With JCE 1.2.1, the framework is exportable outside the US and Canada, enabled by mechanisms JCE implements to ensure that only qualified providers can be plugged in. The cryptographic strength can be controlled in the jurisdiction policy files. Several clean-room JCE 1.2 implementations exist as well (see Resources).

JCE classes

JCE's classes and interfaces exist in the following packages:

  • javax.crypto
  • javax.crypto.interfaces
  • javax.crypto.spec

The classes and interfaces in javax.crypto.spec provide key and parameter specifications for the different algorithms like DES, Diffie-Hellman, and so on.

Additionally, JCE employs a number of classes in java.security, including:

  • Cipher
  • Mac
  • Cipher stream classes comprising CipherInputStream and CipherOutputStream
  • KeyGenerator
  • SecretKeyFactory
  • SealedObject
  • KeyAgreement

We will take a look at some of these classes later.

The package javax.crypto.interfaces contains interfaces to the Diffie-Hellman key.

1 2 3 4 Page 1
Page 1 of 4